BaseShortcutManagerTest.java revision 9e1f5595bd7ffe3af6ca35b3235dfca0ecd07978
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 void deleteAllSavedFiles() { 701 // Empty the data directory. 702 if (mInjectedFilePathRoot.exists()) { 703 Assert.assertTrue("failed to delete dir", 704 FileUtils.deleteContents(mInjectedFilePathRoot)); 705 } 706 mInjectedFilePathRoot.mkdirs(); 707 } 708 709 /** (Re-) init the manager and the service. */ 710 protected void initService() { 711 shutdownServices(); 712 713 LocalServices.removeServiceForTest(ShortcutServiceInternal.class); 714 715 // Instantiate targets. 716 mService = new ShortcutServiceTestable(mServiceContext, Looper.getMainLooper()); 717 mManager = new ShortcutManagerTestable(mClientContext, mService); 718 719 mInternal = LocalServices.getService(ShortcutServiceInternal.class); 720 721 mLauncherAppImpl = new LauncherAppImplTestable(mServiceContext); 722 mLauncherApps = null; 723 mLauncherAppsMap.clear(); 724 725 // Send boot sequence events. 726 mService.onBootPhase(SystemService.PHASE_LOCK_SETTINGS_READY); 727 728 // Make sure a call to onSystemLocaleChangedNoLock() before PHASE_BOOT_COMPLETED will be 729 // ignored. 730 final long origSequenceNumber = mService.getLocaleChangeSequenceNumber(); 731 mInternal.onSystemLocaleChangedNoLock(); 732 assertEquals(origSequenceNumber, mService.getLocaleChangeSequenceNumber()); 733 734 mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); 735 } 736 737 protected void shutdownServices() { 738 if (mService != null) { 739 // Flush all the unsaved data from the previous instance. 740 mService.saveDirtyInfo(); 741 742 // Make sure everything is consistent. 743 mService.verifyStates(); 744 } 745 LocalServices.removeServiceForTest(ShortcutServiceInternal.class); 746 747 mService = null; 748 mManager = null; 749 mInternal = null; 750 mLauncherAppImpl = null; 751 mLauncherApps = null; 752 mLauncherAppsMap.clear(); 753 } 754 755 protected void addPackage(String packageName, int uid, int version) { 756 addPackage(packageName, uid, version, packageName); 757 } 758 759 protected Signature[] genSignatures(String... signatures) { 760 final Signature[] sigs = new Signature[signatures.length]; 761 for (int i = 0; i < signatures.length; i++){ 762 sigs[i] = new Signature(signatures[i].getBytes()); 763 } 764 return sigs; 765 } 766 767 protected PackageInfo genPackage(String packageName, int uid, int version, String... signatures) { 768 final PackageInfo pi = new PackageInfo(); 769 pi.packageName = packageName; 770 pi.applicationInfo = new ApplicationInfo(); 771 pi.applicationInfo.uid = uid; 772 pi.applicationInfo.flags = ApplicationInfo.FLAG_INSTALLED 773 | ApplicationInfo.FLAG_ALLOW_BACKUP; 774 pi.versionCode = version; 775 pi.applicationInfo.versionCode = version; 776 pi.signatures = genSignatures(signatures); 777 778 return pi; 779 } 780 781 protected void addPackage(String packageName, int uid, int version, String... signatures) { 782 mInjectedPackages.put(packageName, genPackage(packageName, uid, version, signatures)); 783 } 784 785 protected void updatePackageInfo(String packageName, Consumer<PackageInfo> c) { 786 c.accept(mInjectedPackages.get(packageName)); 787 } 788 789 protected void updatePackageVersion(String packageName, int increment) { 790 updatePackageInfo(packageName, pi -> { 791 pi.versionCode += increment; 792 pi.applicationInfo.versionCode += increment; 793 }); 794 } 795 796 protected void updatePackageLastUpdateTime(String packageName, long increment) { 797 updatePackageInfo(packageName, pi -> { 798 pi.lastUpdateTime += increment; 799 }); 800 } 801 802 protected void uninstallPackage(int userId, String packageName) { 803 if (ENABLE_DUMP) { 804 Log.v(TAG, "Unnstall package " + packageName + " / " + userId); 805 } 806 mUninstalledPackages.add(PackageWithUser.of(userId, packageName)); 807 } 808 809 protected void installPackage(int userId, String packageName) { 810 if (ENABLE_DUMP) { 811 Log.v(TAG, "Install package " + packageName + " / " + userId); 812 } 813 mUninstalledPackages.remove(PackageWithUser.of(userId, packageName)); 814 } 815 816 PackageInfo getInjectedPackageInfo(String packageName, @UserIdInt int userId, 817 boolean getSignatures) { 818 final PackageInfo pi = mInjectedPackages.get(packageName); 819 if (pi == null) return null; 820 821 final PackageInfo ret = new PackageInfo(); 822 ret.packageName = pi.packageName; 823 ret.versionCode = pi.versionCode; 824 ret.lastUpdateTime = pi.lastUpdateTime; 825 826 ret.applicationInfo = new ApplicationInfo(pi.applicationInfo); 827 ret.applicationInfo.uid = UserHandle.getUid(userId, pi.applicationInfo.uid); 828 ret.applicationInfo.packageName = pi.packageName; 829 830 if (mUninstalledPackages.contains(PackageWithUser.of(userId, packageName))) { 831 ret.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED; 832 } 833 834 if (getSignatures) { 835 ret.signatures = pi.signatures; 836 } 837 838 return ret; 839 } 840 841 protected void addApplicationInfo(PackageInfo pi, List<ApplicationInfo> list) { 842 if (pi != null && pi.applicationInfo != null) { 843 list.add(pi.applicationInfo); 844 } 845 } 846 847 protected List<ApplicationInfo> getInstalledApplications(int userId) { 848 final ArrayList<ApplicationInfo> ret = new ArrayList<>(); 849 850 addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_1, userId, false), ret); 851 addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_2, userId, false), ret); 852 addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_3, userId, false), ret); 853 addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_4, userId, false), ret); 854 addApplicationInfo(getInjectedPackageInfo(LAUNCHER_1, userId, false), ret); 855 addApplicationInfo(getInjectedPackageInfo(LAUNCHER_2, userId, false), ret); 856 addApplicationInfo(getInjectedPackageInfo(LAUNCHER_3, userId, false), ret); 857 addApplicationInfo(getInjectedPackageInfo(LAUNCHER_4, userId, false), ret); 858 859 return ret; 860 } 861 862 private void addPackageInfo(PackageInfo pi, List<PackageInfo> list) { 863 if (pi != null) { 864 list.add(pi); 865 } 866 } 867 868 private List<PackageInfo> getInstalledPackages(int userId) { 869 final ArrayList<PackageInfo> ret = new ArrayList<>(); 870 871 addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_1, userId, false), ret); 872 addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_2, userId, false), ret); 873 addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_3, userId, false), ret); 874 addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_4, userId, false), ret); 875 addPackageInfo(getInjectedPackageInfo(LAUNCHER_1, userId, false), ret); 876 addPackageInfo(getInjectedPackageInfo(LAUNCHER_2, userId, false), ret); 877 addPackageInfo(getInjectedPackageInfo(LAUNCHER_3, userId, false), ret); 878 addPackageInfo(getInjectedPackageInfo(LAUNCHER_4, userId, false), ret); 879 880 return ret; 881 } 882 883 protected void addManifestShortcutResource(ComponentName activity, int resId) { 884 final String packageName = activity.getPackageName(); 885 LinkedHashMap<ComponentName, Integer> map = mActivityMetadataResId.get(packageName); 886 if (map == null) { 887 map = new LinkedHashMap<>(); 888 mActivityMetadataResId.put(packageName, map); 889 } 890 map.put(activity, resId); 891 } 892 893 protected PackageInfo injectGetActivitiesWithMetadata(String packageName, @UserIdInt int userId) { 894 final PackageInfo ret = getInjectedPackageInfo(packageName, userId, 895 /* getSignatures=*/ false); 896 897 final HashMap<ComponentName, Integer> activities = mActivityMetadataResId.get(packageName); 898 if (activities != null) { 899 final ArrayList<ActivityInfo> list = new ArrayList<>(); 900 901 for (ComponentName cn : activities.keySet()) { 902 ActivityInfo ai = new ActivityInfo(); 903 ai.packageName = cn.getPackageName(); 904 ai.name = cn.getClassName(); 905 ai.metaData = new Bundle(); 906 ai.metaData.putInt(ShortcutParser.METADATA_KEY, activities.get(cn)); 907 list.add(ai); 908 } 909 ret.activities = list.toArray(new ActivityInfo[list.size()]); 910 } 911 return ret; 912 } 913 914 protected XmlResourceParser injectXmlMetaData(ActivityInfo activityInfo, String key) { 915 if (!ShortcutParser.METADATA_KEY.equals(key) || activityInfo.metaData == null) { 916 return null; 917 } 918 final int resId = activityInfo.metaData.getInt(key); 919 return getTestContext().getResources().getXml(resId); 920 } 921 922 /** Replace the current calling package */ 923 protected void setCaller(String packageName, int userId) { 924 mInjectedClientPackage = packageName; 925 mInjectedCallingUid = 926 Preconditions.checkNotNull(getInjectedPackageInfo(packageName, userId, false), 927 "Unknown package").applicationInfo.uid; 928 929 // Set up LauncherApps for this caller. 930 final Pair<Integer, String> key = Pair.create(userId, packageName); 931 if (!mLauncherAppsMap.containsKey(key)) { 932 mLauncherAppsMap.put(key, new LauncherAppsTestable(mClientContext, mLauncherAppImpl)); 933 } 934 mLauncherApps = mLauncherAppsMap.get(key); 935 } 936 937 protected void setCaller(String packageName) { 938 setCaller(packageName, UserHandle.USER_SYSTEM); 939 } 940 941 protected String getCallingPackage() { 942 return mInjectedClientPackage; 943 } 944 945 protected void setDefaultLauncherChecker(BiPredicate<String, Integer> p) { 946 mDefaultLauncherChecker = p; 947 } 948 949 protected void runWithCaller(String packageName, int userId, Runnable r) { 950 final String previousPackage = mInjectedClientPackage; 951 final int previousUserId = UserHandle.getUserId(mInjectedCallingUid); 952 953 setCaller(packageName, userId); 954 955 r.run(); 956 957 setCaller(previousPackage, previousUserId); 958 } 959 960 protected void runWithSystemUid(Runnable r) { 961 final int origUid = mInjectedCallingUid; 962 mInjectedCallingUid = Process.SYSTEM_UID; 963 r.run(); 964 mInjectedCallingUid = origUid; 965 } 966 967 protected void lookupAndFillInResourceNames(ShortcutInfo si) { 968 runWithSystemUid(() -> si.lookupAndFillInResourceNames( 969 mService.injectGetResourcesForApplicationAsUser(si.getPackage(), si.getUserId()))); 970 } 971 972 protected int getCallingUserId() { 973 return UserHandle.getUserId(mInjectedCallingUid); 974 } 975 976 protected UserHandle getCallingUser() { 977 return UserHandle.of(getCallingUserId()); 978 } 979 980 /** For debugging */ 981 protected void dumpsysOnLogcat() { 982 dumpsysOnLogcat(""); 983 } 984 985 protected void dumpsysOnLogcat(String message) { 986 dumpsysOnLogcat(message, false); 987 } 988 989 protected void dumpsysOnLogcat(String message, boolean force) { 990 if (force || !ENABLE_DUMP) return; 991 992 final ByteArrayOutputStream out = new ByteArrayOutputStream(); 993 final PrintWriter pw = new PrintWriter(out); 994 mService.dumpInner(pw, null); 995 pw.close(); 996 997 Log.v(TAG, "Dumping ShortcutService: " + message); 998 for (String line : out.toString().split("\n")) { 999 Log.v(TAG, line); 1000 } 1001 } 1002 1003 /** 1004 * For debugging, dump arbitrary file on logcat. 1005 */ 1006 protected void dumpFileOnLogcat(String path) { 1007 dumpFileOnLogcat(path, ""); 1008 } 1009 1010 protected void dumpFileOnLogcat(String path, String message) { 1011 if (!ENABLE_DUMP) return; 1012 1013 Log.v(TAG, "Dumping file: " + path + " " + message); 1014 final StringBuilder sb = new StringBuilder(); 1015 try (BufferedReader br = new BufferedReader(new FileReader(path))) { 1016 String line; 1017 while ((line = br.readLine()) != null) { 1018 Log.v(TAG, line); 1019 } 1020 } catch (Exception e) { 1021 Log.e(TAG, "Couldn't read file", e); 1022 fail("Exception " + e); 1023 } 1024 } 1025 1026 /** 1027 * For debugging, dump the main state file on logcat. 1028 */ 1029 protected void dumpBaseStateFile() { 1030 mService.saveDirtyInfo(); 1031 dumpFileOnLogcat(mInjectedFilePathRoot.getAbsolutePath() 1032 + "/system/" + ShortcutService.FILENAME_BASE_STATE); 1033 } 1034 1035 /** 1036 * For debugging, dump per-user state file on logcat. 1037 */ 1038 protected void dumpUserFile(int userId) { 1039 dumpUserFile(userId, ""); 1040 } 1041 1042 protected void dumpUserFile(int userId, String message) { 1043 mService.saveDirtyInfo(); 1044 dumpFileOnLogcat(mInjectedFilePathRoot.getAbsolutePath() 1045 + "/user-" + userId 1046 + "/" + ShortcutService.FILENAME_USER_PACKAGES, message); 1047 } 1048 1049 protected void waitOnMainThread() throws Throwable { 1050 runTestOnUiThread(() -> {}); 1051 } 1052 1053 /** 1054 * Make a shortcut with an ID. 1055 */ 1056 protected ShortcutInfo makeShortcut(String id) { 1057 return makeShortcut( 1058 id, "Title-" + id, /* activity =*/ null, /* icon =*/ null, 1059 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); 1060 } 1061 1062 protected ShortcutInfo makeShortcutWithTitle(String id, String title) { 1063 return makeShortcut( 1064 id, title, /* activity =*/ null, /* icon =*/ null, 1065 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); 1066 } 1067 1068 /** 1069 * Make a shortcut with an ID and timestamp. 1070 */ 1071 protected ShortcutInfo makeShortcutWithTimestamp(String id, long timestamp) { 1072 final ShortcutInfo s = makeShortcut( 1073 id, "Title-" + id, /* activity =*/ null, /* icon =*/ null, 1074 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); 1075 s.setTimestamp(timestamp); 1076 return s; 1077 } 1078 1079 /** 1080 * Make a shortcut with an ID, a timestamp and an activity component 1081 */ 1082 protected ShortcutInfo makeShortcutWithTimestampWithActivity(String id, long timestamp, 1083 ComponentName activity) { 1084 final ShortcutInfo s = makeShortcut( 1085 id, "Title-" + id, activity, /* icon =*/ null, 1086 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); 1087 s.setTimestamp(timestamp); 1088 return s; 1089 } 1090 1091 /** 1092 * Make a shortcut with an ID and icon. 1093 */ 1094 protected ShortcutInfo makeShortcutWithIcon(String id, Icon icon) { 1095 return makeShortcut( 1096 id, "Title-" + id, /* activity =*/ null, icon, 1097 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); 1098 } 1099 1100 protected ShortcutInfo makePackageShortcut(String packageName, String id) { 1101 String origCaller = getCallingPackage(); 1102 1103 setCaller(packageName); 1104 ShortcutInfo s = makeShortcut( 1105 id, "Title-" + id, /* activity =*/ null, /* icon =*/ null, 1106 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); 1107 setCaller(origCaller); // restore the caller 1108 1109 return s; 1110 } 1111 1112 /** 1113 * Make multiple shortcuts with IDs. 1114 */ 1115 protected List<ShortcutInfo> makeShortcuts(String... ids) { 1116 final ArrayList<ShortcutInfo> ret = new ArrayList(); 1117 for (String id : ids) { 1118 ret.add(makeShortcut(id)); 1119 } 1120 return ret; 1121 } 1122 1123 protected ShortcutInfo.Builder makeShortcutBuilder() { 1124 return new ShortcutInfo.Builder(mClientContext); 1125 } 1126 1127 protected ShortcutInfo makeShortcutWithActivity(String id, ComponentName activity) { 1128 return makeShortcut( 1129 id, "Title-" + id, activity, /* icon =*/ null, 1130 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); 1131 } 1132 1133 protected ShortcutInfo makeShortcutWithActivityAndTitle(String id, ComponentName activity, 1134 String title) { 1135 return makeShortcut( 1136 id, title, activity, /* icon =*/ null, 1137 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); 1138 } 1139 1140 protected ShortcutInfo makeShortcutWithActivityAndRank(String id, ComponentName activity, 1141 int rank) { 1142 return makeShortcut( 1143 id, "Title-" + id, activity, /* icon =*/ null, 1144 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), rank); 1145 } 1146 1147 /** 1148 * Make a shortcut with details. 1149 */ 1150 protected ShortcutInfo makeShortcut(String id, String title, ComponentName activity, 1151 Icon icon, Intent intent, int rank) { 1152 final ShortcutInfo.Builder b = new ShortcutInfo.Builder(mClientContext) 1153 .setId(id) 1154 .setActivity(new ComponentName(mClientContext.getPackageName(), "dummy")) 1155 .setTitle(title) 1156 .setRank(rank) 1157 .setIntent(intent); 1158 if (icon != null) { 1159 b.setIcon(icon); 1160 } 1161 if (activity != null) { 1162 b.setActivity(activity); 1163 } 1164 final ShortcutInfo s = b.build(); 1165 1166 s.setTimestamp(mInjectedCurrentTimeMillis); // HACK 1167 1168 return s; 1169 } 1170 1171 /** 1172 * Make an intent. 1173 */ 1174 protected Intent makeIntent(String action, Class<?> clazz, Object... bundleKeysAndValues) { 1175 final Intent intent = new Intent(action); 1176 intent.setComponent(makeComponent(clazz)); 1177 intent.replaceExtras(makeBundle(bundleKeysAndValues)); 1178 return intent; 1179 } 1180 1181 /** 1182 * Make an component name, with the client context. 1183 */ 1184 @NonNull 1185 protected ComponentName makeComponent(Class<?> clazz) { 1186 return new ComponentName(mClientContext, clazz); 1187 } 1188 1189 @NonNull 1190 protected ShortcutInfo findById(List<ShortcutInfo> list, String id) { 1191 for (ShortcutInfo s : list) { 1192 if (s.getId().equals(id)) { 1193 return s; 1194 } 1195 } 1196 fail("Shortcut with id " + id + " not found"); 1197 return null; 1198 } 1199 1200 protected void assertSystem() { 1201 assertEquals("Caller must be system", Process.SYSTEM_UID, mInjectedCallingUid); 1202 } 1203 1204 protected void assertResetTimes(long expectedLastResetTime, long expectedNextResetTime) { 1205 assertEquals(expectedLastResetTime, mService.getLastResetTimeLocked()); 1206 assertEquals(expectedNextResetTime, mService.getNextResetTimeLocked()); 1207 } 1208 1209 public static List<ShortcutInfo> assertAllNotHaveIcon( 1210 List<ShortcutInfo> actualShortcuts) { 1211 for (ShortcutInfo s : actualShortcuts) { 1212 assertNull("ID " + s.getId(), s.getIcon()); 1213 } 1214 return actualShortcuts; 1215 } 1216 1217 @NonNull 1218 protected List<ShortcutInfo> assertAllHaveFlags(@NonNull List<ShortcutInfo> actualShortcuts, 1219 int shortcutFlags) { 1220 for (ShortcutInfo s : actualShortcuts) { 1221 assertTrue("ID " + s.getId() + " doesn't have flags " + shortcutFlags, 1222 s.hasFlags(shortcutFlags)); 1223 } 1224 return actualShortcuts; 1225 } 1226 1227 protected ShortcutInfo getPackageShortcut(String packageName, String shortcutId, int userId) { 1228 return mService.getPackageShortcutForTest(packageName, shortcutId, userId); 1229 } 1230 1231 protected void assertShortcutExists(String packageName, String shortcutId, int userId) { 1232 assertTrue(getPackageShortcut(packageName, shortcutId, userId) != null); 1233 } 1234 1235 protected void assertShortcutNotExists(String packageName, String shortcutId, int userId) { 1236 assertTrue(getPackageShortcut(packageName, shortcutId, userId) == null); 1237 } 1238 1239 protected Intent launchShortcutAndGetIntent( 1240 @NonNull String packageName, @NonNull String shortcutId, int userId) { 1241 reset(mServiceContext); 1242 assertTrue(mLauncherApps.startShortcut(packageName, shortcutId, null, null, 1243 UserHandle.of(userId))); 1244 1245 final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); 1246 verify(mServiceContext).startActivityAsUser( 1247 intentCaptor.capture(), 1248 any(Bundle.class), 1249 eq(UserHandle.of(userId))); 1250 return intentCaptor.getValue(); 1251 } 1252 1253 protected Intent launchShortcutAndGetIntent_withShortcutInfo( 1254 @NonNull String packageName, @NonNull String shortcutId, int userId) { 1255 reset(mServiceContext); 1256 1257 assertTrue(mLauncherApps.startShortcut( 1258 getShortcutInfoAsLauncher(packageName, shortcutId, userId), null, null)); 1259 1260 final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); 1261 verify(mServiceContext).startActivityAsUser( 1262 intentCaptor.capture(), 1263 any(Bundle.class), 1264 eq(UserHandle.of(userId))); 1265 return intentCaptor.getValue(); 1266 } 1267 1268 protected void assertShortcutLaunchable(@NonNull String packageName, @NonNull String shortcutId, 1269 int userId) { 1270 assertNotNull(launchShortcutAndGetIntent(packageName, shortcutId, userId)); 1271 assertNotNull(launchShortcutAndGetIntent_withShortcutInfo(packageName, shortcutId, userId)); 1272 } 1273 1274 protected void assertShortcutNotLaunchable(@NonNull String packageName, 1275 @NonNull String shortcutId, int userId) { 1276 try { 1277 final boolean ok = mLauncherApps.startShortcut(packageName, shortcutId, null, null, 1278 UserHandle.of(userId)); 1279 if (!ok) { 1280 return; // didn't launch, okay. 1281 } 1282 fail(); 1283 } catch (SecurityException expected) { 1284 // security exception is okay too. 1285 } 1286 } 1287 1288 protected void assertBitmapDirectories(int userId, String... expectedDirectories) { 1289 final Set<String> expected = hashSet(set(expectedDirectories)); 1290 1291 final Set<String> actual = new HashSet<>(); 1292 1293 final File[] files = mService.getUserBitmapFilePath(userId).listFiles(); 1294 if (files != null) { 1295 for (File child : files) { 1296 if (child.isDirectory()) { 1297 actual.add(child.getName()); 1298 } 1299 } 1300 } 1301 1302 assertEquals(expected, actual); 1303 } 1304 1305 protected void assertBitmapFiles(int userId, String packageName, String... expectedFiles) { 1306 final Set<String> expected = hashSet(set(expectedFiles)); 1307 1308 final Set<String> actual = new HashSet<>(); 1309 1310 final File[] files = new File(mService.getUserBitmapFilePath(userId), packageName) 1311 .listFiles(); 1312 if (files != null) { 1313 for (File child : files) { 1314 if (child.isFile()) { 1315 actual.add(child.getName()); 1316 } 1317 } 1318 } 1319 1320 assertEquals(expected, actual); 1321 } 1322 1323 protected String getBitmapFilename(int userId, String packageName, String shortcutId) { 1324 final ShortcutInfo si = mService.getPackageShortcutForTest(packageName, shortcutId, userId); 1325 if (si == null) { 1326 return null; 1327 } 1328 return new File(si.getBitmapPath()).getName(); 1329 } 1330 1331 protected List<ShortcutInfo> getCallerShortcuts() { 1332 final ShortcutPackage p = mService.getPackageShortcutForTest( 1333 getCallingPackage(), getCallingUserId()); 1334 return p == null ? null : p.getAllShortcutsForTest(); 1335 } 1336 1337 protected ShortcutInfo getCallerShortcut(String shortcutId) { 1338 return getPackageShortcut(getCallingPackage(), shortcutId, getCallingUserId()); 1339 } 1340 1341 protected List<ShortcutInfo> getLauncherShortcuts(String launcher, int userId, int queryFlags) { 1342 final List<ShortcutInfo>[] ret = new List[1]; 1343 runWithCaller(launcher, userId, () -> { 1344 final ShortcutQuery q = new ShortcutQuery(); 1345 q.setQueryFlags(queryFlags); 1346 ret[0] = mLauncherApps.getShortcuts(q, UserHandle.of(userId)); 1347 }); 1348 return ret[0]; 1349 } 1350 1351 protected List<ShortcutInfo> getLauncherPinnedShortcuts(String launcher, int userId) { 1352 return getLauncherShortcuts(launcher, userId, ShortcutQuery.FLAG_GET_PINNED); 1353 } 1354 1355 protected ShortcutInfo getShortcutInfoAsLauncher(String packageName, String shortcutId, 1356 int userId) { 1357 final List<ShortcutInfo> infoList = 1358 mLauncherApps.getShortcutInfo(packageName, list(shortcutId), 1359 UserHandle.of(userId)); 1360 assertEquals("No shortcutInfo found (or too many of them)", 1, infoList.size()); 1361 return infoList.get(0); 1362 } 1363 1364 protected Intent genPackageAddIntent(String pakcageName, int userId) { 1365 Intent i = new Intent(Intent.ACTION_PACKAGE_ADDED); 1366 i.setData(Uri.parse("package:" + pakcageName)); 1367 i.putExtra(Intent.EXTRA_USER_HANDLE, userId); 1368 return i; 1369 } 1370 1371 protected Intent genPackageDeleteIntent(String pakcageName, int userId) { 1372 Intent i = new Intent(Intent.ACTION_PACKAGE_REMOVED); 1373 i.setData(Uri.parse("package:" + pakcageName)); 1374 i.putExtra(Intent.EXTRA_USER_HANDLE, userId); 1375 return i; 1376 } 1377 1378 protected Intent genPackageUpdateIntent(String pakcageName, int userId) { 1379 Intent i = new Intent(Intent.ACTION_PACKAGE_ADDED); 1380 i.setData(Uri.parse("package:" + pakcageName)); 1381 i.putExtra(Intent.EXTRA_USER_HANDLE, userId); 1382 i.putExtra(Intent.EXTRA_REPLACING, true); 1383 return i; 1384 } 1385 1386 protected Intent genPackageDataClear(String packageName, int userId) { 1387 Intent i = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED); 1388 i.setData(Uri.parse("package:" + packageName)); 1389 i.putExtra(Intent.EXTRA_USER_HANDLE, userId); 1390 return i; 1391 } 1392 1393 protected void assertExistsAndShadow(ShortcutPackageItem spi) { 1394 assertNotNull(spi); 1395 assertTrue(spi.getPackageInfo().isShadow()); 1396 } 1397 1398 protected File makeFile(File baseDirectory, String... paths) { 1399 File ret = baseDirectory; 1400 1401 for (String path : paths) { 1402 ret = new File(ret, path); 1403 } 1404 1405 return ret; 1406 } 1407 1408 protected boolean bitmapDirectoryExists(String packageName, int userId) { 1409 final File path = new File(mService.getUserBitmapFilePath(userId), packageName); 1410 return path.isDirectory(); 1411 } 1412 protected static ShortcutQuery buildQuery(long changedSince, 1413 String packageName, ComponentName componentName, 1414 /* @ShortcutQuery.QueryFlags */ int flags) { 1415 return buildQuery(changedSince, packageName, null, componentName, flags); 1416 } 1417 1418 protected static ShortcutQuery buildQuery(long changedSince, 1419 String packageName, List<String> shortcutIds, ComponentName componentName, 1420 /* @ShortcutQuery.QueryFlags */ int flags) { 1421 final ShortcutQuery q = new ShortcutQuery(); 1422 q.setChangedSince(changedSince); 1423 q.setPackage(packageName); 1424 q.setShortcutIds(shortcutIds); 1425 q.setActivity(componentName); 1426 q.setQueryFlags(flags); 1427 return q; 1428 } 1429 1430 protected static ShortcutQuery buildAllQuery(String packageName) { 1431 final ShortcutQuery q = new ShortcutQuery(); 1432 q.setPackage(packageName); 1433 q.setQueryFlags(ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_PINNED); 1434 return q; 1435 } 1436 1437 protected static ShortcutQuery buildPinnedQuery(String packageName) { 1438 final ShortcutQuery q = new ShortcutQuery(); 1439 q.setPackage(packageName); 1440 q.setQueryFlags(ShortcutQuery.FLAG_GET_PINNED); 1441 return q; 1442 } 1443 1444 protected void backupAndRestore() { 1445 int prevUid = mInjectedCallingUid; 1446 1447 mInjectedCallingUid = Process.SYSTEM_UID; // Only system can call it. 1448 1449 dumpsysOnLogcat("Before backup"); 1450 1451 final byte[] payload = mService.getBackupPayload(USER_0); 1452 if (ENABLE_DUMP) { 1453 final String xml = new String(payload); 1454 Log.v(TAG, "Backup payload:"); 1455 for (String line : xml.split("\n")) { 1456 Log.v(TAG, line); 1457 } 1458 } 1459 1460 // Before doing anything else, uninstall all packages. 1461 for (int userId : list(USER_0, USER_P0)) { 1462 for (String pkg : list(CALLING_PACKAGE_1, CALLING_PACKAGE_2, CALLING_PACKAGE_3, 1463 LAUNCHER_1, LAUNCHER_2, LAUNCHER_3)) { 1464 uninstallPackage(userId, pkg); 1465 } 1466 } 1467 1468 shutdownServices(); 1469 1470 deleteAllSavedFiles(); 1471 1472 initService(); 1473 mService.applyRestore(payload, USER_0); 1474 1475 // handleUnlockUser will perform the gone package check, but it shouldn't remove 1476 // shadow information. 1477 mService.handleUnlockUser(USER_0); 1478 1479 dumpsysOnLogcat("After restore"); 1480 1481 mInjectedCallingUid = prevUid; 1482 } 1483 1484 protected void prepareCrossProfileDataSet() { 1485 runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { 1486 assertTrue(mManager.setDynamicShortcuts(list( 1487 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"), 1488 makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6")))); 1489 }); 1490 runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { 1491 assertTrue(mManager.setDynamicShortcuts(list( 1492 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"), 1493 makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6")))); 1494 }); 1495 runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { 1496 assertTrue(mManager.setDynamicShortcuts(list( 1497 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"), 1498 makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6")))); 1499 }); 1500 runWithCaller(CALLING_PACKAGE_4, USER_0, () -> { 1501 assertTrue(mManager.setDynamicShortcuts(list())); 1502 }); 1503 runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { 1504 assertTrue(mManager.setDynamicShortcuts(list( 1505 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"), 1506 makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6")))); 1507 }); 1508 runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { 1509 assertTrue(mManager.setDynamicShortcuts(list( 1510 makeShortcut("x1"), makeShortcut("x2"), makeShortcut("x3"), 1511 makeShortcut("x4"), makeShortcut("x5"), makeShortcut("x6")))); 1512 }); 1513 1514 runWithCaller(LAUNCHER_1, USER_0, () -> { 1515 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_0); 1516 mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s1", "s2"), HANDLE_USER_0); 1517 mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s1", "s2", "s3"), HANDLE_USER_0); 1518 1519 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1", "s4"), HANDLE_USER_P0); 1520 }); 1521 runWithCaller(LAUNCHER_2, USER_0, () -> { 1522 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0); 1523 mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s2", "s3"), HANDLE_USER_0); 1524 mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s2", "s3", "s4"), HANDLE_USER_0); 1525 1526 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2", "s5"), HANDLE_USER_P0); 1527 }); 1528 runWithCaller(LAUNCHER_3, USER_0, () -> { 1529 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0); 1530 mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s3", "s4"), HANDLE_USER_0); 1531 mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s3", "s4", "s5"), HANDLE_USER_0); 1532 1533 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3", "s6"), HANDLE_USER_P0); 1534 }); 1535 runWithCaller(LAUNCHER_4, USER_0, () -> { 1536 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list(), HANDLE_USER_0); 1537 mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list(), HANDLE_USER_0); 1538 mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list(), HANDLE_USER_0); 1539 mLauncherApps.pinShortcuts(CALLING_PACKAGE_4, list(), HANDLE_USER_0); 1540 }); 1541 1542 // Launcher on a managed profile is referring ot user 0! 1543 runWithCaller(LAUNCHER_1, USER_P0, () -> { 1544 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3", "s4"), HANDLE_USER_0); 1545 mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s3", "s4", "s5"), HANDLE_USER_0); 1546 mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s3", "s4", "s5", "s6"), 1547 HANDLE_USER_0); 1548 1549 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s4", "s1"), HANDLE_USER_P0); 1550 }); 1551 runWithCaller(LAUNCHER_1, USER_10, () -> { 1552 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("x4", "x5"), HANDLE_USER_10); 1553 mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("x4", "x5", "x6"), HANDLE_USER_10); 1554 mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("x4", "x5", "x6", "x1"), 1555 HANDLE_USER_10); 1556 }); 1557 1558 // Then remove some dynamic shortcuts. 1559 runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { 1560 assertTrue(mManager.setDynamicShortcuts(list( 1561 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); 1562 }); 1563 runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { 1564 assertTrue(mManager.setDynamicShortcuts(list( 1565 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); 1566 }); 1567 runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { 1568 assertTrue(mManager.setDynamicShortcuts(list( 1569 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); 1570 }); 1571 runWithCaller(CALLING_PACKAGE_4, USER_0, () -> { 1572 assertTrue(mManager.setDynamicShortcuts(list())); 1573 }); 1574 runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { 1575 assertTrue(mManager.setDynamicShortcuts(list( 1576 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); 1577 }); 1578 runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { 1579 assertTrue(mManager.setDynamicShortcuts(list( 1580 makeShortcut("x1"), makeShortcut("x2"), makeShortcut("x3")))); 1581 }); 1582 } 1583} 1584