From 0cc11dbcac9ad0f6e985a78a429eeb33956c3091 Mon Sep 17 00:00:00 2001 From: Himanshu Gupta Date: Thu, 21 Dec 2023 17:54:15 +0000 Subject: [PATCH] Separating system and user-installed apps in PS container. We add a horizontal line separator in PS container which demarcates user-installed vs system installed apps in private space. User-installed are shown above the separator, system ones below. UX Mock: https://www.figma.com/file/K6bIIcG882EiJNjxvSWsFT/V%E2%80%A2-Private-Space?node-id=11546%3A310574&mode=dev Mock Image: https://photos.app.goo.gl/Wj8sJkS7P7bRbovg8 Demo video: https://photos.app.goo.gl/MBw6HpDnf6PJqUfs8 Bug: 308054233 Flag: ACONFIG com.android.launcher3.Flags.private_space_sys_apps_separation DEVELOPMENT Test: AlphabeticalAppsListTest Change-Id: Iad8e289c49a05ac7ef1978bd8e4ebe7aa0add0ca --- res/drawable/private_space_app_divider.xml | 21 ++++++ res/layout/private_space_divider.xml | 25 +++++++ res/values/dimens.xml | 1 + .../allapps/AlphabeticalAppsList.java | 43 +++++++++--- .../launcher3/allapps/BaseAllAppsAdapter.java | 20 +++++- .../allapps/PrivateProfileManager.java | 69 +++++++++++++++---- .../allapps/AlphabeticalAppsListTest.java | 58 +++++++++++++++- .../allapps/PrivateProfileManagerTest.java | 15 ++++ 8 files changed, 226 insertions(+), 26 deletions(-) create mode 100644 res/drawable/private_space_app_divider.xml create mode 100644 res/layout/private_space_divider.xml diff --git a/res/drawable/private_space_app_divider.xml b/res/drawable/private_space_app_divider.xml new file mode 100644 index 0000000000..7d069efd8b --- /dev/null +++ b/res/drawable/private_space_app_divider.xml @@ -0,0 +1,21 @@ + + + + + + \ No newline at end of file diff --git a/res/layout/private_space_divider.xml b/res/layout/private_space_divider.xml new file mode 100644 index 0000000000..fff862970a --- /dev/null +++ b/res/layout/private_space_divider.xml @@ -0,0 +1,25 @@ + + \ No newline at end of file diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 603e697395..3016559f96 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -487,4 +487,5 @@ 36dp 36dp 89dp + 16dp diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java index ad875e0dc3..fba7537dac 100644 --- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java +++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java @@ -35,6 +35,7 @@ import com.android.launcher3.views.ActivityContext; import java.util.ArrayList; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Objects; import java.util.TreeMap; import java.util.function.Predicate; @@ -269,10 +270,10 @@ public class AlphabeticalAppsList implement addApps = mWorkProviderManager.shouldShowWorkApps(); } if (addApps) { - addAppsWithSections(mApps, position); + position = addAppsWithSections(mApps, position); } if (Flags.enablePrivateSpace()) { - addPrivateSpaceItems(position); + position = addPrivateSpaceItems(position); } } mAccessibilityResultsCount = (int) mAdapterItems.stream() @@ -287,7 +288,8 @@ public class AlphabeticalAppsList implement for (AdapterItem item : mAdapterItems) { item.rowIndex = 0; if (BaseAllAppsAdapter.isDividerViewType(item.viewType) - || BaseAllAppsAdapter.isPrivateSpaceHeaderView(item.viewType)) { + || BaseAllAppsAdapter.isPrivateSpaceHeaderView(item.viewType) + || BaseAllAppsAdapter.isPrivateSpaceSysAppsDividerView(item.viewType)) { numAppsInSection = 0; } else if (BaseAllAppsAdapter.isIconViewType(item.viewType)) { if (numAppsInSection % mNumAppsPerRowAllApps == 0) { @@ -309,12 +311,12 @@ public class AlphabeticalAppsList implement } } - void addPrivateSpaceItems(int position) { + int addPrivateSpaceItems(int position) { if (mPrivateProviderManager != null && !mPrivateProviderManager.isPrivateSpaceHidden() && !mPrivateApps.isEmpty()) { // Always add PS Header if Space is present and visible. - position += mPrivateProviderManager.addPrivateSpaceHeader(mAdapterItems); + position = mPrivateProviderManager.addPrivateSpaceHeader(mAdapterItems); int privateSpaceState = mPrivateProviderManager.getCurrentState(); switch (privateSpaceState) { case PrivateProfileManager.STATE_DISABLED: @@ -322,15 +324,37 @@ public class AlphabeticalAppsList implement break; case PrivateProfileManager.STATE_ENABLED: // Add PS Apps only in Enabled State. - mPrivateProviderManager.addPrivateSpaceInstallAppButton(mAdapterItems); - position++; - addAppsWithSections(mPrivateApps, position); + position = addPrivateSpaceApps(position); break; } } + return position; } - private void addAppsWithSections(List appList, int startPosition) { + private int addPrivateSpaceApps(int position) { + // Add Install Apps Button first. + if (Flags.privateSpaceAppInstallerButton()) { + mPrivateProviderManager.addPrivateSpaceInstallAppButton(mAdapterItems); + position++; + } + + // Split of private space apps into user-installed and system apps. + Map> split = mPrivateApps.stream() + .collect(Collectors.partitioningBy(mPrivateProviderManager + .splitIntoUserInstalledAndSystemApps())); + // Add user installed apps + position = addAppsWithSections(split.get(true), position); + // Add system apps separator. + if (Flags.privateSpaceSysAppsSeparation()) { + position = mPrivateProviderManager.addSystemAppsDivider(mAdapterItems); + } + // Add system apps. + position = addAppsWithSections(split.get(false), position); + + return position; + } + + private int addAppsWithSections(List appList, int startPosition) { String lastSectionName = null; boolean hasPrivateApps = false; if (mPrivateProviderManager != null) { @@ -357,6 +381,7 @@ public class AlphabeticalAppsList implement } startPosition++; } + return startPosition; } /** diff --git a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java index 5eeb259fe5..28c87b6fa7 100644 --- a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java +++ b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java @@ -17,6 +17,7 @@ package com.android.launcher3.allapps; import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_BOTTOM_LEFT; import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_BOTTOM_RIGHT; +import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_NOTHING; import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_TOP_LEFT; import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_TOP_RIGHT; import static com.android.launcher3.allapps.UserProfileManager.STATE_DISABLED; @@ -61,7 +62,8 @@ public abstract class BaseAllAppsAdapter ex public static final int VIEW_TYPE_WORK_EDU_CARD = 1 << 4; public static final int VIEW_TYPE_WORK_DISABLED_CARD = 1 << 5; public static final int VIEW_TYPE_PRIVATE_SPACE_HEADER = 1 << 6; - public static final int NEXT_ID = 7; + public static final int VIEW_TYPE_PRIVATE_SPACE_SYS_APPS_DIVIDER = 1 << 7; + public static final int NEXT_ID = 8; // Common view type masks public static final int VIEW_TYPE_MASK_DIVIDER = VIEW_TYPE_ALL_APPS_DIVIDER; @@ -69,6 +71,8 @@ public abstract class BaseAllAppsAdapter ex public static final int VIEW_TYPE_MASK_PRIVATE_SPACE_HEADER = VIEW_TYPE_PRIVATE_SPACE_HEADER; + public static final int VIEW_TYPE_MASK_PRIVATE_SPACE_SYS_APPS_DIVIDER = + VIEW_TYPE_PRIVATE_SPACE_SYS_APPS_DIVIDER; protected final SearchAdapterProvider mAdapterProvider; @@ -199,6 +203,11 @@ public abstract class BaseAllAppsAdapter ex return isViewType(viewType, VIEW_TYPE_MASK_PRIVATE_SPACE_HEADER); } + /** Checks if the passed viewType represents private space system apps divider. */ + public static boolean isPrivateSpaceSysAppsDividerView(int viewType) { + return isViewType(viewType, VIEW_TYPE_MASK_PRIVATE_SPACE_SYS_APPS_DIVIDER); + } + public void setIconFocusListener(OnFocusChangeListener focusListener) { mIconFocusListener = focusListener; } @@ -227,9 +236,9 @@ public abstract class BaseAllAppsAdapter ex case VIEW_TYPE_EMPTY_SEARCH: return new ViewHolder(mLayoutInflater.inflate(R.layout.all_apps_empty_search, parent, false)); - case VIEW_TYPE_ALL_APPS_DIVIDER: + case VIEW_TYPE_ALL_APPS_DIVIDER, VIEW_TYPE_PRIVATE_SPACE_SYS_APPS_DIVIDER: return new ViewHolder(mLayoutInflater.inflate( - R.layout.all_apps_divider, parent, false)); + R.layout.private_space_divider, parent, false)); case VIEW_TYPE_WORK_EDU_CARD: return new ViewHolder(mLayoutInflater.inflate( R.layout.work_apps_edu, parent, false)); @@ -282,6 +291,11 @@ public abstract class BaseAllAppsAdapter ex new SectionDecorationInfo(mActivityContext, roundRegions, false /* decorateTogether */); break; + case VIEW_TYPE_PRIVATE_SPACE_SYS_APPS_DIVIDER: + adapterItem = mApps.getAdapterItems().get(position); + adapterItem.decorationInfo = new SectionDecorationInfo(mActivityContext, + ROUND_NOTHING, true /* decorateTogether */); + break; case VIEW_TYPE_ALL_APPS_DIVIDER: case VIEW_TYPE_WORK_DISABLED_CARD: // nothing to do diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java index aee511cad7..e3c56d37ee 100644 --- a/src/com/android/launcher3/allapps/PrivateProfileManager.java +++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java @@ -19,6 +19,7 @@ package com.android.launcher3.allapps; import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.MAIN; import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_ICON; import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_HEADER; +import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_SYS_APPS_DIVIDER; import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_NOTHING; import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; @@ -44,10 +45,11 @@ import com.android.launcher3.pm.UserCache; import com.android.launcher3.uioverrides.ApiWrapper; import com.android.launcher3.util.Preconditions; import com.android.launcher3.util.SettingsCache; -import com.android.launcher3.util.UserIconInfo; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.function.Predicate; /** @@ -61,6 +63,8 @@ public class PrivateProfileManager extends UserProfileManager { private static final String PS_SETTINGS_FRAGMENT_VALUE = "AndroidPrivateSpace_personal"; private final ActivityAllAppsContainerView mAllApps; private final Predicate mPrivateProfileMatcher; + private Set mPreInstalledSystemPackages = new HashSet<>(); + private Intent mAppInstallerIntent = new Intent(); private PrivateAppsSectionDecorator mPrivateAppsSectionDecorator; private boolean mPrivateSpaceSettingsAvailable; private Runnable mUnlockRunnable; @@ -72,7 +76,7 @@ public class PrivateProfileManager extends UserProfileManager { super(userManager, statsLogManager, userCache); mAllApps = allApps; mPrivateProfileMatcher = (user) -> userCache.getUserInfo(user).isPrivate(); - UI_HELPER_EXECUTOR.post(this::setPrivateSpaceSettingsAvailable); + UI_HELPER_EXECUTOR.post(this::initializeInBackgroundThread); } /** Adds Private Space Header to the layout. */ @@ -82,18 +86,17 @@ public class PrivateProfileManager extends UserProfileManager { return adapterItems.size(); } + /** Adds Private Space System Apps Divider to the layout. */ + public int addSystemAppsDivider(List adapterItems) { + adapterItems.add(new BaseAllAppsAdapter + .AdapterItem(VIEW_TYPE_PRIVATE_SPACE_SYS_APPS_DIVIDER)); + mAllApps.mAH.get(MAIN).mAdapter.notifyItemInserted(adapterItems.size() - 1); + return adapterItems.size(); + } + /** Adds Private Space install app button to the layout. */ public void addPrivateSpaceInstallAppButton(List adapterItems) { Context context = mAllApps.getContext(); - // Prepare intent - UserCache userCache = UserCache.getInstance(context); - UserHandle userHandle = userCache.getUserProfiles().stream() - .filter(user -> userCache.getUserInfo(user).type == UserIconInfo.TYPE_PRIVATE) - .findFirst() - .orElse(null); - Intent intent = ApiWrapper.getAppMarketActivityIntent(context, - BuildConfig.APPLICATION_ID, userHandle); - // Prepare bitmapInfo Intent.ShortcutIconResource shortcut = Intent.ShortcutIconResource.fromContext( context, com.android.launcher3.R.drawable.private_space_install_app_icon); @@ -101,7 +104,7 @@ public class PrivateProfileManager extends UserProfileManager { AppInfo itemInfo = new AppInfo(); itemInfo.title = context.getResources().getString(R.string.ps_add_button_label); - itemInfo.intent = intent; + itemInfo.intent = mAppInstallerIntent; itemInfo.bitmap = bitmapInfo; itemInfo.contentDescription = context.getResources().getString( com.android.launcher3.R.string.ps_add_button_content_description); @@ -164,6 +167,22 @@ public class PrivateProfileManager extends UserProfileManager { return mPrivateSpaceSettingsAvailable; } + /** Initializes binder call based properties in non-main thread. + *

+ * This can cause the Private Space container items to not load/respond correctly sometimes, + * when the All Apps Container loads for the first time (device restarts, new profiles + * added/removed, etc.), as the properties are being set in non-ui thread whereas the container + * loads in the ui thread. + * This case should still be ok, as locking the Private Space container and unlocking it, + * reloads the values, fixing the incorrect UI. + */ + private void initializeInBackgroundThread() { + Preconditions.assertNonUiThread(); + setPreInstalledSystemPackages(); + setAppInstallerIntent(); + setPrivateSpaceSettingsAvailable(); + } + private void setPrivateSpaceSettingsAvailable() { if (mPrivateSpaceSettingsAvailable) { return; @@ -176,6 +195,22 @@ public class PrivateProfileManager extends UserProfileManager { mPrivateSpaceSettingsAvailable = resolveInfo != null; } + private void setPreInstalledSystemPackages() { + Preconditions.assertNonUiThread(); + if (getProfileUser() != null) { + mPreInstalledSystemPackages = new HashSet<>(ApiWrapper + .getPreInstalledSystemPackages(mAllApps.getContext(), getProfileUser())); + } + } + + private void setAppInstallerIntent() { + Preconditions.assertNonUiThread(); + if (getProfileUser() != null) { + mAppInstallerIntent = ApiWrapper.getAppMarketActivityIntent(mAllApps.getContext(), + BuildConfig.APPLICATION_ID, getProfileUser()); + } + } + @VisibleForTesting void resetPrivateSpaceDecorator(int updatedState) { ActivityAllAppsContainerView.AdapterHolder mainAdapterHolder = mAllApps.mAH.get(MAIN); @@ -223,4 +258,14 @@ public class PrivateProfileManager extends UserProfileManager { public Predicate getUserMatcher() { return mPrivateProfileMatcher; } + + /** + * Splits private apps into user installed and system apps. + * When the list of system apps is empty, all apps are treated as system. + */ + public Predicate splitIntoUserInstalledAndSystemApps() { + return appInfo -> !mPreInstalledSystemPackages.isEmpty() + && (appInfo.componentName == null + || !(mPreInstalledSystemPackages.contains(appInfo.componentName.getPackageName()))); + } } diff --git a/tests/src/com/android/launcher3/allapps/AlphabeticalAppsListTest.java b/tests/src/com/android/launcher3/allapps/AlphabeticalAppsListTest.java index 306878531c..423ca2415f 100644 --- a/tests/src/com/android/launcher3/allapps/AlphabeticalAppsListTest.java +++ b/tests/src/com/android/launcher3/allapps/AlphabeticalAppsListTest.java @@ -19,6 +19,7 @@ package com.android.launcher3.allapps; import static androidx.test.core.app.ApplicationProvider.getApplicationContext; import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_HEADER; +import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_SYS_APPS_DIVIDER; import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_BOTTOM_LEFT; import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_BOTTOM_RIGHT; import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_NOTHING; @@ -63,9 +64,10 @@ public class AlphabeticalAppsListTest { private static final int PRIVATE_SPACE_HEADER_ITEM_COUNT = 1; private static final int MAIN_USER_APP_COUNT = 2; - private static final int PRIVATE_USER_APP_COUNT = 1; + private static final int PRIVATE_USER_APP_COUNT = 2; private static final int NUM_APP_COLS = 4; private static final int NUM_APP_ROWS = 3; + private static final int PRIVATE_SPACE_SYS_APP_SEPARATOR_ITEM_COUNT = 1; private AlphabeticalAppsList mAlphabeticalAppsList; @Mock @@ -96,6 +98,10 @@ public class AlphabeticalAppsListTest { when(mPrivateProfileManager.addPrivateSpaceHeader(any())) .thenAnswer(answer(this::addPrivateSpaceHeader)); when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED); + when(mPrivateProfileManager.splitIntoUserInstalledAndSystemApps()) + .thenReturn(iteminfo -> iteminfo.componentName == null + || !iteminfo.componentName.getPackageName() + .equals("com.android.launcher3.tests.camera")); mAlphabeticalAppsList.updateItemFilter(info -> info != null && info.user.equals(MAIN_HANDLE)); @@ -111,6 +117,44 @@ public class AlphabeticalAppsListTest { && item.itemInfo.user.equals(PRIVATE_HANDLE)).toList().size()); } + @Test + public void privateProfileEnabled_privateProfileAppsShownWithSeparator() { + mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_PRIVATE_SPACE); + mSetFlagsRule.enableFlags(Flags.FLAG_PRIVATE_SPACE_SYS_APPS_SEPARATION); + when(mAllAppsStore.getApps()).thenReturn(createAppInfoListForMainAndPrivateUser()); + when(mPrivateProfileManager.addPrivateSpaceHeader(any())) + .thenAnswer(answer(this::addPrivateSpaceHeader)); + when(mPrivateProfileManager.addSystemAppsDivider(any())) + .thenAnswer(answer(this::addSystemAppsDivider)); + when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED); + when(mPrivateProfileManager.splitIntoUserInstalledAndSystemApps()) + .thenReturn(iteminfo -> iteminfo.componentName == null + || !iteminfo.componentName.getPackageName() + .equals("com.android.launcher3.tests.camera")); + + mAlphabeticalAppsList.updateItemFilter(info -> info != null + && info.user.equals(MAIN_HANDLE)); + + assertEquals(MAIN_USER_APP_COUNT + PRIVATE_SPACE_HEADER_ITEM_COUNT + + PRIVATE_SPACE_SYS_APP_SEPARATOR_ITEM_COUNT + + PRIVATE_USER_APP_COUNT, mAlphabeticalAppsList.getAdapterItems().size()); + assertEquals(PRIVATE_SPACE_HEADER_ITEM_COUNT, + mAlphabeticalAppsList.getAdapterItems().stream().filter(item -> + item.viewType == VIEW_TYPE_PRIVATE_SPACE_HEADER).toList().size()); + assertEquals(PRIVATE_SPACE_SYS_APP_SEPARATOR_ITEM_COUNT, + mAlphabeticalAppsList.getAdapterItems().stream().filter(item -> + item.viewType == VIEW_TYPE_PRIVATE_SPACE_SYS_APPS_DIVIDER).toList().size()); + List psApps = mAlphabeticalAppsList.getAdapterItems() + .stream() + .filter(item -> item.itemInfo != null && item.itemInfo.user.equals(PRIVATE_HANDLE)) + .toList(); + assertEquals(PRIVATE_USER_APP_COUNT, psApps.size()); + assert psApps.get(0).itemInfo.title != null; + assertEquals("Private Messenger", psApps.get(0).itemInfo.title.toString()); + assert psApps.get(1).itemInfo.title != null; + assertEquals("Private Camera", psApps.get(1).itemInfo.title.toString()); + } + @Test public void privateProfileDisabled_onlyPrivateProfileHeaderViewIsPresent() { mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_PRIVATE_SPACE); @@ -281,6 +325,12 @@ public class AlphabeticalAppsListTest { return adapterItemList.size(); } + private int addSystemAppsDivider(List adapterItemList) { + adapterItemList.add(new BaseAllAppsAdapter + .AdapterItem(VIEW_TYPE_PRIVATE_SPACE_SYS_APPS_DIVIDER)); + return adapterItemList.size(); + } + private AppInfo[] createAppInfoListForMainUser() { ComponentName gmailComponentName = new ComponentName(mContext, "com.android.launcher3.tests.Activity" + "Gmail"); @@ -298,7 +348,11 @@ public class AlphabeticalAppsListTest { "com.android.launcher3.tests.Activity" + "PrivateMessenger"); AppInfo privateMessengerAppInfo = new AppInfo(privateMessengercomponentName, "Private Messenger", PRIVATE_HANDLE, new Intent()); - return new AppInfo[]{privateMessengerAppInfo}; + ComponentName privateCameraComponentName = new ComponentName( + "com.android.launcher3.tests.camera", "CameraActivity"); + AppInfo privateCameraAppInfo = new AppInfo(privateCameraComponentName, + "Private Camera", PRIVATE_HANDLE, new Intent()); + return new AppInfo[]{privateMessengerAppInfo, privateCameraAppInfo}; } private AppInfo[] createAppInfoListForMainAndPrivateUser() { diff --git a/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java b/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java index 69edd0f2a5..fd8739c48a 100644 --- a/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java +++ b/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java @@ -16,6 +16,8 @@ package com.android.launcher3.allapps; +import static androidx.test.core.app.ApplicationProvider.getApplicationContext; + import static com.android.launcher3.allapps.UserProfileManager.STATE_DISABLED; import static com.android.launcher3.allapps.UserProfileManager.STATE_ENABLED; import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED; @@ -31,8 +33,10 @@ import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; +import android.app.PendingIntent; import android.content.Context; import android.content.Intent; +import android.content.pm.LauncherApps; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.Process; @@ -43,6 +47,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.pm.UserCache; +import com.android.launcher3.util.ActivityContextWrapper; import com.android.launcher3.util.UserIconInfo; import com.android.launcher3.util.rule.TestStabilityRule; @@ -56,6 +61,7 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; +import java.util.ArrayList; import java.util.Arrays; @RunWith(AndroidJUnit4.class) @@ -89,6 +95,8 @@ public class PrivateProfileManagerTest { private AllAppsStore mAllAppsStore; @Mock private PackageManager mPackageManager; + @Mock + private LauncherApps mLauncherApps; private boolean mRunnableCalled = false; @@ -103,6 +111,13 @@ public class PrivateProfileManagerTest { when(mActivityAllAppsContainerView.getAppsStore()).thenReturn(mAllAppsStore); when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mPackageManager.resolveActivity(any(), any())).thenReturn(new ResolveInfo()); + when(mContext.getSystemService(LauncherApps.class)).thenReturn(mLauncherApps); + when(mLauncherApps.getAppMarketActivityIntent(any(), any())).thenReturn(PendingIntent + .getActivity(new ActivityContextWrapper(getApplicationContext()), 0, + new Intent(), PendingIntent.FLAG_IMMUTABLE).getIntentSender()); + when(mContext.getPackageName()) + .thenReturn("com.android.launcher3.tests.privateProfileManager"); + when(mLauncherApps.getPreInstalledSystemPackages(any())).thenReturn(new ArrayList<>()); mPrivateProfileManager = new PrivateProfileManager(mUserManager, mActivityAllAppsContainerView, mStatsLogManager, mUserCache); }