BaseShortcutManagerTest.java revision 3107ff78454d54c0494911bf69ca952152af7cf0
1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
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
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16package com.android.server.pm;
17
18import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.cloneShortcutList;
19import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.hashSet;
20import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
21import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.makeBundle;
22import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.set;
23
24import static org.mockito.Matchers.any;
25import static org.mockito.Matchers.anyInt;
26import static org.mockito.Matchers.anyString;
27import static org.mockito.Matchers.eq;
28import static org.mockito.Mockito.doAnswer;
29import static org.mockito.Mockito.mock;
30import static org.mockito.Mockito.reset;
31import static org.mockito.Mockito.spy;
32import static org.mockito.Mockito.times;
33import static org.mockito.Mockito.verify;
34import static org.mockito.Mockito.when;
35
36import android.annotation.NonNull;
37import android.annotation.UserIdInt;
38import android.app.Activity;
39import android.app.ActivityManager;
40import android.app.ActivityManagerInternal;
41import android.app.IUidObserver;
42import android.app.usage.UsageStatsManagerInternal;
43import android.content.ActivityNotFoundException;
44import android.content.BroadcastReceiver;
45import android.content.ComponentName;
46import android.content.Context;
47import android.content.Intent;
48import android.content.IntentFilter;
49import android.content.pm.ActivityInfo;
50import android.content.pm.ApplicationInfo;
51import android.content.pm.ILauncherApps;
52import android.content.pm.LauncherApps;
53import android.content.pm.LauncherApps.ShortcutQuery;
54import android.content.pm.PackageInfo;
55import android.content.pm.PackageManager;
56import android.content.pm.PackageManagerInternal;
57import android.content.pm.ResolveInfo;
58import android.content.pm.ShortcutInfo;
59import android.content.pm.ShortcutManager;
60import android.content.pm.ShortcutServiceInternal;
61import android.content.pm.Signature;
62import android.content.pm.UserInfo;
63import android.content.res.Resources;
64import android.content.res.XmlResourceParser;
65import android.graphics.drawable.Icon;
66import android.net.Uri;
67import android.os.Bundle;
68import android.os.FileUtils;
69import android.os.Handler;
70import android.os.Looper;
71import android.os.PersistableBundle;
72import android.os.Process;
73import android.os.UserHandle;
74import android.os.UserManager;
75import android.test.InstrumentationTestCase;
76import android.test.mock.MockContext;
77import android.util.Log;
78import android.util.Pair;
79
80import com.android.internal.util.Preconditions;
81import com.android.server.LocalServices;
82import com.android.server.SystemService;
83import com.android.server.pm.LauncherAppsService.LauncherAppsImpl;
84import com.android.server.pm.ShortcutUser.PackageWithUser;
85
86import org.junit.Assert;
87import org.mockito.ArgumentCaptor;
88import org.mockito.invocation.InvocationOnMock;
89import org.mockito.stubbing.Answer;
90
91import java.io.BufferedReader;
92import java.io.ByteArrayOutputStream;
93import java.io.File;
94import java.io.FileReader;
95import java.io.IOException;
96import java.io.InputStreamReader;
97import java.io.PrintWriter;
98import java.util.ArrayList;
99import java.util.HashMap;
100import java.util.HashSet;
101import java.util.LinkedHashMap;
102import java.util.List;
103import java.util.Locale;
104import java.util.Map;
105import java.util.Set;
106import java.util.function.BiFunction;
107import java.util.function.BiPredicate;
108import java.util.function.Consumer;
109import java.util.function.Function;
110
111public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
112    protected static final String TAG = "ShortcutManagerTest";
113
114    protected static final boolean DUMP_IN_TEARDOWN = false; // DO NOT SUBMIT WITH true
115
116    /**
117     * Whether to enable dump or not.  Should be only true when debugging to avoid bugs where
118     * dump affecting the behavior.
119     */
120    protected static final boolean ENABLE_DUMP = false // DO NOT SUBMIT WITH true
121            || DUMP_IN_TEARDOWN || ShortcutService.DEBUG;
122
123    protected static final String[] EMPTY_STRINGS = new String[0]; // Just for readability.
124
125    protected static final String MAIN_ACTIVITY_CLASS = "MainActivity";
126
127    // public for mockito
128    public class BaseContext extends MockContext {
129        @Override
130        public Object getSystemService(String name) {
131            switch (name) {
132                case Context.USER_SERVICE:
133                    return mMockUserManager;
134            }
135            throw new UnsupportedOperationException();
136        }
137
138        @Override
139        public String getSystemServiceName(Class<?> serviceClass) {
140            return getTestContext().getSystemServiceName(serviceClass);
141        }
142
143        @Override
144        public PackageManager getPackageManager() {
145            return mMockPackageManager;
146        }
147
148        @Override
149        public Resources getResources() {
150            return getTestContext().getResources();
151        }
152
153        @Override
154        public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
155                IntentFilter filter, String broadcastPermission, Handler scheduler) {
156            // ignore.
157            return null;
158        }
159
160        @Override
161        public void unregisterReceiver(BroadcastReceiver receiver) {
162            // ignore.
163        }
164    }
165
166    /** Context used in the client side */
167    public class ClientContext extends BaseContext {
168        @Override
169        public String getPackageName() {
170            return mInjectedClientPackage;
171        }
172
173        @Override
174        public int getUserId() {
175            return getCallingUserId();
176        }
177    }
178
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;
185        }
186
187        void injectRestoreCallingIdentity(long token) {
188            mInjectedCallingUid = (int) token;
189        }
190
191        @Override
192        public int getUserId() {
193            return UserHandle.USER_SYSTEM;
194        }
195
196        public PackageInfo injectGetActivitiesWithMetadata(
197                String packageName, @UserIdInt int userId) {
198            return BaseShortcutManagerTest.this.injectGetActivitiesWithMetadata(packageName, userId);
199        }
200
201        public XmlResourceParser injectXmlMetaData(ActivityInfo activityInfo, String key) {
202            return BaseShortcutManagerTest.this.injectXmlMetaData(activityInfo, key);
203        }
204    }
205
206    /** ShortcutService with injection override methods. */
207    protected final class ShortcutServiceTestable extends ShortcutService {
208        final ServiceContext mContext;
209        IUidObserver mUidObserver;
210
211        public ShortcutServiceTestable(ServiceContext context, Looper looper) {
212            super(context, looper, /* onyForPackageManagerApis */ false);
213            mContext = context;
214        }
215
216        @Override
217        public String injectGetLocaleTagsForUser(@UserIdInt int userId) {
218            return mInjectedLocale.toLanguageTag();
219        }
220
221        @Override
222        boolean injectShouldPerformVerification() {
223            return true; // Always verify during unit tests.
224        }
225
226        @Override
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";
237        }
238
239        @Override
240        long injectClearCallingIdentity() {
241            return mContext.injectClearCallingIdentity();
242        }
243
244        @Override
245        void injectRestoreCallingIdentity(long token) {
246            mContext.injectRestoreCallingIdentity(token);
247        }
248
249        @Override
250        int injectDipToPixel(int dip) {
251            return dip;
252        }
253
254        @Override
255        long injectCurrentTimeMillis() {
256            return mInjectedCurrentTimeMillis;
257        }
258
259        @Override
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;
264        }
265
266        @Override
267        int injectBinderCallingUid() {
268            return mInjectedCallingUid;
269        }
270
271        @Override
272        int injectGetPackageUid(String packageName, int userId) {
273            return getInjectedPackageInfo(packageName, userId, false).applicationInfo.uid;
274        }
275
276        @Override
277        File injectSystemDataPath() {
278            return new File(mInjectedFilePathRoot, "system");
279        }
280
281        @Override
282        File injectUserDataPath(@UserIdInt int userId) {
283            return new File(mInjectedFilePathRoot, "user-" + userId);
284        }
285
286        @Override
287        void injectValidateIconResPackage(ShortcutInfo shortcut, Icon icon) {
288            // Can't check
289        }
290
291        @Override
292        boolean injectIsLowRamDevice() {
293            return mInjectedIsLowRamDevice;
294        }
295
296        @Override
297        void injectRegisterUidObserver(IUidObserver observer, int which) {
298            mUidObserver = observer;
299        }
300
301        @Override
302        boolean hasShortcutHostPermission(@NonNull String callingPackage, int userId) {
303            return mDefaultLauncherChecker.test(callingPackage, userId);
304        }
305
306        @Override
307        PackageInfo injectPackageInfoWithUninstalled(String packageName, @UserIdInt int userId,
308                boolean getSignatures) {
309            return getInjectedPackageInfo(packageName, userId, getSignatures);
310        }
311
312        @Override
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;
318        }
319
320        @Override
321        List<PackageInfo> injectGetPackagesWithUninstalled(@UserIdInt int userId) {
322            return BaseShortcutManagerTest.this.getInstalledPackagesWithUninstalled(userId);
323        }
324
325        @Override
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) {
331                return null;
332            }
333            for (ActivityInfo ai : pi.activities) {
334                if (!mEnabledActivityChecker.test(ai.getComponentName(), userId)) {
335                    continue;
336                }
337                if (activity.equals(ai.getComponentName())) {
338                    return ai;
339                }
340            }
341            return null;
342        }
343
344        @Override
345        boolean injectIsMainActivity(@NonNull ComponentName activity, int userId) {
346            if (!mEnabledActivityChecker.test(activity, userId)) {
347                return false;
348            }
349            return mMainActivityChecker.test(activity, userId);
350        }
351
352        @Override
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) {
357                return null;
358            }
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)) {
362                    continue;
363                }
364                final ResolveInfo ri = new ResolveInfo();
365                ri.activityInfo = pi.activities[i];
366                ret.add(ri);
367            }
368
369            return ret;
370        }
371
372        @Override
373        ComponentName injectGetDefaultMainActivity(@NonNull String packageName, int userId) {
374            return mMainActivityFetcher.apply(packageName, userId);
375        }
376
377        @Override
378        boolean injectIsActivityEnabledAndExported(ComponentName activity, @UserIdInt int userId) {
379            return mEnabledActivityChecker.test(activity, userId);
380        }
381
382        @Override
383        XmlResourceParser injectXmlMetaData(ActivityInfo activityInfo, String key) {
384            return mContext.injectXmlMetaData(activityInfo, key);
385        }
386
387        @Override
388        void injectPostToHandler(Runnable r) {
389            runOnHandler(r);
390        }
391
392        @Override
393        void injectRunOnNewThread(Runnable r) {
394            runOnHandler(r);
395        }
396
397        @Override
398        void injectEnforceCallingPermission(String permission, String message) {
399            if (!mCallerPermissions.contains(permission)) {
400                throw new SecurityException("Missing permission: " + permission);
401            }
402        }
403
404        @Override
405        boolean injectIsSafeModeEnabled() {
406            return mSafeMode;
407        }
408
409        @Override
410        void wtf(String message, Throwable th) {
411            // During tests, WTF is fatal.
412            fail(message + "  exception: " + th + "\n" + Log.getStackTraceString(th));
413        }
414    }
415
416    /** ShortcutManager with injection override methods. */
417    protected class ShortcutManagerTestable extends ShortcutManager {
418        public ShortcutManagerTestable(Context context, ShortcutServiceTestable service) {
419            super(context, service);
420        }
421
422        @Override
423        protected int injectMyUserId() {
424            return UserHandle.getUserId(mInjectedCallingUid);
425        }
426
427        @Override
428        public boolean setDynamicShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) {
429            // Note to simulate the binder RPC, we need to clone the incoming arguments.
430            // Otherwise bad things will happen because they're mutable.
431            return super.setDynamicShortcuts(cloneShortcutList(shortcutInfoList));
432        }
433
434        @Override
435        public boolean addDynamicShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) {
436            // Note to simulate the binder RPC, we need to clone the incoming arguments.
437            return super.addDynamicShortcuts(cloneShortcutList(shortcutInfoList));
438        }
439
440        @Override
441        public boolean updateShortcuts(List<ShortcutInfo> shortcutInfoList) {
442            // Note to simulate the binder RPC, we need to clone the incoming arguments.
443            return super.updateShortcuts(cloneShortcutList(shortcutInfoList));
444        }
445    }
446
447    protected class LauncherAppImplTestable extends LauncherAppsImpl {
448        final ServiceContext mContext;
449
450        public LauncherAppImplTestable(ServiceContext context) {
451            super(context);
452            mContext = context;
453        }
454
455        @Override
456        public void verifyCallingPackage(String callingPackage) {
457            // SKIP
458        }
459
460        @Override
461        void postToPackageMonitorHandler(Runnable r) {
462            runOnHandler(r);
463        }
464
465        @Override
466        int injectBinderCallingUid() {
467            return mInjectedCallingUid;
468        }
469
470        @Override
471        long injectClearCallingIdentity() {
472            final int prevCallingUid = mInjectedCallingUid;
473            mInjectedCallingUid = Process.SYSTEM_UID;
474            return prevCallingUid;
475        }
476
477        @Override
478        void injectRestoreCallingIdentity(long token) {
479            mInjectedCallingUid = (int) token;
480        }
481    }
482
483    protected class LauncherAppsTestable extends LauncherApps {
484        public LauncherAppsTestable(Context context, ILauncherApps service) {
485            super(context, service);
486        }
487    }
488
489    public static class ShortcutActivity extends Activity {
490    }
491
492    public static class ShortcutActivity2 extends Activity {
493    }
494
495    public static class ShortcutActivity3 extends Activity {
496    }
497
498    protected Looper mLooper;
499    protected Handler mHandler;
500
501    protected ServiceContext mServiceContext;
502    protected ClientContext mClientContext;
503
504    protected ShortcutServiceTestable mService;
505    protected ShortcutManagerTestable mManager;
506    protected ShortcutServiceInternal mInternal;
507
508    protected LauncherAppImplTestable mLauncherAppImpl;
509
510    // LauncherApps has per-instace state, so we need a differnt instance for each launcher.
511    protected final Map<Pair<Integer, String>, LauncherAppsTestable>
512            mLauncherAppsMap = new HashMap<>();
513    protected LauncherAppsTestable mLauncherApps; // Current one
514
515    protected File mInjectedFilePathRoot;
516
517    protected boolean mSafeMode;
518
519    protected long mInjectedCurrentTimeMillis;
520
521    protected boolean mInjectedIsLowRamDevice;
522
523    protected Locale mInjectedLocale = Locale.ENGLISH;
524
525    protected int mInjectedCallingUid;
526    protected String mInjectedClientPackage;
527
528    protected Map<String, PackageInfo> mInjectedPackages;
529
530    protected Set<PackageWithUser> mUninstalledPackages;
531
532    protected PackageManager mMockPackageManager;
533    protected PackageManagerInternal mMockPackageManagerInternal;
534    protected UserManager mMockUserManager;
535    protected UsageStatsManagerInternal mMockUsageStatsManagerInternal;
536    protected ActivityManagerInternal mMockActivityManagerInternal;
537
538    protected static final String CALLING_PACKAGE_1 = "com.android.test.1";
539    protected static final int CALLING_UID_1 = 10001;
540
541    protected static final String CALLING_PACKAGE_2 = "com.android.test.2";
542    protected static final int CALLING_UID_2 = 10002;
543
544    protected static final String CALLING_PACKAGE_3 = "com.android.test.3";
545    protected static final int CALLING_UID_3 = 10003;
546
547    protected static final String CALLING_PACKAGE_4 = "com.android.test.4";
548    protected static final int CALLING_UID_4 = 10004;
549
550    protected static final String LAUNCHER_1 = "com.android.launcher.1";
551    protected static final int LAUNCHER_UID_1 = 10011;
552
553    protected static final String LAUNCHER_2 = "com.android.launcher.2";
554    protected static final int LAUNCHER_UID_2 = 10012;
555
556    protected static final String LAUNCHER_3 = "com.android.launcher.3";
557    protected static final int LAUNCHER_UID_3 = 10013;
558
559    protected static final String LAUNCHER_4 = "com.android.launcher.4";
560    protected static final int LAUNCHER_UID_4 = 10014;
561
562    protected static final int USER_0 = UserHandle.USER_SYSTEM;
563    protected static final int USER_10 = 10;
564    protected static final int USER_11 = 11;
565    protected static final int USER_P0 = 20; // profile of user 0
566
567    protected static final UserHandle HANDLE_USER_0 = UserHandle.of(USER_0);
568    protected static final UserHandle HANDLE_USER_10 = UserHandle.of(USER_10);
569    protected static final UserHandle HANDLE_USER_11 = UserHandle.of(USER_11);
570    protected static final UserHandle HANDLE_USER_P0 = UserHandle.of(USER_P0);
571
572    protected static final UserInfo USER_INFO_0 = withProfileGroupId(
573            new UserInfo(USER_0, "user0",
574                    UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY | UserInfo.FLAG_INITIALIZED), 10);
575
576    protected static final UserInfo USER_INFO_10 =
577            new UserInfo(USER_10, "user10", UserInfo.FLAG_INITIALIZED);
578
579    protected static final UserInfo USER_INFO_11 =
580            new UserInfo(USER_11, "user11", UserInfo.FLAG_INITIALIZED);
581
582    protected static final UserInfo USER_INFO_P0 = withProfileGroupId(
583            new UserInfo(USER_P0, "userP0",
584                    UserInfo.FLAG_MANAGED_PROFILE), 10);
585
586    protected BiPredicate<String, Integer> mDefaultLauncherChecker =
587            (callingPackage, userId) ->
588            LAUNCHER_1.equals(callingPackage) || LAUNCHER_2.equals(callingPackage)
589            || LAUNCHER_3.equals(callingPackage) || LAUNCHER_4.equals(callingPackage);
590
591    protected BiPredicate<ComponentName, Integer> mMainActivityChecker =
592            (activity, userId) -> true;
593
594    protected BiFunction<String, Integer, ComponentName> mMainActivityFetcher =
595            (packageName, userId) -> new ComponentName(packageName, MAIN_ACTIVITY_CLASS);
596
597    protected BiPredicate<ComponentName, Integer> mEnabledActivityChecker
598            = (activity, userId) -> true; // all activities are enabled.
599
600    protected static final long START_TIME = 1440000000101L;
601
602    protected static final long INTERVAL = 10000;
603
604    protected static final int MAX_SHORTCUTS = 10;
605
606    protected static final int MAX_UPDATES_PER_INTERVAL = 3;
607
608    protected static final int MAX_ICON_DIMENSION = 128;
609
610    protected static final int MAX_ICON_DIMENSION_LOWRAM = 32;
611
612    protected static final ShortcutQuery QUERY_ALL = new ShortcutQuery();
613
614    protected final ArrayList<String> mCallerPermissions = new ArrayList<>();
615
616    protected final HashMap<String, LinkedHashMap<ComponentName, Integer>> mActivityMetadataResId
617            = new HashMap<>();
618
619    protected final Map<Integer, UserInfo> mUserInfos = new HashMap<>();
620    protected final Map<Integer, Boolean> mRunningUsers = new HashMap<>();
621    protected final Map<Integer, Boolean> mUnlockedUsers = new HashMap<>();
622
623    protected static final String PACKAGE_SYSTEM_LAUNCHER = "com.android.systemlauncher";
624    protected static final String PACKAGE_SYSTEM_LAUNCHER_NAME = "systemlauncher_name";
625    protected static final int PACKAGE_SYSTEM_LAUNCHER_PRIORITY = 0;
626
627    protected static final String PACKAGE_FALLBACK_LAUNCHER = "com.android.settings";
628    protected static final String PACKAGE_FALLBACK_LAUNCHER_NAME = "fallback";
629    protected static final int PACKAGE_FALLBACK_LAUNCHER_PRIORITY = -999;
630
631    static {
632        QUERY_ALL.setQueryFlags(
633                ShortcutQuery.FLAG_GET_ALL_KINDS);
634    }
635
636    @Override
637    protected void setUp() throws Exception {
638        super.setUp();
639
640        mLooper = Looper.getMainLooper();
641        mHandler = new Handler(mLooper);
642
643        mServiceContext = spy(new ServiceContext());
644        mClientContext = new ClientContext();
645
646        mMockPackageManager = mock(PackageManager.class);
647        mMockPackageManagerInternal = mock(PackageManagerInternal.class);
648        mMockUserManager = mock(UserManager.class);
649        mMockUsageStatsManagerInternal = mock(UsageStatsManagerInternal.class);
650        mMockActivityManagerInternal = mock(ActivityManagerInternal.class);
651
652        LocalServices.removeServiceForTest(PackageManagerInternal.class);
653        LocalServices.addService(PackageManagerInternal.class, mMockPackageManagerInternal);
654        LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
655        LocalServices.addService(UsageStatsManagerInternal.class, mMockUsageStatsManagerInternal);
656        LocalServices.removeServiceForTest(ActivityManagerInternal.class);
657        LocalServices.addService(ActivityManagerInternal.class, mMockActivityManagerInternal);
658
659        // Prepare injection values.
660
661        mInjectedCurrentTimeMillis = START_TIME;
662
663        mInjectedPackages = new HashMap<>();
664        addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 1);
665        addPackage(CALLING_PACKAGE_2, CALLING_UID_2, 2);
666        addPackage(CALLING_PACKAGE_3, CALLING_UID_3, 3);
667        addPackage(CALLING_PACKAGE_4, CALLING_UID_4, 10);
668        addPackage(LAUNCHER_1, LAUNCHER_UID_1, 4);
669        addPackage(LAUNCHER_2, LAUNCHER_UID_2, 5);
670        addPackage(LAUNCHER_3, LAUNCHER_UID_3, 6);
671        addPackage(LAUNCHER_4, LAUNCHER_UID_4, 10);
672
673        // CALLING_PACKAGE_3 / LAUNCHER_3 are not backup target.
674        updatePackageInfo(CALLING_PACKAGE_3,
675                pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
676        updatePackageInfo(LAUNCHER_3,
677                pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
678
679        mUninstalledPackages = new HashSet<>();
680
681        mInjectedFilePathRoot = new File(getTestContext().getCacheDir(), "test-files");
682
683        deleteAllSavedFiles();
684
685        // Set up users.
686        when(mMockUserManager.getUserInfo(anyInt())).thenAnswer(new AnswerWithSystemCheck<>(
687                inv -> mUserInfos.get((Integer) inv.getArguments()[0])));
688
689        mUserInfos.put(USER_0, USER_INFO_0);
690        mUserInfos.put(USER_10, USER_INFO_10);
691        mUserInfos.put(USER_11, USER_INFO_11);
692        mUserInfos.put(USER_P0, USER_INFO_P0);
693
694        // Set up isUserRunning and isUserUnlocked.
695        when(mMockUserManager.isUserRunning(anyInt())).thenAnswer(new AnswerWithSystemCheck<>(
696                        inv -> b(mRunningUsers.get((Integer) inv.getArguments()[0]))));
697
698        when(mMockUserManager.isUserUnlocked(anyInt()))
699                .thenAnswer(new AnswerWithSystemCheck<>(inv -> {
700                    final int userId = (Integer) inv.getArguments()[0];
701                    return b(mRunningUsers.get(userId)) && b(mUnlockedUsers.get(userId));
702                }));
703        // isUserUnlockingOrUnlocked() return the same value as isUserUnlocked().
704        when(mMockUserManager.isUserUnlockingOrUnlocked(anyInt()))
705                .thenAnswer(new AnswerWithSystemCheck<>(inv -> {
706                    final int userId = (Integer) inv.getArguments()[0];
707                    return b(mRunningUsers.get(userId)) && b(mUnlockedUsers.get(userId));
708                }));
709
710        when(mMockActivityManagerInternal.getUidProcessState(anyInt())).thenReturn(
711                ActivityManager.PROCESS_STATE_CACHED_EMPTY);
712
713        // User 0 and P0 are always running
714        mRunningUsers.put(USER_0, true);
715        mRunningUsers.put(USER_10, false);
716        mRunningUsers.put(USER_11, false);
717        mRunningUsers.put(USER_P0, true);
718
719        // Unlock all users by default.
720        mUnlockedUsers.put(USER_0, true);
721        mUnlockedUsers.put(USER_10, true);
722        mUnlockedUsers.put(USER_11, true);
723        mUnlockedUsers.put(USER_P0, true);
724
725        // Set up resources
726        setUpAppResources();
727
728        // Start the service.
729        initService();
730        setCaller(CALLING_PACKAGE_1);
731    }
732
733    private static boolean b(Boolean value) {
734        return (value != null && value);
735    }
736
737    /**
738     * Returns a boolean but also checks if the current UID is SYSTEM_UID.
739     */
740    protected class AnswerWithSystemCheck<T> implements Answer<T> {
741        private final Function<InvocationOnMock, T> mChecker;
742
743        public AnswerWithSystemCheck(Function<InvocationOnMock, T> checker) {
744            mChecker = checker;
745        }
746
747        @Override
748        public T answer(InvocationOnMock invocation) throws Throwable {
749            assertEquals("Must be called on SYSTEM UID.",
750                    Process.SYSTEM_UID, mInjectedCallingUid);
751            return mChecker.apply(invocation);
752        }
753    }
754
755    protected void setUpAppResources() throws Exception {
756        setUpAppResources(/* offset = */ 0);
757    }
758
759    protected void setUpAppResources(int ressIdOffset) throws Exception {
760        // ressIdOffset is used to adjust resource IDs to emulate the case where an updated app
761        // has resource IDs changed.
762
763        doAnswer(pmInvocation -> {
764            assertEquals(Process.SYSTEM_UID, mInjectedCallingUid);
765
766            final String packageName = (String) pmInvocation.getArguments()[0];
767            final int userId = (Integer) pmInvocation.getArguments()[1];
768
769            final Resources res = mock(Resources.class);
770
771            doAnswer(resInvocation -> {
772                final int argResId = (Integer) resInvocation.getArguments()[0];
773
774                return "string-" + packageName + "-user:" + userId + "-res:" + argResId
775                        + "/" + mInjectedLocale;
776            }).when(res).getString(anyInt());
777
778            doAnswer(resInvocation -> {
779                final int resId = (Integer) resInvocation.getArguments()[0];
780
781                // Always use the "string" resource type.  The type doesn't matter during the test.
782                return packageName + ":string/r" + resId;
783            }).when(res).getResourceName(anyInt());
784
785            doAnswer(resInvocation -> {
786                final String argResName = (String) resInvocation.getArguments()[0];
787                final String argType = (String) resInvocation.getArguments()[1];
788                final String argPackageName = (String) resInvocation.getArguments()[2];
789
790                // See the above code.  getResourceName() will just use "r" + res ID as the entry
791                // name.
792                String entryName = argResName;
793                if (entryName.contains("/")) {
794                    entryName = ShortcutInfo.getResourceEntryName(entryName);
795                }
796                return Integer.parseInt(entryName.substring(1)) + ressIdOffset;
797            }).when(res).getIdentifier(anyString(), anyString(), anyString());
798            return res;
799        }).when(mMockPackageManager).getResourcesForApplicationAsUser(anyString(), anyInt());
800    }
801
802    protected static UserInfo withProfileGroupId(UserInfo in, int groupId) {
803        in.profileGroupId = groupId;
804        return in;
805    }
806
807    @Override
808    protected void tearDown() throws Exception {
809        if (DUMP_IN_TEARDOWN) dumpsysOnLogcat("Teardown");
810
811        shutdownServices();
812
813        super.tearDown();
814    }
815
816    protected Context getTestContext() {
817        return getInstrumentation().getContext();
818    }
819
820    protected ShortcutManager getManager() {
821        return mManager;
822    }
823
824    protected void deleteAllSavedFiles() {
825        // Empty the data directory.
826        if (mInjectedFilePathRoot.exists()) {
827            Assert.assertTrue("failed to delete dir",
828                    FileUtils.deleteContents(mInjectedFilePathRoot));
829        }
830        mInjectedFilePathRoot.mkdirs();
831    }
832
833    /** (Re-) init the manager and the service. */
834    protected void initService() {
835        shutdownServices();
836
837        LocalServices.removeServiceForTest(ShortcutServiceInternal.class);
838
839        // Instantiate targets.
840        mService = new ShortcutServiceTestable(mServiceContext, mLooper);
841        mManager = new ShortcutManagerTestable(mClientContext, mService);
842
843        mInternal = LocalServices.getService(ShortcutServiceInternal.class);
844
845        mLauncherAppImpl = new LauncherAppImplTestable(mServiceContext);
846        mLauncherApps = null;
847        mLauncherAppsMap.clear();
848
849        // Send boot sequence events.
850        mService.onBootPhase(SystemService.PHASE_LOCK_SETTINGS_READY);
851
852        mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
853    }
854
855    protected void shutdownServices() {
856        if (mService != null) {
857            // Flush all the unsaved data from the previous instance.
858            mService.saveDirtyInfo();
859
860            // Make sure everything is consistent.
861            mService.verifyStates();
862        }
863        LocalServices.removeServiceForTest(ShortcutServiceInternal.class);
864
865        mService = null;
866        mManager = null;
867        mInternal = null;
868        mLauncherAppImpl = null;
869        mLauncherApps = null;
870        mLauncherAppsMap.clear();
871    }
872
873    protected void runOnHandler(Runnable r) {
874        final long token = mServiceContext.injectClearCallingIdentity();
875        try {
876            r.run();
877        } finally {
878            mServiceContext.injectRestoreCallingIdentity(token);
879        }
880    }
881
882    protected void addPackage(String packageName, int uid, int version) {
883        addPackage(packageName, uid, version, packageName);
884    }
885
886    protected Signature[] genSignatures(String... signatures) {
887        final Signature[] sigs = new Signature[signatures.length];
888        for (int i = 0; i < signatures.length; i++){
889            sigs[i] = new Signature(signatures[i].getBytes());
890        }
891        return sigs;
892    }
893
894    protected PackageInfo genPackage(String packageName, int uid, int version, String... signatures) {
895        final PackageInfo pi = new PackageInfo();
896        pi.packageName = packageName;
897        pi.applicationInfo = new ApplicationInfo();
898        pi.applicationInfo.uid = uid;
899        pi.applicationInfo.flags = ApplicationInfo.FLAG_INSTALLED
900                | ApplicationInfo.FLAG_ALLOW_BACKUP;
901        pi.versionCode = version;
902        pi.applicationInfo.versionCode = version;
903        pi.signatures = genSignatures(signatures);
904
905        return pi;
906    }
907
908    protected void addPackage(String packageName, int uid, int version, String... signatures) {
909        mInjectedPackages.put(packageName, genPackage(packageName, uid, version, signatures));
910    }
911
912    protected void updatePackageInfo(String packageName, Consumer<PackageInfo> c) {
913        c.accept(mInjectedPackages.get(packageName));
914    }
915
916    protected void updatePackageVersion(String packageName, int increment) {
917        updatePackageInfo(packageName, pi -> {
918            pi.versionCode += increment;
919            pi.applicationInfo.versionCode += increment;
920        });
921    }
922
923    protected void updatePackageLastUpdateTime(String packageName, long increment) {
924        updatePackageInfo(packageName, pi -> {
925            pi.lastUpdateTime += increment;
926        });
927    }
928
929    protected void setPackageLastUpdateTime(String packageName, long value) {
930        updatePackageInfo(packageName, pi -> {
931            pi.lastUpdateTime = value;
932        });
933    }
934
935    protected void uninstallPackage(int userId, String packageName) {
936        if (ENABLE_DUMP) {
937            Log.v(TAG, "Unnstall package " + packageName + " / " + userId);
938        }
939        mUninstalledPackages.add(PackageWithUser.of(userId, packageName));
940    }
941
942    protected void installPackage(int userId, String packageName) {
943        if (ENABLE_DUMP) {
944            Log.v(TAG, "Install package " + packageName + " / " + userId);
945        }
946        mUninstalledPackages.remove(PackageWithUser.of(userId, packageName));
947    }
948
949    PackageInfo getInjectedPackageInfo(String packageName, @UserIdInt int userId,
950            boolean getSignatures) {
951        final PackageInfo pi = mInjectedPackages.get(packageName);
952        if (pi == null) return null;
953
954        final PackageInfo ret = new PackageInfo();
955        ret.packageName = pi.packageName;
956        ret.versionCode = pi.versionCode;
957        ret.lastUpdateTime = pi.lastUpdateTime;
958
959        ret.applicationInfo = new ApplicationInfo(pi.applicationInfo);
960        ret.applicationInfo.uid = UserHandle.getUid(userId, pi.applicationInfo.uid);
961        ret.applicationInfo.packageName = pi.packageName;
962
963        if (mUninstalledPackages.contains(PackageWithUser.of(userId, packageName))) {
964            ret.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED;
965        }
966
967        if (getSignatures) {
968            ret.signatures = pi.signatures;
969        }
970
971        return ret;
972    }
973
974    protected void addApplicationInfo(PackageInfo pi, List<ApplicationInfo> list) {
975        if (pi != null && pi.applicationInfo != null) {
976            list.add(pi.applicationInfo);
977        }
978    }
979
980    protected List<ApplicationInfo> getInstalledApplications(int userId) {
981        final ArrayList<ApplicationInfo> ret = new ArrayList<>();
982
983        addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_1, userId, false), ret);
984        addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_2, userId, false), ret);
985        addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_3, userId, false), ret);
986        addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_4, userId, false), ret);
987        addApplicationInfo(getInjectedPackageInfo(LAUNCHER_1, userId, false), ret);
988        addApplicationInfo(getInjectedPackageInfo(LAUNCHER_2, userId, false), ret);
989        addApplicationInfo(getInjectedPackageInfo(LAUNCHER_3, userId, false), ret);
990        addApplicationInfo(getInjectedPackageInfo(LAUNCHER_4, userId, false), ret);
991
992        return ret;
993    }
994
995    private void addPackageInfo(PackageInfo pi, List<PackageInfo> list) {
996        if (pi != null) {
997            list.add(pi);
998        }
999    }
1000
1001    private List<PackageInfo> getInstalledPackagesWithUninstalled(int userId) {
1002        final ArrayList<PackageInfo> ret = new ArrayList<>();
1003
1004        addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_1, userId, false), ret);
1005        addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_2, userId, false), ret);
1006        addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_3, userId, false), ret);
1007        addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_4, userId, false), ret);
1008        addPackageInfo(getInjectedPackageInfo(LAUNCHER_1, userId, false), ret);
1009        addPackageInfo(getInjectedPackageInfo(LAUNCHER_2, userId, false), ret);
1010        addPackageInfo(getInjectedPackageInfo(LAUNCHER_3, userId, false), ret);
1011        addPackageInfo(getInjectedPackageInfo(LAUNCHER_4, userId, false), ret);
1012
1013        return ret;
1014    }
1015
1016    protected void addManifestShortcutResource(ComponentName activity, int resId) {
1017        final String packageName = activity.getPackageName();
1018        LinkedHashMap<ComponentName, Integer> map = mActivityMetadataResId.get(packageName);
1019        if (map == null) {
1020            map = new LinkedHashMap<>();
1021            mActivityMetadataResId.put(packageName, map);
1022        }
1023        map.put(activity, resId);
1024    }
1025
1026    protected PackageInfo injectGetActivitiesWithMetadata(String packageName, @UserIdInt int userId) {
1027        final PackageInfo ret = getInjectedPackageInfo(packageName, userId,
1028                /* getSignatures=*/ false);
1029
1030        final HashMap<ComponentName, Integer> activities = mActivityMetadataResId.get(packageName);
1031        if (activities != null) {
1032            final ArrayList<ActivityInfo> list = new ArrayList<>();
1033
1034            for (ComponentName cn : activities.keySet()) {
1035                ActivityInfo ai = new ActivityInfo();
1036                ai.packageName = cn.getPackageName();
1037                ai.name = cn.getClassName();
1038                ai.metaData = new Bundle();
1039                ai.metaData.putInt(ShortcutParser.METADATA_KEY, activities.get(cn));
1040                ai.applicationInfo = ret.applicationInfo;
1041                list.add(ai);
1042            }
1043            ret.activities = list.toArray(new ActivityInfo[list.size()]);
1044        }
1045        return ret;
1046    }
1047
1048    protected XmlResourceParser injectXmlMetaData(ActivityInfo activityInfo, String key) {
1049        if (!ShortcutParser.METADATA_KEY.equals(key) || activityInfo.metaData == null) {
1050            return null;
1051        }
1052        final int resId = activityInfo.metaData.getInt(key);
1053        return getTestContext().getResources().getXml(resId);
1054    }
1055
1056    /** Replace the current calling package */
1057    protected void setCaller(String packageName, int userId) {
1058        mInjectedClientPackage = packageName;
1059        mInjectedCallingUid =
1060                Preconditions.checkNotNull(getInjectedPackageInfo(packageName, userId, false),
1061                        "Unknown package").applicationInfo.uid;
1062
1063        // Set up LauncherApps for this caller.
1064        final Pair<Integer, String> key = Pair.create(userId, packageName);
1065        if (!mLauncherAppsMap.containsKey(key)) {
1066            mLauncherAppsMap.put(key, new LauncherAppsTestable(mClientContext, mLauncherAppImpl));
1067        }
1068        mLauncherApps = mLauncherAppsMap.get(key);
1069    }
1070
1071    protected void setCaller(String packageName) {
1072        setCaller(packageName, UserHandle.USER_SYSTEM);
1073    }
1074
1075    protected String getCallingPackage() {
1076        return mInjectedClientPackage;
1077    }
1078
1079    protected void setDefaultLauncherChecker(BiPredicate<String, Integer> p) {
1080        mDefaultLauncherChecker = p;
1081    }
1082
1083    protected void runWithCaller(String packageName, int userId, Runnable r) {
1084        final String previousPackage = mInjectedClientPackage;
1085        final int previousUserId = UserHandle.getUserId(mInjectedCallingUid);
1086
1087        setCaller(packageName, userId);
1088
1089        r.run();
1090
1091        setCaller(previousPackage, previousUserId);
1092    }
1093
1094    protected void runWithSystemUid(Runnable r) {
1095        final int origUid = mInjectedCallingUid;
1096        mInjectedCallingUid = Process.SYSTEM_UID;
1097        r.run();
1098        mInjectedCallingUid = origUid;
1099    }
1100
1101    protected void lookupAndFillInResourceNames(ShortcutInfo si) {
1102        runWithSystemUid(() -> si.lookupAndFillInResourceNames(
1103                mService.injectGetResourcesForApplicationAsUser(si.getPackage(), si.getUserId())));
1104    }
1105
1106    protected int getCallingUserId() {
1107        return UserHandle.getUserId(mInjectedCallingUid);
1108    }
1109
1110    protected UserHandle getCallingUser() {
1111        return UserHandle.of(getCallingUserId());
1112    }
1113
1114    /** For debugging */
1115    protected void dumpsysOnLogcat() {
1116        dumpsysOnLogcat("");
1117    }
1118
1119    protected void dumpsysOnLogcat(String message) {
1120        dumpsysOnLogcat(message, false);
1121    }
1122
1123    protected void dumpsysOnLogcat(String message, boolean force) {
1124        if (force || !ENABLE_DUMP) return;
1125
1126        Log.v(TAG, "Dumping ShortcutService: " + message);
1127        for (String line : dumpsys(null).split("\n")) {
1128            Log.v(TAG, line);
1129        }
1130    }
1131
1132    protected String dumpCheckin() {
1133        return dumpsys(new String[]{"--checkin"});
1134    }
1135
1136    private String dumpsys(String[] args) {
1137        final ArrayList<String> origPermissions = new ArrayList<>(mCallerPermissions);
1138        mCallerPermissions.add(android.Manifest.permission.DUMP);
1139        try {
1140            final ByteArrayOutputStream out = new ByteArrayOutputStream();
1141            final PrintWriter pw = new PrintWriter(out);
1142            mService.dump(/* fd */ null, pw, args);
1143            pw.close();
1144
1145            return out.toString();
1146        } finally {
1147            mCallerPermissions.clear();
1148            mCallerPermissions.addAll(origPermissions);
1149        }
1150    }
1151
1152    /**
1153     * For debugging, dump arbitrary file on logcat.
1154     */
1155    protected void dumpFileOnLogcat(String path) {
1156        dumpFileOnLogcat(path, "");
1157    }
1158
1159    protected void dumpFileOnLogcat(String path, String message) {
1160        if (!ENABLE_DUMP) return;
1161
1162        Log.v(TAG, "Dumping file: " + path + " " + message);
1163        final StringBuilder sb = new StringBuilder();
1164        try (BufferedReader br = new BufferedReader(new FileReader(path))) {
1165            String line;
1166            while ((line = br.readLine()) != null) {
1167                Log.v(TAG, line);
1168            }
1169        } catch (Exception e) {
1170            Log.e(TAG, "Couldn't read file", e);
1171            fail("Exception " + e);
1172        }
1173    }
1174
1175    /**
1176     * For debugging, dump the main state file on logcat.
1177     */
1178    protected void dumpBaseStateFile() {
1179        mService.saveDirtyInfo();
1180        dumpFileOnLogcat(mInjectedFilePathRoot.getAbsolutePath()
1181                + "/system/" + ShortcutService.FILENAME_BASE_STATE);
1182    }
1183
1184    /**
1185     * For debugging, dump per-user state file on logcat.
1186     */
1187    protected void dumpUserFile(int userId) {
1188        dumpUserFile(userId, "");
1189    }
1190
1191    protected void dumpUserFile(int userId, String message) {
1192        mService.saveDirtyInfo();
1193        dumpFileOnLogcat(mInjectedFilePathRoot.getAbsolutePath()
1194                + "/user-" + userId
1195                + "/" + ShortcutService.FILENAME_USER_PACKAGES, message);
1196    }
1197
1198    /**
1199     * Make a shortcut with an ID.
1200     */
1201    protected ShortcutInfo makeShortcut(String id) {
1202        return makeShortcut(
1203                id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
1204                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
1205    }
1206
1207    protected ShortcutInfo makeShortcutWithTitle(String id, String title) {
1208        return makeShortcut(
1209                id, title, /* activity =*/ null, /* icon =*/ null,
1210                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
1211    }
1212
1213    /**
1214     * Make a shortcut with an ID and timestamp.
1215     */
1216    protected ShortcutInfo makeShortcutWithTimestamp(String id, long timestamp) {
1217        final ShortcutInfo s = makeShortcut(
1218                id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
1219                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
1220        s.setTimestamp(timestamp);
1221        return s;
1222    }
1223
1224    /**
1225     * Make a shortcut with an ID, a timestamp and an activity component
1226     */
1227    protected ShortcutInfo makeShortcutWithTimestampWithActivity(String id, long timestamp,
1228            ComponentName activity) {
1229        final ShortcutInfo s = makeShortcut(
1230                id, "Title-" + id, activity, /* icon =*/ null,
1231                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
1232        s.setTimestamp(timestamp);
1233        return s;
1234    }
1235
1236    /**
1237     * Make a shortcut with an ID and icon.
1238     */
1239    protected ShortcutInfo makeShortcutWithIcon(String id, Icon icon) {
1240        return makeShortcut(
1241                id, "Title-" + id, /* activity =*/ null, icon,
1242                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
1243    }
1244
1245    protected ShortcutInfo makePackageShortcut(String packageName, String id) {
1246        String origCaller = getCallingPackage();
1247
1248        setCaller(packageName);
1249        ShortcutInfo s = makeShortcut(
1250                id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
1251                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
1252        setCaller(origCaller); // restore the caller
1253
1254        return s;
1255    }
1256
1257    /**
1258     * Make multiple shortcuts with IDs.
1259     */
1260    protected List<ShortcutInfo> makeShortcuts(String... ids) {
1261        final ArrayList<ShortcutInfo> ret = new ArrayList();
1262        for (String id : ids) {
1263            ret.add(makeShortcut(id));
1264        }
1265        return ret;
1266    }
1267
1268    protected ShortcutInfo.Builder makeShortcutBuilder() {
1269        return new ShortcutInfo.Builder(mClientContext);
1270    }
1271
1272    protected ShortcutInfo makeShortcutWithActivity(String id, ComponentName activity) {
1273        return makeShortcut(
1274                id, "Title-" + id, activity, /* icon =*/ null,
1275                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
1276    }
1277
1278    protected ShortcutInfo makeShortcutWithIntent(String id, Intent intent) {
1279        return makeShortcut(
1280                id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
1281                intent, /* rank =*/ 0);
1282    }
1283
1284    protected ShortcutInfo makeShortcutWithActivityAndTitle(String id, ComponentName activity,
1285            String title) {
1286        return makeShortcut(
1287                id, title, activity, /* icon =*/ null,
1288                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
1289    }
1290
1291    protected ShortcutInfo makeShortcutWithActivityAndRank(String id, ComponentName activity,
1292            int rank) {
1293        return makeShortcut(
1294                id, "Title-" + id, activity, /* icon =*/ null,
1295                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), rank);
1296    }
1297
1298    /**
1299     * Make a shortcut with details.
1300     */
1301    protected ShortcutInfo makeShortcut(String id, String title, ComponentName activity,
1302            Icon icon, Intent intent, int rank) {
1303        final ShortcutInfo.Builder  b = new ShortcutInfo.Builder(mClientContext, id)
1304                .setActivity(new ComponentName(mClientContext.getPackageName(), "dummy"))
1305                .setShortLabel(title)
1306                .setRank(rank)
1307                .setIntent(intent);
1308        if (icon != null) {
1309            b.setIcon(icon);
1310        }
1311        if (activity != null) {
1312            b.setActivity(activity);
1313        }
1314        final ShortcutInfo s = b.build();
1315
1316        s.setTimestamp(mInjectedCurrentTimeMillis); // HACK
1317
1318        return s;
1319    }
1320
1321    protected ShortcutInfo makeShortcutWithIntents(String id, Intent... intents) {
1322        return makeShortcut(
1323                id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
1324                intents, /* rank =*/ 0);
1325    }
1326
1327    /**
1328     * Make a shortcut with details.
1329     */
1330    protected ShortcutInfo makeShortcut(String id, String title, ComponentName activity,
1331            Icon icon, Intent[] intents, int rank) {
1332        final ShortcutInfo.Builder  b = new ShortcutInfo.Builder(mClientContext, id)
1333                .setActivity(new ComponentName(mClientContext.getPackageName(), "dummy"))
1334                .setShortLabel(title)
1335                .setRank(rank)
1336                .setIntents(intents);
1337        if (icon != null) {
1338            b.setIcon(icon);
1339        }
1340        if (activity != null) {
1341            b.setActivity(activity);
1342        }
1343        final ShortcutInfo s = b.build();
1344
1345        s.setTimestamp(mInjectedCurrentTimeMillis); // HACK
1346
1347        return s;
1348    }
1349
1350    /**
1351     * Make a shortcut with details.
1352     */
1353    protected ShortcutInfo makeShortcutWithExtras(String id, Intent intent,
1354            PersistableBundle extras) {
1355        final ShortcutInfo.Builder  b = new ShortcutInfo.Builder(mClientContext, id)
1356                .setActivity(new ComponentName(mClientContext.getPackageName(), "dummy"))
1357                .setShortLabel("title-" + id)
1358                .setExtras(extras)
1359                .setIntent(intent);
1360        final ShortcutInfo s = b.build();
1361
1362        s.setTimestamp(mInjectedCurrentTimeMillis); // HACK
1363
1364        return s;
1365    }
1366
1367    /**
1368     * Make an intent.
1369     */
1370    protected Intent makeIntent(String action, Class<?> clazz, Object... bundleKeysAndValues) {
1371        final Intent intent = new Intent(action);
1372        intent.setComponent(makeComponent(clazz));
1373        intent.replaceExtras(makeBundle(bundleKeysAndValues));
1374        return intent;
1375    }
1376
1377    /**
1378     * Make an component name, with the client context.
1379     */
1380    @NonNull
1381    protected ComponentName makeComponent(Class<?> clazz) {
1382        return new ComponentName(mClientContext, clazz);
1383    }
1384
1385    @NonNull
1386    protected ShortcutInfo findById(List<ShortcutInfo> list, String id) {
1387        for (ShortcutInfo s : list) {
1388            if (s.getId().equals(id)) {
1389                return s;
1390            }
1391        }
1392        fail("Shortcut with id " + id + " not found");
1393        return null;
1394    }
1395
1396    protected void assertSystem() {
1397        assertEquals("Caller must be system", Process.SYSTEM_UID, mInjectedCallingUid);
1398    }
1399
1400    protected void assertResetTimes(long expectedLastResetTime, long expectedNextResetTime) {
1401        assertEquals(expectedLastResetTime, mService.getLastResetTimeLocked());
1402        assertEquals(expectedNextResetTime, mService.getNextResetTimeLocked());
1403    }
1404
1405    public static List<ShortcutInfo> assertAllNotHaveIcon(
1406            List<ShortcutInfo> actualShortcuts) {
1407        for (ShortcutInfo s : actualShortcuts) {
1408            assertNull("ID " + s.getId(), s.getIcon());
1409        }
1410        return actualShortcuts;
1411    }
1412
1413    @NonNull
1414    protected List<ShortcutInfo> assertAllHaveFlags(@NonNull List<ShortcutInfo> actualShortcuts,
1415            int shortcutFlags) {
1416        for (ShortcutInfo s : actualShortcuts) {
1417            assertTrue("ID " + s.getId() + " doesn't have flags " + shortcutFlags,
1418                    s.hasFlags(shortcutFlags));
1419        }
1420        return actualShortcuts;
1421    }
1422
1423    protected ShortcutInfo getPackageShortcut(String packageName, String shortcutId, int userId) {
1424        return mService.getPackageShortcutForTest(packageName, shortcutId, userId);
1425    }
1426
1427    protected void assertShortcutExists(String packageName, String shortcutId, int userId) {
1428        assertTrue(getPackageShortcut(packageName, shortcutId, userId) != null);
1429    }
1430
1431    protected void assertShortcutNotExists(String packageName, String shortcutId, int userId) {
1432        assertTrue(getPackageShortcut(packageName, shortcutId, userId) == null);
1433    }
1434
1435    protected Intent[] launchShortcutAndGetIntentsInner(Runnable shortcutStarter,
1436            @NonNull String packageName, @NonNull String shortcutId, int userId) {
1437        reset(mMockActivityManagerInternal);
1438        shortcutStarter.run();
1439
1440        final ArgumentCaptor<Intent[]> intentsCaptor = ArgumentCaptor.forClass(Intent[].class);
1441        verify(mMockActivityManagerInternal).startActivitiesAsPackage(
1442                eq(packageName),
1443                eq(userId),
1444                intentsCaptor.capture(),
1445                any(Bundle.class));
1446        return intentsCaptor.getValue();
1447    }
1448
1449    protected Intent[] launchShortcutAndGetIntents(
1450            @NonNull String packageName, @NonNull String shortcutId, int userId) {
1451        return launchShortcutAndGetIntentsInner(
1452                () -> {
1453                    mLauncherApps.startShortcut(packageName, shortcutId, null, null,
1454                            UserHandle.of(userId));
1455                }, packageName, shortcutId, userId
1456        );
1457    }
1458
1459    protected Intent launchShortcutAndGetIntent(
1460            @NonNull String packageName, @NonNull String shortcutId, int userId) {
1461        final Intent[] intents = launchShortcutAndGetIntents(packageName, shortcutId, userId);
1462        assertEquals(1, intents.length);
1463        return intents[0];
1464    }
1465
1466    protected Intent[] launchShortcutAndGetIntents_withShortcutInfo(
1467            @NonNull String packageName, @NonNull String shortcutId, int userId) {
1468        return launchShortcutAndGetIntentsInner(
1469                () -> {
1470                    mLauncherApps.startShortcut(
1471                            getShortcutInfoAsLauncher(packageName, shortcutId, userId), null, null);
1472                }, packageName, shortcutId, userId
1473        );
1474    }
1475
1476    protected Intent launchShortcutAndGetIntent_withShortcutInfo(
1477            @NonNull String packageName, @NonNull String shortcutId, int userId) {
1478        final Intent[] intents = launchShortcutAndGetIntents_withShortcutInfo(
1479                packageName, shortcutId, userId);
1480        assertEquals(1, intents.length);
1481        return intents[0];
1482    }
1483
1484    protected void assertShortcutLaunchable(@NonNull String packageName, @NonNull String shortcutId,
1485            int userId) {
1486        assertNotNull(launchShortcutAndGetIntent(packageName, shortcutId, userId));
1487        assertNotNull(launchShortcutAndGetIntent_withShortcutInfo(packageName, shortcutId, userId));
1488    }
1489
1490    protected void assertShortcutNotLaunched(@NonNull String packageName,
1491            @NonNull String shortcutId, int userId) {
1492        reset(mMockActivityManagerInternal);
1493        try {
1494            mLauncherApps.startShortcut(packageName, shortcutId, null, null,
1495                    UserHandle.of(userId));
1496            fail("ActivityNotFoundException was not thrown");
1497        } catch (ActivityNotFoundException expected) {
1498        }
1499        // This shouldn't have been called.
1500        verify(mMockActivityManagerInternal, times(0)).startActivitiesAsPackage(
1501                anyString(),
1502                anyInt(),
1503                any(Intent[].class),
1504                any(Bundle.class));
1505    }
1506
1507    protected void assertStartShortcutThrowsException(@NonNull String packageName,
1508            @NonNull String shortcutId, int userId, Class<?> expectedException) {
1509        Exception thrown = null;
1510        try {
1511            mLauncherApps.startShortcut(packageName, shortcutId, null, null,
1512                    UserHandle.of(userId));
1513        } catch (Exception e) {
1514            thrown = e;
1515        }
1516        assertNotNull("Exception was not thrown", thrown);
1517        assertEquals("Exception type different", expectedException, thrown.getClass());
1518    }
1519
1520    protected void assertBitmapDirectories(int userId, String... expectedDirectories) {
1521        final Set<String> expected = hashSet(set(expectedDirectories));
1522
1523        final Set<String> actual = new HashSet<>();
1524
1525        final File[] files = mService.getUserBitmapFilePath(userId).listFiles();
1526        if (files != null) {
1527            for (File child : files) {
1528                if (child.isDirectory()) {
1529                    actual.add(child.getName());
1530                }
1531            }
1532        }
1533
1534        assertEquals(expected, actual);
1535    }
1536
1537    protected void assertBitmapFiles(int userId, String packageName, String... expectedFiles) {
1538        final Set<String> expected = hashSet(set(expectedFiles));
1539
1540        final Set<String> actual = new HashSet<>();
1541
1542        final File[] files = new File(mService.getUserBitmapFilePath(userId), packageName)
1543                .listFiles();
1544        if (files != null) {
1545            for (File child : files) {
1546                if (child.isFile()) {
1547                    actual.add(child.getName());
1548                }
1549            }
1550        }
1551
1552        assertEquals(expected, actual);
1553    }
1554
1555    protected String getBitmapFilename(int userId, String packageName, String shortcutId) {
1556        final ShortcutInfo si = mService.getPackageShortcutForTest(packageName, shortcutId, userId);
1557        if (si == null) {
1558            return null;
1559        }
1560        return new File(si.getBitmapPath()).getName();
1561    }
1562
1563    /**
1564     * @return all shortcuts stored internally for the caller.  This reflects the *internal* view
1565     * of shortcuts, which may be different from what {@link #getCallerVisibleShortcuts} would
1566     * return, because getCallerVisibleShortcuts() will get shortcuts from the proper "front door"
1567     * which performs some extra checks, like {@link ShortcutPackage#onRestored}.
1568     */
1569    protected List<ShortcutInfo> getCallerShortcuts() {
1570        final ShortcutPackage p = mService.getPackageShortcutForTest(
1571                getCallingPackage(), getCallingUserId());
1572        return p == null ? null : p.getAllShortcutsForTest();
1573    }
1574
1575    /**
1576     * @return all shortcuts owned by caller that are actually visible via ShortcutManager.
1577     * See also {@link #getCallerShortcuts}.
1578     */
1579    protected List<ShortcutInfo> getCallerVisibleShortcuts() {
1580        final ArrayList<ShortcutInfo> ret = new ArrayList<>();
1581        ret.addAll(mManager.getDynamicShortcuts());
1582        ret.addAll(mManager.getPinnedShortcuts());
1583        ret.addAll(mManager.getManifestShortcuts());
1584        return ret;
1585    }
1586
1587    protected ShortcutInfo getCallerShortcut(String shortcutId) {
1588        return getPackageShortcut(getCallingPackage(), shortcutId, getCallingUserId());
1589    }
1590
1591    protected List<ShortcutInfo> getLauncherShortcuts(String launcher, int userId, int queryFlags) {
1592        final List<ShortcutInfo>[] ret = new List[1];
1593        runWithCaller(launcher, userId, () -> {
1594            final ShortcutQuery q = new ShortcutQuery();
1595            q.setQueryFlags(queryFlags);
1596            ret[0] = mLauncherApps.getShortcuts(q, UserHandle.of(userId));
1597        });
1598        return ret[0];
1599    }
1600
1601    protected List<ShortcutInfo> getLauncherPinnedShortcuts(String launcher, int userId) {
1602        return getLauncherShortcuts(launcher, userId, ShortcutQuery.FLAG_GET_PINNED);
1603    }
1604
1605    protected ShortcutInfo getShortcutInfoAsLauncher(String packageName, String shortcutId,
1606            int userId) {
1607        final List<ShortcutInfo> infoList =
1608                mLauncherApps.getShortcutInfo(packageName, list(shortcutId),
1609                        UserHandle.of(userId));
1610        assertEquals("No shortcutInfo found (or too many of them)", 1, infoList.size());
1611        return infoList.get(0);
1612    }
1613
1614    protected Intent genPackageAddIntent(String packageName, int userId) {
1615        installPackage(userId, packageName);
1616
1617        Intent i = new Intent(Intent.ACTION_PACKAGE_ADDED);
1618        i.setData(Uri.parse("package:" + packageName));
1619        i.putExtra(Intent.EXTRA_USER_HANDLE, userId);
1620        return i;
1621    }
1622
1623    protected Intent genPackageDeleteIntent(String pakcageName, int userId) {
1624        uninstallPackage(userId, pakcageName);
1625
1626        Intent i = new Intent(Intent.ACTION_PACKAGE_REMOVED);
1627        i.setData(Uri.parse("package:" + pakcageName));
1628        i.putExtra(Intent.EXTRA_USER_HANDLE, userId);
1629        return i;
1630    }
1631
1632    protected Intent genPackageUpdateIntent(String pakcageName, int userId) {
1633        installPackage(userId, pakcageName);
1634
1635        Intent i = new Intent(Intent.ACTION_PACKAGE_ADDED);
1636        i.setData(Uri.parse("package:" + pakcageName));
1637        i.putExtra(Intent.EXTRA_USER_HANDLE, userId);
1638        i.putExtra(Intent.EXTRA_REPLACING, true);
1639        return i;
1640    }
1641
1642    protected Intent genPackageChangedIntent(String pakcageName, int userId) {
1643        Intent i = new Intent(Intent.ACTION_PACKAGE_CHANGED);
1644        i.setData(Uri.parse("package:" + pakcageName));
1645        i.putExtra(Intent.EXTRA_USER_HANDLE, userId);
1646        return i;
1647    }
1648
1649    protected Intent genPackageDataClear(String packageName, int userId) {
1650        Intent i = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED);
1651        i.setData(Uri.parse("package:" + packageName));
1652        i.putExtra(Intent.EXTRA_USER_HANDLE, userId);
1653        return i;
1654    }
1655
1656    protected void assertExistsAndShadow(ShortcutPackageItem spi) {
1657        assertNotNull(spi);
1658        assertTrue(spi.getPackageInfo().isShadow());
1659    }
1660
1661    protected File makeFile(File baseDirectory, String... paths) {
1662        File ret = baseDirectory;
1663
1664        for (String path : paths) {
1665            ret = new File(ret, path);
1666        }
1667
1668        return ret;
1669    }
1670
1671    protected boolean bitmapDirectoryExists(String packageName, int userId) {
1672        final File path = new File(mService.getUserBitmapFilePath(userId), packageName);
1673        return path.isDirectory();
1674    }
1675    protected static ShortcutQuery buildQuery(long changedSince,
1676            String packageName, ComponentName componentName,
1677            /* @ShortcutQuery.QueryFlags */ int flags) {
1678        return buildQuery(changedSince, packageName, null, componentName, flags);
1679    }
1680
1681    protected static ShortcutQuery buildQuery(long changedSince,
1682            String packageName, List<String> shortcutIds, ComponentName componentName,
1683            /* @ShortcutQuery.QueryFlags */ int flags) {
1684        final ShortcutQuery q = new ShortcutQuery();
1685        q.setChangedSince(changedSince);
1686        q.setPackage(packageName);
1687        q.setShortcutIds(shortcutIds);
1688        q.setActivity(componentName);
1689        q.setQueryFlags(flags);
1690        return q;
1691    }
1692
1693    protected static ShortcutQuery buildAllQuery(String packageName) {
1694        final ShortcutQuery q = new ShortcutQuery();
1695        q.setPackage(packageName);
1696        q.setQueryFlags(ShortcutQuery.FLAG_GET_ALL_KINDS);
1697        return q;
1698    }
1699
1700    protected static ShortcutQuery buildPinnedQuery(String packageName) {
1701        final ShortcutQuery q = new ShortcutQuery();
1702        q.setPackage(packageName);
1703        q.setQueryFlags(ShortcutQuery.FLAG_GET_PINNED);
1704        return q;
1705    }
1706
1707    protected static ShortcutQuery buildQueryWithFlags(int queryFlags) {
1708        final ShortcutQuery q = new ShortcutQuery();
1709        q.setQueryFlags(queryFlags);
1710        return q;
1711    }
1712
1713    protected void backupAndRestore() {
1714        int prevUid = mInjectedCallingUid;
1715
1716        mInjectedCallingUid = Process.SYSTEM_UID; // Only system can call it.
1717
1718        dumpsysOnLogcat("Before backup");
1719
1720        final byte[] payload =  mService.getBackupPayload(USER_0);
1721        if (ENABLE_DUMP) {
1722            final String xml = new String(payload);
1723            Log.v(TAG, "Backup payload:");
1724            for (String line : xml.split("\n")) {
1725                Log.v(TAG, line);
1726            }
1727        }
1728
1729        // Before doing anything else, uninstall all packages.
1730        for (int userId : list(USER_0, USER_P0)) {
1731            for (String pkg : list(CALLING_PACKAGE_1, CALLING_PACKAGE_2, CALLING_PACKAGE_3,
1732                    LAUNCHER_1, LAUNCHER_2, LAUNCHER_3)) {
1733                uninstallPackage(userId, pkg);
1734            }
1735        }
1736
1737        shutdownServices();
1738
1739        deleteAllSavedFiles();
1740
1741        initService();
1742        mService.applyRestore(payload, USER_0);
1743
1744        // handleUnlockUser will perform the gone package check, but it shouldn't remove
1745        // shadow information.
1746        mService.handleUnlockUser(USER_0);
1747
1748        dumpsysOnLogcat("After restore");
1749
1750        mInjectedCallingUid = prevUid;
1751    }
1752
1753    protected void prepareCrossProfileDataSet() {
1754        mRunningUsers.put(USER_10, true); // this test needs user 10.
1755
1756        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1757            assertTrue(mManager.setDynamicShortcuts(list(
1758                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
1759                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
1760        });
1761        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1762            assertTrue(mManager.setDynamicShortcuts(list(
1763                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
1764                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
1765        });
1766        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
1767            assertTrue(mManager.setDynamicShortcuts(list(
1768                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
1769                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
1770        });
1771        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
1772            assertTrue(mManager.setDynamicShortcuts(list()));
1773        });
1774        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
1775            assertTrue(mManager.setDynamicShortcuts(list(
1776                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
1777                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
1778        });
1779        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
1780            assertTrue(mManager.setDynamicShortcuts(list(
1781                    makeShortcut("x1"), makeShortcut("x2"), makeShortcut("x3"),
1782                    makeShortcut("x4"), makeShortcut("x5"), makeShortcut("x6"))));
1783        });
1784
1785        runWithCaller(LAUNCHER_1, USER_0, () -> {
1786            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_0);
1787            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s1", "s2"), HANDLE_USER_0);
1788            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s1", "s2", "s3"), HANDLE_USER_0);
1789
1790            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1", "s4"), HANDLE_USER_P0);
1791        });
1792        runWithCaller(LAUNCHER_2, USER_0, () -> {
1793            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0);
1794            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s2", "s3"), HANDLE_USER_0);
1795            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s2", "s3", "s4"), HANDLE_USER_0);
1796
1797            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2", "s5"), HANDLE_USER_P0);
1798        });
1799
1800        // Note LAUNCHER_3 has allowBackup=false.
1801        runWithCaller(LAUNCHER_3, USER_0, () -> {
1802            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0);
1803            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s3", "s4"), HANDLE_USER_0);
1804            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s3", "s4", "s5"), HANDLE_USER_0);
1805
1806            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3", "s6"), HANDLE_USER_P0);
1807        });
1808        runWithCaller(LAUNCHER_4, USER_0, () -> {
1809            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list(), HANDLE_USER_0);
1810            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list(), HANDLE_USER_0);
1811            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list(), HANDLE_USER_0);
1812            mLauncherApps.pinShortcuts(CALLING_PACKAGE_4, list(), HANDLE_USER_0);
1813        });
1814
1815        // Launcher on a managed profile is referring ot user 0!
1816        runWithCaller(LAUNCHER_1, USER_P0, () -> {
1817            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3", "s4"), HANDLE_USER_0);
1818            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s3", "s4", "s5"), HANDLE_USER_0);
1819            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s3", "s4", "s5", "s6"),
1820                    HANDLE_USER_0);
1821
1822            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s4", "s1"), HANDLE_USER_P0);
1823        });
1824        runWithCaller(LAUNCHER_1, USER_10, () -> {
1825            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("x4", "x5"), HANDLE_USER_10);
1826            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("x4", "x5", "x6"), HANDLE_USER_10);
1827            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("x4", "x5", "x6", "x1"),
1828                    HANDLE_USER_10);
1829        });
1830
1831        // Then remove some dynamic shortcuts.
1832        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1833            assertTrue(mManager.setDynamicShortcuts(list(
1834                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
1835        });
1836        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1837            assertTrue(mManager.setDynamicShortcuts(list(
1838                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
1839        });
1840        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
1841            assertTrue(mManager.setDynamicShortcuts(list(
1842                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
1843        });
1844        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
1845            assertTrue(mManager.setDynamicShortcuts(list()));
1846        });
1847        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
1848            assertTrue(mManager.setDynamicShortcuts(list(
1849                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
1850        });
1851        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
1852            assertTrue(mManager.setDynamicShortcuts(list(
1853                    makeShortcut("x1"), makeShortcut("x2"), makeShortcut("x3"))));
1854        });
1855    }
1856
1857    public static List<ShortcutInfo> assertAllHaveIconResId(
1858            List<ShortcutInfo> actualShortcuts) {
1859        for (ShortcutInfo s : actualShortcuts) {
1860            assertTrue("ID " + s.getId() + " not have icon res ID", s.hasIconResource());
1861            assertFalse("ID " + s.getId() + " shouldn't have icon FD", s.hasIconFile());
1862        }
1863        return actualShortcuts;
1864    }
1865
1866    public static List<ShortcutInfo> assertAllHaveIconFile(
1867            List<ShortcutInfo> actualShortcuts) {
1868        for (ShortcutInfo s : actualShortcuts) {
1869            assertFalse("ID " + s.getId() + " shouldn't have icon res ID", s.hasIconResource());
1870            assertTrue("ID " + s.getId() + " not have icon FD", s.hasIconFile());
1871        }
1872        return actualShortcuts;
1873    }
1874
1875    public static List<ShortcutInfo> assertAllHaveIcon(
1876            List<ShortcutInfo> actualShortcuts) {
1877        for (ShortcutInfo s : actualShortcuts) {
1878            assertTrue("ID " + s.getId() + " has no icon ", s.hasIconFile() || s.hasIconResource());
1879        }
1880        return actualShortcuts;
1881    }
1882
1883    public static List<ShortcutInfo> assertAllStringsResolved(
1884            List<ShortcutInfo> actualShortcuts) {
1885        for (ShortcutInfo s : actualShortcuts) {
1886            assertTrue("ID " + s.getId(), s.hasStringResourcesResolved());
1887        }
1888        return actualShortcuts;
1889    }
1890
1891    public String readTestAsset(String assetPath) throws IOException {
1892        final StringBuilder sb = new StringBuilder();
1893        try (BufferedReader br = new BufferedReader(
1894                new InputStreamReader(
1895                        getTestContext().getResources().getAssets().open(assetPath)))) {
1896            String line;
1897            while ((line = br.readLine()) != null) {
1898                sb.append(line);
1899                sb.append(System.lineSeparator());
1900            }
1901        }
1902        return sb.toString();
1903    }
1904
1905    protected void prepareGetHomeActivitiesAsUser(ComponentName preferred,
1906            List<ResolveInfo> candidates, int userId) {
1907        doAnswer(inv -> {
1908            ((List) inv.getArguments()[0]).addAll(candidates);
1909            return preferred;
1910        }).when(mMockPackageManagerInternal).getHomeActivitiesAsUser(any(List.class), eq(userId));
1911    }
1912
1913    protected static ComponentName cn(String packageName, String name) {
1914        return new ComponentName(packageName, name);
1915    }
1916
1917    protected static ResolveInfo ri(String packageName, String name, boolean isSystem, int priority) {
1918        final ResolveInfo ri = new ResolveInfo();
1919        ri.activityInfo = new ActivityInfo();
1920        ri.activityInfo.applicationInfo = new ApplicationInfo();
1921
1922        ri.activityInfo.packageName = packageName;
1923        ri.activityInfo.name = name;
1924        if (isSystem) {
1925            ri.activityInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
1926        }
1927        ri.priority = priority;
1928        return ri;
1929    }
1930
1931    protected static ResolveInfo getSystemLauncher() {
1932        return ri(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME, true,
1933                PACKAGE_SYSTEM_LAUNCHER_PRIORITY);
1934    }
1935
1936    protected static ResolveInfo getFallbackLauncher() {
1937        return ri(PACKAGE_FALLBACK_LAUNCHER, PACKAGE_FALLBACK_LAUNCHER_NAME, true,
1938                PACKAGE_FALLBACK_LAUNCHER_PRIORITY);
1939    }
1940}
1941