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