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