BaseShortcutManagerTest.java revision efbbe7ea9db8adab6bff407db1d7fc54bbaf31ee
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 409 /** ShortcutManager with injection override methods. */ 410 protected class ShortcutManagerTestable extends ShortcutManager { 411 public ShortcutManagerTestable(Context context, ShortcutServiceTestable service) { 412 super(context, service); 413 } 414 415 @Override 416 protected int injectMyUserId() { 417 return UserHandle.getUserId(mInjectedCallingUid); 418 } 419 420 @Override 421 public boolean setDynamicShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) { 422 // Note to simulate the binder RPC, we need to clone the incoming arguments. 423 // Otherwise bad things will happen because they're mutable. 424 return super.setDynamicShortcuts(cloneShortcutList(shortcutInfoList)); 425 } 426 427 @Override 428 public boolean addDynamicShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) { 429 // Note to simulate the binder RPC, we need to clone the incoming arguments. 430 return super.addDynamicShortcuts(cloneShortcutList(shortcutInfoList)); 431 } 432 433 @Override 434 public boolean updateShortcuts(List<ShortcutInfo> shortcutInfoList) { 435 // Note to simulate the binder RPC, we need to clone the incoming arguments. 436 return super.updateShortcuts(cloneShortcutList(shortcutInfoList)); 437 } 438 } 439 440 protected class LauncherAppImplTestable extends LauncherAppsImpl { 441 final ServiceContext mContext; 442 443 public LauncherAppImplTestable(ServiceContext context) { 444 super(context); 445 mContext = context; 446 } 447 448 @Override 449 public void verifyCallingPackage(String callingPackage) { 450 // SKIP 451 } 452 453 @Override 454 void postToPackageMonitorHandler(Runnable r) { 455 runOnHandler(r); 456 } 457 458 @Override 459 int injectBinderCallingUid() { 460 return mInjectedCallingUid; 461 } 462 463 @Override 464 long injectClearCallingIdentity() { 465 final int prevCallingUid = mInjectedCallingUid; 466 mInjectedCallingUid = Process.SYSTEM_UID; 467 return prevCallingUid; 468 } 469 470 @Override 471 void injectRestoreCallingIdentity(long token) { 472 mInjectedCallingUid = (int) token; 473 } 474 } 475 476 protected class LauncherAppsTestable extends LauncherApps { 477 public LauncherAppsTestable(Context context, ILauncherApps service) { 478 super(context, service); 479 } 480 } 481 482 public static class ShortcutActivity extends Activity { 483 } 484 485 public static class ShortcutActivity2 extends Activity { 486 } 487 488 public static class ShortcutActivity3 extends Activity { 489 } 490 491 protected Looper mLooper; 492 protected Handler mHandler; 493 494 protected ServiceContext mServiceContext; 495 protected ClientContext mClientContext; 496 497 protected ShortcutServiceTestable mService; 498 protected ShortcutManagerTestable mManager; 499 protected ShortcutServiceInternal mInternal; 500 501 protected LauncherAppImplTestable mLauncherAppImpl; 502 503 // LauncherApps has per-instace state, so we need a differnt instance for each launcher. 504 protected final Map<Pair<Integer, String>, LauncherAppsTestable> 505 mLauncherAppsMap = new HashMap<>(); 506 protected LauncherAppsTestable mLauncherApps; // Current one 507 508 protected File mInjectedFilePathRoot; 509 510 protected boolean mSafeMode; 511 512 protected long mInjectedCurrentTimeMillis; 513 514 protected boolean mInjectedIsLowRamDevice; 515 516 protected Locale mInjectedLocale = Locale.ENGLISH; 517 518 protected int mInjectedCallingUid; 519 protected String mInjectedClientPackage; 520 521 protected Map<String, PackageInfo> mInjectedPackages; 522 523 protected Set<PackageWithUser> mUninstalledPackages; 524 525 protected PackageManager mMockPackageManager; 526 protected PackageManagerInternal mMockPackageManagerInternal; 527 protected UserManager mMockUserManager; 528 protected UsageStatsManagerInternal mMockUsageStatsManagerInternal; 529 protected ActivityManagerInternal mMockActivityManagerInternal; 530 531 protected static final String CALLING_PACKAGE_1 = "com.android.test.1"; 532 protected static final int CALLING_UID_1 = 10001; 533 534 protected static final String CALLING_PACKAGE_2 = "com.android.test.2"; 535 protected static final int CALLING_UID_2 = 10002; 536 537 protected static final String CALLING_PACKAGE_3 = "com.android.test.3"; 538 protected static final int CALLING_UID_3 = 10003; 539 540 protected static final String CALLING_PACKAGE_4 = "com.android.test.4"; 541 protected static final int CALLING_UID_4 = 10004; 542 543 protected static final String LAUNCHER_1 = "com.android.launcher.1"; 544 protected static final int LAUNCHER_UID_1 = 10011; 545 546 protected static final String LAUNCHER_2 = "com.android.launcher.2"; 547 protected static final int LAUNCHER_UID_2 = 10012; 548 549 protected static final String LAUNCHER_3 = "com.android.launcher.3"; 550 protected static final int LAUNCHER_UID_3 = 10013; 551 552 protected static final String LAUNCHER_4 = "com.android.launcher.4"; 553 protected static final int LAUNCHER_UID_4 = 10014; 554 555 protected static final int USER_0 = UserHandle.USER_SYSTEM; 556 protected static final int USER_10 = 10; 557 protected static final int USER_11 = 11; 558 protected static final int USER_P0 = 20; // profile of user 0 559 560 protected static final UserHandle HANDLE_USER_0 = UserHandle.of(USER_0); 561 protected static final UserHandle HANDLE_USER_10 = UserHandle.of(USER_10); 562 protected static final UserHandle HANDLE_USER_11 = UserHandle.of(USER_11); 563 protected static final UserHandle HANDLE_USER_P0 = UserHandle.of(USER_P0); 564 565 protected static final UserInfo USER_INFO_0 = withProfileGroupId( 566 new UserInfo(USER_0, "user0", 567 UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY | UserInfo.FLAG_INITIALIZED), 10); 568 569 protected static final UserInfo USER_INFO_10 = 570 new UserInfo(USER_10, "user10", UserInfo.FLAG_INITIALIZED); 571 572 protected static final UserInfo USER_INFO_11 = 573 new UserInfo(USER_11, "user11", UserInfo.FLAG_INITIALIZED); 574 575 protected static final UserInfo USER_INFO_P0 = withProfileGroupId( 576 new UserInfo(USER_P0, "userP0", 577 UserInfo.FLAG_MANAGED_PROFILE), 10); 578 579 protected BiPredicate<String, Integer> mDefaultLauncherChecker = 580 (callingPackage, userId) -> 581 LAUNCHER_1.equals(callingPackage) || LAUNCHER_2.equals(callingPackage) 582 || LAUNCHER_3.equals(callingPackage) || LAUNCHER_4.equals(callingPackage); 583 584 protected BiPredicate<ComponentName, Integer> mMainActivityChecker = 585 (activity, userId) -> true; 586 587 protected BiFunction<String, Integer, ComponentName> mMainActivityFetcher = 588 (packageName, userId) -> new ComponentName(packageName, MAIN_ACTIVITY_CLASS); 589 590 protected BiPredicate<ComponentName, Integer> mEnabledActivityChecker 591 = (activity, userId) -> true; // all activities are enabled. 592 593 protected static final long START_TIME = 1440000000101L; 594 595 protected static final long INTERVAL = 10000; 596 597 protected static final int MAX_SHORTCUTS = 10; 598 599 protected static final int MAX_UPDATES_PER_INTERVAL = 3; 600 601 protected static final int MAX_ICON_DIMENSION = 128; 602 603 protected static final int MAX_ICON_DIMENSION_LOWRAM = 32; 604 605 protected static final ShortcutQuery QUERY_ALL = new ShortcutQuery(); 606 607 protected final ArrayList<String> mCallerPermissions = new ArrayList<>(); 608 609 protected final HashMap<String, LinkedHashMap<ComponentName, Integer>> mActivityMetadataResId 610 = new HashMap<>(); 611 612 protected final Map<Integer, UserInfo> mUserInfos = new HashMap<>(); 613 protected final Map<Integer, Boolean> mRunningUsers = new HashMap<>(); 614 protected final Map<Integer, Boolean> mUnlockedUsers = new HashMap<>(); 615 616 static { 617 QUERY_ALL.setQueryFlags( 618 ShortcutQuery.FLAG_GET_ALL_KINDS); 619 } 620 621 @Override 622 protected void setUp() throws Exception { 623 super.setUp(); 624 625 mLooper = Looper.getMainLooper(); 626 mHandler = new Handler(mLooper); 627 628 mServiceContext = spy(new ServiceContext()); 629 mClientContext = new ClientContext(); 630 631 mMockPackageManager = mock(PackageManager.class); 632 mMockPackageManagerInternal = mock(PackageManagerInternal.class); 633 mMockUserManager = mock(UserManager.class); 634 mMockUsageStatsManagerInternal = mock(UsageStatsManagerInternal.class); 635 mMockActivityManagerInternal = mock(ActivityManagerInternal.class); 636 637 LocalServices.removeServiceForTest(PackageManagerInternal.class); 638 LocalServices.addService(PackageManagerInternal.class, mMockPackageManagerInternal); 639 LocalServices.removeServiceForTest(UsageStatsManagerInternal.class); 640 LocalServices.addService(UsageStatsManagerInternal.class, mMockUsageStatsManagerInternal); 641 LocalServices.removeServiceForTest(ActivityManagerInternal.class); 642 LocalServices.addService(ActivityManagerInternal.class, mMockActivityManagerInternal); 643 644 // Prepare injection values. 645 646 mInjectedCurrentTimeMillis = START_TIME; 647 648 mInjectedPackages = new HashMap<>(); 649 addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 1); 650 addPackage(CALLING_PACKAGE_2, CALLING_UID_2, 2); 651 addPackage(CALLING_PACKAGE_3, CALLING_UID_3, 3); 652 addPackage(CALLING_PACKAGE_4, CALLING_UID_4, 10); 653 addPackage(LAUNCHER_1, LAUNCHER_UID_1, 4); 654 addPackage(LAUNCHER_2, LAUNCHER_UID_2, 5); 655 addPackage(LAUNCHER_3, LAUNCHER_UID_3, 6); 656 addPackage(LAUNCHER_4, LAUNCHER_UID_4, 10); 657 658 // CALLING_PACKAGE_3 / LAUNCHER_3 are not backup target. 659 updatePackageInfo(CALLING_PACKAGE_3, 660 pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP); 661 updatePackageInfo(LAUNCHER_3, 662 pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP); 663 664 mUninstalledPackages = new HashSet<>(); 665 666 mInjectedFilePathRoot = new File(getTestContext().getCacheDir(), "test-files"); 667 668 deleteAllSavedFiles(); 669 670 // Set up users. 671 when(mMockUserManager.getUserInfo(anyInt())).thenAnswer(new AnswerWithSystemCheck<>( 672 inv -> mUserInfos.get((Integer) inv.getArguments()[0]))); 673 674 mUserInfos.put(USER_0, USER_INFO_0); 675 mUserInfos.put(USER_10, USER_INFO_10); 676 mUserInfos.put(USER_11, USER_INFO_11); 677 mUserInfos.put(USER_P0, USER_INFO_P0); 678 679 // Set up isUserRunning and isUserUnlocked. 680 when(mMockUserManager.isUserRunning(anyInt())).thenAnswer(new AnswerWithSystemCheck<>( 681 inv -> mRunningUsers.get((Integer) inv.getArguments()[0]))); 682 683 when(mMockUserManager.isUserUnlocked(anyInt())).thenAnswer(new AnswerWithSystemCheck<>( 684 inv -> { 685 final int userId = (Integer) inv.getArguments()[0]; 686 return mRunningUsers.get(userId) && mUnlockedUsers.get(userId); 687 })); 688 689 // User 0 is always running 690 mRunningUsers.put(USER_0, true); 691 mRunningUsers.put(USER_10, false); 692 mRunningUsers.put(USER_11, false); 693 mRunningUsers.put(USER_P0, false); 694 695 // Unlock all users by default. 696 mUnlockedUsers.put(USER_0, true); 697 mUnlockedUsers.put(USER_10, true); 698 mUnlockedUsers.put(USER_11, true); 699 mUnlockedUsers.put(USER_P0, true); 700 701 // Set up mMockActivityManagerInternal. 702 // By default, startActivityAsPackage() will simply forward to startActivityAsUser(). 703 doAnswer(new AnswerWithSystemCheck<>(inv -> { 704 mServiceContext.startActivityAsUser( 705 (Intent) inv.getArguments()[2], 706 (Bundle) inv.getArguments()[3], 707 UserHandle.of((Integer) inv.getArguments()[1])); 708 return ActivityManager.START_SUCCESS; 709 })).when(mMockActivityManagerInternal).startActivityAsPackage(anyString(), anyInt(), 710 any(Intent.class), any(Bundle.class)); 711 712 // Set up resources 713 setUpAppResources(); 714 715 // Start the service. 716 initService(); 717 setCaller(CALLING_PACKAGE_1); 718 719 // In order to complicate the situation, we set mLocaleChangeSequenceNumber to 1 by 720 // calling this. Running test with mLocaleChangeSequenceNumber == 0 might make us miss 721 // some edge cases. 722 mInternal.onSystemLocaleChangedNoLock(); 723 } 724 725 /** 726 * Returns a boolean but also checks if the current UID is SYSTEM_UID. 727 */ 728 protected class AnswerWithSystemCheck<T> implements Answer<T> { 729 private final Function<InvocationOnMock, T> mChecker; 730 731 public AnswerWithSystemCheck(Function<InvocationOnMock, T> checker) { 732 mChecker = checker; 733 } 734 735 @Override 736 public T answer(InvocationOnMock invocation) throws Throwable { 737 assertEquals("Must be called on SYSTEM UID.", 738 Process.SYSTEM_UID, mInjectedCallingUid); 739 return mChecker.apply(invocation); 740 } 741 } 742 743 protected void setUpAppResources() throws Exception { 744 setUpAppResources(/* offset = */ 0); 745 } 746 747 protected void setUpAppResources(int ressIdOffset) throws Exception { 748 // ressIdOffset is used to adjust resource IDs to emulate the case where an updated app 749 // has resource IDs changed. 750 751 doAnswer(pmInvocation -> { 752 assertEquals(Process.SYSTEM_UID, mInjectedCallingUid); 753 754 final String packageName = (String) pmInvocation.getArguments()[0]; 755 final int userId = (Integer) pmInvocation.getArguments()[1]; 756 757 final Resources res = mock(Resources.class); 758 759 doAnswer(resInvocation -> { 760 final int argResId = (Integer) resInvocation.getArguments()[0]; 761 762 return "string-" + packageName + "-user:" + userId + "-res:" + argResId 763 + "/" + mInjectedLocale; 764 }).when(res).getString(anyInt()); 765 766 doAnswer(resInvocation -> { 767 final int resId = (Integer) resInvocation.getArguments()[0]; 768 769 // Always use the "string" resource type. The type doesn't matter during the test. 770 return packageName + ":string/r" + resId; 771 }).when(res).getResourceName(anyInt()); 772 773 doAnswer(resInvocation -> { 774 final String argResName = (String) resInvocation.getArguments()[0]; 775 final String argType = (String) resInvocation.getArguments()[1]; 776 final String argPackageName = (String) resInvocation.getArguments()[2]; 777 778 // See the above code. getResourceName() will just use "r" + res ID as the entry 779 // name. 780 String entryName = argResName; 781 if (entryName.contains("/")) { 782 entryName = ShortcutInfo.getResourceEntryName(entryName); 783 } 784 return Integer.parseInt(entryName.substring(1)) + ressIdOffset; 785 }).when(res).getIdentifier(anyString(), anyString(), anyString()); 786 return res; 787 }).when(mMockPackageManager).getResourcesForApplicationAsUser(anyString(), anyInt()); 788 } 789 790 protected static UserInfo withProfileGroupId(UserInfo in, int groupId) { 791 in.profileGroupId = groupId; 792 return in; 793 } 794 795 @Override 796 protected void tearDown() throws Exception { 797 if (DUMP_IN_TEARDOWN) dumpsysOnLogcat("Teardown"); 798 799 shutdownServices(); 800 801 super.tearDown(); 802 } 803 804 protected Context getTestContext() { 805 return getInstrumentation().getContext(); 806 } 807 808 protected ShortcutManager getManager() { 809 return mManager; 810 } 811 812 protected void deleteAllSavedFiles() { 813 // Empty the data directory. 814 if (mInjectedFilePathRoot.exists()) { 815 Assert.assertTrue("failed to delete dir", 816 FileUtils.deleteContents(mInjectedFilePathRoot)); 817 } 818 mInjectedFilePathRoot.mkdirs(); 819 } 820 821 /** (Re-) init the manager and the service. */ 822 protected void initService() { 823 shutdownServices(); 824 825 LocalServices.removeServiceForTest(ShortcutServiceInternal.class); 826 827 // Instantiate targets. 828 mService = new ShortcutServiceTestable(mServiceContext, mLooper); 829 mManager = new ShortcutManagerTestable(mClientContext, mService); 830 831 mInternal = LocalServices.getService(ShortcutServiceInternal.class); 832 833 mLauncherAppImpl = new LauncherAppImplTestable(mServiceContext); 834 mLauncherApps = null; 835 mLauncherAppsMap.clear(); 836 837 // Send boot sequence events. 838 mService.onBootPhase(SystemService.PHASE_LOCK_SETTINGS_READY); 839 840 // Make sure a call to onSystemLocaleChangedNoLock() before PHASE_BOOT_COMPLETED will be 841 // ignored. 842 final long origSequenceNumber = mService.getLocaleChangeSequenceNumber(); 843 mInternal.onSystemLocaleChangedNoLock(); 844 assertEquals(origSequenceNumber, mService.getLocaleChangeSequenceNumber()); 845 846 mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); 847 } 848 849 protected void shutdownServices() { 850 if (mService != null) { 851 // Flush all the unsaved data from the previous instance. 852 mService.saveDirtyInfo(); 853 854 // Make sure everything is consistent. 855 mService.verifyStates(); 856 } 857 LocalServices.removeServiceForTest(ShortcutServiceInternal.class); 858 859 mService = null; 860 mManager = null; 861 mInternal = null; 862 mLauncherAppImpl = null; 863 mLauncherApps = null; 864 mLauncherAppsMap.clear(); 865 } 866 867 protected void runOnHandler(Runnable r) { 868 final long token = mServiceContext.injectClearCallingIdentity(); 869 try { 870 r.run(); 871 } finally { 872 mServiceContext.injectRestoreCallingIdentity(token); 873 } 874 } 875 876 protected void addPackage(String packageName, int uid, int version) { 877 addPackage(packageName, uid, version, packageName); 878 } 879 880 protected Signature[] genSignatures(String... signatures) { 881 final Signature[] sigs = new Signature[signatures.length]; 882 for (int i = 0; i < signatures.length; i++){ 883 sigs[i] = new Signature(signatures[i].getBytes()); 884 } 885 return sigs; 886 } 887 888 protected PackageInfo genPackage(String packageName, int uid, int version, String... signatures) { 889 final PackageInfo pi = new PackageInfo(); 890 pi.packageName = packageName; 891 pi.applicationInfo = new ApplicationInfo(); 892 pi.applicationInfo.uid = uid; 893 pi.applicationInfo.flags = ApplicationInfo.FLAG_INSTALLED 894 | ApplicationInfo.FLAG_ALLOW_BACKUP; 895 pi.versionCode = version; 896 pi.applicationInfo.versionCode = version; 897 pi.signatures = genSignatures(signatures); 898 899 return pi; 900 } 901 902 protected void addPackage(String packageName, int uid, int version, String... signatures) { 903 mInjectedPackages.put(packageName, genPackage(packageName, uid, version, signatures)); 904 } 905 906 protected void updatePackageInfo(String packageName, Consumer<PackageInfo> c) { 907 c.accept(mInjectedPackages.get(packageName)); 908 } 909 910 protected void updatePackageVersion(String packageName, int increment) { 911 updatePackageInfo(packageName, pi -> { 912 pi.versionCode += increment; 913 pi.applicationInfo.versionCode += increment; 914 }); 915 } 916 917 protected void updatePackageLastUpdateTime(String packageName, long increment) { 918 updatePackageInfo(packageName, pi -> { 919 pi.lastUpdateTime += increment; 920 }); 921 } 922 923 protected void uninstallPackage(int userId, String packageName) { 924 if (ENABLE_DUMP) { 925 Log.v(TAG, "Unnstall package " + packageName + " / " + userId); 926 } 927 mUninstalledPackages.add(PackageWithUser.of(userId, packageName)); 928 } 929 930 protected void installPackage(int userId, String packageName) { 931 if (ENABLE_DUMP) { 932 Log.v(TAG, "Install package " + packageName + " / " + userId); 933 } 934 mUninstalledPackages.remove(PackageWithUser.of(userId, packageName)); 935 } 936 937 PackageInfo getInjectedPackageInfo(String packageName, @UserIdInt int userId, 938 boolean getSignatures) { 939 final PackageInfo pi = mInjectedPackages.get(packageName); 940 if (pi == null) return null; 941 942 final PackageInfo ret = new PackageInfo(); 943 ret.packageName = pi.packageName; 944 ret.versionCode = pi.versionCode; 945 ret.lastUpdateTime = pi.lastUpdateTime; 946 947 ret.applicationInfo = new ApplicationInfo(pi.applicationInfo); 948 ret.applicationInfo.uid = UserHandle.getUid(userId, pi.applicationInfo.uid); 949 ret.applicationInfo.packageName = pi.packageName; 950 951 if (mUninstalledPackages.contains(PackageWithUser.of(userId, packageName))) { 952 ret.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED; 953 } 954 955 if (getSignatures) { 956 ret.signatures = pi.signatures; 957 } 958 959 return ret; 960 } 961 962 protected void addApplicationInfo(PackageInfo pi, List<ApplicationInfo> list) { 963 if (pi != null && pi.applicationInfo != null) { 964 list.add(pi.applicationInfo); 965 } 966 } 967 968 protected List<ApplicationInfo> getInstalledApplications(int userId) { 969 final ArrayList<ApplicationInfo> ret = new ArrayList<>(); 970 971 addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_1, userId, false), ret); 972 addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_2, userId, false), ret); 973 addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_3, userId, false), ret); 974 addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_4, userId, false), ret); 975 addApplicationInfo(getInjectedPackageInfo(LAUNCHER_1, userId, false), ret); 976 addApplicationInfo(getInjectedPackageInfo(LAUNCHER_2, userId, false), ret); 977 addApplicationInfo(getInjectedPackageInfo(LAUNCHER_3, userId, false), ret); 978 addApplicationInfo(getInjectedPackageInfo(LAUNCHER_4, userId, false), ret); 979 980 return ret; 981 } 982 983 private void addPackageInfo(PackageInfo pi, List<PackageInfo> list) { 984 if (pi != null) { 985 list.add(pi); 986 } 987 } 988 989 private List<PackageInfo> getInstalledPackagesWithUninstalled(int userId) { 990 final ArrayList<PackageInfo> ret = new ArrayList<>(); 991 992 addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_1, userId, false), ret); 993 addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_2, userId, false), ret); 994 addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_3, userId, false), ret); 995 addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_4, userId, false), ret); 996 addPackageInfo(getInjectedPackageInfo(LAUNCHER_1, userId, false), ret); 997 addPackageInfo(getInjectedPackageInfo(LAUNCHER_2, userId, false), ret); 998 addPackageInfo(getInjectedPackageInfo(LAUNCHER_3, userId, false), ret); 999 addPackageInfo(getInjectedPackageInfo(LAUNCHER_4, userId, false), ret); 1000 1001 return ret; 1002 } 1003 1004 protected void addManifestShortcutResource(ComponentName activity, int resId) { 1005 final String packageName = activity.getPackageName(); 1006 LinkedHashMap<ComponentName, Integer> map = mActivityMetadataResId.get(packageName); 1007 if (map == null) { 1008 map = new LinkedHashMap<>(); 1009 mActivityMetadataResId.put(packageName, map); 1010 } 1011 map.put(activity, resId); 1012 } 1013 1014 protected PackageInfo injectGetActivitiesWithMetadata(String packageName, @UserIdInt int userId) { 1015 final PackageInfo ret = getInjectedPackageInfo(packageName, userId, 1016 /* getSignatures=*/ false); 1017 1018 final HashMap<ComponentName, Integer> activities = mActivityMetadataResId.get(packageName); 1019 if (activities != null) { 1020 final ArrayList<ActivityInfo> list = new ArrayList<>(); 1021 1022 for (ComponentName cn : activities.keySet()) { 1023 ActivityInfo ai = new ActivityInfo(); 1024 ai.packageName = cn.getPackageName(); 1025 ai.name = cn.getClassName(); 1026 ai.metaData = new Bundle(); 1027 ai.metaData.putInt(ShortcutParser.METADATA_KEY, activities.get(cn)); 1028 ai.applicationInfo = ret.applicationInfo; 1029 list.add(ai); 1030 } 1031 ret.activities = list.toArray(new ActivityInfo[list.size()]); 1032 } 1033 return ret; 1034 } 1035 1036 protected XmlResourceParser injectXmlMetaData(ActivityInfo activityInfo, String key) { 1037 if (!ShortcutParser.METADATA_KEY.equals(key) || activityInfo.metaData == null) { 1038 return null; 1039 } 1040 final int resId = activityInfo.metaData.getInt(key); 1041 return getTestContext().getResources().getXml(resId); 1042 } 1043 1044 /** Replace the current calling package */ 1045 protected void setCaller(String packageName, int userId) { 1046 mInjectedClientPackage = packageName; 1047 mInjectedCallingUid = 1048 Preconditions.checkNotNull(getInjectedPackageInfo(packageName, userId, false), 1049 "Unknown package").applicationInfo.uid; 1050 1051 // Set up LauncherApps for this caller. 1052 final Pair<Integer, String> key = Pair.create(userId, packageName); 1053 if (!mLauncherAppsMap.containsKey(key)) { 1054 mLauncherAppsMap.put(key, new LauncherAppsTestable(mClientContext, mLauncherAppImpl)); 1055 } 1056 mLauncherApps = mLauncherAppsMap.get(key); 1057 } 1058 1059 protected void setCaller(String packageName) { 1060 setCaller(packageName, UserHandle.USER_SYSTEM); 1061 } 1062 1063 protected String getCallingPackage() { 1064 return mInjectedClientPackage; 1065 } 1066 1067 protected void setDefaultLauncherChecker(BiPredicate<String, Integer> p) { 1068 mDefaultLauncherChecker = p; 1069 } 1070 1071 protected void runWithCaller(String packageName, int userId, Runnable r) { 1072 final String previousPackage = mInjectedClientPackage; 1073 final int previousUserId = UserHandle.getUserId(mInjectedCallingUid); 1074 1075 setCaller(packageName, userId); 1076 1077 r.run(); 1078 1079 setCaller(previousPackage, previousUserId); 1080 } 1081 1082 protected void runWithSystemUid(Runnable r) { 1083 final int origUid = mInjectedCallingUid; 1084 mInjectedCallingUid = Process.SYSTEM_UID; 1085 r.run(); 1086 mInjectedCallingUid = origUid; 1087 } 1088 1089 protected void lookupAndFillInResourceNames(ShortcutInfo si) { 1090 runWithSystemUid(() -> si.lookupAndFillInResourceNames( 1091 mService.injectGetResourcesForApplicationAsUser(si.getPackage(), si.getUserId()))); 1092 } 1093 1094 protected int getCallingUserId() { 1095 return UserHandle.getUserId(mInjectedCallingUid); 1096 } 1097 1098 protected UserHandle getCallingUser() { 1099 return UserHandle.of(getCallingUserId()); 1100 } 1101 1102 /** For debugging */ 1103 protected void dumpsysOnLogcat() { 1104 dumpsysOnLogcat(""); 1105 } 1106 1107 protected void dumpsysOnLogcat(String message) { 1108 dumpsysOnLogcat(message, false); 1109 } 1110 1111 protected void dumpsysOnLogcat(String message, boolean force) { 1112 if (force || !ENABLE_DUMP) return; 1113 1114 final ByteArrayOutputStream out = new ByteArrayOutputStream(); 1115 final PrintWriter pw = new PrintWriter(out); 1116 mService.dumpInner(pw, null); 1117 pw.close(); 1118 1119 Log.v(TAG, "Dumping ShortcutService: " + message); 1120 for (String line : out.toString().split("\n")) { 1121 Log.v(TAG, line); 1122 } 1123 } 1124 1125 /** 1126 * For debugging, dump arbitrary file on logcat. 1127 */ 1128 protected void dumpFileOnLogcat(String path) { 1129 dumpFileOnLogcat(path, ""); 1130 } 1131 1132 protected void dumpFileOnLogcat(String path, String message) { 1133 if (!ENABLE_DUMP) return; 1134 1135 Log.v(TAG, "Dumping file: " + path + " " + message); 1136 final StringBuilder sb = new StringBuilder(); 1137 try (BufferedReader br = new BufferedReader(new FileReader(path))) { 1138 String line; 1139 while ((line = br.readLine()) != null) { 1140 Log.v(TAG, line); 1141 } 1142 } catch (Exception e) { 1143 Log.e(TAG, "Couldn't read file", e); 1144 fail("Exception " + e); 1145 } 1146 } 1147 1148 /** 1149 * For debugging, dump the main state file on logcat. 1150 */ 1151 protected void dumpBaseStateFile() { 1152 mService.saveDirtyInfo(); 1153 dumpFileOnLogcat(mInjectedFilePathRoot.getAbsolutePath() 1154 + "/system/" + ShortcutService.FILENAME_BASE_STATE); 1155 } 1156 1157 /** 1158 * For debugging, dump per-user state file on logcat. 1159 */ 1160 protected void dumpUserFile(int userId) { 1161 dumpUserFile(userId, ""); 1162 } 1163 1164 protected void dumpUserFile(int userId, String message) { 1165 mService.saveDirtyInfo(); 1166 dumpFileOnLogcat(mInjectedFilePathRoot.getAbsolutePath() 1167 + "/user-" + userId 1168 + "/" + ShortcutService.FILENAME_USER_PACKAGES, message); 1169 } 1170 1171 /** 1172 * Make a shortcut with an ID. 1173 */ 1174 protected ShortcutInfo makeShortcut(String id) { 1175 return makeShortcut( 1176 id, "Title-" + id, /* activity =*/ null, /* icon =*/ null, 1177 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); 1178 } 1179 1180 protected ShortcutInfo makeShortcutWithTitle(String id, String title) { 1181 return makeShortcut( 1182 id, title, /* activity =*/ null, /* icon =*/ null, 1183 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); 1184 } 1185 1186 /** 1187 * Make a shortcut with an ID and timestamp. 1188 */ 1189 protected ShortcutInfo makeShortcutWithTimestamp(String id, long timestamp) { 1190 final ShortcutInfo s = makeShortcut( 1191 id, "Title-" + id, /* activity =*/ null, /* icon =*/ null, 1192 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); 1193 s.setTimestamp(timestamp); 1194 return s; 1195 } 1196 1197 /** 1198 * Make a shortcut with an ID, a timestamp and an activity component 1199 */ 1200 protected ShortcutInfo makeShortcutWithTimestampWithActivity(String id, long timestamp, 1201 ComponentName activity) { 1202 final ShortcutInfo s = makeShortcut( 1203 id, "Title-" + id, activity, /* icon =*/ null, 1204 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); 1205 s.setTimestamp(timestamp); 1206 return s; 1207 } 1208 1209 /** 1210 * Make a shortcut with an ID and icon. 1211 */ 1212 protected ShortcutInfo makeShortcutWithIcon(String id, Icon icon) { 1213 return makeShortcut( 1214 id, "Title-" + id, /* activity =*/ null, icon, 1215 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); 1216 } 1217 1218 protected ShortcutInfo makePackageShortcut(String packageName, String id) { 1219 String origCaller = getCallingPackage(); 1220 1221 setCaller(packageName); 1222 ShortcutInfo s = makeShortcut( 1223 id, "Title-" + id, /* activity =*/ null, /* icon =*/ null, 1224 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); 1225 setCaller(origCaller); // restore the caller 1226 1227 return s; 1228 } 1229 1230 /** 1231 * Make multiple shortcuts with IDs. 1232 */ 1233 protected List<ShortcutInfo> makeShortcuts(String... ids) { 1234 final ArrayList<ShortcutInfo> ret = new ArrayList(); 1235 for (String id : ids) { 1236 ret.add(makeShortcut(id)); 1237 } 1238 return ret; 1239 } 1240 1241 protected ShortcutInfo.Builder makeShortcutBuilder() { 1242 return new ShortcutInfo.Builder(mClientContext); 1243 } 1244 1245 protected ShortcutInfo makeShortcutWithActivity(String id, ComponentName activity) { 1246 return makeShortcut( 1247 id, "Title-" + id, activity, /* icon =*/ null, 1248 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); 1249 } 1250 1251 protected ShortcutInfo makeShortcutWithIntent(String id, Intent intent) { 1252 return makeShortcut( 1253 id, "Title-" + id, /* activity =*/ null, /* icon =*/ null, 1254 intent, /* rank =*/ 0); 1255 } 1256 1257 protected ShortcutInfo makeShortcutWithActivityAndTitle(String id, ComponentName activity, 1258 String title) { 1259 return makeShortcut( 1260 id, title, activity, /* icon =*/ null, 1261 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); 1262 } 1263 1264 protected ShortcutInfo makeShortcutWithActivityAndRank(String id, ComponentName activity, 1265 int rank) { 1266 return makeShortcut( 1267 id, "Title-" + id, activity, /* icon =*/ null, 1268 makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), rank); 1269 } 1270 1271 /** 1272 * Make a shortcut with details. 1273 */ 1274 protected ShortcutInfo makeShortcut(String id, String title, ComponentName activity, 1275 Icon icon, Intent intent, int rank) { 1276 final ShortcutInfo.Builder b = new ShortcutInfo.Builder(mClientContext, id) 1277 .setActivity(new ComponentName(mClientContext.getPackageName(), "dummy")) 1278 .setShortLabel(title) 1279 .setRank(rank) 1280 .setIntent(intent); 1281 if (icon != null) { 1282 b.setIcon(icon); 1283 } 1284 if (activity != null) { 1285 b.setActivity(activity); 1286 } 1287 final ShortcutInfo s = b.build(); 1288 1289 s.setTimestamp(mInjectedCurrentTimeMillis); // HACK 1290 1291 return s; 1292 } 1293 1294 /** 1295 * Make a shortcut with details. 1296 */ 1297 protected ShortcutInfo makeShortcutWithExtras(String id, Intent intent, 1298 PersistableBundle extras) { 1299 final ShortcutInfo.Builder b = new ShortcutInfo.Builder(mClientContext, id) 1300 .setActivity(new ComponentName(mClientContext.getPackageName(), "dummy")) 1301 .setShortLabel("title-" + id) 1302 .setExtras(extras) 1303 .setIntent(intent); 1304 final ShortcutInfo s = b.build(); 1305 1306 s.setTimestamp(mInjectedCurrentTimeMillis); // HACK 1307 1308 return s; 1309 } 1310 1311 /** 1312 * Make an intent. 1313 */ 1314 protected Intent makeIntent(String action, Class<?> clazz, Object... bundleKeysAndValues) { 1315 final Intent intent = new Intent(action); 1316 intent.setComponent(makeComponent(clazz)); 1317 intent.replaceExtras(makeBundle(bundleKeysAndValues)); 1318 return intent; 1319 } 1320 1321 /** 1322 * Make an component name, with the client context. 1323 */ 1324 @NonNull 1325 protected ComponentName makeComponent(Class<?> clazz) { 1326 return new ComponentName(mClientContext, clazz); 1327 } 1328 1329 @NonNull 1330 protected ShortcutInfo findById(List<ShortcutInfo> list, String id) { 1331 for (ShortcutInfo s : list) { 1332 if (s.getId().equals(id)) { 1333 return s; 1334 } 1335 } 1336 fail("Shortcut with id " + id + " not found"); 1337 return null; 1338 } 1339 1340 protected void assertSystem() { 1341 assertEquals("Caller must be system", Process.SYSTEM_UID, mInjectedCallingUid); 1342 } 1343 1344 protected void assertResetTimes(long expectedLastResetTime, long expectedNextResetTime) { 1345 assertEquals(expectedLastResetTime, mService.getLastResetTimeLocked()); 1346 assertEquals(expectedNextResetTime, mService.getNextResetTimeLocked()); 1347 } 1348 1349 public static List<ShortcutInfo> assertAllNotHaveIcon( 1350 List<ShortcutInfo> actualShortcuts) { 1351 for (ShortcutInfo s : actualShortcuts) { 1352 assertNull("ID " + s.getId(), s.getIcon()); 1353 } 1354 return actualShortcuts; 1355 } 1356 1357 @NonNull 1358 protected List<ShortcutInfo> assertAllHaveFlags(@NonNull List<ShortcutInfo> actualShortcuts, 1359 int shortcutFlags) { 1360 for (ShortcutInfo s : actualShortcuts) { 1361 assertTrue("ID " + s.getId() + " doesn't have flags " + shortcutFlags, 1362 s.hasFlags(shortcutFlags)); 1363 } 1364 return actualShortcuts; 1365 } 1366 1367 protected ShortcutInfo getPackageShortcut(String packageName, String shortcutId, int userId) { 1368 return mService.getPackageShortcutForTest(packageName, shortcutId, userId); 1369 } 1370 1371 protected void assertShortcutExists(String packageName, String shortcutId, int userId) { 1372 assertTrue(getPackageShortcut(packageName, shortcutId, userId) != null); 1373 } 1374 1375 protected void assertShortcutNotExists(String packageName, String shortcutId, int userId) { 1376 assertTrue(getPackageShortcut(packageName, shortcutId, userId) == null); 1377 } 1378 1379 protected Intent launchShortcutAndGetIntent( 1380 @NonNull String packageName, @NonNull String shortcutId, int userId) { 1381 reset(mServiceContext); 1382 mLauncherApps.startShortcut(packageName, shortcutId, null, null, 1383 UserHandle.of(userId)); 1384 1385 final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); 1386 verify(mServiceContext).startActivityAsUser( 1387 intentCaptor.capture(), 1388 any(Bundle.class), 1389 eq(UserHandle.of(userId))); 1390 return intentCaptor.getValue(); 1391 } 1392 1393 protected Intent launchShortcutAndGetIntent_withShortcutInfo( 1394 @NonNull String packageName, @NonNull String shortcutId, int userId) { 1395 reset(mServiceContext); 1396 1397 mLauncherApps.startShortcut( 1398 getShortcutInfoAsLauncher(packageName, shortcutId, userId), null, null); 1399 1400 final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); 1401 verify(mServiceContext).startActivityAsUser( 1402 intentCaptor.capture(), 1403 any(Bundle.class), 1404 eq(UserHandle.of(userId))); 1405 return intentCaptor.getValue(); 1406 } 1407 1408 protected void assertShortcutLaunchable(@NonNull String packageName, @NonNull String shortcutId, 1409 int userId) { 1410 assertNotNull(launchShortcutAndGetIntent(packageName, shortcutId, userId)); 1411 assertNotNull(launchShortcutAndGetIntent_withShortcutInfo(packageName, shortcutId, userId)); 1412 } 1413 1414 protected void assertShortcutNotLaunchable(@NonNull String packageName, 1415 @NonNull String shortcutId, int userId, Class<?> expectedException) { 1416 reset(mServiceContext); 1417 Exception thrown = null; 1418 try { 1419 mLauncherApps.startShortcut(packageName, shortcutId, null, null, 1420 UserHandle.of(userId)); 1421 } catch (Exception e) { 1422 thrown = e; 1423 } 1424 // This shouldn't have been called. 1425 verify(mServiceContext, times(0)).startActivityAsUser( 1426 any(Intent.class), 1427 any(Bundle.class), 1428 any(UserHandle.class)); 1429 assertNotNull("Exception was not thrown", thrown); 1430 assertEquals("Exception type different", expectedException, thrown.getClass()); 1431 } 1432 1433 protected void assertBitmapDirectories(int userId, String... expectedDirectories) { 1434 final Set<String> expected = hashSet(set(expectedDirectories)); 1435 1436 final Set<String> actual = new HashSet<>(); 1437 1438 final File[] files = mService.getUserBitmapFilePath(userId).listFiles(); 1439 if (files != null) { 1440 for (File child : files) { 1441 if (child.isDirectory()) { 1442 actual.add(child.getName()); 1443 } 1444 } 1445 } 1446 1447 assertEquals(expected, actual); 1448 } 1449 1450 protected void assertBitmapFiles(int userId, String packageName, String... expectedFiles) { 1451 final Set<String> expected = hashSet(set(expectedFiles)); 1452 1453 final Set<String> actual = new HashSet<>(); 1454 1455 final File[] files = new File(mService.getUserBitmapFilePath(userId), packageName) 1456 .listFiles(); 1457 if (files != null) { 1458 for (File child : files) { 1459 if (child.isFile()) { 1460 actual.add(child.getName()); 1461 } 1462 } 1463 } 1464 1465 assertEquals(expected, actual); 1466 } 1467 1468 protected String getBitmapFilename(int userId, String packageName, String shortcutId) { 1469 final ShortcutInfo si = mService.getPackageShortcutForTest(packageName, shortcutId, userId); 1470 if (si == null) { 1471 return null; 1472 } 1473 return new File(si.getBitmapPath()).getName(); 1474 } 1475 1476 protected List<ShortcutInfo> getCallerShortcuts() { 1477 final ShortcutPackage p = mService.getPackageShortcutForTest( 1478 getCallingPackage(), getCallingUserId()); 1479 return p == null ? null : p.getAllShortcutsForTest(); 1480 } 1481 1482 protected ShortcutInfo getCallerShortcut(String shortcutId) { 1483 return getPackageShortcut(getCallingPackage(), shortcutId, getCallingUserId()); 1484 } 1485 1486 protected List<ShortcutInfo> getLauncherShortcuts(String launcher, int userId, int queryFlags) { 1487 final List<ShortcutInfo>[] ret = new List[1]; 1488 runWithCaller(launcher, userId, () -> { 1489 final ShortcutQuery q = new ShortcutQuery(); 1490 q.setQueryFlags(queryFlags); 1491 ret[0] = mLauncherApps.getShortcuts(q, UserHandle.of(userId)); 1492 }); 1493 return ret[0]; 1494 } 1495 1496 protected List<ShortcutInfo> getLauncherPinnedShortcuts(String launcher, int userId) { 1497 return getLauncherShortcuts(launcher, userId, ShortcutQuery.FLAG_GET_PINNED); 1498 } 1499 1500 protected ShortcutInfo getShortcutInfoAsLauncher(String packageName, String shortcutId, 1501 int userId) { 1502 final List<ShortcutInfo> infoList = 1503 mLauncherApps.getShortcutInfo(packageName, list(shortcutId), 1504 UserHandle.of(userId)); 1505 assertEquals("No shortcutInfo found (or too many of them)", 1, infoList.size()); 1506 return infoList.get(0); 1507 } 1508 1509 protected Intent genPackageAddIntent(String packageName, int userId) { 1510 installPackage(userId, packageName); 1511 1512 Intent i = new Intent(Intent.ACTION_PACKAGE_ADDED); 1513 i.setData(Uri.parse("package:" + packageName)); 1514 i.putExtra(Intent.EXTRA_USER_HANDLE, userId); 1515 return i; 1516 } 1517 1518 protected Intent genPackageDeleteIntent(String pakcageName, int userId) { 1519 uninstallPackage(userId, pakcageName); 1520 1521 Intent i = new Intent(Intent.ACTION_PACKAGE_REMOVED); 1522 i.setData(Uri.parse("package:" + pakcageName)); 1523 i.putExtra(Intent.EXTRA_USER_HANDLE, userId); 1524 return i; 1525 } 1526 1527 protected Intent genPackageUpdateIntent(String pakcageName, int userId) { 1528 installPackage(userId, pakcageName); 1529 1530 Intent i = new Intent(Intent.ACTION_PACKAGE_ADDED); 1531 i.setData(Uri.parse("package:" + pakcageName)); 1532 i.putExtra(Intent.EXTRA_USER_HANDLE, userId); 1533 i.putExtra(Intent.EXTRA_REPLACING, true); 1534 return i; 1535 } 1536 1537 protected Intent genPackageChangedIntent(String pakcageName, int userId) { 1538 Intent i = new Intent(Intent.ACTION_PACKAGE_CHANGED); 1539 i.setData(Uri.parse("package:" + pakcageName)); 1540 i.putExtra(Intent.EXTRA_USER_HANDLE, userId); 1541 return i; 1542 } 1543 1544 protected Intent genPackageDataClear(String packageName, int userId) { 1545 Intent i = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED); 1546 i.setData(Uri.parse("package:" + packageName)); 1547 i.putExtra(Intent.EXTRA_USER_HANDLE, userId); 1548 return i; 1549 } 1550 1551 protected void assertExistsAndShadow(ShortcutPackageItem spi) { 1552 assertNotNull(spi); 1553 assertTrue(spi.getPackageInfo().isShadow()); 1554 } 1555 1556 protected File makeFile(File baseDirectory, String... paths) { 1557 File ret = baseDirectory; 1558 1559 for (String path : paths) { 1560 ret = new File(ret, path); 1561 } 1562 1563 return ret; 1564 } 1565 1566 protected boolean bitmapDirectoryExists(String packageName, int userId) { 1567 final File path = new File(mService.getUserBitmapFilePath(userId), packageName); 1568 return path.isDirectory(); 1569 } 1570 protected static ShortcutQuery buildQuery(long changedSince, 1571 String packageName, ComponentName componentName, 1572 /* @ShortcutQuery.QueryFlags */ int flags) { 1573 return buildQuery(changedSince, packageName, null, componentName, flags); 1574 } 1575 1576 protected static ShortcutQuery buildQuery(long changedSince, 1577 String packageName, List<String> shortcutIds, ComponentName componentName, 1578 /* @ShortcutQuery.QueryFlags */ int flags) { 1579 final ShortcutQuery q = new ShortcutQuery(); 1580 q.setChangedSince(changedSince); 1581 q.setPackage(packageName); 1582 q.setShortcutIds(shortcutIds); 1583 q.setActivity(componentName); 1584 q.setQueryFlags(flags); 1585 return q; 1586 } 1587 1588 protected static ShortcutQuery buildAllQuery(String packageName) { 1589 final ShortcutQuery q = new ShortcutQuery(); 1590 q.setPackage(packageName); 1591 q.setQueryFlags(ShortcutQuery.FLAG_GET_ALL_KINDS); 1592 return q; 1593 } 1594 1595 protected static ShortcutQuery buildPinnedQuery(String packageName) { 1596 final ShortcutQuery q = new ShortcutQuery(); 1597 q.setPackage(packageName); 1598 q.setQueryFlags(ShortcutQuery.FLAG_GET_PINNED); 1599 return q; 1600 } 1601 1602 protected static ShortcutQuery buildQueryWithFlags(int queryFlags) { 1603 final ShortcutQuery q = new ShortcutQuery(); 1604 q.setQueryFlags(queryFlags); 1605 return q; 1606 } 1607 1608 protected void backupAndRestore() { 1609 int prevUid = mInjectedCallingUid; 1610 1611 mInjectedCallingUid = Process.SYSTEM_UID; // Only system can call it. 1612 1613 dumpsysOnLogcat("Before backup"); 1614 1615 final byte[] payload = mService.getBackupPayload(USER_0); 1616 if (ENABLE_DUMP) { 1617 final String xml = new String(payload); 1618 Log.v(TAG, "Backup payload:"); 1619 for (String line : xml.split("\n")) { 1620 Log.v(TAG, line); 1621 } 1622 } 1623 1624 // Before doing anything else, uninstall all packages. 1625 for (int userId : list(USER_0, USER_P0)) { 1626 for (String pkg : list(CALLING_PACKAGE_1, CALLING_PACKAGE_2, CALLING_PACKAGE_3, 1627 LAUNCHER_1, LAUNCHER_2, LAUNCHER_3)) { 1628 uninstallPackage(userId, pkg); 1629 } 1630 } 1631 1632 shutdownServices(); 1633 1634 deleteAllSavedFiles(); 1635 1636 initService(); 1637 mService.applyRestore(payload, USER_0); 1638 1639 // handleUnlockUser will perform the gone package check, but it shouldn't remove 1640 // shadow information. 1641 mService.handleUnlockUser(USER_0); 1642 1643 dumpsysOnLogcat("After restore"); 1644 1645 mInjectedCallingUid = prevUid; 1646 } 1647 1648 protected void prepareCrossProfileDataSet() { 1649 runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { 1650 assertTrue(mManager.setDynamicShortcuts(list( 1651 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"), 1652 makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6")))); 1653 }); 1654 runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { 1655 assertTrue(mManager.setDynamicShortcuts(list( 1656 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"), 1657 makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6")))); 1658 }); 1659 runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { 1660 assertTrue(mManager.setDynamicShortcuts(list( 1661 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"), 1662 makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6")))); 1663 }); 1664 runWithCaller(CALLING_PACKAGE_4, USER_0, () -> { 1665 assertTrue(mManager.setDynamicShortcuts(list())); 1666 }); 1667 runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { 1668 assertTrue(mManager.setDynamicShortcuts(list( 1669 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"), 1670 makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6")))); 1671 }); 1672 runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { 1673 assertTrue(mManager.setDynamicShortcuts(list( 1674 makeShortcut("x1"), makeShortcut("x2"), makeShortcut("x3"), 1675 makeShortcut("x4"), makeShortcut("x5"), makeShortcut("x6")))); 1676 }); 1677 1678 runWithCaller(LAUNCHER_1, USER_0, () -> { 1679 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_0); 1680 mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s1", "s2"), HANDLE_USER_0); 1681 mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s1", "s2", "s3"), HANDLE_USER_0); 1682 1683 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1", "s4"), HANDLE_USER_P0); 1684 }); 1685 runWithCaller(LAUNCHER_2, USER_0, () -> { 1686 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0); 1687 mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s2", "s3"), HANDLE_USER_0); 1688 mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s2", "s3", "s4"), HANDLE_USER_0); 1689 1690 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2", "s5"), HANDLE_USER_P0); 1691 }); 1692 runWithCaller(LAUNCHER_3, USER_0, () -> { 1693 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0); 1694 mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s3", "s4"), HANDLE_USER_0); 1695 mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s3", "s4", "s5"), HANDLE_USER_0); 1696 1697 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3", "s6"), HANDLE_USER_P0); 1698 }); 1699 runWithCaller(LAUNCHER_4, USER_0, () -> { 1700 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list(), HANDLE_USER_0); 1701 mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list(), HANDLE_USER_0); 1702 mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list(), HANDLE_USER_0); 1703 mLauncherApps.pinShortcuts(CALLING_PACKAGE_4, list(), HANDLE_USER_0); 1704 }); 1705 1706 // Launcher on a managed profile is referring ot user 0! 1707 runWithCaller(LAUNCHER_1, USER_P0, () -> { 1708 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3", "s4"), HANDLE_USER_0); 1709 mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s3", "s4", "s5"), HANDLE_USER_0); 1710 mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s3", "s4", "s5", "s6"), 1711 HANDLE_USER_0); 1712 1713 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s4", "s1"), HANDLE_USER_P0); 1714 }); 1715 runWithCaller(LAUNCHER_1, USER_10, () -> { 1716 mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("x4", "x5"), HANDLE_USER_10); 1717 mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("x4", "x5", "x6"), HANDLE_USER_10); 1718 mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("x4", "x5", "x6", "x1"), 1719 HANDLE_USER_10); 1720 }); 1721 1722 // Then remove some dynamic shortcuts. 1723 runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { 1724 assertTrue(mManager.setDynamicShortcuts(list( 1725 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); 1726 }); 1727 runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { 1728 assertTrue(mManager.setDynamicShortcuts(list( 1729 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); 1730 }); 1731 runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { 1732 assertTrue(mManager.setDynamicShortcuts(list( 1733 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); 1734 }); 1735 runWithCaller(CALLING_PACKAGE_4, USER_0, () -> { 1736 assertTrue(mManager.setDynamicShortcuts(list())); 1737 }); 1738 runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { 1739 assertTrue(mManager.setDynamicShortcuts(list( 1740 makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); 1741 }); 1742 runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { 1743 assertTrue(mManager.setDynamicShortcuts(list( 1744 makeShortcut("x1"), makeShortcut("x2"), makeShortcut("x3")))); 1745 }); 1746 } 1747 1748 public static List<ShortcutInfo> assertAllHaveIconResId( 1749 List<ShortcutInfo> actualShortcuts) { 1750 for (ShortcutInfo s : actualShortcuts) { 1751 assertTrue("ID " + s.getId() + " not have icon res ID", s.hasIconResource()); 1752 assertFalse("ID " + s.getId() + " shouldn't have icon FD", s.hasIconFile()); 1753 } 1754 return actualShortcuts; 1755 } 1756 1757 public static List<ShortcutInfo> assertAllHaveIconFile( 1758 List<ShortcutInfo> actualShortcuts) { 1759 for (ShortcutInfo s : actualShortcuts) { 1760 assertFalse("ID " + s.getId() + " shouldn't have icon res ID", s.hasIconResource()); 1761 assertTrue("ID " + s.getId() + " not have icon FD", s.hasIconFile()); 1762 } 1763 return actualShortcuts; 1764 } 1765 1766 public static List<ShortcutInfo> assertAllHaveIcon( 1767 List<ShortcutInfo> actualShortcuts) { 1768 for (ShortcutInfo s : actualShortcuts) { 1769 assertTrue("ID " + s.getId() + " has no icon ", s.hasIconFile() || s.hasIconResource()); 1770 } 1771 return actualShortcuts; 1772 } 1773 1774 public static List<ShortcutInfo> assertAllStringsResolved( 1775 List<ShortcutInfo> actualShortcuts) { 1776 for (ShortcutInfo s : actualShortcuts) { 1777 assertTrue("ID " + s.getId(), s.hasStringResourcesResolved()); 1778 } 1779 return actualShortcuts; 1780 } 1781} 1782