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