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