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