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