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
diff --git a/res/drawable/private_space_app_divider.xml b/res/drawable/private_space_app_divider.xml
new file mode 100644
index 0000000..7d069ef
--- /dev/null
+++ b/res/drawable/private_space_app_divider.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2023 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.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="?attr/materialColorOutlineVariant"/>
+ <size android:height="1dp" />
+</shape>
\ 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 0000000..fff8629
--- /dev/null
+++ b/res/layout/private_space_divider.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 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.
+ -->
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/private_space_divider"
+ android:importantForAccessibility="no"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/ps_app_divider_padding"
+ android:paddingRight="@dimen/ps_app_divider_padding"
+ android:src="@drawable/private_space_app_divider"
+ android:scaleType="fitXY"
+ android:focusable="false" />
\ No newline at end of file
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 603e697..3016559 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -487,4 +487,5 @@
<dimen name="ps_button_height">36dp</dimen>
<dimen name="ps_button_width">36dp</dimen>
<dimen name="ps_lock_button_width">89dp</dimen>
+ <dimen name="ps_app_divider_padding">16dp</dimen>
</resources>
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index ad875e0..fba7537 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -35,6 +35,7 @@
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 @@
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 @@
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 @@
}
}
- 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 @@
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<AppInfo> 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<Boolean, List<AppInfo>> 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<AppInfo> appList, int startPosition) {
String lastSectionName = null;
boolean hasPrivateApps = false;
if (mPrivateProviderManager != null) {
@@ -357,6 +381,7 @@
}
startPosition++;
}
+ return startPosition;
}
/**
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
index 5eeb259..28c87b6 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
@@ -17,6 +17,7 @@
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 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 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 @@
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 @@
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 @@
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 aee511c..e3c56d3 100644
--- a/src/com/android/launcher3/allapps/PrivateProfileManager.java
+++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java
@@ -19,6 +19,7 @@
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.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 @@
private static final String PS_SETTINGS_FRAGMENT_VALUE = "AndroidPrivateSpace_personal";
private final ActivityAllAppsContainerView<?> mAllApps;
private final Predicate<UserHandle> mPrivateProfileMatcher;
+ private Set<String> mPreInstalledSystemPackages = new HashSet<>();
+ private Intent mAppInstallerIntent = new Intent();
private PrivateAppsSectionDecorator mPrivateAppsSectionDecorator;
private boolean mPrivateSpaceSettingsAvailable;
private Runnable mUnlockRunnable;
@@ -72,7 +76,7 @@
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 @@
return adapterItems.size();
}
+ /** Adds Private Space System Apps Divider to the layout. */
+ public int addSystemAppsDivider(List<BaseAllAppsAdapter.AdapterItem> 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<BaseAllAppsAdapter.AdapterItem> 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 @@
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 @@
return mPrivateSpaceSettingsAvailable;
}
+ /** Initializes binder call based properties in non-main thread.
+ * <p>
+ * 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 @@
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 Predicate<UserHandle> 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<AppInfo> 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 3068785..423ca24 100644
--- a/tests/src/com/android/launcher3/allapps/AlphabeticalAppsListTest.java
+++ b/tests/src/com/android/launcher3/allapps/AlphabeticalAppsListTest.java
@@ -19,6 +19,7 @@
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 @@
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 @@
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));
@@ -112,6 +118,44 @@
}
@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<BaseAllAppsAdapter.AdapterItem> 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);
when(mAllAppsStore.getApps()).thenReturn(createAppInfoListForMainAndPrivateUser());
@@ -281,6 +325,12 @@
return adapterItemList.size();
}
+ private int addSystemAppsDivider(List<BaseAllAppsAdapter.AdapterItem> 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 @@
"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 69edd0f..fd8739c 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.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 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.Mockito;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
import java.util.Arrays;
@RunWith(AndroidJUnit4.class)
@@ -89,6 +95,8 @@
private AllAppsStore mAllAppsStore;
@Mock
private PackageManager mPackageManager;
+ @Mock
+ private LauncherApps mLauncherApps;
private boolean mRunnableCalled = false;
@@ -103,6 +111,13 @@
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);
}