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

Commit 777d4906 authored by Sunny Goyal's avatar Sunny Goyal Committed by Alex Chau
Browse files

Revert "Revert "Migrating all model tests to Instrumentation tests""

This reverts commit 7a4a30d8.

Test: Presubmit
Reason for revert: Fixing original bug

Bug: 196825541
Change-Id: Id4b1eb24a89564d264266d305aebea52917dfcd9
parent ee3814de
Loading
Loading
Loading
Loading
+64 −64
Original line number Diff line number Diff line
@@ -15,24 +15,31 @@
 */
package com.android.launcher3.model;

import static android.os.Process.myUserHandle;

import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import static com.android.launcher3.util.WidgetUtils.createAppWidgetProviderInfo;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.robolectric.Shadows.shadowOf;
import static org.mockito.Mockito.doReturn;

import android.app.prediction.AppTarget;
import android.app.prediction.AppTargetId;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
import android.content.Context;
import android.os.Process;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;

import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;

import com.android.launcher3.LauncherAppState;
import com.android.launcher3.config.FeatureFlags;
@@ -40,38 +47,34 @@ import com.android.launcher3.icons.ComponentWithLabel;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.model.BgDataModel.FixedContainerItems;
import com.android.launcher3.model.QuickstepModelDelegate.PredictorState;
import com.android.launcher3.shadows.ShadowDeviceFlag;
import com.android.launcher3.util.LauncherModelHelper;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.PendingAddWidgetInfo;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.shadow.api.Shadow;
import org.robolectric.shadows.ShadowAppWidgetManager;
import org.robolectric.shadows.ShadowPackageManager;
import org.robolectric.util.ReflectionHelpers;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@RunWith(RobolectricTestRunner.class)
@SmallTest
@RunWith(AndroidJUnit4.class)
public final class WidgetsPredicationUpdateTaskTest {

    private AppWidgetProviderInfo mApp1Provider1 = new AppWidgetProviderInfo();
    private AppWidgetProviderInfo mApp1Provider2 = new AppWidgetProviderInfo();
    private AppWidgetProviderInfo mApp2Provider1 = new AppWidgetProviderInfo();
    private AppWidgetProviderInfo mApp4Provider1 = new AppWidgetProviderInfo();
    private AppWidgetProviderInfo mApp4Provider2 = new AppWidgetProviderInfo();
    private AppWidgetProviderInfo mApp5Provider1 = new AppWidgetProviderInfo();
    private AppWidgetProviderInfo mApp1Provider1;
    private AppWidgetProviderInfo mApp1Provider2;
    private AppWidgetProviderInfo mApp2Provider1;
    private AppWidgetProviderInfo mApp4Provider1;
    private AppWidgetProviderInfo mApp4Provider2;
    private AppWidgetProviderInfo mApp5Provider1;
    private List<AppWidgetProviderInfo> allWidgets;

    private FakeBgDataModelCallback mCallback = new FakeBgDataModelCallback();
    private Context mContext;
    private LauncherModelHelper mModelHelper;
    private UserHandle mUserHandle;

@@ -80,54 +83,56 @@ public final class WidgetsPredicationUpdateTaskTest {

    @Before
    public void setup() throws Exception {
        mModelHelper = new LauncherModelHelper();
        MockitoAnnotations.initMocks(this);
        doAnswer(invocation -> {
            ComponentWithLabel componentWithLabel = invocation.getArgument(0);
            return componentWithLabel.getComponent().getShortClassName();
        }).when(mIconCache).getTitleNoCache(any());

        mContext = RuntimeEnvironment.application;
        mModelHelper = new LauncherModelHelper();
        mUserHandle = Process.myUserHandle();
        mUserHandle = myUserHandle();
        mApp1Provider1 = createAppWidgetProviderInfo(
                ComponentName.createRelative("app1", "provider1"));
        mApp1Provider2 = createAppWidgetProviderInfo(
                ComponentName.createRelative("app1", "provider2"));
        mApp2Provider1 = createAppWidgetProviderInfo(
                ComponentName.createRelative("app2", "provider1"));
        mApp4Provider1 = createAppWidgetProviderInfo(
                ComponentName.createRelative("app4", "provider1"));
        mApp4Provider2 = createAppWidgetProviderInfo(
                ComponentName.createRelative("app4", ".provider2"));
        mApp5Provider1 = createAppWidgetProviderInfo(
                ComponentName.createRelative("app5", "provider1"));
        allWidgets = Arrays.asList(mApp1Provider1, mApp1Provider2, mApp2Provider1,
                mApp4Provider1, mApp4Provider2, mApp5Provider1);

        AppWidgetManager manager = mModelHelper.sandboxContext.spyService(AppWidgetManager.class);
        doReturn(allWidgets).when(manager).getInstalledProviders();
        doReturn(allWidgets).when(manager).getInstalledProvidersForProfile(eq(myUserHandle()));
        doAnswer(i -> {
            String pkg = i.getArgument(0);
            Log.e("Hello", "Getting v " + pkg);
            return TextUtils.isEmpty(pkg) ? allWidgets : allWidgets.stream()
                    .filter(a -> pkg.equals(a.provider.getPackageName()))
                    .collect(Collectors.toList());
        }).when(manager).getInstalledProvidersForPackage(any(), eq(myUserHandle()));

        // 2 widgets, app4/provider1 & app5/provider1, have already been added to the workspace.
        mModelHelper.initializeData("/widgets_predication_update_task_data.txt");

        ShadowPackageManager packageManager = shadowOf(mContext.getPackageManager());
        mApp1Provider1.provider = ComponentName.createRelative("app1", "provider1");
        ReflectionHelpers.setField(mApp1Provider1, "providerInfo",
                packageManager.addReceiverIfNotPresent(mApp1Provider1.provider));
        mApp1Provider2.provider = ComponentName.createRelative("app1", "provider2");
        ReflectionHelpers.setField(mApp1Provider2, "providerInfo",
                packageManager.addReceiverIfNotPresent(mApp1Provider2.provider));
        mApp2Provider1.provider = ComponentName.createRelative("app2", "provider1");
        ReflectionHelpers.setField(mApp2Provider1, "providerInfo",
                packageManager.addReceiverIfNotPresent(mApp2Provider1.provider));
        mApp4Provider1.provider = ComponentName.createRelative("app4", "provider1");
        ReflectionHelpers.setField(mApp4Provider1, "providerInfo",
                packageManager.addReceiverIfNotPresent(mApp4Provider1.provider));
        mApp4Provider2.provider = ComponentName.createRelative("app4", ".provider2");
        ReflectionHelpers.setField(mApp4Provider2, "providerInfo",
                packageManager.addReceiverIfNotPresent(mApp4Provider2.provider));
        mApp5Provider1.provider = ComponentName.createRelative("app5", "provider1");
        ReflectionHelpers.setField(mApp5Provider1, "providerInfo",
                packageManager.addReceiverIfNotPresent(mApp5Provider1.provider));

        ShadowAppWidgetManager shadowAppWidgetManager =
                shadowOf(mContext.getSystemService(AppWidgetManager.class));
        shadowAppWidgetManager.addInstalledProvider(mApp1Provider1);
        shadowAppWidgetManager.addInstalledProvider(mApp1Provider2);
        shadowAppWidgetManager.addInstalledProvider(mApp2Provider1);
        shadowAppWidgetManager.addInstalledProvider(mApp4Provider1);
        shadowAppWidgetManager.addInstalledProvider(mApp4Provider2);
        shadowAppWidgetManager.addInstalledProvider(mApp5Provider1);

        mModelHelper.getModel().addCallbacks(mCallback);
        mModelHelper.initializeData("widgets_predication_update_task_data");

        MAIN_EXECUTOR.submit(() -> mModelHelper.getModel().addCallbacks(mCallback)).get();
        MODEL_EXECUTOR.post(() -> mModelHelper.getBgDataModel().widgetsModel.update(
                LauncherAppState.getInstance(mContext), /* packageUser= */ null));
        waitUntilIdle();
                LauncherAppState.getInstance(mModelHelper.sandboxContext),
                /* packageUser= */ null));

        MODEL_EXECUTOR.submit(() -> { }).get();
        MAIN_EXECUTOR.submit(() -> { }).get();
    }

    @After
    public void tearDown() {
        mModelHelper.destroy();
    }

    @Test
    public void widgetsRecommendationRan_shouldOnlyReturnNotAddedWidgetsInAppPredictionOrder()
@@ -165,9 +170,9 @@ public final class WidgetsPredicationUpdateTaskTest {
    @Test
    public void widgetsRecommendationRan_localFilterDisabled_shouldReturnWidgetsInPredicationOrder()
            throws Exception {
        ShadowDeviceFlag shadowDeviceFlag = Shadow.extract(
                FeatureFlags.ENABLE_LOCAL_RECOMMENDED_WIDGETS_FILTER);
        shadowDeviceFlag.setValue(false);
        if (FeatureFlags.ENABLE_LOCAL_RECOMMENDED_WIDGETS_FILTER.get()) {
            return;
        }

        // WHEN newPredicationTask is executed with 5 predicated widgets.
        AppTarget widget1 = new AppTarget(new AppTargetId("app1"), "app1", "provider1",
@@ -203,11 +208,6 @@ public final class WidgetsPredicationUpdateTaskTest {
        assertThat(actual.getUser()).isEqualTo(expected.getProfile());
    }

    private void waitUntilIdle() {
        shadowOf(MODEL_EXECUTOR.getLooper()).idle();
        shadowOf(MAIN_EXECUTOR.getLooper()).idle();
    }

    private WidgetsPredictionUpdateTask newWidgetsPredicationTask(List<AppTarget> appTargets) {
       return new WidgetsPredictionUpdateTask(
                new PredictorState(CONTAINER_WIDGETS_PREDICTION, "test_widgets_prediction"),
+0 −125
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 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.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;

    @Before
    public void setup() throws Exception {
        mModelHelper = new LauncherModelHelper();
        mTargetContext = RuntimeEnvironment.application;
        mIdp = InvariantDeviceProfile.INSTANCE.get(mTargetContext);
        Settings.Global.putFloat(mTargetContext.getContentResolver(),
                Settings.Global.WINDOW_ANIMATION_SCALE, 0);

        mModelHelper.installApp(TEST_PACKAGE);
    }

    @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.addProfile(SYSTEM_USER, 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);
    }
}
+0 −101
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.util;

import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.makeMeasureSpec;

import static com.android.launcher3.Utilities.createHomeIntent;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.graphics.Point;
import android.view.View;
import android.view.WindowManager;

import com.android.launcher3.Launcher;

import org.robolectric.Robolectric;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.android.controller.ActivityController;
import org.robolectric.shadows.ShadowLooper;
import org.robolectric.util.ReflectionHelpers;

import java.util.List;

/**
 * Utility class to help manage Launcher UI and related objects for test.
 */
public class LauncherUIHelper {

    /**
     * Returns the class name for the Launcher activity as defined in the manifest
     */
    public static String getLauncherClassName() {
        Context context = RuntimeEnvironment.application;
        Intent homeIntent = createHomeIntent().setPackage(context.getPackageName());

        List<ResolveInfo> launchers = context.getPackageManager()
                .queryIntentActivities(homeIntent, 0);
        if (launchers.size() != 1) {
            return null;
        }
        return launchers.get(0).activityInfo.name;
    }

    /**
     * Returns an activity controller for Launcher activity defined in the manifest
     */
    public static <T extends Launcher> ActivityController<T> buildLauncher() {
        try {
            Class<T> tClass = (Class<T>) Class.forName(getLauncherClassName());
            return Robolectric.buildActivity(tClass);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Creates and binds a Launcher activity defined in the manifest.
     * Note that the model must be bound before calling this
     */
    public static <T extends Launcher> T buildAndBindLauncher() {
        ActivityController<T> controller = buildLauncher();

        T launcher = controller.setup().get();
        doLayout(launcher);
        ViewOnDrawExecutor executor = ReflectionHelpers.getField(launcher, "mPendingExecutor");
        if (executor != null) {
            executor.markCompleted();
        }
        return launcher;
    }

    /**
     * Performs a measure and layout pass for the given activity
     */
    public static void doLayout(Activity activity) {
        Point size = new Point();
        RuntimeEnvironment.application.getSystemService(WindowManager.class)
                .getDefaultDisplay().getSize(size);
        View view = activity.getWindow().getDecorView();
        view.measure(makeMeasureSpec(size.x, EXACTLY), makeMeasureSpec(size.y, EXACTLY));
        view.layout(0, 0, size.x, size.y);
        ShadowLooper.idleMainLooper();
    }
}
+3 −2
Original line number Diff line number Diff line
@@ -50,7 +50,7 @@ import com.android.launcher3.util.SimpleBroadcastReceiver;
import com.android.launcher3.util.Themes;
import com.android.launcher3.widget.custom.CustomWidgetManager;

public class LauncherAppState {
public class LauncherAppState implements SafeCloseable {

    public static final String ACTION_FORCE_ROLOAD = "force-reload-launcher";
    private static final String KEY_ICON_STATE = "pref_icon_shape_path";
@@ -158,7 +158,8 @@ public class LauncherAppState {
    /**
     * Call from Application.onTerminate(), which is not guaranteed to ever be called.
     */
    public void onTerminate() {
    @Override
    public void close() {
        mModel.destroy();
        mContext.getSystemService(LauncherApps.class).unregisterCallback(mModel);
        CustomWidgetManager.INSTANCE.get(mContext).setWidgetRefreshCallback(null);
+6 −1
Original line number Diff line number Diff line
@@ -96,9 +96,10 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi
    // our monitoring of the package manager provides all updates and we never
    // need to do a requery. This is only ever touched from the loader thread.
    private boolean mModelLoaded;
    private boolean mModelDestroyed = false;
    public boolean isModelLoaded() {
        synchronized (mLock) {
            return mModelLoaded && mLoaderTask == null;
            return mModelLoaded && mLoaderTask == null && !mModelDestroyed;
        }
    }

@@ -245,6 +246,7 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi
     * Called when the model is destroyed
     */
    public void destroy() {
        mModelDestroyed = true;
        MODEL_EXECUTOR.execute(mModelDelegate::destroy);
    }

@@ -557,6 +559,9 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi
    }

    public void enqueueModelUpdateTask(ModelUpdateTask task) {
        if (mModelDestroyed) {
            return;
        }
        task.init(mApp, this, mBgDataModel, mBgAllAppsList, MAIN_EXECUTOR);
        MODEL_EXECUTOR.execute(task);
    }
Loading