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