• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
16 package android.content.pm.cts.shortcutmanager;
17 
18 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.*;
19 
20 import android.app.Activity;
21 import android.app.ActivityManager;
22 import android.content.ComponentName;
23 import android.content.Context;
24 import android.content.ContextWrapper;
25 import android.content.Intent;
26 import android.content.LocusId;
27 import android.content.pm.LauncherApps;
28 import android.content.pm.LauncherApps.ShortcutQuery;
29 import android.content.pm.PackageManager;
30 import android.content.pm.ShortcutInfo;
31 import android.content.pm.ShortcutManager;
32 import android.content.res.Resources;
33 import android.graphics.drawable.AdaptiveIconDrawable;
34 import android.graphics.drawable.Drawable;
35 import android.graphics.drawable.Icon;
36 import android.os.Bundle;
37 import android.os.PersistableBundle;
38 import android.os.StrictMode;
39 import android.os.StrictMode.ThreadPolicy;
40 import android.os.UserHandle;
41 import android.provider.DeviceConfig;
42 import android.test.InstrumentationTestCase;
43 import android.text.TextUtils;
44 
45 import androidx.annotation.NonNull;
46 
47 import com.android.compatibility.common.util.SystemUtil;
48 
49 import java.util.ArrayList;
50 import java.util.HashMap;
51 import java.util.List;
52 import java.util.Map;
53 import java.util.concurrent.atomic.AtomicReference;
54 
55 public abstract class ShortcutManagerCtsTestsBase extends InstrumentationTestCase {
56     protected static final String TAG = "ShortcutCTS";
57 
58     private static final boolean DUMPSYS_IN_TEARDOWN = false; // DO NOT SUBMIT WITH true
59 
60     /**
61      * Whether to enable strict mode or not.
62      *
63      * TODO Enable it after fixing b/68051728. Somehow violations would happen on the dashboard
64      * only and can't reproduce it locally.
65      */
66     private static final boolean ENABLE_STRICT_MODE = false;
67 
68     private static class SpoofingContext extends ContextWrapper {
69         private final String mPackageName;
70 
SpoofingContext(Context base, String packageName)71         public SpoofingContext(Context base, String packageName) {
72             super(base);
73             mPackageName = packageName;
74         }
75 
76         @Override
getPackageName()77         public String getPackageName() {
78             return mPackageName;
79         }
80     }
81 
82     private Context mCurrentCallerPackage;
83     private int mUserId;
84     private UserHandle mUserHandle;
85 
86     private String mOriginalLauncher;
87 
88     protected Context mPackageContext1;
89     protected Context mPackageContext2;
90     protected Context mPackageContext3;
91     protected Context mPackageContext4;
92 
93     protected Context mLauncherContext1;
94     protected Context mLauncherContext2;
95     protected Context mLauncherContext3;
96     protected Context mLauncherContext4;
97 
98     private LauncherApps mLauncherApps1;
99     private LauncherApps mLauncherApps2;
100     private LauncherApps mLauncherApps3;
101     private LauncherApps mLauncherApps4;
102 
103     private Map<Context, ShortcutManager> mManagers = new HashMap<>();
104     private Map<Context, LauncherApps> mLauncherAppses = new HashMap<>();
105 
106     private ShortcutManager mCurrentManager;
107     private LauncherApps mCurrentLauncherApps;
108 
109     private static final String[] ACTIVITIES_WITH_MANIFEST_SHORTCUTS = {
110             "Launcher_manifest_1",
111             "Launcher_manifest_2",
112             "Launcher_manifest_3",
113             "Launcher_manifest_4a",
114             "Launcher_manifest_4b",
115             "Launcher_manifest_error_1",
116             "Launcher_manifest_error_2",
117             "Launcher_manifest_error_3"
118     };
119 
120     private ComponentName mTargetActivityOverride;
121 
122     private static class ShortcutActivity extends Activity {
123     }
124 
125     @Override
setUp()126     protected void setUp() throws Exception {
127         super.setUp();
128 
129         mUserId = getTestContext().getUserId();
130         mUserHandle = android.os.Process.myUserHandle();
131 
132         resetConfig(getInstrumentation());
133         final String config = getOverrideConfig();
134         if (config != null) {
135             overrideConfig(getInstrumentation(), config);
136         }
137         mOriginalLauncher = getDefaultLauncher(getInstrumentation());
138 
139         mPackageContext1 = new SpoofingContext(getTestContext(),
140                 "android.content.pm.cts.shortcutmanager.packages.package1");
141         mPackageContext2 = new SpoofingContext(getTestContext(),
142                 "android.content.pm.cts.shortcutmanager.packages.package2");
143         mPackageContext3 = new SpoofingContext(getTestContext(),
144                 "android.content.pm.cts.shortcutmanager.packages.package3");
145         mPackageContext4 = new SpoofingContext(getTestContext(),
146                 "android.content.pm.cts.shortcutmanager.packages.package4");
147         mLauncherContext1 = new SpoofingContext(getTestContext(),
148                 "android.content.pm.cts.shortcutmanager.packages.launcher1");
149         mLauncherContext2 = new SpoofingContext(getTestContext(),
150                 "android.content.pm.cts.shortcutmanager.packages.launcher2");
151         mLauncherContext3 = new SpoofingContext(getTestContext(),
152                 "android.content.pm.cts.shortcutmanager.packages.launcher3");
153         mLauncherContext4 = new SpoofingContext(getTestContext(),
154                 "android.content.pm.cts.shortcutmanager.packages.launcher4");
155 
156         mLauncherApps1 = new LauncherApps(mLauncherContext1);
157         mLauncherApps2 = new LauncherApps(mLauncherContext2);
158         mLauncherApps3 = new LauncherApps(mLauncherContext3);
159         mLauncherApps4 = new LauncherApps(mLauncherContext4);
160 
161         clearShortcuts(getInstrumentation(), mUserId, mPackageContext1.getPackageName());
162         clearShortcuts(getInstrumentation(), mUserId, mPackageContext2.getPackageName());
163         clearShortcuts(getInstrumentation(), mUserId, mPackageContext3.getPackageName());
164         clearShortcuts(getInstrumentation(), mUserId, mPackageContext4.getPackageName());
165 
166         setCurrentCaller(mPackageContext1);
167 
168         // Make sure shortcuts are removed.
169         withCallers(getAllPublishers(), () -> {
170             // Clear all shortcuts.
171             clearShortcuts(getInstrumentation(), mUserId, getCurrentCallingPackage());
172 
173             disableActivitiesWithManifestShortucts();
174 
175             assertEquals("for " + getCurrentCallingPackage(),
176                     0, getManager().getDynamicShortcuts().size());
177             assertEquals("for " + getCurrentCallingPackage(),
178                     0, getManager().getPinnedShortcuts().size());
179             assertEquals("for " + getCurrentCallingPackage(),
180                     0, getManager().getManifestShortcuts().size());
181         });
182     }
183 
184     @Override
tearDown()185     protected void tearDown() throws Exception {
186         if (DUMPSYS_IN_TEARDOWN) {
187             dumpsysShortcut(getInstrumentation());
188         }
189 
190         withCallers(getAllPublishers(), () -> disableActivitiesWithManifestShortucts());
191 
192         resetConfig(getInstrumentation());
193 
194         if (!TextUtils.isEmpty(mOriginalLauncher)) {
195             setDefaultLauncher(getInstrumentation(), mOriginalLauncher);
196         }
197 
198         super.tearDown();
199     }
200 
getTestContext()201     protected Context getTestContext() {
202         return getInstrumentation().getContext();
203     }
204 
getUserHandle()205     protected UserHandle getUserHandle() {
206         return mUserHandle;
207     }
208 
getAllPublishers()209     protected List<Context> getAllPublishers() {
210         // 4 has a different signature, so we can't call for it.
211         return list(mPackageContext1, mPackageContext2, mPackageContext3);
212     }
213 
getAllLaunchers()214     protected List<Context> getAllLaunchers() {
215         // 4 has a different signature, so we can't call for it.
216         return list(mLauncherContext1, mLauncherContext2, mLauncherContext3);
217     }
218 
getAllCallers()219     protected List<Context> getAllCallers() {
220         return list(
221                 mPackageContext1, mPackageContext2, mPackageContext3, mPackageContext4,
222                 mLauncherContext1, mLauncherContext2, mLauncherContext3, mLauncherContext4);
223     }
224 
getActivity(String className)225     protected ComponentName getActivity(String className) {
226         return new ComponentName(getCurrentCallingPackage(),
227                 "android.content.pm.cts.shortcutmanager.packages." + className);
228 
229     }
230 
disableActivitiesWithManifestShortucts()231     protected void disableActivitiesWithManifestShortucts() {
232         if (getManager().getManifestShortcuts().size() > 0) {
233             // Disable DISABLED_ACTIVITIES
234             for (String className : ACTIVITIES_WITH_MANIFEST_SHORTCUTS) {
235                 enableManifestActivity(className, false);
236             }
237         }
238     }
239 
enableManifestActivity(String className, boolean enabled)240     protected void enableManifestActivity(String className, boolean enabled) {
241         getTestContext().getPackageManager().setComponentEnabledSetting(getActivity(className),
242                 enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
243                         : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
244                 PackageManager.DONT_KILL_APP);
245     }
246 
setTargetActivityOverride(String className)247     protected void setTargetActivityOverride(String className) {
248         mTargetActivityOverride = getActivity(className);
249     }
250 
251 
withCallers(List<Context> callers, Runnable r)252     protected void withCallers(List<Context> callers, Runnable r) {
253         for (Context c : callers) {
254             runWithCaller(c, r);
255         }
256     }
257 
getOverrideConfig()258     protected String getOverrideConfig() {
259         return null;
260     }
261 
setCurrentCaller(Context callerContext)262     protected void setCurrentCaller(Context callerContext) {
263         mCurrentCallerPackage = callerContext;
264 
265         if (!mManagers.containsKey(mCurrentCallerPackage)) {
266             mManagers.put(mCurrentCallerPackage, new ShortcutManager(mCurrentCallerPackage));
267         }
268         mCurrentManager = mManagers.get(mCurrentCallerPackage);
269 
270         if (!mLauncherAppses.containsKey(mCurrentCallerPackage)) {
271             mLauncherAppses.put(mCurrentCallerPackage, new LauncherApps(mCurrentCallerPackage));
272         }
273         mCurrentLauncherApps = mLauncherAppses.get(mCurrentCallerPackage);
274 
275         mTargetActivityOverride = null;
276     }
277 
getCurrentCallerContext()278     protected Context getCurrentCallerContext() {
279         return mCurrentCallerPackage;
280     }
281 
getCurrentCallingPackage()282     protected String getCurrentCallingPackage() {
283         return getCurrentCallerContext().getPackageName();
284     }
285 
getManager()286     protected ShortcutManager getManager() {
287         return mCurrentManager;
288     }
289 
getLauncherApps()290     protected LauncherApps getLauncherApps() {
291         return mCurrentLauncherApps;
292     }
293 
runWithStrictMode(Runnable r)294     protected void runWithStrictMode(Runnable r) {
295         final ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
296         try {
297             if (ENABLE_STRICT_MODE) {
298                 StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
299                         .detectAll()
300                         .penaltyDeath()
301                         .build());
302             }
303             r.run();
304         } finally {
305             StrictMode.setThreadPolicy(oldPolicy);
306         }
307     }
308 
runWithNoStrictMode(Runnable r)309     protected void runWithNoStrictMode(Runnable r) {
310         final ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
311         try {
312             StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
313                     .permitAll()
314                     .build());
315             r.run();
316         } finally {
317             StrictMode.setThreadPolicy(oldPolicy);
318         }
319     }
320 
runWithCaller(Context callerContext, Runnable r)321     protected void runWithCaller(Context callerContext, Runnable r) {
322         final Context prev = mCurrentCallerPackage;
323 
324         setCurrentCaller(callerContext);
325 
326         r.run();
327 
328         setCurrentCaller(prev);
329     }
330 
runWithCallerWithStrictMode(Context callerContext, Runnable r)331     protected void runWithCallerWithStrictMode(Context callerContext, Runnable r) {
332         runWithCaller(callerContext, () -> runWithStrictMode(r));
333     }
334 
runWithCallerWithNoStrictMode(Context callerContext, Runnable r)335     protected void runWithCallerWithNoStrictMode(Context callerContext, Runnable r) {
336         runWithCaller(callerContext, () -> runWithNoStrictMode(r));
337     }
338 
makeBundle(Object... keysAndValues)339     public static Bundle makeBundle(Object... keysAndValues) {
340         assertTrue((keysAndValues.length % 2) == 0);
341 
342         if (keysAndValues.length == 0) {
343             return null;
344         }
345         final Bundle ret = new Bundle();
346 
347         for (int i = keysAndValues.length - 2; i >= 0; i -= 2) {
348             final String key = keysAndValues[i].toString();
349             final Object value = keysAndValues[i + 1];
350 
351             if (value == null) {
352                 ret.putString(key, null);
353             } else if (value instanceof Integer) {
354                 ret.putInt(key, (Integer) value);
355             } else if (value instanceof String) {
356                 ret.putString(key, (String) value);
357             } else if (value instanceof Bundle) {
358                 ret.putBundle(key, (Bundle) value);
359             } else {
360                 fail("Type not supported yet: " + value.getClass().getName());
361             }
362         }
363         return ret;
364     }
365 
makePersistableBundle(Object... keysAndValues)366     public static PersistableBundle makePersistableBundle(Object... keysAndValues) {
367         assertTrue((keysAndValues.length % 2) == 0);
368 
369         if (keysAndValues.length == 0) {
370             return null;
371         }
372         final PersistableBundle ret = new PersistableBundle();
373 
374         for (int i = keysAndValues.length - 2; i >= 0; i -= 2) {
375             final String key = keysAndValues[i].toString();
376             final Object value = keysAndValues[i + 1];
377 
378             if (value == null) {
379                 ret.putString(key, null);
380             } else if (value instanceof Integer) {
381                 ret.putInt(key, (Integer) value);
382             } else if (value instanceof String) {
383                 ret.putString(key, (String) value);
384             } else if (value instanceof PersistableBundle) {
385                 ret.putPersistableBundle(key, (PersistableBundle) value);
386             } else {
387                 fail("Type not supported yet: " + value.getClass().getName());
388             }
389         }
390         return ret;
391     }
392 
393     /**
394      * Make a shortcut with an ID.
395      */
makeShortcut(String id)396     protected ShortcutInfo makeShortcut(String id) {
397         return makeShortcut(id, "Title-" + id);
398     }
399 
400     /**
401      * Make a shortcut with an ID and explicit rank.
402      */
makeShortcutWithRank(String id, int rank)403     protected ShortcutInfo makeShortcutWithRank(String id, int rank) {
404         return makeShortcut(
405                 id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
406                 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), rank, /* locusId =*/ null,
407                 /* longLived =*/ false);
408     }
409 
410     /**
411      * Make a shortcut with an ID and a locus ID.
412      */
makeShortcutWithLocusId(String id, String locusId)413     protected ShortcutInfo makeShortcutWithLocusId(String id, String locusId) {
414         return makeShortcut(
415                 id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
416                 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0,
417                 new LocusId(locusId), /* longLived =*/ false);
418     }
419 
420     /**
421      * Make a shortcut with an ID and a title.
422      */
makeShortcut(String id, String shortLabel)423     protected ShortcutInfo makeShortcut(String id, String shortLabel) {
424         return makeShortcut(
425                 id, shortLabel, /* activity =*/ null, /* icon =*/ null,
426                 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0,
427                 /* locusId =*/ null, /* longLived =*/ false);
428     }
429 
makeShortcut(String id, ComponentName activity)430     protected ShortcutInfo makeShortcut(String id, ComponentName activity) {
431         return makeShortcut(
432                 id, "Title-" + id, activity, /* icon =*/ null,
433                 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0,
434                 /* locusId =*/ null, /* longLived =*/ false);
435     }
436 
437     /**
438      * Make a shortcut with an ID and icon.
439      */
makeShortcutWithIcon(String id, Icon icon)440     protected ShortcutInfo makeShortcutWithIcon(String id, Icon icon) {
441         return makeShortcut(
442                 id, "Title-" + id, /* activity =*/ null, icon,
443                 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0,
444                 /* locusId =*/ null, /* longLived =*/ false);
445     }
446 
447     /**
448      * Make a long-lived shortcut with an ID.
449      */
makeLongLivedShortcut(String id)450     protected ShortcutInfo makeLongLivedShortcut(String id) {
451         return makeShortcut(
452                 id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
453                 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0,
454                 /* locusId =*/ null, /* longLived =*/ true);
455     }
456 
457     /**
458      * Make a shortcut excluded from launcher with an ID.
459      */
makeShortcutExcludedFromLauncher(String id)460     protected ShortcutInfo makeShortcutExcludedFromLauncher(String id) {
461         return makeShortcut(
462                 id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
463                 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0,
464                 /* locusId =*/ null, /* longLived =*/ true,
465                 /* excludedSurfaces */ ShortcutInfo.SURFACE_LAUNCHER);
466     }
467 
468     /**
469      * Make multiple shortcuts with IDs.
470      */
makeShortcuts(String... ids)471     protected List<ShortcutInfo> makeShortcuts(String... ids) {
472         final ArrayList<ShortcutInfo> ret = new ArrayList();
473         for (String id : ids) {
474             ret.add(makeShortcut(id));
475         }
476         return ret;
477     }
478 
479     /**
480      * Makes an array of shortcut IDs.
481      * For example, makeIds("sX", 4, 9) will return {"sX4", "sX5", "sX6", "sX7", "sX8", "sX9"}.
482      */
makeIds(String prefix, int first, int last)483     protected String[] makeIds(String prefix, int first, int last) {
484         final int len = last - first + 1;
485         final String[] ret = new String[len];
486         for (int i = 0; i < len; i++) {
487             ret[i] = prefix + (first + i);
488         }
489         return ret;
490     }
491 
makeShortcutBuilder(String id)492     protected ShortcutInfo.Builder makeShortcutBuilder(String id) {
493         return new ShortcutInfo.Builder(getCurrentCallerContext(), id);
494     }
495 
496     /**
497      * Make a shortcut with details.
498      */
makeShortcut(String id, String shortLabel, ComponentName activity, Icon icon, Intent intent, int rank, LocusId locusId, boolean longLived)499     protected ShortcutInfo makeShortcut(String id, String shortLabel, ComponentName activity,
500             Icon icon, Intent intent, int rank, LocusId locusId, boolean longLived) {
501         return makeShortcut(id, shortLabel, activity, icon, intent, rank, locusId, longLived, 0);
502     }
503 
504     /**
505      * Make a shortcut with details.
506      */
makeShortcut(String id, String shortLabel, ComponentName activity, Icon icon, Intent intent, int rank, LocusId locusId, boolean longLived, int excludedSurfaces)507     protected ShortcutInfo makeShortcut(String id, String shortLabel, ComponentName activity,
508             Icon icon, Intent intent, int rank, LocusId locusId, boolean longLived,
509             int excludedSurfaces) {
510         final ShortcutInfo.Builder b = makeShortcutBuilder(id)
511                 .setShortLabel(shortLabel)
512                 .setRank(rank)
513                 .setIntent(intent)
514                 .setLongLived(longLived)
515                 .setExcludedFromSurfaces(excludedSurfaces);
516         if (activity != null) {
517             b.setActivity(activity);
518         } else if (mTargetActivityOverride != null) {
519             b.setActivity(mTargetActivityOverride);
520         }
521         if (icon != null) {
522             b.setIcon(icon);
523         }
524         if (locusId != null) {
525             b.setLocusId(locusId);
526         }
527         return b.build();
528     }
529 
530     /**
531      * Make an intent.
532      */
makeIntent(String action, Class<?> clazz, Object... bundleKeysAndValues)533     protected Intent makeIntent(String action, Class<?> clazz, Object... bundleKeysAndValues) {
534         final Intent intent = new Intent(action);
535         intent.setComponent(makeComponent(clazz));
536         intent.replaceExtras(makeBundle(bundleKeysAndValues));
537         return intent;
538     }
539 
540     /**
541      * Make an component name, with the client context.
542      */
543     @NonNull
makeComponent(Class<?> clazz)544     protected ComponentName makeComponent(Class<?> clazz) {
545         return new ComponentName(getCurrentCallerContext(), clazz);
546     }
547 
getIconAsLauncher(Context launcherContext, String packageName, String shortcutId)548     protected Drawable getIconAsLauncher(Context launcherContext, String packageName,
549             String shortcutId) {
550         return getIconAsLauncher(launcherContext, packageName, shortcutId, /* withBadge=*/ true);
551     }
552 
getIconAsLauncher(Context launcherContext, String packageName, String shortcutId, boolean withBadge)553     protected Drawable getIconAsLauncher(Context launcherContext, String packageName,
554             String shortcutId, boolean withBadge) {
555         runWithNoStrictMode(() -> setDefaultLauncher(getInstrumentation(), launcherContext));
556 
557         final AtomicReference<Drawable> ret = new AtomicReference<>();
558 
559         runWithCallerWithNoStrictMode(launcherContext, () -> {
560             final ShortcutQuery q = new ShortcutQuery()
561                     .setQueryFlags(ShortcutQuery.FLAG_MATCH_DYNAMIC
562                                     | ShortcutQuery.FLAG_MATCH_MANIFEST
563                                     | ShortcutQuery.FLAG_MATCH_PINNED
564                                     | ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY)
565                     .setPackage(packageName)
566                     .setShortcutIds(list(shortcutId));
567             final List<ShortcutInfo> found = getLauncherApps().getShortcuts(q, getUserHandle());
568 
569             assertEquals("Shortcut not found", 1, found.size());
570 
571             if (withBadge) {
572                 ret.set(getLauncherApps().getShortcutBadgedIconDrawable(found.get(0), 0));
573             } else {
574                 ret.set(getLauncherApps().getShortcutIconDrawable(found.get(0), 0));
575             }
576         });
577         return ret.get();
578     }
579 
assertIconDimensions(Context launcherContext, String packageName, String shortcutId, Icon expectedIcon)580     protected void assertIconDimensions(Context launcherContext, String packageName,
581             String shortcutId, Icon expectedIcon) {
582         final Drawable actual = getIconAsLauncher(launcherContext, packageName, shortcutId);
583         if (actual == null && expectedIcon == null) {
584             return; // okay
585         }
586         final Drawable expected = expectedIcon.loadDrawable(getTestContext());
587         assertEquals(expected.getIntrinsicWidth(), actual.getIntrinsicWidth());
588         assertEquals(expected.getIntrinsicHeight(), actual.getIntrinsicHeight());
589     }
590 
assertIconDimensions(Icon expectedIcon, Drawable actual)591     protected void assertIconDimensions(Icon expectedIcon, Drawable actual) {
592         if (actual == null && expectedIcon == null) {
593             return; // okay
594         }
595         final Drawable expected = expectedIcon.loadDrawable(getTestContext());
596 
597         if (expected instanceof AdaptiveIconDrawable) {
598             assertTrue(actual instanceof AdaptiveIconDrawable);
599         }
600         assertEquals(expected.getIntrinsicWidth(), actual.getIntrinsicWidth());
601         assertEquals(expected.getIntrinsicHeight(), actual.getIntrinsicHeight());
602     }
603 
loadPackageDrawableIcon(Context packageContext, String resName)604     protected Icon loadPackageDrawableIcon(Context packageContext, String resName)
605             throws Exception {
606         final Resources res = getTestContext().getPackageManager().getResourcesForApplication(
607                 packageContext.getPackageName());
608 
609         // Note the resource package names don't have the numbers.
610         final int id = res.getIdentifier(resName, "drawable",
611                 "android.content.pm.cts.shortcutmanager.packages");
612         if (id == 0) {
613             fail("Drawable " + resName + " is not found in package "
614                     + packageContext.getPackageName());
615         }
616         return Icon.createWithResource(packageContext, id);
617     }
618 
loadCallerDrawableIcon(String resName)619     protected Icon loadCallerDrawableIcon(String resName) throws Exception {
620         return loadPackageDrawableIcon(getCurrentCallerContext(), resName);
621     }
622 
getShortcutsAsLauncher(int flags, String packageName)623     protected List<ShortcutInfo> getShortcutsAsLauncher(int flags, String packageName) {
624         return getShortcutsAsLauncher(flags, packageName, null, 0, null, null);
625     }
626 
getShortcutsAsLauncher( int flags, String packageName, String activityName, long changedSince, List<String> ids, List<LocusId> locusIds)627     protected List<ShortcutInfo> getShortcutsAsLauncher(
628             int flags, String packageName, String activityName,
629             long changedSince, List<String> ids, List<LocusId> locusIds) {
630         final ShortcutQuery q = new ShortcutQuery();
631         q.setQueryFlags(flags);
632         if (packageName != null) {
633             q.setPackage(packageName);
634             if (activityName != null) {
635                 q.setActivity(new ComponentName(packageName,
636                         "android.content.pm.cts.shortcutmanager.packages." + activityName));
637             }
638         }
639         q.setChangedSince(changedSince);
640         if (ids != null && ids.size() > 0) {
641             q.setShortcutIds(ids);
642         }
643         if (locusIds != null && locusIds.size() > 0) {
644             q.setLocusIds(locusIds);
645         }
646         return getLauncherApps().getShortcuts(q, getUserHandle());
647     }
648 
isAppSearchEnabled()649     protected boolean isAppSearchEnabled() {
650         return SystemUtil.runWithShellPermissionIdentity(() ->
651                 DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
652                         "shortcut_appsearch_integration", true))
653                 && !getTestContext().getSystemService(ActivityManager.class).isLowRamDevice();
654     }
655 }
656