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