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