Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0e7a338e authored by Sunny Goyal's avatar Sunny Goyal
Browse files

Fixing SecondaryDisplay Launcher

> All apps layout broken in landscpae UI
> Crash when manager profile is added
> Wrong icon size on low resolution

Change-Id: If01dacf9f62a0384ebd8b31b62500178416d3ab4
parent 8451542a
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -17,7 +17,8 @@
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/drag_layer" >
    android:id="@+id/drag_layer"
    android:padding="@dimen/dynamic_grid_edge_margin">

    <GridView
        android:layout_width="match_parent"
@@ -119,8 +120,7 @@
            android:singleLine="true"
            android:textColor="?android:attr/textColorSecondary"
            android:textColorHint="@drawable/all_apps_search_hint"
            android:textSize="16sp"
            android:translationY="24dp" />
            android:textSize="16sp" />

        <include layout="@layout/all_apps_fast_scroller" />
    </com.android.launcher3.allapps.AllAppsContainerView>
+1 −0
Original line number Diff line number Diff line
sdk=29
shadows= \
    com.android.launcher3.shadows.LShadowApplicationPackageManager \
    com.android.launcher3.shadows.LShadowAppPredictionManager \
    com.android.launcher3.shadows.LShadowAppWidgetManager \
    com.android.launcher3.shadows.LShadowBackupManager \
+133 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.launcher3.secondarydisplay;

import static com.android.launcher3.util.LauncherModelHelper.TEST_PACKAGE;
import static com.android.launcher3.util.LauncherUIHelper.doLayout;
import static com.android.launcher3.util.Preconditions.assertNotNull;

import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;

import android.content.Context;
import android.os.UserManager;
import android.provider.Settings;

import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.allapps.AllAppsPagedView;
import com.android.launcher3.allapps.AllAppsRecyclerView;
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.shadows.ShadowOverrides;
import com.android.launcher3.util.LauncherLayoutBuilder;
import com.android.launcher3.util.LauncherModelHelper;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.LooperMode;
import org.robolectric.annotation.LooperMode.Mode;
import org.robolectric.shadow.api.Shadow;
import org.robolectric.shadows.ShadowUserManager;

/**
 * Tests for {@link SecondaryDisplayLauncher} with work profile
 */
@RunWith(RobolectricTestRunner.class)
@LooperMode(Mode.PAUSED)
public class SDWorkModeTest {

    private static final int SYSTEM_USER = 0;
    private static final int FLAG_SYSTEM = 0x00000800;
    private static final int WORK_PROFILE_ID = 10;
    private static final int FLAG_PROFILE = 0x00001000;

    private Context mTargetContext;
    private InvariantDeviceProfile mIdp;
    private LauncherModelHelper mModelHelper;

    private LauncherLayoutBuilder mLayoutBuilder;

    @Before
    public void setup() throws Exception {
        mModelHelper = new LauncherModelHelper();
        mTargetContext = RuntimeEnvironment.application;
        mIdp = InvariantDeviceProfile.INSTANCE.get(mTargetContext);
        ShadowOverrides.setProvider(UserEventDispatcher.class,
                c -> mock(UserEventDispatcher.class));
        Settings.Global.putFloat(mTargetContext.getContentResolver(),
                Settings.Global.WINDOW_ANIMATION_SCALE, 0);

        mModelHelper.installApp(TEST_PACKAGE);
        mLayoutBuilder = new LauncherLayoutBuilder();
    }

    @Test
    public void testAllAppsList_noWorkProfile() throws Exception {
        SecondaryDisplayLauncher launcher = loadLauncher();
        launcher.showAppDrawer(true);
        doLayout(launcher);

        verifyRecyclerViewCount(launcher.getAppsView().getActiveRecyclerView());
    }

    @Test
    public void testAllAppsList_workProfile() throws Exception {
        ShadowUserManager sum = Shadow.extract(mTargetContext.getSystemService(UserManager.class));
        sum.addUser(SYSTEM_USER, "me", FLAG_SYSTEM);
        sum.addUser(WORK_PROFILE_ID, "work", FLAG_PROFILE);

        SecondaryDisplayLauncher launcher = loadLauncher();
        launcher.showAppDrawer(true);
        doLayout(launcher);

        AllAppsRecyclerView rv1 = launcher.getAppsView().getActiveRecyclerView();
        verifyRecyclerViewCount(rv1);

        assertNotNull(launcher.getAppsView().getWorkModeSwitch());
        assertTrue(launcher.getAppsView().getRecyclerViewContainer() instanceof AllAppsPagedView);

        AllAppsPagedView pagedView =
                (AllAppsPagedView) launcher.getAppsView().getRecyclerViewContainer();
        pagedView.snapToPageImmediately(1);
        doLayout(launcher);

        AllAppsRecyclerView rv2 = launcher.getAppsView().getActiveRecyclerView();
        verifyRecyclerViewCount(rv2);
        assertNotSame(rv1, rv2);
    }

    private SecondaryDisplayLauncher loadLauncher() throws Exception {
        // Install 100 apps
        for (int i = 0; i < 100; i++) {
            mModelHelper.installApp(TEST_PACKAGE + i);
        }
        mModelHelper.setupDefaultLayoutProvider(new LauncherLayoutBuilder()).loadModelSync();
        SecondaryDisplayLauncher launcher =
                Robolectric.buildActivity(SecondaryDisplayLauncher.class).setup().get();
        doLayout(launcher);
        return launcher;
    }

    private void verifyRecyclerViewCount(AllAppsRecyclerView rv) {
        int childCount = rv.getChildCount();
        assertTrue(childCount > 0);
        assertTrue(childCount < 100);
    }
}
+36 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.launcher3.shadows;

import android.os.Process;
import android.os.UserHandle;

import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.shadows.ShadowApplicationPackageManager;

/**
 * Shadow for {@link ShadowApplicationPackageManager} which create mock predictors
 */
@Implements(className = "android.app.ApplicationPackageManager")
public class LShadowApplicationPackageManager extends ShadowApplicationPackageManager {

    @Implementation
    public CharSequence getUserBadgedLabel(CharSequence label, UserHandle user) {
        return Process.myUserHandle().equals(user) ? label : "Work " + label;
    }
}
+6 −6
Original line number Diff line number Diff line
@@ -30,7 +30,6 @@ import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ShortcutInfo;
import android.os.Process;
import android.os.UserHandle;
import android.util.ArraySet;

@@ -80,14 +79,15 @@ public class LShadowLauncherApps extends ShadowLauncherApps {
    protected LauncherActivityInfo resolveActivity(Intent intent, UserHandle user) {
        ResolveInfo ri = RuntimeEnvironment.application.getPackageManager()
                .resolveActivity(intent, 0);
        return ri == null ? null : getLauncherActivityInfo(ri.activityInfo);
        return ri == null ? null : getLauncherActivityInfo(ri.activityInfo, user);
    }

    public LauncherActivityInfo getLauncherActivityInfo(ActivityInfo activityInfo) {
    public LauncherActivityInfo getLauncherActivityInfo(
            ActivityInfo activityInfo, UserHandle user) {
        return callConstructor(LauncherActivityInfo.class,
                ClassParameter.from(Context.class, RuntimeEnvironment.application),
                ClassParameter.from(ActivityInfo.class, activityInfo),
                ClassParameter.from(UserHandle.class, Process.myUserHandle()));
                ClassParameter.from(UserHandle.class, user));
    }

    @Implementation
@@ -104,7 +104,7 @@ public class LShadowLauncherApps extends ShadowLauncherApps {
                .setPackage(packageName);
        return RuntimeEnvironment.application.getPackageManager().queryIntentActivities(intent, 0)
                .stream()
                .map(ri -> getLauncherActivityInfo(ri.activityInfo))
                .map(ri -> getLauncherActivityInfo(ri.activityInfo, user))
                .collect(Collectors.toList());
    }

@@ -130,7 +130,7 @@ public class LShadowLauncherApps extends ShadowLauncherApps {
        Intent intent = new Intent(Intent.ACTION_CREATE_SHORTCUT).setPackage(packageName);
        return RuntimeEnvironment.application.getPackageManager().queryIntentActivities(intent, 0)
                .stream()
                .map(ri -> getLauncherActivityInfo(ri.activityInfo))
                .map(ri -> getLauncherActivityInfo(ri.activityInfo, user))
                .collect(Collectors.toList());
    }
}
Loading