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