BaseShortcutManagerTest.java revision a1d38b3c95cd6a38ee7336fd90729d3b3be6ae25
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 ShortcutManager getManager() {
701        return mManager;
702    }
703
704    protected void deleteAllSavedFiles() {
705        // Empty the data directory.
706        if (mInjectedFilePathRoot.exists()) {
707            Assert.assertTrue("failed to delete dir",
708                    FileUtils.deleteContents(mInjectedFilePathRoot));
709        }
710        mInjectedFilePathRoot.mkdirs();
711    }
712
713    /** (Re-) init the manager and the service. */
714    protected void initService() {
715        shutdownServices();
716
717        LocalServices.removeServiceForTest(ShortcutServiceInternal.class);
718
719        // Instantiate targets.
720        mService = new ShortcutServiceTestable(mServiceContext, Looper.getMainLooper());
721        mManager = new ShortcutManagerTestable(mClientContext, mService);
722
723        mInternal = LocalServices.getService(ShortcutServiceInternal.class);
724
725        mLauncherAppImpl = new LauncherAppImplTestable(mServiceContext);
726        mLauncherApps = null;
727        mLauncherAppsMap.clear();
728
729        // Send boot sequence events.
730        mService.onBootPhase(SystemService.PHASE_LOCK_SETTINGS_READY);
731
732        // Make sure a call to onSystemLocaleChangedNoLock() before PHASE_BOOT_COMPLETED will be
733        // ignored.
734        final long origSequenceNumber = mService.getLocaleChangeSequenceNumber();
735        mInternal.onSystemLocaleChangedNoLock();
736        assertEquals(origSequenceNumber, mService.getLocaleChangeSequenceNumber());
737
738        mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
739    }
740
741    protected void shutdownServices() {
742        if (mService != null) {
743            // Flush all the unsaved data from the previous instance.
744            mService.saveDirtyInfo();
745        }
746        LocalServices.removeServiceForTest(ShortcutServiceInternal.class);
747
748        mService = null;
749        mManager = null;
750        mInternal = null;
751        mLauncherAppImpl = null;
752        mLauncherApps = null;
753        mLauncherAppsMap.clear();
754    }
755
756    protected void addPackage(String packageName, int uid, int version) {
757        addPackage(packageName, uid, version, packageName);
758    }
759
760    protected Signature[] genSignatures(String... signatures) {
761        final Signature[] sigs = new Signature[signatures.length];
762        for (int i = 0; i < signatures.length; i++){
763            sigs[i] = new Signature(signatures[i].getBytes());
764        }
765        return sigs;
766    }
767
768    protected PackageInfo genPackage(String packageName, int uid, int version, String... signatures) {
769        final PackageInfo pi = new PackageInfo();
770        pi.packageName = packageName;
771        pi.applicationInfo = new ApplicationInfo();
772        pi.applicationInfo.uid = uid;
773        pi.applicationInfo.flags = ApplicationInfo.FLAG_INSTALLED
774                | ApplicationInfo.FLAG_ALLOW_BACKUP;
775        pi.versionCode = version;
776        pi.applicationInfo.versionCode = version;
777        pi.signatures = genSignatures(signatures);
778
779        return pi;
780    }
781
782    protected void addPackage(String packageName, int uid, int version, String... signatures) {
783        mInjectedPackages.put(packageName, genPackage(packageName, uid, version, signatures));
784    }
785
786    protected void updatePackageInfo(String packageName, Consumer<PackageInfo> c) {
787        c.accept(mInjectedPackages.get(packageName));
788    }
789
790    protected void updatePackageVersion(String packageName, int increment) {
791        updatePackageInfo(packageName, pi -> {
792            pi.versionCode += increment;
793            pi.applicationInfo.versionCode += increment;
794        });
795    }
796
797    protected void updatePackageLastUpdateTime(String packageName, long increment) {
798        updatePackageInfo(packageName, pi -> {
799            pi.lastUpdateTime += increment;
800        });
801    }
802
803    protected void uninstallPackage(int userId, String packageName) {
804        if (ENABLE_DUMP) {
805            Log.v(TAG, "Unnstall package " + packageName + " / " + userId);
806        }
807        mUninstalledPackages.add(PackageWithUser.of(userId, packageName));
808    }
809
810    protected void installPackage(int userId, String packageName) {
811        if (ENABLE_DUMP) {
812            Log.v(TAG, "Install package " + packageName + " / " + userId);
813        }
814        mUninstalledPackages.remove(PackageWithUser.of(userId, packageName));
815    }
816
817    PackageInfo getInjectedPackageInfo(String packageName, @UserIdInt int userId,
818            boolean getSignatures) {
819        final PackageInfo pi = mInjectedPackages.get(packageName);
820        if (pi == null) return null;
821
822        final PackageInfo ret = new PackageInfo();
823        ret.packageName = pi.packageName;
824        ret.versionCode = pi.versionCode;
825        ret.lastUpdateTime = pi.lastUpdateTime;
826
827        ret.applicationInfo = new ApplicationInfo(pi.applicationInfo);
828        ret.applicationInfo.uid = UserHandle.getUid(userId, pi.applicationInfo.uid);
829        ret.applicationInfo.packageName = pi.packageName;
830
831        if (mUninstalledPackages.contains(PackageWithUser.of(userId, packageName))) {
832            ret.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED;
833        }
834
835        if (getSignatures) {
836            ret.signatures = pi.signatures;
837        }
838
839        return ret;
840    }
841
842    protected void addApplicationInfo(PackageInfo pi, List<ApplicationInfo> list) {
843        if (pi != null && pi.applicationInfo != null) {
844            list.add(pi.applicationInfo);
845        }
846    }
847
848    protected List<ApplicationInfo> getInstalledApplications(int userId) {
849        final ArrayList<ApplicationInfo> ret = new ArrayList<>();
850
851        addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_1, userId, false), ret);
852        addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_2, userId, false), ret);
853        addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_3, userId, false), ret);
854        addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_4, userId, false), ret);
855        addApplicationInfo(getInjectedPackageInfo(LAUNCHER_1, userId, false), ret);
856        addApplicationInfo(getInjectedPackageInfo(LAUNCHER_2, userId, false), ret);
857        addApplicationInfo(getInjectedPackageInfo(LAUNCHER_3, userId, false), ret);
858        addApplicationInfo(getInjectedPackageInfo(LAUNCHER_4, userId, false), ret);
859
860        return ret;
861    }
862
863    private void addPackageInfo(PackageInfo pi, List<PackageInfo> list) {
864        if (pi != null) {
865            list.add(pi);
866        }
867    }
868
869    private List<PackageInfo> getInstalledPackages(int userId) {
870        final ArrayList<PackageInfo> ret = new ArrayList<>();
871
872        addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_1, userId, false), ret);
873        addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_2, userId, false), ret);
874        addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_3, userId, false), ret);
875        addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_4, userId, false), ret);
876        addPackageInfo(getInjectedPackageInfo(LAUNCHER_1, userId, false), ret);
877        addPackageInfo(getInjectedPackageInfo(LAUNCHER_2, userId, false), ret);
878        addPackageInfo(getInjectedPackageInfo(LAUNCHER_3, userId, false), ret);
879        addPackageInfo(getInjectedPackageInfo(LAUNCHER_4, userId, false), ret);
880
881        return ret;
882    }
883
884    protected void addManifestShortcutResource(ComponentName activity, int resId) {
885        final String packageName = activity.getPackageName();
886        LinkedHashMap<ComponentName, Integer> map = mActivityMetadataResId.get(packageName);
887        if (map == null) {
888            map = new LinkedHashMap<>();
889            mActivityMetadataResId.put(packageName, map);
890        }
891        map.put(activity, resId);
892    }
893
894    protected PackageInfo injectGetActivitiesWithMetadata(String packageName, @UserIdInt int userId) {
895        final PackageInfo ret = getInjectedPackageInfo(packageName, userId,
896                /* getSignatures=*/ false);
897
898        final HashMap<ComponentName, Integer> activities = mActivityMetadataResId.get(packageName);
899        if (activities != null) {
900            final ArrayList<ActivityInfo> list = new ArrayList<>();
901
902            for (ComponentName cn : activities.keySet()) {
903                ActivityInfo ai = new ActivityInfo();
904                ai.packageName = cn.getPackageName();
905                ai.name = cn.getClassName();
906                ai.metaData = new Bundle();
907                ai.metaData.putInt(ShortcutParser.METADATA_KEY, activities.get(cn));
908                list.add(ai);
909            }
910            ret.activities = list.toArray(new ActivityInfo[list.size()]);
911        }
912        return ret;
913    }
914
915    protected XmlResourceParser injectXmlMetaData(ActivityInfo activityInfo, String key) {
916        if (!ShortcutParser.METADATA_KEY.equals(key) || activityInfo.metaData == null) {
917            return null;
918        }
919        final int resId = activityInfo.metaData.getInt(key);
920        return getTestContext().getResources().getXml(resId);
921    }
922
923    /** Replace the current calling package */
924    protected void setCaller(String packageName, int userId) {
925        mInjectedClientPackage = packageName;
926        mInjectedCallingUid =
927                Preconditions.checkNotNull(getInjectedPackageInfo(packageName, userId, false),
928                        "Unknown package").applicationInfo.uid;
929
930        // Set up LauncherApps for this caller.
931        final Pair<Integer, String> key = Pair.create(userId, packageName);
932        if (!mLauncherAppsMap.containsKey(key)) {
933            mLauncherAppsMap.put(key, new LauncherAppsTestable(mClientContext, mLauncherAppImpl));
934        }
935        mLauncherApps = mLauncherAppsMap.get(key);
936    }
937
938    protected void setCaller(String packageName) {
939        setCaller(packageName, UserHandle.USER_SYSTEM);
940    }
941
942    protected String getCallingPackage() {
943        return mInjectedClientPackage;
944    }
945
946    protected void setDefaultLauncherChecker(BiPredicate<String, Integer> p) {
947        mDefaultLauncherChecker = p;
948    }
949
950    protected void runWithCaller(String packageName, int userId, Runnable r) {
951        final String previousPackage = mInjectedClientPackage;
952        final int previousUserId = UserHandle.getUserId(mInjectedCallingUid);
953
954        setCaller(packageName, userId);
955
956        r.run();
957
958        setCaller(previousPackage, previousUserId);
959    }
960
961    protected void runWithSystemUid(Runnable r) {
962        final int origUid = mInjectedCallingUid;
963        mInjectedCallingUid = Process.SYSTEM_UID;
964        r.run();
965        mInjectedCallingUid = origUid;
966    }
967
968    protected void lookupAndFillInResourceNames(ShortcutInfo si) {
969        runWithSystemUid(() -> si.lookupAndFillInResourceNames(
970                mService.injectGetResourcesForApplicationAsUser(si.getPackage(), si.getUserId())));
971    }
972
973    protected int getCallingUserId() {
974        return UserHandle.getUserId(mInjectedCallingUid);
975    }
976
977    protected UserHandle getCallingUser() {
978        return UserHandle.of(getCallingUserId());
979    }
980
981    /** For debugging */
982    protected void dumpsysOnLogcat() {
983        dumpsysOnLogcat("");
984    }
985
986    protected void dumpsysOnLogcat(String message) {
987        dumpsysOnLogcat(message, false);
988    }
989
990    protected void dumpsysOnLogcat(String message, boolean force) {
991        if (force || !ENABLE_DUMP) return;
992
993        final ByteArrayOutputStream out = new ByteArrayOutputStream();
994        final PrintWriter pw = new PrintWriter(out);
995        mService.dumpInner(pw, null);
996        pw.close();
997
998        Log.v(TAG, "Dumping ShortcutService: " + message);
999        for (String line : out.toString().split("\n")) {
1000            Log.v(TAG, line);
1001        }
1002    }
1003
1004    /**
1005     * For debugging, dump arbitrary file on logcat.
1006     */
1007    protected void dumpFileOnLogcat(String path) {
1008        dumpFileOnLogcat(path, "");
1009    }
1010
1011    protected void dumpFileOnLogcat(String path, String message) {
1012        if (!ENABLE_DUMP) return;
1013
1014        Log.v(TAG, "Dumping file: " + path + " " + message);
1015        final StringBuilder sb = new StringBuilder();
1016        try (BufferedReader br = new BufferedReader(new FileReader(path))) {
1017            String line;
1018            while ((line = br.readLine()) != null) {
1019                Log.v(TAG, line);
1020            }
1021        } catch (Exception e) {
1022            Log.e(TAG, "Couldn't read file", e);
1023            fail("Exception " + e);
1024        }
1025    }
1026
1027    /**
1028     * For debugging, dump the main state file on logcat.
1029     */
1030    protected void dumpBaseStateFile() {
1031        mService.saveDirtyInfo();
1032        dumpFileOnLogcat(mInjectedFilePathRoot.getAbsolutePath()
1033                + "/system/" + ShortcutService.FILENAME_BASE_STATE);
1034    }
1035
1036    /**
1037     * For debugging, dump per-user state file on logcat.
1038     */
1039    protected void dumpUserFile(int userId) {
1040        dumpUserFile(userId, "");
1041    }
1042
1043    protected void dumpUserFile(int userId, String message) {
1044        mService.saveDirtyInfo();
1045        dumpFileOnLogcat(mInjectedFilePathRoot.getAbsolutePath()
1046                + "/user-" + userId
1047                + "/" + ShortcutService.FILENAME_USER_PACKAGES, message);
1048    }
1049
1050    protected void waitOnMainThread() throws Throwable {
1051        runTestOnUiThread(() -> {});
1052    }
1053
1054    /**
1055     * Make a shortcut with an ID.
1056     */
1057    protected ShortcutInfo makeShortcut(String id) {
1058        return makeShortcut(
1059                id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
1060                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
1061    }
1062
1063    protected ShortcutInfo makeShortcutWithTitle(String id, String title) {
1064        return makeShortcut(
1065                id, title, /* activity =*/ null, /* icon =*/ null,
1066                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
1067    }
1068
1069    /**
1070     * Make a shortcut with an ID and timestamp.
1071     */
1072    protected ShortcutInfo makeShortcutWithTimestamp(String id, long timestamp) {
1073        final ShortcutInfo s = makeShortcut(
1074                id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
1075                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
1076        s.setTimestamp(timestamp);
1077        return s;
1078    }
1079
1080    /**
1081     * Make a shortcut with an ID, a timestamp and an activity component
1082     */
1083    protected ShortcutInfo makeShortcutWithTimestampWithActivity(String id, long timestamp,
1084            ComponentName activity) {
1085        final ShortcutInfo s = makeShortcut(
1086                id, "Title-" + id, activity, /* icon =*/ null,
1087                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
1088        s.setTimestamp(timestamp);
1089        return s;
1090    }
1091
1092    /**
1093     * Make a shortcut with an ID and icon.
1094     */
1095    protected ShortcutInfo makeShortcutWithIcon(String id, Icon icon) {
1096        return makeShortcut(
1097                id, "Title-" + id, /* activity =*/ null, icon,
1098                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
1099    }
1100
1101    protected ShortcutInfo makePackageShortcut(String packageName, String id) {
1102        String origCaller = getCallingPackage();
1103
1104        setCaller(packageName);
1105        ShortcutInfo s = makeShortcut(
1106                id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
1107                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
1108        setCaller(origCaller); // restore the caller
1109
1110        return s;
1111    }
1112
1113    /**
1114     * Make multiple shortcuts with IDs.
1115     */
1116    protected List<ShortcutInfo> makeShortcuts(String... ids) {
1117        final ArrayList<ShortcutInfo> ret = new ArrayList();
1118        for (String id : ids) {
1119            ret.add(makeShortcut(id));
1120        }
1121        return ret;
1122    }
1123
1124    protected ShortcutInfo.Builder makeShortcutBuilder() {
1125        return new ShortcutInfo.Builder(mClientContext);
1126    }
1127
1128    protected ShortcutInfo makeShortcutWithActivity(String id, ComponentName activity) {
1129        return makeShortcut(
1130                id, "Title-" + id, activity, /* icon =*/ null,
1131                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
1132    }
1133
1134    protected ShortcutInfo makeShortcutWithActivityAndTitle(String id, ComponentName activity,
1135            String title) {
1136        return makeShortcut(
1137                id, title, activity, /* icon =*/ null,
1138                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
1139    }
1140
1141    protected ShortcutInfo makeShortcutWithActivityAndRank(String id, ComponentName activity,
1142            int rank) {
1143        return makeShortcut(
1144                id, "Title-" + id, activity, /* icon =*/ null,
1145                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), rank);
1146    }
1147
1148    /**
1149     * Make a shortcut with details.
1150     */
1151    protected ShortcutInfo makeShortcut(String id, String title, ComponentName activity,
1152            Icon icon, Intent intent, int rank) {
1153        final ShortcutInfo.Builder  b = new ShortcutInfo.Builder(mClientContext)
1154                .setId(id)
1155                .setActivity(new ComponentName(mClientContext.getPackageName(), "dummy"))
1156                .setTitle(title)
1157                .setRank(rank)
1158                .setIntent(intent);
1159        if (icon != null) {
1160            b.setIcon(icon);
1161        }
1162        if (activity != null) {
1163            b.setActivity(activity);
1164        }
1165        final ShortcutInfo s = b.build();
1166
1167        s.setTimestamp(mInjectedCurrentTimeMillis); // HACK
1168
1169        return s;
1170    }
1171
1172    /**
1173     * Make an intent.
1174     */
1175    protected Intent makeIntent(String action, Class<?> clazz, Object... bundleKeysAndValues) {
1176        final Intent intent = new Intent(action);
1177        intent.setComponent(makeComponent(clazz));
1178        intent.replaceExtras(makeBundle(bundleKeysAndValues));
1179        return intent;
1180    }
1181
1182    /**
1183     * Make an component name, with the client context.
1184     */
1185    @NonNull
1186    protected ComponentName makeComponent(Class<?> clazz) {
1187        return new ComponentName(mClientContext, clazz);
1188    }
1189
1190    @NonNull
1191    protected ShortcutInfo findById(List<ShortcutInfo> list, String id) {
1192        for (ShortcutInfo s : list) {
1193            if (s.getId().equals(id)) {
1194                return s;
1195            }
1196        }
1197        fail("Shortcut with id " + id + " not found");
1198        return null;
1199    }
1200
1201    protected void assertSystem() {
1202        assertEquals("Caller must be system", Process.SYSTEM_UID, mInjectedCallingUid);
1203    }
1204
1205    protected void assertResetTimes(long expectedLastResetTime, long expectedNextResetTime) {
1206        assertEquals(expectedLastResetTime, mService.getLastResetTimeLocked());
1207        assertEquals(expectedNextResetTime, mService.getNextResetTimeLocked());
1208    }
1209
1210    public static List<ShortcutInfo> assertAllNotHaveIcon(
1211            List<ShortcutInfo> actualShortcuts) {
1212        for (ShortcutInfo s : actualShortcuts) {
1213            assertNull("ID " + s.getId(), s.getIcon());
1214        }
1215        return actualShortcuts;
1216    }
1217
1218    @NonNull
1219    protected List<ShortcutInfo> assertAllHaveFlags(@NonNull List<ShortcutInfo> actualShortcuts,
1220            int shortcutFlags) {
1221        for (ShortcutInfo s : actualShortcuts) {
1222            assertTrue("ID " + s.getId() + " doesn't have flags " + shortcutFlags,
1223                    s.hasFlags(shortcutFlags));
1224        }
1225        return actualShortcuts;
1226    }
1227
1228    protected ShortcutInfo getPackageShortcut(String packageName, String shortcutId, int userId) {
1229        return mService.getPackageShortcutForTest(packageName, shortcutId, userId);
1230    }
1231
1232    protected void assertShortcutExists(String packageName, String shortcutId, int userId) {
1233        assertTrue(getPackageShortcut(packageName, shortcutId, userId) != null);
1234    }
1235
1236    protected void assertShortcutNotExists(String packageName, String shortcutId, int userId) {
1237        assertTrue(getPackageShortcut(packageName, shortcutId, userId) == null);
1238    }
1239
1240    protected Intent launchShortcutAndGetIntent(
1241            @NonNull String packageName, @NonNull String shortcutId, int userId) {
1242        reset(mServiceContext);
1243        assertTrue(mLauncherApps.startShortcut(packageName, shortcutId, null, null,
1244                UserHandle.of(userId)));
1245
1246        final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
1247        verify(mServiceContext).startActivityAsUser(
1248                intentCaptor.capture(),
1249                any(Bundle.class),
1250                eq(UserHandle.of(userId)));
1251        return intentCaptor.getValue();
1252    }
1253
1254    protected Intent launchShortcutAndGetIntent_withShortcutInfo(
1255            @NonNull String packageName, @NonNull String shortcutId, int userId) {
1256        reset(mServiceContext);
1257
1258        assertTrue(mLauncherApps.startShortcut(
1259                getShortcutInfoAsLauncher(packageName, shortcutId, userId), null, null));
1260
1261        final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
1262        verify(mServiceContext).startActivityAsUser(
1263                intentCaptor.capture(),
1264                any(Bundle.class),
1265                eq(UserHandle.of(userId)));
1266        return intentCaptor.getValue();
1267    }
1268
1269    protected void assertShortcutLaunchable(@NonNull String packageName, @NonNull String shortcutId,
1270            int userId) {
1271        assertNotNull(launchShortcutAndGetIntent(packageName, shortcutId, userId));
1272        assertNotNull(launchShortcutAndGetIntent_withShortcutInfo(packageName, shortcutId, userId));
1273    }
1274
1275    protected void assertShortcutNotLaunchable(@NonNull String packageName,
1276            @NonNull String shortcutId, int userId) {
1277        try {
1278            final boolean ok = mLauncherApps.startShortcut(packageName, shortcutId, null, null,
1279                    UserHandle.of(userId));
1280            if (!ok) {
1281                return; // didn't launch, okay.
1282            }
1283            fail();
1284        } catch (SecurityException expected) {
1285            // security exception is okay too.
1286        }
1287    }
1288
1289    protected void assertBitmapDirectories(int userId, String... expectedDirectories) {
1290        final Set<String> expected = hashSet(set(expectedDirectories));
1291
1292        final Set<String> actual = new HashSet<>();
1293
1294        final File[] files = mService.getUserBitmapFilePath(userId).listFiles();
1295        if (files != null) {
1296            for (File child : files) {
1297                if (child.isDirectory()) {
1298                    actual.add(child.getName());
1299                }
1300            }
1301        }
1302
1303        assertEquals(expected, actual);
1304    }
1305
1306    protected void assertBitmapFiles(int userId, String packageName, String... expectedFiles) {
1307        final Set<String> expected = hashSet(set(expectedFiles));
1308
1309        final Set<String> actual = new HashSet<>();
1310
1311        final File[] files = new File(mService.getUserBitmapFilePath(userId), packageName)
1312                .listFiles();
1313        if (files != null) {
1314            for (File child : files) {
1315                if (child.isFile()) {
1316                    actual.add(child.getName());
1317                }
1318            }
1319        }
1320
1321        assertEquals(expected, actual);
1322    }
1323
1324    protected String getBitmapFilename(int userId, String packageName, String shortcutId) {
1325        final ShortcutInfo si = mService.getPackageShortcutForTest(packageName, shortcutId, userId);
1326        if (si == null) {
1327            return null;
1328        }
1329        return new File(si.getBitmapPath()).getName();
1330    }
1331
1332    protected List<ShortcutInfo> getCallerShortcuts() {
1333        final ShortcutPackage p = mService.getPackageShortcutForTest(
1334                getCallingPackage(), getCallingUserId());
1335        return p == null ? null : p.getAllShortcutsForTest();
1336    }
1337
1338    protected ShortcutInfo getCallerShortcut(String shortcutId) {
1339        return getPackageShortcut(getCallingPackage(), shortcutId, getCallingUserId());
1340    }
1341
1342    protected List<ShortcutInfo> getLauncherShortcuts(String launcher, int userId, int queryFlags) {
1343        final List<ShortcutInfo>[] ret = new List[1];
1344        runWithCaller(launcher, userId, () -> {
1345            final ShortcutQuery q = new ShortcutQuery();
1346            q.setQueryFlags(queryFlags);
1347            ret[0] = mLauncherApps.getShortcuts(q, UserHandle.of(userId));
1348        });
1349        return ret[0];
1350    }
1351
1352    protected List<ShortcutInfo> getLauncherPinnedShortcuts(String launcher, int userId) {
1353        return getLauncherShortcuts(launcher, userId, ShortcutQuery.FLAG_GET_PINNED);
1354    }
1355
1356    protected ShortcutInfo getShortcutInfoAsLauncher(String packageName, String shortcutId,
1357            int userId) {
1358        final List<ShortcutInfo> infoList =
1359                mLauncherApps.getShortcutInfo(packageName, list(shortcutId),
1360                        UserHandle.of(userId));
1361        assertEquals("No shortcutInfo found (or too many of them)", 1, infoList.size());
1362        return infoList.get(0);
1363    }
1364
1365    protected Intent genPackageAddIntent(String pakcageName, int userId) {
1366        Intent i = new Intent(Intent.ACTION_PACKAGE_ADDED);
1367        i.setData(Uri.parse("package:" + pakcageName));
1368        i.putExtra(Intent.EXTRA_USER_HANDLE, userId);
1369        return i;
1370    }
1371
1372    protected Intent genPackageDeleteIntent(String pakcageName, int userId) {
1373        Intent i = new Intent(Intent.ACTION_PACKAGE_REMOVED);
1374        i.setData(Uri.parse("package:" + pakcageName));
1375        i.putExtra(Intent.EXTRA_USER_HANDLE, userId);
1376        return i;
1377    }
1378
1379    protected Intent genPackageUpdateIntent(String pakcageName, int userId) {
1380        Intent i = new Intent(Intent.ACTION_PACKAGE_ADDED);
1381        i.setData(Uri.parse("package:" + pakcageName));
1382        i.putExtra(Intent.EXTRA_USER_HANDLE, userId);
1383        i.putExtra(Intent.EXTRA_REPLACING, true);
1384        return i;
1385    }
1386
1387    protected Intent genPackageDataClear(String packageName, int userId) {
1388        Intent i = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED);
1389        i.setData(Uri.parse("package:" + packageName));
1390        i.putExtra(Intent.EXTRA_USER_HANDLE, userId);
1391        return i;
1392    }
1393
1394    protected void assertExistsAndShadow(ShortcutPackageItem spi) {
1395        assertNotNull(spi);
1396        assertTrue(spi.getPackageInfo().isShadow());
1397    }
1398
1399    protected File makeFile(File baseDirectory, String... paths) {
1400        File ret = baseDirectory;
1401
1402        for (String path : paths) {
1403            ret = new File(ret, path);
1404        }
1405
1406        return ret;
1407    }
1408
1409    protected boolean bitmapDirectoryExists(String packageName, int userId) {
1410        final File path = new File(mService.getUserBitmapFilePath(userId), packageName);
1411        return path.isDirectory();
1412    }
1413    protected static ShortcutQuery buildQuery(long changedSince,
1414            String packageName, ComponentName componentName,
1415            /* @ShortcutQuery.QueryFlags */ int flags) {
1416        return buildQuery(changedSince, packageName, null, componentName, flags);
1417    }
1418
1419    protected static ShortcutQuery buildQuery(long changedSince,
1420            String packageName, List<String> shortcutIds, ComponentName componentName,
1421            /* @ShortcutQuery.QueryFlags */ int flags) {
1422        final ShortcutQuery q = new ShortcutQuery();
1423        q.setChangedSince(changedSince);
1424        q.setPackage(packageName);
1425        q.setShortcutIds(shortcutIds);
1426        q.setActivity(componentName);
1427        q.setQueryFlags(flags);
1428        return q;
1429    }
1430
1431    protected static ShortcutQuery buildAllQuery(String packageName) {
1432        final ShortcutQuery q = new ShortcutQuery();
1433        q.setPackage(packageName);
1434        q.setQueryFlags(ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_PINNED);
1435        return q;
1436    }
1437
1438    protected static ShortcutQuery buildPinnedQuery(String packageName) {
1439        final ShortcutQuery q = new ShortcutQuery();
1440        q.setPackage(packageName);
1441        q.setQueryFlags(ShortcutQuery.FLAG_GET_PINNED);
1442        return q;
1443    }
1444
1445    protected void backupAndRestore() {
1446        int prevUid = mInjectedCallingUid;
1447
1448        mInjectedCallingUid = Process.SYSTEM_UID; // Only system can call it.
1449
1450        dumpsysOnLogcat("Before backup");
1451
1452        final byte[] payload =  mService.getBackupPayload(USER_0);
1453        if (ENABLE_DUMP) {
1454            final String xml = new String(payload);
1455            Log.v(TAG, "Backup payload:");
1456            for (String line : xml.split("\n")) {
1457                Log.v(TAG, line);
1458            }
1459        }
1460
1461        // Before doing anything else, uninstall all packages.
1462        for (int userId : list(USER_0, USER_P0)) {
1463            for (String pkg : list(CALLING_PACKAGE_1, CALLING_PACKAGE_2, CALLING_PACKAGE_3,
1464                    LAUNCHER_1, LAUNCHER_2, LAUNCHER_3)) {
1465                uninstallPackage(userId, pkg);
1466            }
1467        }
1468
1469        shutdownServices();
1470
1471        deleteAllSavedFiles();
1472
1473        initService();
1474        mService.applyRestore(payload, USER_0);
1475
1476        // handleUnlockUser will perform the gone package check, but it shouldn't remove
1477        // shadow information.
1478        mService.handleUnlockUser(USER_0);
1479
1480        dumpsysOnLogcat("After restore");
1481
1482        mInjectedCallingUid = prevUid;
1483    }
1484
1485    protected void prepareCrossProfileDataSet() {
1486        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1487            assertTrue(mManager.setDynamicShortcuts(list(
1488                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
1489                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
1490        });
1491        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1492            assertTrue(mManager.setDynamicShortcuts(list(
1493                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
1494                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
1495        });
1496        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
1497            assertTrue(mManager.setDynamicShortcuts(list(
1498                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
1499                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
1500        });
1501        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
1502            assertTrue(mManager.setDynamicShortcuts(list()));
1503        });
1504        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
1505            assertTrue(mManager.setDynamicShortcuts(list(
1506                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
1507                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
1508        });
1509        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
1510            assertTrue(mManager.setDynamicShortcuts(list(
1511                    makeShortcut("x1"), makeShortcut("x2"), makeShortcut("x3"),
1512                    makeShortcut("x4"), makeShortcut("x5"), makeShortcut("x6"))));
1513        });
1514
1515        runWithCaller(LAUNCHER_1, USER_0, () -> {
1516            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_0);
1517            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s1", "s2"), HANDLE_USER_0);
1518            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s1", "s2", "s3"), HANDLE_USER_0);
1519
1520            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1", "s4"), HANDLE_USER_P0);
1521        });
1522        runWithCaller(LAUNCHER_2, USER_0, () -> {
1523            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0);
1524            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s2", "s3"), HANDLE_USER_0);
1525            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s2", "s3", "s4"), HANDLE_USER_0);
1526
1527            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2", "s5"), HANDLE_USER_P0);
1528        });
1529        runWithCaller(LAUNCHER_3, USER_0, () -> {
1530            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0);
1531            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s3", "s4"), HANDLE_USER_0);
1532            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s3", "s4", "s5"), HANDLE_USER_0);
1533
1534            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3", "s6"), HANDLE_USER_P0);
1535        });
1536        runWithCaller(LAUNCHER_4, USER_0, () -> {
1537            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list(), HANDLE_USER_0);
1538            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list(), HANDLE_USER_0);
1539            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list(), HANDLE_USER_0);
1540            mLauncherApps.pinShortcuts(CALLING_PACKAGE_4, list(), HANDLE_USER_0);
1541        });
1542
1543        // Launcher on a managed profile is referring ot user 0!
1544        runWithCaller(LAUNCHER_1, USER_P0, () -> {
1545            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3", "s4"), HANDLE_USER_0);
1546            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s3", "s4", "s5"), HANDLE_USER_0);
1547            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s3", "s4", "s5", "s6"),
1548                    HANDLE_USER_0);
1549
1550            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s4", "s1"), HANDLE_USER_P0);
1551        });
1552        runWithCaller(LAUNCHER_1, USER_10, () -> {
1553            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("x4", "x5"), HANDLE_USER_10);
1554            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("x4", "x5", "x6"), HANDLE_USER_10);
1555            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("x4", "x5", "x6", "x1"),
1556                    HANDLE_USER_10);
1557        });
1558
1559        // Then remove some dynamic shortcuts.
1560        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1561            assertTrue(mManager.setDynamicShortcuts(list(
1562                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
1563        });
1564        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1565            assertTrue(mManager.setDynamicShortcuts(list(
1566                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
1567        });
1568        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
1569            assertTrue(mManager.setDynamicShortcuts(list(
1570                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
1571        });
1572        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
1573            assertTrue(mManager.setDynamicShortcuts(list()));
1574        });
1575        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
1576            assertTrue(mManager.setDynamicShortcuts(list(
1577                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
1578        });
1579        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
1580            assertTrue(mManager.setDynamicShortcuts(list(
1581                    makeShortcut("x1"), makeShortcut("x2"), makeShortcut("x3"))));
1582        });
1583    }
1584}
1585