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