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