2 * Copyright (C) 2016 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.android.server.pm;
18 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.cloneShortcutList;
19 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.hashSet;
20 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
21 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.makeBundle;
22 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.set;
24 import static org.mockito.Matchers.any;
25 import static org.mockito.Matchers.anyInt;
26 import static org.mockito.Matchers.anyString;
27 import static org.mockito.Matchers.eq;
28 import static org.mockito.Mockito.doAnswer;
29 import static org.mockito.Mockito.mock;
30 import static org.mockito.Mockito.reset;
31 import static org.mockito.Mockito.spy;
32 import static org.mockito.Mockito.times;
33 import static org.mockito.Mockito.verify;
34 import static org.mockito.Mockito.when;
36 import android.annotation.NonNull;
37 import android.annotation.UserIdInt;
38 import android.app.Activity;
39 import android.app.ActivityManager;
40 import android.app.ActivityManagerInternal;
41 import android.app.IUidObserver;
42 import android.app.usage.UsageStatsManagerInternal;
43 import android.content.ActivityNotFoundException;
44 import android.content.BroadcastReceiver;
45 import android.content.ComponentName;
46 import android.content.Context;
47 import android.content.Intent;
48 import android.content.IntentFilter;
49 import android.content.pm.ActivityInfo;
50 import android.content.pm.ApplicationInfo;
51 import android.content.pm.ILauncherApps;
52 import android.content.pm.LauncherApps;
53 import android.content.pm.LauncherApps.ShortcutQuery;
54 import android.content.pm.PackageInfo;
55 import android.content.pm.PackageManager;
56 import android.content.pm.PackageManagerInternal;
57 import android.content.pm.ResolveInfo;
58 import android.content.pm.ShortcutInfo;
59 import android.content.pm.ShortcutManager;
60 import android.content.pm.ShortcutServiceInternal;
61 import android.content.pm.Signature;
62 import android.content.pm.UserInfo;
63 import android.content.res.Resources;
64 import android.content.res.XmlResourceParser;
65 import android.graphics.drawable.Icon;
66 import android.net.Uri;
67 import android.os.Bundle;
68 import android.os.FileUtils;
69 import android.os.Handler;
70 import android.os.Looper;
71 import android.os.PersistableBundle;
72 import android.os.Process;
73 import android.os.UserHandle;
74 import android.os.UserManager;
75 import android.test.InstrumentationTestCase;
76 import android.test.mock.MockContext;
77 import android.util.Log;
78 import android.util.Pair;
80 import com.android.internal.util.Preconditions;
81 import com.android.server.LocalServices;
82 import com.android.server.SystemService;
83 import com.android.server.pm.LauncherAppsService.LauncherAppsImpl;
84 import com.android.server.pm.ShortcutUser.PackageWithUser;
86 import org.junit.Assert;
87 import org.mockito.ArgumentCaptor;
88 import org.mockito.invocation.InvocationOnMock;
89 import org.mockito.stubbing.Answer;
91 import java.io.BufferedReader;
92 import java.io.ByteArrayOutputStream;
94 import java.io.FileReader;
95 import java.io.IOException;
96 import java.io.InputStreamReader;
97 import java.io.PrintWriter;
98 import java.util.ArrayList;
99 import java.util.HashMap;
100 import java.util.HashSet;
101 import java.util.LinkedHashMap;
102 import java.util.List;
103 import java.util.Locale;
104 import java.util.Map;
105 import java.util.Set;
106 import java.util.function.BiFunction;
107 import java.util.function.BiPredicate;
108 import java.util.function.Consumer;
109 import java.util.function.Function;
111 public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
112 protected static final String TAG = "ShortcutManagerTest";
114 protected static final boolean DUMP_IN_TEARDOWN = false; // DO NOT SUBMIT WITH true
117 * Whether to enable dump or not. Should be only true when debugging to avoid bugs where
118 * dump affecting the behavior.
120 protected static final boolean ENABLE_DUMP = false // DO NOT SUBMIT WITH true
121 || DUMP_IN_TEARDOWN || ShortcutService.DEBUG;
123 protected static final String[] EMPTY_STRINGS = new String[0]; // Just for readability.
125 protected static final String MAIN_ACTIVITY_CLASS = "MainActivity";
127 // public for mockito
128 public class BaseContext extends MockContext {
130 public Object getSystemService(String name) {
132 case Context.USER_SERVICE:
133 return mMockUserManager;
135 throw new UnsupportedOperationException();
139 public String getSystemServiceName(Class<?> serviceClass) {
140 return getTestContext().getSystemServiceName(serviceClass);
144 public PackageManager getPackageManager() {
145 return mMockPackageManager;
149 public Resources getResources() {
150 return getTestContext().getResources();
154 public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
155 IntentFilter filter, String broadcastPermission, Handler scheduler) {
161 public void unregisterReceiver(BroadcastReceiver receiver) {
166 /** Context used in the client side */
167 public class ClientContext extends BaseContext {
169 public String getPackageName() {
170 return mInjectedClientPackage;
174 public int getUserId() {
175 return getCallingUserId();
179 /** Context used in the service side */
180 public class ServiceContext extends BaseContext {
181 long injectClearCallingIdentity() {
182 final int prevCallingUid = mInjectedCallingUid;
183 mInjectedCallingUid = Process.SYSTEM_UID;
184 return prevCallingUid;
187 void injectRestoreCallingIdentity(long token) {
188 mInjectedCallingUid = (int) token;
192 public int getUserId() {
193 return UserHandle.USER_SYSTEM;
196 public PackageInfo injectGetActivitiesWithMetadata(
197 String packageName, @UserIdInt int userId) {
198 return BaseShortcutManagerTest.this.injectGetActivitiesWithMetadata(packageName, userId);
201 public XmlResourceParser injectXmlMetaData(ActivityInfo activityInfo, String key) {
202 return BaseShortcutManagerTest.this.injectXmlMetaData(activityInfo, key);
206 /** ShortcutService with injection override methods. */
207 protected final class ShortcutServiceTestable extends ShortcutService {
208 final ServiceContext mContext;
209 IUidObserver mUidObserver;
211 public ShortcutServiceTestable(ServiceContext context, Looper looper) {
212 super(context, looper, /* onyForPackageManagerApis */ false);
217 public String injectGetLocaleTagsForUser(@UserIdInt int userId) {
218 return mInjectedLocale.toLanguageTag();
222 boolean injectShouldPerformVerification() {
223 return true; // Always verify during unit tests.
227 String injectShortcutManagerConstants() {
228 return ConfigConstants.KEY_RESET_INTERVAL_SEC + "=" + (INTERVAL / 1000) + ","
229 + ConfigConstants.KEY_MAX_SHORTCUTS + "=" + MAX_SHORTCUTS + ","
230 + ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL + "="
231 + MAX_UPDATES_PER_INTERVAL + ","
232 + ConfigConstants.KEY_MAX_ICON_DIMENSION_DP + "=" + MAX_ICON_DIMENSION + ","
233 + ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM + "="
234 + MAX_ICON_DIMENSION_LOWRAM + ","
235 + ConfigConstants.KEY_ICON_FORMAT + "=PNG,"
236 + ConfigConstants.KEY_ICON_QUALITY + "=100";
240 long injectClearCallingIdentity() {
241 return mContext.injectClearCallingIdentity();
245 void injectRestoreCallingIdentity(long token) {
246 mContext.injectRestoreCallingIdentity(token);
250 int injectDipToPixel(int dip) {
255 long injectCurrentTimeMillis() {
256 return mInjectedCurrentTimeMillis;
260 long injectElapsedRealtime() {
261 // TODO This should be kept separately from mInjectedCurrentTimeMillis, since
262 // this should increase even if we rewind mInjectedCurrentTimeMillis in some tests.
263 return mInjectedCurrentTimeMillis - START_TIME;
267 int injectBinderCallingUid() {
268 return mInjectedCallingUid;
272 int injectGetPackageUid(String packageName, int userId) {
273 return getInjectedPackageInfo(packageName, userId, false).applicationInfo.uid;
277 File injectSystemDataPath() {
278 return new File(mInjectedFilePathRoot, "system");
282 File injectUserDataPath(@UserIdInt int userId) {
283 return new File(mInjectedFilePathRoot, "user-" + userId);
287 void injectValidateIconResPackage(ShortcutInfo shortcut, Icon icon) {
292 boolean injectIsLowRamDevice() {
293 return mInjectedIsLowRamDevice;
297 void injectRegisterUidObserver(IUidObserver observer, int which) {
298 mUidObserver = observer;
302 boolean hasShortcutHostPermission(@NonNull String callingPackage, int userId) {
303 return mDefaultLauncherChecker.test(callingPackage, userId);
307 PackageInfo injectPackageInfoWithUninstalled(String packageName, @UserIdInt int userId,
308 boolean getSignatures) {
309 return getInjectedPackageInfo(packageName, userId, getSignatures);
313 ApplicationInfo injectApplicationInfoWithUninstalled(
314 String packageName, @UserIdInt int userId) {
315 PackageInfo pi = injectPackageInfoWithUninstalled(
316 packageName, userId, /* getSignatures= */ false);
317 return pi != null ? pi.applicationInfo : null;
321 List<PackageInfo> injectGetPackagesWithUninstalled(@UserIdInt int userId) {
322 return BaseShortcutManagerTest.this.getInstalledPackagesWithUninstalled(userId);
326 ActivityInfo injectGetActivityInfoWithMetadataWithUninstalled(ComponentName activity,
327 @UserIdInt int userId) {
328 final PackageInfo pi = mContext.injectGetActivitiesWithMetadata(
329 activity.getPackageName(), userId);
330 if (pi == null || pi.activities == null) {
333 for (ActivityInfo ai : pi.activities) {
334 if (!mEnabledActivityChecker.test(ai.getComponentName(), userId)) {
337 if (activity.equals(ai.getComponentName())) {
345 boolean injectIsMainActivity(@NonNull ComponentName activity, int userId) {
346 if (!mEnabledActivityChecker.test(activity, userId)) {
349 return mMainActivityChecker.test(activity, userId);
353 List<ResolveInfo> injectGetMainActivities(@NonNull String packageName, int userId) {
354 final PackageInfo pi = mContext.injectGetActivitiesWithMetadata(
355 packageName, userId);
356 if (pi == null || pi.activities == null) {
359 final ArrayList<ResolveInfo> ret = new ArrayList<>(pi.activities.length);
360 for (int i = 0; i < pi.activities.length; i++) {
361 if (!mEnabledActivityChecker.test(pi.activities[i].getComponentName(), userId)) {
364 final ResolveInfo ri = new ResolveInfo();
365 ri.activityInfo = pi.activities[i];
373 ComponentName injectGetDefaultMainActivity(@NonNull String packageName, int userId) {
374 return mMainActivityFetcher.apply(packageName, userId);
378 boolean injectIsActivityEnabledAndExported(ComponentName activity, @UserIdInt int userId) {
379 return mEnabledActivityChecker.test(activity, userId);
383 XmlResourceParser injectXmlMetaData(ActivityInfo activityInfo, String key) {
384 return mContext.injectXmlMetaData(activityInfo, key);
388 void injectPostToHandler(Runnable r) {
393 void injectRunOnNewThread(Runnable r) {
398 void injectEnforceCallingPermission(String permission, String message) {
399 if (!mCallerPermissions.contains(permission)) {
400 throw new SecurityException("Missing permission: " + permission);
405 boolean injectIsSafeModeEnabled() {
410 String injectBuildFingerprint() {
411 return mInjectedBuildFingerprint;
415 void wtf(String message, Throwable th) {
416 // During tests, WTF is fatal.
417 fail(message + " exception: " + th + "\n" + Log.getStackTraceString(th));
421 /** ShortcutManager with injection override methods. */
422 protected class ShortcutManagerTestable extends ShortcutManager {
423 public ShortcutManagerTestable(Context context, ShortcutServiceTestable service) {
424 super(context, service);
428 protected int injectMyUserId() {
429 return UserHandle.getUserId(mInjectedCallingUid);
433 public boolean setDynamicShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) {
434 // Note to simulate the binder RPC, we need to clone the incoming arguments.
435 // Otherwise bad things will happen because they're mutable.
436 return super.setDynamicShortcuts(cloneShortcutList(shortcutInfoList));
440 public boolean addDynamicShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) {
441 // Note to simulate the binder RPC, we need to clone the incoming arguments.
442 return super.addDynamicShortcuts(cloneShortcutList(shortcutInfoList));
446 public boolean updateShortcuts(List<ShortcutInfo> shortcutInfoList) {
447 // Note to simulate the binder RPC, we need to clone the incoming arguments.
448 return super.updateShortcuts(cloneShortcutList(shortcutInfoList));
452 protected class LauncherAppImplTestable extends LauncherAppsImpl {
453 final ServiceContext mContext;
455 public LauncherAppImplTestable(ServiceContext context) {
461 public void verifyCallingPackage(String callingPackage) {
466 void postToPackageMonitorHandler(Runnable r) {
471 int injectBinderCallingUid() {
472 return mInjectedCallingUid;
476 long injectClearCallingIdentity() {
477 final int prevCallingUid = mInjectedCallingUid;
478 mInjectedCallingUid = Process.SYSTEM_UID;
479 return prevCallingUid;
483 void injectRestoreCallingIdentity(long token) {
484 mInjectedCallingUid = (int) token;
488 protected class LauncherAppsTestable extends LauncherApps {
489 public LauncherAppsTestable(Context context, ILauncherApps service) {
490 super(context, service);
494 public static class ShortcutActivity extends Activity {
497 public static class ShortcutActivity2 extends Activity {
500 public static class ShortcutActivity3 extends Activity {
503 protected Looper mLooper;
504 protected Handler mHandler;
506 protected ServiceContext mServiceContext;
507 protected ClientContext mClientContext;
509 protected ShortcutServiceTestable mService;
510 protected ShortcutManagerTestable mManager;
511 protected ShortcutServiceInternal mInternal;
513 protected LauncherAppImplTestable mLauncherAppImpl;
515 // LauncherApps has per-instace state, so we need a differnt instance for each launcher.
516 protected final Map<Pair<Integer, String>, LauncherAppsTestable>
517 mLauncherAppsMap = new HashMap<>();
518 protected LauncherAppsTestable mLauncherApps; // Current one
520 protected File mInjectedFilePathRoot;
522 protected boolean mSafeMode;
524 protected long mInjectedCurrentTimeMillis;
526 protected boolean mInjectedIsLowRamDevice;
528 protected Locale mInjectedLocale = Locale.ENGLISH;
530 protected int mInjectedCallingUid;
531 protected String mInjectedClientPackage;
533 protected Map<String, PackageInfo> mInjectedPackages;
535 protected Set<PackageWithUser> mUninstalledPackages;
536 protected Set<String> mSystemPackages;
538 protected PackageManager mMockPackageManager;
539 protected PackageManagerInternal mMockPackageManagerInternal;
540 protected UserManager mMockUserManager;
541 protected UsageStatsManagerInternal mMockUsageStatsManagerInternal;
542 protected ActivityManagerInternal mMockActivityManagerInternal;
544 protected static final String CALLING_PACKAGE_1 = "com.android.test.1";
545 protected static final int CALLING_UID_1 = 10001;
547 protected static final String CALLING_PACKAGE_2 = "com.android.test.2";
548 protected static final int CALLING_UID_2 = 10002;
550 protected static final String CALLING_PACKAGE_3 = "com.android.test.3";
551 protected static final int CALLING_UID_3 = 10003;
553 protected static final String CALLING_PACKAGE_4 = "com.android.test.4";
554 protected static final int CALLING_UID_4 = 10004;
556 protected static final String LAUNCHER_1 = "com.android.launcher.1";
557 protected static final int LAUNCHER_UID_1 = 10011;
559 protected static final String LAUNCHER_2 = "com.android.launcher.2";
560 protected static final int LAUNCHER_UID_2 = 10012;
562 protected static final String LAUNCHER_3 = "com.android.launcher.3";
563 protected static final int LAUNCHER_UID_3 = 10013;
565 protected static final String LAUNCHER_4 = "com.android.launcher.4";
566 protected static final int LAUNCHER_UID_4 = 10014;
568 protected static final int USER_0 = UserHandle.USER_SYSTEM;
569 protected static final int USER_10 = 10;
570 protected static final int USER_11 = 11;
571 protected static final int USER_P0 = 20; // profile of user 0
573 protected static final UserHandle HANDLE_USER_0 = UserHandle.of(USER_0);
574 protected static final UserHandle HANDLE_USER_10 = UserHandle.of(USER_10);
575 protected static final UserHandle HANDLE_USER_11 = UserHandle.of(USER_11);
576 protected static final UserHandle HANDLE_USER_P0 = UserHandle.of(USER_P0);
578 protected static final UserInfo USER_INFO_0 = withProfileGroupId(
579 new UserInfo(USER_0, "user0",
580 UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY | UserInfo.FLAG_INITIALIZED), 10);
582 protected static final UserInfo USER_INFO_10 =
583 new UserInfo(USER_10, "user10", UserInfo.FLAG_INITIALIZED);
585 protected static final UserInfo USER_INFO_11 =
586 new UserInfo(USER_11, "user11", UserInfo.FLAG_INITIALIZED);
588 protected static final UserInfo USER_INFO_P0 = withProfileGroupId(
589 new UserInfo(USER_P0, "userP0",
590 UserInfo.FLAG_MANAGED_PROFILE), 10);
592 protected BiPredicate<String, Integer> mDefaultLauncherChecker =
593 (callingPackage, userId) ->
594 LAUNCHER_1.equals(callingPackage) || LAUNCHER_2.equals(callingPackage)
595 || LAUNCHER_3.equals(callingPackage) || LAUNCHER_4.equals(callingPackage);
597 protected BiPredicate<ComponentName, Integer> mMainActivityChecker =
598 (activity, userId) -> true;
600 protected BiFunction<String, Integer, ComponentName> mMainActivityFetcher =
601 (packageName, userId) -> new ComponentName(packageName, MAIN_ACTIVITY_CLASS);
603 protected BiPredicate<ComponentName, Integer> mEnabledActivityChecker
604 = (activity, userId) -> true; // all activities are enabled.
606 protected static final long START_TIME = 1440000000101L;
608 protected static final long INTERVAL = 10000;
610 protected static final int MAX_SHORTCUTS = 10;
612 protected static final int MAX_UPDATES_PER_INTERVAL = 3;
614 protected static final int MAX_ICON_DIMENSION = 128;
616 protected static final int MAX_ICON_DIMENSION_LOWRAM = 32;
618 protected static final ShortcutQuery QUERY_ALL = new ShortcutQuery();
620 protected final ArrayList<String> mCallerPermissions = new ArrayList<>();
622 protected final HashMap<String, LinkedHashMap<ComponentName, Integer>> mActivityMetadataResId
625 protected final Map<Integer, UserInfo> mUserInfos = new HashMap<>();
626 protected final Map<Integer, Boolean> mRunningUsers = new HashMap<>();
627 protected final Map<Integer, Boolean> mUnlockedUsers = new HashMap<>();
629 protected static final String PACKAGE_SYSTEM_LAUNCHER = "com.android.systemlauncher";
630 protected static final String PACKAGE_SYSTEM_LAUNCHER_NAME = "systemlauncher_name";
631 protected static final int PACKAGE_SYSTEM_LAUNCHER_PRIORITY = 0;
633 protected static final String PACKAGE_FALLBACK_LAUNCHER = "com.android.settings";
634 protected static final String PACKAGE_FALLBACK_LAUNCHER_NAME = "fallback";
635 protected static final int PACKAGE_FALLBACK_LAUNCHER_PRIORITY = -999;
637 protected String mInjectedBuildFingerprint = "build1";
640 QUERY_ALL.setQueryFlags(
641 ShortcutQuery.FLAG_GET_ALL_KINDS);
645 protected void setUp() throws Exception {
648 mLooper = Looper.getMainLooper();
649 mHandler = new Handler(mLooper);
651 mServiceContext = spy(new ServiceContext());
652 mClientContext = new ClientContext();
654 mMockPackageManager = mock(PackageManager.class);
655 mMockPackageManagerInternal = mock(PackageManagerInternal.class);
656 mMockUserManager = mock(UserManager.class);
657 mMockUsageStatsManagerInternal = mock(UsageStatsManagerInternal.class);
658 mMockActivityManagerInternal = mock(ActivityManagerInternal.class);
660 LocalServices.removeServiceForTest(PackageManagerInternal.class);
661 LocalServices.addService(PackageManagerInternal.class, mMockPackageManagerInternal);
662 LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
663 LocalServices.addService(UsageStatsManagerInternal.class, mMockUsageStatsManagerInternal);
664 LocalServices.removeServiceForTest(ActivityManagerInternal.class);
665 LocalServices.addService(ActivityManagerInternal.class, mMockActivityManagerInternal);
667 // Prepare injection values.
669 mInjectedCurrentTimeMillis = START_TIME;
671 mInjectedPackages = new HashMap<>();
672 addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 1);
673 addPackage(CALLING_PACKAGE_2, CALLING_UID_2, 2);
674 addPackage(CALLING_PACKAGE_3, CALLING_UID_3, 3);
675 addPackage(CALLING_PACKAGE_4, CALLING_UID_4, 10);
676 addPackage(LAUNCHER_1, LAUNCHER_UID_1, 4);
677 addPackage(LAUNCHER_2, LAUNCHER_UID_2, 5);
678 addPackage(LAUNCHER_3, LAUNCHER_UID_3, 6);
679 addPackage(LAUNCHER_4, LAUNCHER_UID_4, 10);
681 // CALLING_PACKAGE_3 / LAUNCHER_3 are not backup target.
682 updatePackageInfo(CALLING_PACKAGE_3,
683 pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
684 updatePackageInfo(LAUNCHER_3,
685 pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
687 mUninstalledPackages = new HashSet<>();
688 mSystemPackages = new HashSet<>();
690 mInjectedFilePathRoot = new File(getTestContext().getCacheDir(), "test-files");
692 deleteAllSavedFiles();
695 when(mMockUserManager.getUserInfo(anyInt())).thenAnswer(new AnswerWithSystemCheck<>(
696 inv -> mUserInfos.get((Integer) inv.getArguments()[0])));
698 mUserInfos.put(USER_0, USER_INFO_0);
699 mUserInfos.put(USER_10, USER_INFO_10);
700 mUserInfos.put(USER_11, USER_INFO_11);
701 mUserInfos.put(USER_P0, USER_INFO_P0);
703 // Set up isUserRunning and isUserUnlocked.
704 when(mMockUserManager.isUserRunning(anyInt())).thenAnswer(new AnswerWithSystemCheck<>(
705 inv -> b(mRunningUsers.get((Integer) inv.getArguments()[0]))));
707 when(mMockUserManager.isUserUnlocked(anyInt()))
708 .thenAnswer(new AnswerWithSystemCheck<>(inv -> {
709 final int userId = (Integer) inv.getArguments()[0];
710 return b(mRunningUsers.get(userId)) && b(mUnlockedUsers.get(userId));
712 // isUserUnlockingOrUnlocked() return the same value as isUserUnlocked().
713 when(mMockUserManager.isUserUnlockingOrUnlocked(anyInt()))
714 .thenAnswer(new AnswerWithSystemCheck<>(inv -> {
715 final int userId = (Integer) inv.getArguments()[0];
716 return b(mRunningUsers.get(userId)) && b(mUnlockedUsers.get(userId));
719 when(mMockActivityManagerInternal.getUidProcessState(anyInt())).thenReturn(
720 ActivityManager.PROCESS_STATE_CACHED_EMPTY);
722 // User 0 and P0 are always running
723 mRunningUsers.put(USER_0, true);
724 mRunningUsers.put(USER_10, false);
725 mRunningUsers.put(USER_11, false);
726 mRunningUsers.put(USER_P0, true);
728 // Unlock all users by default.
729 mUnlockedUsers.put(USER_0, true);
730 mUnlockedUsers.put(USER_10, true);
731 mUnlockedUsers.put(USER_11, true);
732 mUnlockedUsers.put(USER_P0, true);
737 // Start the service.
739 setCaller(CALLING_PACKAGE_1);
742 private static boolean b(Boolean value) {
743 return (value != null && value);
747 * Returns a boolean but also checks if the current UID is SYSTEM_UID.
749 protected class AnswerWithSystemCheck<T> implements Answer<T> {
750 private final Function<InvocationOnMock, T> mChecker;
752 public AnswerWithSystemCheck(Function<InvocationOnMock, T> checker) {
757 public T answer(InvocationOnMock invocation) throws Throwable {
758 assertEquals("Must be called on SYSTEM UID.",
759 Process.SYSTEM_UID, mInjectedCallingUid);
760 return mChecker.apply(invocation);
764 protected void setUpAppResources() throws Exception {
765 setUpAppResources(/* offset = */ 0);
768 protected void setUpAppResources(int ressIdOffset) throws Exception {
769 // ressIdOffset is used to adjust resource IDs to emulate the case where an updated app
770 // has resource IDs changed.
772 doAnswer(pmInvocation -> {
773 assertEquals(Process.SYSTEM_UID, mInjectedCallingUid);
775 final String packageName = (String) pmInvocation.getArguments()[0];
776 final int userId = (Integer) pmInvocation.getArguments()[1];
778 final Resources res = mock(Resources.class);
780 doAnswer(resInvocation -> {
781 final int argResId = (Integer) resInvocation.getArguments()[0];
783 return "string-" + packageName + "-user:" + userId + "-res:" + argResId
784 + "/" + mInjectedLocale;
785 }).when(res).getString(anyInt());
787 doAnswer(resInvocation -> {
788 final int resId = (Integer) resInvocation.getArguments()[0];
790 // Always use the "string" resource type. The type doesn't matter during the test.
791 return packageName + ":string/r" + resId;
792 }).when(res).getResourceName(anyInt());
794 doAnswer(resInvocation -> {
795 final String argResName = (String) resInvocation.getArguments()[0];
796 final String argType = (String) resInvocation.getArguments()[1];
797 final String argPackageName = (String) resInvocation.getArguments()[2];
799 // See the above code. getResourceName() will just use "r" + res ID as the entry
801 String entryName = argResName;
802 if (entryName.contains("/")) {
803 entryName = ShortcutInfo.getResourceEntryName(entryName);
805 return Integer.parseInt(entryName.substring(1)) + ressIdOffset;
806 }).when(res).getIdentifier(anyString(), anyString(), anyString());
808 }).when(mMockPackageManager).getResourcesForApplicationAsUser(anyString(), anyInt());
811 protected static UserInfo withProfileGroupId(UserInfo in, int groupId) {
812 in.profileGroupId = groupId;
817 protected void tearDown() throws Exception {
818 if (DUMP_IN_TEARDOWN) dumpsysOnLogcat("Teardown");
825 protected Context getTestContext() {
826 return getInstrumentation().getContext();
829 protected ShortcutManager getManager() {
833 protected void deleteAllSavedFiles() {
834 // Empty the data directory.
835 if (mInjectedFilePathRoot.exists()) {
836 Assert.assertTrue("failed to delete dir",
837 FileUtils.deleteContents(mInjectedFilePathRoot));
839 mInjectedFilePathRoot.mkdirs();
842 /** (Re-) init the manager and the service. */
843 protected void initService() {
846 LocalServices.removeServiceForTest(ShortcutServiceInternal.class);
848 // Instantiate targets.
849 mService = new ShortcutServiceTestable(mServiceContext, mLooper);
850 mManager = new ShortcutManagerTestable(mClientContext, mService);
852 mInternal = LocalServices.getService(ShortcutServiceInternal.class);
854 mLauncherAppImpl = new LauncherAppImplTestable(mServiceContext);
855 mLauncherApps = null;
856 mLauncherAppsMap.clear();
858 // Send boot sequence events.
859 mService.onBootPhase(SystemService.PHASE_LOCK_SETTINGS_READY);
861 mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
864 protected void shutdownServices() {
865 if (mService != null) {
866 // Flush all the unsaved data from the previous instance.
867 mService.saveDirtyInfo();
869 // Make sure everything is consistent.
870 mService.verifyStates();
872 LocalServices.removeServiceForTest(ShortcutServiceInternal.class);
877 mLauncherAppImpl = null;
878 mLauncherApps = null;
879 mLauncherAppsMap.clear();
882 protected void runOnHandler(Runnable r) {
883 final long token = mServiceContext.injectClearCallingIdentity();
887 mServiceContext.injectRestoreCallingIdentity(token);
891 protected void addPackage(String packageName, int uid, int version) {
892 addPackage(packageName, uid, version, packageName);
895 protected Signature[] genSignatures(String... signatures) {
896 final Signature[] sigs = new Signature[signatures.length];
897 for (int i = 0; i < signatures.length; i++){
898 sigs[i] = new Signature(signatures[i].getBytes());
903 protected PackageInfo genPackage(String packageName, int uid, int version, String... signatures) {
904 final PackageInfo pi = new PackageInfo();
905 pi.packageName = packageName;
906 pi.applicationInfo = new ApplicationInfo();
907 pi.applicationInfo.uid = uid;
908 pi.applicationInfo.flags = ApplicationInfo.FLAG_INSTALLED
909 | ApplicationInfo.FLAG_ALLOW_BACKUP;
910 pi.versionCode = version;
911 pi.applicationInfo.versionCode = version;
912 pi.signatures = genSignatures(signatures);
917 protected void addPackage(String packageName, int uid, int version, String... signatures) {
918 mInjectedPackages.put(packageName, genPackage(packageName, uid, version, signatures));
921 protected void updatePackageInfo(String packageName, Consumer<PackageInfo> c) {
922 c.accept(mInjectedPackages.get(packageName));
925 protected void updatePackageVersion(String packageName, int increment) {
926 updatePackageInfo(packageName, pi -> {
927 pi.versionCode += increment;
928 pi.applicationInfo.versionCode += increment;
932 protected void updatePackageLastUpdateTime(String packageName, long increment) {
933 updatePackageInfo(packageName, pi -> {
934 pi.lastUpdateTime += increment;
938 protected void setPackageLastUpdateTime(String packageName, long value) {
939 updatePackageInfo(packageName, pi -> {
940 pi.lastUpdateTime = value;
944 protected void uninstallPackage(int userId, String packageName) {
946 Log.v(TAG, "Unnstall package " + packageName + " / " + userId);
948 mUninstalledPackages.add(PackageWithUser.of(userId, packageName));
951 protected void installPackage(int userId, String packageName) {
953 Log.v(TAG, "Install package " + packageName + " / " + userId);
955 mUninstalledPackages.remove(PackageWithUser.of(userId, packageName));
958 PackageInfo getInjectedPackageInfo(String packageName, @UserIdInt int userId,
959 boolean getSignatures) {
960 final PackageInfo pi = mInjectedPackages.get(packageName);
961 if (pi == null) return null;
963 final PackageInfo ret = new PackageInfo();
964 ret.packageName = pi.packageName;
965 ret.versionCode = pi.versionCode;
966 ret.lastUpdateTime = pi.lastUpdateTime;
968 ret.applicationInfo = new ApplicationInfo(pi.applicationInfo);
969 ret.applicationInfo.uid = UserHandle.getUid(userId, pi.applicationInfo.uid);
970 ret.applicationInfo.packageName = pi.packageName;
972 if (mUninstalledPackages.contains(PackageWithUser.of(userId, packageName))) {
973 ret.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED;
975 if (mSystemPackages.contains(packageName)) {
976 ret.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
980 ret.signatures = pi.signatures;
986 protected void addApplicationInfo(PackageInfo pi, List<ApplicationInfo> list) {
987 if (pi != null && pi.applicationInfo != null) {
988 list.add(pi.applicationInfo);
992 protected List<ApplicationInfo> getInstalledApplications(int userId) {
993 final ArrayList<ApplicationInfo> ret = new ArrayList<>();
995 addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_1, userId, false), ret);
996 addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_2, userId, false), ret);
997 addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_3, userId, false), ret);
998 addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_4, userId, false), ret);
999 addApplicationInfo(getInjectedPackageInfo(LAUNCHER_1, userId, false), ret);
1000 addApplicationInfo(getInjectedPackageInfo(LAUNCHER_2, userId, false), ret);
1001 addApplicationInfo(getInjectedPackageInfo(LAUNCHER_3, userId, false), ret);
1002 addApplicationInfo(getInjectedPackageInfo(LAUNCHER_4, userId, false), ret);
1007 private void addPackageInfo(PackageInfo pi, List<PackageInfo> list) {
1013 private List<PackageInfo> getInstalledPackagesWithUninstalled(int userId) {
1014 final ArrayList<PackageInfo> ret = new ArrayList<>();
1016 addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_1, userId, false), ret);
1017 addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_2, userId, false), ret);
1018 addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_3, userId, false), ret);
1019 addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_4, userId, false), ret);
1020 addPackageInfo(getInjectedPackageInfo(LAUNCHER_1, userId, false), ret);
1021 addPackageInfo(getInjectedPackageInfo(LAUNCHER_2, userId, false), ret);
1022 addPackageInfo(getInjectedPackageInfo(LAUNCHER_3, userId, false), ret);
1023 addPackageInfo(getInjectedPackageInfo(LAUNCHER_4, userId, false), ret);
1028 protected void addManifestShortcutResource(ComponentName activity, int resId) {
1029 final String packageName = activity.getPackageName();
1030 LinkedHashMap<ComponentName, Integer> map = mActivityMetadataResId.get(packageName);
1032 map = new LinkedHashMap<>();
1033 mActivityMetadataResId.put(packageName, map);
1035 map.put(activity, resId);
1038 protected PackageInfo injectGetActivitiesWithMetadata(String packageName, @UserIdInt int userId) {
1039 final PackageInfo ret = getInjectedPackageInfo(packageName, userId,
1040 /* getSignatures=*/ false);
1042 final HashMap<ComponentName, Integer> activities = mActivityMetadataResId.get(packageName);
1043 if (activities != null) {
1044 final ArrayList<ActivityInfo> list = new ArrayList<>();
1046 for (ComponentName cn : activities.keySet()) {
1047 ActivityInfo ai = new ActivityInfo();
1048 ai.packageName = cn.getPackageName();
1049 ai.name = cn.getClassName();
1050 ai.metaData = new Bundle();
1051 ai.metaData.putInt(ShortcutParser.METADATA_KEY, activities.get(cn));
1052 ai.applicationInfo = ret.applicationInfo;
1055 ret.activities = list.toArray(new ActivityInfo[list.size()]);
1060 protected XmlResourceParser injectXmlMetaData(ActivityInfo activityInfo, String key) {
1061 if (!ShortcutParser.METADATA_KEY.equals(key) || activityInfo.metaData == null) {
1064 final int resId = activityInfo.metaData.getInt(key);
1065 return getTestContext().getResources().getXml(resId);
1068 /** Replace the current calling package */
1069 protected void setCaller(String packageName, int userId) {
1070 mInjectedClientPackage = packageName;
1071 mInjectedCallingUid =
1072 Preconditions.checkNotNull(getInjectedPackageInfo(packageName, userId, false),
1073 "Unknown package").applicationInfo.uid;
1075 // Set up LauncherApps for this caller.
1076 final Pair<Integer, String> key = Pair.create(userId, packageName);
1077 if (!mLauncherAppsMap.containsKey(key)) {
1078 mLauncherAppsMap.put(key, new LauncherAppsTestable(mClientContext, mLauncherAppImpl));
1080 mLauncherApps = mLauncherAppsMap.get(key);
1083 protected void setCaller(String packageName) {
1084 setCaller(packageName, UserHandle.USER_SYSTEM);
1087 protected String getCallingPackage() {
1088 return mInjectedClientPackage;
1091 protected void setDefaultLauncherChecker(BiPredicate<String, Integer> p) {
1092 mDefaultLauncherChecker = p;
1095 protected void runWithCaller(String packageName, int userId, Runnable r) {
1096 final String previousPackage = mInjectedClientPackage;
1097 final int previousUserId = UserHandle.getUserId(mInjectedCallingUid);
1099 setCaller(packageName, userId);
1103 setCaller(previousPackage, previousUserId);
1106 protected void runWithSystemUid(Runnable r) {
1107 final int origUid = mInjectedCallingUid;
1108 mInjectedCallingUid = Process.SYSTEM_UID;
1110 mInjectedCallingUid = origUid;
1113 protected void lookupAndFillInResourceNames(ShortcutInfo si) {
1114 runWithSystemUid(() -> si.lookupAndFillInResourceNames(
1115 mService.injectGetResourcesForApplicationAsUser(si.getPackage(), si.getUserId())));
1118 protected int getCallingUserId() {
1119 return UserHandle.getUserId(mInjectedCallingUid);
1122 protected UserHandle getCallingUser() {
1123 return UserHandle.of(getCallingUserId());
1126 /** For debugging */
1127 protected void dumpsysOnLogcat() {
1128 dumpsysOnLogcat("");
1131 protected void dumpsysOnLogcat(String message) {
1132 dumpsysOnLogcat(message, false);
1135 protected void dumpsysOnLogcat(String message, boolean force) {
1136 if (force || !ENABLE_DUMP) return;
1138 Log.v(TAG, "Dumping ShortcutService: " + message);
1139 for (String line : dumpsys(null).split("\n")) {
1144 protected String dumpCheckin() {
1145 return dumpsys(new String[]{"--checkin"});
1148 private String dumpsys(String[] args) {
1149 final ArrayList<String> origPermissions = new ArrayList<>(mCallerPermissions);
1150 mCallerPermissions.add(android.Manifest.permission.DUMP);
1152 final ByteArrayOutputStream out = new ByteArrayOutputStream();
1153 final PrintWriter pw = new PrintWriter(out);
1154 mService.dump(/* fd */ null, pw, args);
1157 return out.toString();
1159 mCallerPermissions.clear();
1160 mCallerPermissions.addAll(origPermissions);
1165 * For debugging, dump arbitrary file on logcat.
1167 protected void dumpFileOnLogcat(String path) {
1168 dumpFileOnLogcat(path, "");
1171 protected void dumpFileOnLogcat(String path, String message) {
1172 if (!ENABLE_DUMP) return;
1174 Log.v(TAG, "Dumping file: " + path + " " + message);
1175 final StringBuilder sb = new StringBuilder();
1176 try (BufferedReader br = new BufferedReader(new FileReader(path))) {
1178 while ((line = br.readLine()) != null) {
1181 } catch (Exception e) {
1182 Log.e(TAG, "Couldn't read file", e);
1183 fail("Exception " + e);
1188 * For debugging, dump the main state file on logcat.
1190 protected void dumpBaseStateFile() {
1191 mService.saveDirtyInfo();
1192 dumpFileOnLogcat(mInjectedFilePathRoot.getAbsolutePath()
1193 + "/system/" + ShortcutService.FILENAME_BASE_STATE);
1197 * For debugging, dump per-user state file on logcat.
1199 protected void dumpUserFile(int userId) {
1200 dumpUserFile(userId, "");
1203 protected void dumpUserFile(int userId, String message) {
1204 mService.saveDirtyInfo();
1205 dumpFileOnLogcat(mInjectedFilePathRoot.getAbsolutePath()
1207 + "/" + ShortcutService.FILENAME_USER_PACKAGES, message);
1211 * Make a shortcut with an ID.
1213 protected ShortcutInfo makeShortcut(String id) {
1214 return makeShortcut(
1215 id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
1216 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
1219 protected ShortcutInfo makeShortcutWithTitle(String id, String title) {
1220 return makeShortcut(
1221 id, title, /* activity =*/ null, /* icon =*/ null,
1222 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
1226 * Make a shortcut with an ID and timestamp.
1228 protected ShortcutInfo makeShortcutWithTimestamp(String id, long timestamp) {
1229 final ShortcutInfo s = makeShortcut(
1230 id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
1231 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
1232 s.setTimestamp(timestamp);
1237 * Make a shortcut with an ID, a timestamp and an activity component
1239 protected ShortcutInfo makeShortcutWithTimestampWithActivity(String id, long timestamp,
1240 ComponentName activity) {
1241 final ShortcutInfo s = makeShortcut(
1242 id, "Title-" + id, activity, /* icon =*/ null,
1243 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
1244 s.setTimestamp(timestamp);
1249 * Make a shortcut with an ID and icon.
1251 protected ShortcutInfo makeShortcutWithIcon(String id, Icon icon) {
1252 return makeShortcut(
1253 id, "Title-" + id, /* activity =*/ null, icon,
1254 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
1257 protected ShortcutInfo makePackageShortcut(String packageName, String id) {
1258 String origCaller = getCallingPackage();
1260 setCaller(packageName);
1261 ShortcutInfo s = makeShortcut(
1262 id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
1263 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
1264 setCaller(origCaller); // restore the caller
1270 * Make multiple shortcuts with IDs.
1272 protected List<ShortcutInfo> makeShortcuts(String... ids) {
1273 final ArrayList<ShortcutInfo> ret = new ArrayList();
1274 for (String id : ids) {
1275 ret.add(makeShortcut(id));
1280 protected ShortcutInfo.Builder makeShortcutBuilder() {
1281 return new ShortcutInfo.Builder(mClientContext);
1284 protected ShortcutInfo makeShortcutWithActivity(String id, ComponentName activity) {
1285 return makeShortcut(
1286 id, "Title-" + id, activity, /* icon =*/ null,
1287 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
1290 protected ShortcutInfo makeShortcutWithIntent(String id, Intent intent) {
1291 return makeShortcut(
1292 id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
1293 intent, /* rank =*/ 0);
1296 protected ShortcutInfo makeShortcutWithActivityAndTitle(String id, ComponentName activity,
1298 return makeShortcut(
1299 id, title, activity, /* icon =*/ null,
1300 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
1303 protected ShortcutInfo makeShortcutWithActivityAndRank(String id, ComponentName activity,
1305 return makeShortcut(
1306 id, "Title-" + id, activity, /* icon =*/ null,
1307 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), rank);
1311 * Make a shortcut with details.
1313 protected ShortcutInfo makeShortcut(String id, String title, ComponentName activity,
1314 Icon icon, Intent intent, int rank) {
1315 final ShortcutInfo.Builder b = new ShortcutInfo.Builder(mClientContext, id)
1316 .setActivity(new ComponentName(mClientContext.getPackageName(), "dummy"))
1317 .setShortLabel(title)
1323 if (activity != null) {
1324 b.setActivity(activity);
1326 final ShortcutInfo s = b.build();
1328 s.setTimestamp(mInjectedCurrentTimeMillis); // HACK
1333 protected ShortcutInfo makeShortcutWithIntents(String id, Intent... intents) {
1334 return makeShortcut(
1335 id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
1336 intents, /* rank =*/ 0);
1340 * Make a shortcut with details.
1342 protected ShortcutInfo makeShortcut(String id, String title, ComponentName activity,
1343 Icon icon, Intent[] intents, int rank) {
1344 final ShortcutInfo.Builder b = new ShortcutInfo.Builder(mClientContext, id)
1345 .setActivity(new ComponentName(mClientContext.getPackageName(), "dummy"))
1346 .setShortLabel(title)
1348 .setIntents(intents);
1352 if (activity != null) {
1353 b.setActivity(activity);
1355 final ShortcutInfo s = b.build();
1357 s.setTimestamp(mInjectedCurrentTimeMillis); // HACK
1363 * Make a shortcut with details.
1365 protected ShortcutInfo makeShortcutWithExtras(String id, Intent intent,
1366 PersistableBundle extras) {
1367 final ShortcutInfo.Builder b = new ShortcutInfo.Builder(mClientContext, id)
1368 .setActivity(new ComponentName(mClientContext.getPackageName(), "dummy"))
1369 .setShortLabel("title-" + id)
1372 final ShortcutInfo s = b.build();
1374 s.setTimestamp(mInjectedCurrentTimeMillis); // HACK
1382 protected Intent makeIntent(String action, Class<?> clazz, Object... bundleKeysAndValues) {
1383 final Intent intent = new Intent(action);
1384 intent.setComponent(makeComponent(clazz));
1385 intent.replaceExtras(makeBundle(bundleKeysAndValues));
1390 * Make an component name, with the client context.
1393 protected ComponentName makeComponent(Class<?> clazz) {
1394 return new ComponentName(mClientContext, clazz);
1398 protected ShortcutInfo findById(List<ShortcutInfo> list, String id) {
1399 for (ShortcutInfo s : list) {
1400 if (s.getId().equals(id)) {
1404 fail("Shortcut with id " + id + " not found");
1408 protected void assertSystem() {
1409 assertEquals("Caller must be system", Process.SYSTEM_UID, mInjectedCallingUid);
1412 protected void assertResetTimes(long expectedLastResetTime, long expectedNextResetTime) {
1413 assertEquals(expectedLastResetTime, mService.getLastResetTimeLocked());
1414 assertEquals(expectedNextResetTime, mService.getNextResetTimeLocked());
1417 public static List<ShortcutInfo> assertAllNotHaveIcon(
1418 List<ShortcutInfo> actualShortcuts) {
1419 for (ShortcutInfo s : actualShortcuts) {
1420 assertNull("ID " + s.getId(), s.getIcon());
1422 return actualShortcuts;
1426 protected List<ShortcutInfo> assertAllHaveFlags(@NonNull List<ShortcutInfo> actualShortcuts,
1427 int shortcutFlags) {
1428 for (ShortcutInfo s : actualShortcuts) {
1429 assertTrue("ID " + s.getId() + " doesn't have flags " + shortcutFlags,
1430 s.hasFlags(shortcutFlags));
1432 return actualShortcuts;
1435 protected ShortcutInfo getPackageShortcut(String packageName, String shortcutId, int userId) {
1436 return mService.getPackageShortcutForTest(packageName, shortcutId, userId);
1439 protected void assertShortcutExists(String packageName, String shortcutId, int userId) {
1440 assertTrue(getPackageShortcut(packageName, shortcutId, userId) != null);
1443 protected void assertShortcutNotExists(String packageName, String shortcutId, int userId) {
1444 assertTrue(getPackageShortcut(packageName, shortcutId, userId) == null);
1447 protected Intent[] launchShortcutAndGetIntentsInner(Runnable shortcutStarter,
1448 @NonNull String packageName, @NonNull String shortcutId, int userId) {
1449 reset(mMockActivityManagerInternal);
1450 shortcutStarter.run();
1452 final ArgumentCaptor<Intent[]> intentsCaptor = ArgumentCaptor.forClass(Intent[].class);
1453 verify(mMockActivityManagerInternal).startActivitiesAsPackage(
1456 intentsCaptor.capture(),
1458 return intentsCaptor.getValue();
1461 protected Intent[] launchShortcutAndGetIntents(
1462 @NonNull String packageName, @NonNull String shortcutId, int userId) {
1463 return launchShortcutAndGetIntentsInner(
1465 mLauncherApps.startShortcut(packageName, shortcutId, null, null,
1466 UserHandle.of(userId));
1467 }, packageName, shortcutId, userId
1471 protected Intent launchShortcutAndGetIntent(
1472 @NonNull String packageName, @NonNull String shortcutId, int userId) {
1473 final Intent[] intents = launchShortcutAndGetIntents(packageName, shortcutId, userId);
1474 assertEquals(1, intents.length);
1478 protected Intent[] launchShortcutAndGetIntents_withShortcutInfo(
1479 @NonNull String packageName, @NonNull String shortcutId, int userId) {
1480 return launchShortcutAndGetIntentsInner(
1482 mLauncherApps.startShortcut(
1483 getShortcutInfoAsLauncher(packageName, shortcutId, userId), null, null);
1484 }, packageName, shortcutId, userId
1488 protected Intent launchShortcutAndGetIntent_withShortcutInfo(
1489 @NonNull String packageName, @NonNull String shortcutId, int userId) {
1490 final Intent[] intents = launchShortcutAndGetIntents_withShortcutInfo(
1491 packageName, shortcutId, userId);
1492 assertEquals(1, intents.length);
1496 protected void assertShortcutLaunchable(@NonNull String packageName, @NonNull String shortcutId,
1498 assertNotNull(launchShortcutAndGetIntent(packageName, shortcutId, userId));
1499 assertNotNull(launchShortcutAndGetIntent_withShortcutInfo(packageName, shortcutId, userId));
1502 protected void assertShortcutNotLaunched(@NonNull String packageName,
1503 @NonNull String shortcutId, int userId) {
1504 reset(mMockActivityManagerInternal);
1506 mLauncherApps.startShortcut(packageName, shortcutId, null, null,
1507 UserHandle.of(userId));
1508 fail("ActivityNotFoundException was not thrown");
1509 } catch (ActivityNotFoundException expected) {
1511 // This shouldn't have been called.
1512 verify(mMockActivityManagerInternal, times(0)).startActivitiesAsPackage(
1515 any(Intent[].class),
1519 protected void assertStartShortcutThrowsException(@NonNull String packageName,
1520 @NonNull String shortcutId, int userId, Class<?> expectedException) {
1521 Exception thrown = null;
1523 mLauncherApps.startShortcut(packageName, shortcutId, null, null,
1524 UserHandle.of(userId));
1525 } catch (Exception e) {
1528 assertNotNull("Exception was not thrown", thrown);
1529 assertEquals("Exception type different", expectedException, thrown.getClass());
1532 protected void assertBitmapDirectories(int userId, String... expectedDirectories) {
1533 final Set<String> expected = hashSet(set(expectedDirectories));
1535 final Set<String> actual = new HashSet<>();
1537 final File[] files = mService.getUserBitmapFilePath(userId).listFiles();
1538 if (files != null) {
1539 for (File child : files) {
1540 if (child.isDirectory()) {
1541 actual.add(child.getName());
1546 assertEquals(expected, actual);
1549 protected void assertBitmapFiles(int userId, String packageName, String... expectedFiles) {
1550 final Set<String> expected = hashSet(set(expectedFiles));
1552 final Set<String> actual = new HashSet<>();
1554 final File[] files = new File(mService.getUserBitmapFilePath(userId), packageName)
1556 if (files != null) {
1557 for (File child : files) {
1558 if (child.isFile()) {
1559 actual.add(child.getName());
1564 assertEquals(expected, actual);
1567 protected String getBitmapFilename(int userId, String packageName, String shortcutId) {
1568 final ShortcutInfo si = mService.getPackageShortcutForTest(packageName, shortcutId, userId);
1572 return new File(si.getBitmapPath()).getName();
1576 * @return all shortcuts stored internally for the caller. This reflects the *internal* view
1577 * of shortcuts, which may be different from what {@link #getCallerVisibleShortcuts} would
1578 * return, because getCallerVisibleShortcuts() will get shortcuts from the proper "front door"
1579 * which performs some extra checks, like {@link ShortcutPackage#onRestored}.
1581 protected List<ShortcutInfo> getCallerShortcuts() {
1582 final ShortcutPackage p = mService.getPackageShortcutForTest(
1583 getCallingPackage(), getCallingUserId());
1584 return p == null ? null : p.getAllShortcutsForTest();
1588 * @return all shortcuts owned by caller that are actually visible via ShortcutManager.
1589 * See also {@link #getCallerShortcuts}.
1591 protected List<ShortcutInfo> getCallerVisibleShortcuts() {
1592 final ArrayList<ShortcutInfo> ret = new ArrayList<>();
1593 ret.addAll(mManager.getDynamicShortcuts());
1594 ret.addAll(mManager.getPinnedShortcuts());
1595 ret.addAll(mManager.getManifestShortcuts());
1599 protected ShortcutInfo getCallerShortcut(String shortcutId) {
1600 return getPackageShortcut(getCallingPackage(), shortcutId, getCallingUserId());
1603 protected List<ShortcutInfo> getLauncherShortcuts(String launcher, int userId, int queryFlags) {
1604 final List<ShortcutInfo>[] ret = new List[1];
1605 runWithCaller(launcher, userId, () -> {
1606 final ShortcutQuery q = new ShortcutQuery();
1607 q.setQueryFlags(queryFlags);
1608 ret[0] = mLauncherApps.getShortcuts(q, UserHandle.of(userId));
1613 protected List<ShortcutInfo> getLauncherPinnedShortcuts(String launcher, int userId) {
1614 return getLauncherShortcuts(launcher, userId, ShortcutQuery.FLAG_GET_PINNED);
1617 protected ShortcutInfo getShortcutInfoAsLauncher(String packageName, String shortcutId,
1619 final List<ShortcutInfo> infoList =
1620 mLauncherApps.getShortcutInfo(packageName, list(shortcutId),
1621 UserHandle.of(userId));
1622 assertEquals("No shortcutInfo found (or too many of them)", 1, infoList.size());
1623 return infoList.get(0);
1626 protected Intent genPackageAddIntent(String packageName, int userId) {
1627 installPackage(userId, packageName);
1629 Intent i = new Intent(Intent.ACTION_PACKAGE_ADDED);
1630 i.setData(Uri.parse("package:" + packageName));
1631 i.putExtra(Intent.EXTRA_USER_HANDLE, userId);
1635 protected Intent genPackageDeleteIntent(String pakcageName, int userId) {
1636 uninstallPackage(userId, pakcageName);
1638 Intent i = new Intent(Intent.ACTION_PACKAGE_REMOVED);
1639 i.setData(Uri.parse("package:" + pakcageName));
1640 i.putExtra(Intent.EXTRA_USER_HANDLE, userId);
1644 protected Intent genPackageUpdateIntent(String pakcageName, int userId) {
1645 installPackage(userId, pakcageName);
1647 Intent i = new Intent(Intent.ACTION_PACKAGE_ADDED);
1648 i.setData(Uri.parse("package:" + pakcageName));
1649 i.putExtra(Intent.EXTRA_USER_HANDLE, userId);
1650 i.putExtra(Intent.EXTRA_REPLACING, true);
1654 protected Intent genPackageChangedIntent(String pakcageName, int userId) {
1655 Intent i = new Intent(Intent.ACTION_PACKAGE_CHANGED);
1656 i.setData(Uri.parse("package:" + pakcageName));
1657 i.putExtra(Intent.EXTRA_USER_HANDLE, userId);
1661 protected Intent genPackageDataClear(String packageName, int userId) {
1662 Intent i = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED);
1663 i.setData(Uri.parse("package:" + packageName));
1664 i.putExtra(Intent.EXTRA_USER_HANDLE, userId);
1668 protected void assertExistsAndShadow(ShortcutPackageItem spi) {
1670 assertTrue(spi.getPackageInfo().isShadow());
1673 protected File makeFile(File baseDirectory, String... paths) {
1674 File ret = baseDirectory;
1676 for (String path : paths) {
1677 ret = new File(ret, path);
1683 protected boolean bitmapDirectoryExists(String packageName, int userId) {
1684 final File path = new File(mService.getUserBitmapFilePath(userId), packageName);
1685 return path.isDirectory();
1687 protected static ShortcutQuery buildQuery(long changedSince,
1688 String packageName, ComponentName componentName,
1689 /* @ShortcutQuery.QueryFlags */ int flags) {
1690 return buildQuery(changedSince, packageName, null, componentName, flags);
1693 protected static ShortcutQuery buildQuery(long changedSince,
1694 String packageName, List<String> shortcutIds, ComponentName componentName,
1695 /* @ShortcutQuery.QueryFlags */ int flags) {
1696 final ShortcutQuery q = new ShortcutQuery();
1697 q.setChangedSince(changedSince);
1698 q.setPackage(packageName);
1699 q.setShortcutIds(shortcutIds);
1700 q.setActivity(componentName);
1701 q.setQueryFlags(flags);
1705 protected static ShortcutQuery buildAllQuery(String packageName) {
1706 final ShortcutQuery q = new ShortcutQuery();
1707 q.setPackage(packageName);
1708 q.setQueryFlags(ShortcutQuery.FLAG_GET_ALL_KINDS);
1712 protected static ShortcutQuery buildPinnedQuery(String packageName) {
1713 final ShortcutQuery q = new ShortcutQuery();
1714 q.setPackage(packageName);
1715 q.setQueryFlags(ShortcutQuery.FLAG_GET_PINNED);
1719 protected static ShortcutQuery buildQueryWithFlags(int queryFlags) {
1720 final ShortcutQuery q = new ShortcutQuery();
1721 q.setQueryFlags(queryFlags);
1725 protected void backupAndRestore() {
1726 int prevUid = mInjectedCallingUid;
1728 mInjectedCallingUid = Process.SYSTEM_UID; // Only system can call it.
1730 dumpsysOnLogcat("Before backup");
1732 final byte[] payload = mService.getBackupPayload(USER_0);
1734 final String xml = new String(payload);
1735 Log.v(TAG, "Backup payload:");
1736 for (String line : xml.split("\n")) {
1741 // Before doing anything else, uninstall all packages.
1742 for (int userId : list(USER_0, USER_P0)) {
1743 for (String pkg : list(CALLING_PACKAGE_1, CALLING_PACKAGE_2, CALLING_PACKAGE_3,
1744 LAUNCHER_1, LAUNCHER_2, LAUNCHER_3)) {
1745 uninstallPackage(userId, pkg);
1751 deleteAllSavedFiles();
1754 mService.applyRestore(payload, USER_0);
1756 // handleUnlockUser will perform the gone package check, but it shouldn't remove
1757 // shadow information.
1758 mService.handleUnlockUser(USER_0);
1760 dumpsysOnLogcat("After restore");
1762 mInjectedCallingUid = prevUid;
1765 protected void prepareCrossProfileDataSet() {
1766 mRunningUsers.put(USER_10, true); // this test needs user 10.
1768 runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1769 assertTrue(mManager.setDynamicShortcuts(list(
1770 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
1771 makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
1773 runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1774 assertTrue(mManager.setDynamicShortcuts(list(
1775 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
1776 makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
1778 runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
1779 assertTrue(mManager.setDynamicShortcuts(list(
1780 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
1781 makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
1783 runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
1784 assertTrue(mManager.setDynamicShortcuts(list()));
1786 runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
1787 assertTrue(mManager.setDynamicShortcuts(list(
1788 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
1789 makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
1791 runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
1792 assertTrue(mManager.setDynamicShortcuts(list(
1793 makeShortcut("x1"), makeShortcut("x2"), makeShortcut("x3"),
1794 makeShortcut("x4"), makeShortcut("x5"), makeShortcut("x6"))));
1797 runWithCaller(LAUNCHER_1, USER_0, () -> {
1798 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_0);
1799 mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s1", "s2"), HANDLE_USER_0);
1800 mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s1", "s2", "s3"), HANDLE_USER_0);
1802 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1", "s4"), HANDLE_USER_P0);
1804 runWithCaller(LAUNCHER_2, USER_0, () -> {
1805 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0);
1806 mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s2", "s3"), HANDLE_USER_0);
1807 mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s2", "s3", "s4"), HANDLE_USER_0);
1809 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2", "s5"), HANDLE_USER_P0);
1812 // Note LAUNCHER_3 has allowBackup=false.
1813 runWithCaller(LAUNCHER_3, USER_0, () -> {
1814 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0);
1815 mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s3", "s4"), HANDLE_USER_0);
1816 mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s3", "s4", "s5"), HANDLE_USER_0);
1818 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3", "s6"), HANDLE_USER_P0);
1820 runWithCaller(LAUNCHER_4, USER_0, () -> {
1821 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list(), HANDLE_USER_0);
1822 mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list(), HANDLE_USER_0);
1823 mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list(), HANDLE_USER_0);
1824 mLauncherApps.pinShortcuts(CALLING_PACKAGE_4, list(), HANDLE_USER_0);
1827 // Launcher on a managed profile is referring ot user 0!
1828 runWithCaller(LAUNCHER_1, USER_P0, () -> {
1829 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3", "s4"), HANDLE_USER_0);
1830 mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s3", "s4", "s5"), HANDLE_USER_0);
1831 mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s3", "s4", "s5", "s6"),
1834 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s4", "s1"), HANDLE_USER_P0);
1836 runWithCaller(LAUNCHER_1, USER_10, () -> {
1837 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("x4", "x5"), HANDLE_USER_10);
1838 mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("x4", "x5", "x6"), HANDLE_USER_10);
1839 mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("x4", "x5", "x6", "x1"),
1843 // Then remove some dynamic shortcuts.
1844 runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1845 assertTrue(mManager.setDynamicShortcuts(list(
1846 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
1848 runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1849 assertTrue(mManager.setDynamicShortcuts(list(
1850 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
1852 runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
1853 assertTrue(mManager.setDynamicShortcuts(list(
1854 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
1856 runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
1857 assertTrue(mManager.setDynamicShortcuts(list()));
1859 runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
1860 assertTrue(mManager.setDynamicShortcuts(list(
1861 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
1863 runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
1864 assertTrue(mManager.setDynamicShortcuts(list(
1865 makeShortcut("x1"), makeShortcut("x2"), makeShortcut("x3"))));
1869 public static List<ShortcutInfo> assertAllHaveIconResId(
1870 List<ShortcutInfo> actualShortcuts) {
1871 for (ShortcutInfo s : actualShortcuts) {
1872 assertTrue("ID " + s.getId() + " not have icon res ID", s.hasIconResource());
1873 assertFalse("ID " + s.getId() + " shouldn't have icon FD", s.hasIconFile());
1875 return actualShortcuts;
1878 public static List<ShortcutInfo> assertAllHaveIconFile(
1879 List<ShortcutInfo> actualShortcuts) {
1880 for (ShortcutInfo s : actualShortcuts) {
1881 assertFalse("ID " + s.getId() + " shouldn't have icon res ID", s.hasIconResource());
1882 assertTrue("ID " + s.getId() + " not have icon FD", s.hasIconFile());
1884 return actualShortcuts;
1887 public static List<ShortcutInfo> assertAllHaveIcon(
1888 List<ShortcutInfo> actualShortcuts) {
1889 for (ShortcutInfo s : actualShortcuts) {
1890 assertTrue("ID " + s.getId() + " has no icon ", s.hasIconFile() || s.hasIconResource());
1892 return actualShortcuts;
1895 public static List<ShortcutInfo> assertAllStringsResolved(
1896 List<ShortcutInfo> actualShortcuts) {
1897 for (ShortcutInfo s : actualShortcuts) {
1898 assertTrue("ID " + s.getId(), s.hasStringResourcesResolved());
1900 return actualShortcuts;
1903 public String readTestAsset(String assetPath) throws IOException {
1904 final StringBuilder sb = new StringBuilder();
1905 try (BufferedReader br = new BufferedReader(
1906 new InputStreamReader(
1907 getTestContext().getResources().getAssets().open(assetPath)))) {
1909 while ((line = br.readLine()) != null) {
1911 sb.append(System.lineSeparator());
1914 return sb.toString();
1917 protected void prepareGetHomeActivitiesAsUser(ComponentName preferred,
1918 List<ResolveInfo> candidates, int userId) {
1920 ((List) inv.getArguments()[0]).addAll(candidates);
1922 }).when(mMockPackageManagerInternal).getHomeActivitiesAsUser(any(List.class), eq(userId));
1925 protected static ComponentName cn(String packageName, String name) {
1926 return new ComponentName(packageName, name);
1929 protected static ResolveInfo ri(String packageName, String name, boolean isSystem, int priority) {
1930 final ResolveInfo ri = new ResolveInfo();
1931 ri.activityInfo = new ActivityInfo();
1932 ri.activityInfo.applicationInfo = new ApplicationInfo();
1934 ri.activityInfo.packageName = packageName;
1935 ri.activityInfo.name = name;
1937 ri.activityInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
1939 ri.priority = priority;
1943 protected static ResolveInfo getSystemLauncher() {
1944 return ri(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME, true,
1945 PACKAGE_SYSTEM_LAUNCHER_PRIORITY);
1948 protected static ResolveInfo getFallbackLauncher() {
1949 return ri(PACKAGE_FALLBACK_LAUNCHER, PACKAGE_FALLBACK_LAUNCHER_NAME, true,
1950 PACKAGE_FALLBACK_LAUNCHER_PRIORITY);