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