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