Merge "ShortcutManager: First cut of CTS" into nyc-dev

am: bc20320

* commit 'bc20320f7f224d1cc5be3c436a1a5ece2067f2ec':
  ShortcutManager: First cut of CTS

Change-Id: I23d24480870644cf69575d2f11bfc55056c0fb96
This commit is contained in:
Makoto Onuki
2016-04-11 23:25:23 +00:00
committed by android-build-merger
11 changed files with 729 additions and 323 deletions

View File

@@ -9505,6 +9505,7 @@ package android.content.pm {
}
public class LauncherApps {
ctor public LauncherApps(android.content.Context);
method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle);
method public android.os.ParcelFileDescriptor getShortcutIconFd(android.content.pm.ShortcutInfo);
@@ -10092,6 +10093,7 @@ package android.content.pm {
}
public class ShortcutManager {
ctor public ShortcutManager(android.content.Context);
method public boolean addDynamicShortcut(android.content.pm.ShortcutInfo);
method public void deleteAllDynamicShortcuts();
method public void deleteDynamicShortcut(java.lang.String);

View File

@@ -589,9 +589,7 @@ final class SystemServiceRegistry {
new CachedServiceFetcher<LauncherApps>() {
@Override
public LauncherApps createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(Context.LAUNCHER_APPS_SERVICE);
ILauncherApps service = ILauncherApps.Stub.asInterface(b);
return new LauncherApps(ctx, service);
return new LauncherApps(ctx);
}});
registerService(Context.RESTRICTIONS_SERVICE, RestrictionsManager.class,
@@ -758,8 +756,7 @@ final class SystemServiceRegistry {
new CachedServiceFetcher<ShortcutManager>() {
@Override
public ShortcutManager createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(Context.SHORTCUT_SERVICE);
return new ShortcutManager(ctx, IShortcutService.Stub.asInterface(b));
return new ShortcutManager(ctx);
}});
registerService(Context.SYSTEM_HEALTH_SERVICE, SystemHealthManager.class,

View File

@@ -19,6 +19,7 @@ package android.content.pm;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -30,6 +31,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
@@ -261,6 +263,13 @@ public class LauncherApps {
mPm = context.getPackageManager();
}
/** @hide */
@TestApi
public LauncherApps(Context context) {
this(context, ILauncherApps.Stub.asInterface(
ServiceManager.getService(Context.LAUNCHER_APPS_SERVICE)));
}
/**
* Retrieves a list of launchable activities that match {@link Intent#ACTION_MAIN} and
* {@link Intent#CATEGORY_LAUNCHER}, for a specified user.

View File

@@ -16,8 +16,11 @@
package android.content.pm;
import android.annotation.NonNull;
import android.annotation.TestApi;
import android.content.Context;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import com.android.internal.annotations.VisibleForTesting;
@@ -96,6 +99,15 @@ public class ShortcutManager {
mService = service;
}
/**
* @hide
*/
@TestApi
public ShortcutManager(Context context) {
this(context, IShortcutService.Stub.asInterface(
ServiceManager.getService(Context.SHORTCUT_SERVICE)));
}
/**
* Publish a list of shortcuts. All existing dynamic shortcuts from the caller application
* will be replaced.

View File

@@ -147,6 +147,7 @@ public class LauncherAppsService extends SystemService {
@Override
public void addOnAppsChangedListener(String callingPackage, IOnAppsChangedListener listener)
throws RemoteException {
verifyCallingPackage(callingPackage);
synchronized (mListeners) {
if (DEBUG) {
Log.d(TAG, "Adding listener from " + Binder.getCallingUserHandle());

View File

@@ -419,26 +419,26 @@ public class ShortcutService extends IShortcutService.Stub {
result = false;
}
mSaveDelayMillis = (int) parser.getLong(ConfigConstants.KEY_SAVE_DELAY_MILLIS,
DEFAULT_SAVE_DELAY_MS);
mSaveDelayMillis = Math.max(0, (int) parser.getLong(ConfigConstants.KEY_SAVE_DELAY_MILLIS,
DEFAULT_SAVE_DELAY_MS));
mResetInterval = parser.getLong(
mResetInterval = Math.max(1, parser.getLong(
ConfigConstants.KEY_RESET_INTERVAL_SEC, DEFAULT_RESET_INTERVAL_SEC)
* 1000L;
* 1000L);
mMaxDailyUpdates = (int) parser.getLong(
ConfigConstants.KEY_MAX_DAILY_UPDATES, DEFAULT_MAX_DAILY_UPDATES);
mMaxDailyUpdates = Math.max(0, (int) parser.getLong(
ConfigConstants.KEY_MAX_DAILY_UPDATES, DEFAULT_MAX_DAILY_UPDATES));
mMaxDynamicShortcuts = (int) parser.getLong(
ConfigConstants.KEY_MAX_SHORTCUTS, DEFAULT_MAX_SHORTCUTS_PER_APP);
mMaxDynamicShortcuts = Math.max(0, (int) parser.getLong(
ConfigConstants.KEY_MAX_SHORTCUTS, DEFAULT_MAX_SHORTCUTS_PER_APP));
final int iconDimensionDp = injectIsLowRamDevice()
final int iconDimensionDp = Math.max(1, injectIsLowRamDevice()
? (int) parser.getLong(
ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM,
DEFAULT_MAX_ICON_DIMENSION_LOWRAM_DP)
: (int) parser.getLong(
ConfigConstants.KEY_MAX_ICON_DIMENSION_DP,
DEFAULT_MAX_ICON_DIMENSION_DP);
DEFAULT_MAX_ICON_DIMENSION_DP));
mMaxIconDimension = injectDipToPixel(iconDimensionDp);
@@ -1128,7 +1128,7 @@ public class ShortcutService extends IShortcutService.Stub {
if (injectGetPackageUid(packageName, userId) == injectBinderCallingUid()) {
return; // Caller is valid.
}
throw new SecurityException("Caller UID= doesn't own " + packageName);
throw new SecurityException("Calling package name mismatch");
}
void postToHandler(Runnable r) {
@@ -1425,6 +1425,8 @@ public class ShortcutService extends IShortcutService.Stub {
@Override
public int getIconMaxDimensions(String packageName, int userId) throws RemoteException {
verifyCaller(packageName, userId);
synchronized (mLock) {
return mMaxIconDimension;
}
@@ -1445,7 +1447,15 @@ public class ShortcutService extends IShortcutService.Stub {
getUserShortcutsLocked(userId).resetThrottling();
}
scheduleSaveUser(userId);
Slog.i(TAG, "ShortcutManager: throttling counter reset");
Slog.i(TAG, "ShortcutManager: throttling counter reset for user " + userId);
}
void resetAllThrottlingInner() {
synchronized (mLock) {
mRawLastResetTime = injectCurrentTimeMillis();
}
scheduleSaveBaseState();
Slog.i(TAG, "ShortcutManager: throttling counter reset for all users");
}
// We override this method in unit tests to do a simpler check.
@@ -1528,14 +1538,20 @@ public class ShortcutService extends IShortcutService.Stub {
// === House keeping ===
@VisibleForTesting
void cleanUpPackageLocked(String packageName, int owningUserId, int packageUserId) {
cleanUpPackageLocked(packageName, owningUserId, packageUserId,
/* forceForCommandLine= */ false);
}
/**
* Remove all the information associated with a package. This will really remove all the
* information, including the restore information (i.e. it'll remove packages even if they're
* shadow).
*/
@VisibleForTesting
void cleanUpPackageLocked(String packageName, int owningUserId, int packageUserId) {
if (isPackageInstalled(packageName, packageUserId)) {
private void cleanUpPackageLocked(String packageName, int owningUserId, int packageUserId,
boolean forceForCommandLine) {
if (!forceForCommandLine && isPackageInstalled(packageName, packageUserId)) {
wtf("Package " + packageName + " is still installed for user " + packageUserId);
return;
}
@@ -1863,9 +1879,15 @@ public class ShortcutService extends IShortcutService.Stub {
Slog.d(TAG, String.format("handlePackageRemoved: %s user=%d", packageName,
packageUserId));
}
handlePackageRemovedInner(packageName, packageUserId, /* forceForCommandLine =*/ false);
}
private void handlePackageRemovedInner(String packageName, @UserIdInt int packageUserId,
boolean forceForCommandLine) {
synchronized (mLock) {
forEachLoadedUserLocked(user ->
cleanUpPackageLocked(packageName, user.getUserId(), packageUserId));
cleanUpPackageLocked(packageName, user.getUserId(), packageUserId,
forceForCommandLine));
}
}
@@ -2046,17 +2068,26 @@ public class ShortcutService extends IShortcutService.Stub {
pw.print(formatTime(next));
pw.println();
pw.print(" Max icon dim: ");
pw.print(mMaxIconDimension);
pw.print(" Icon format: ");
pw.print(mIconPersistFormat);
pw.print(" Icon quality: ");
pw.print(" Config:");
pw.print(" Max icon dim: ");
pw.println(mMaxIconDimension);
pw.print(" Icon format: ");
pw.println(mIconPersistFormat);
pw.print(" Icon quality: ");
pw.println(mIconPersistQuality);
pw.print(" saveDelayMillis:");
pw.println(mSaveDelayMillis);
pw.print(" resetInterval:");
pw.println(mResetInterval);
pw.print(" maxDailyUpdates:");
pw.println(mMaxDailyUpdates);
pw.print(" maxDynamicShortcuts:");
pw.println(mMaxDynamicShortcuts);
pw.println();
pw.println(" Stats:");
synchronized (mStatLock) {
final String p = " ";
final String p = " ";
dumpStatLS(pw, p, Stats.GET_DEFAULT_HOME, "getHomeActivities()");
dumpStatLS(pw, p, Stats.LAUNCHER_PERMISSION_CHECK, "Launcher permission check");
@@ -2142,6 +2173,9 @@ public class ShortcutService extends IShortcutService.Stub {
case "reset-throttling":
handleResetThrottling();
break;
case "reset-all-throttling":
handleResetAllThrottling();
break;
case "override-config":
handleOverrideConfig();
break;
@@ -2160,6 +2194,9 @@ public class ShortcutService extends IShortcutService.Stub {
case "unload-user":
handleUnloadUser();
break;
case "clear-shortcuts":
handleClearShortcuts();
break;
default:
return handleDefaultCommands(cmd);
}
@@ -2179,9 +2216,12 @@ public class ShortcutService extends IShortcutService.Stub {
pw.println("cmd shortcut reset-package-throttling [--user USER_ID] PACKAGE");
pw.println(" Reset throttling for a package");
pw.println();
pw.println("cmd shortcut reset-throttling");
pw.println("cmd shortcut reset-throttling [--user USER_ID]");
pw.println(" Reset throttling for all packages and users");
pw.println();
pw.println("cmd shortcut reset-all-throttling");
pw.println(" Reset the throttling state for all users");
pw.println();
pw.println("cmd shortcut override-config CONFIG");
pw.println(" Override the configuration for testing (will last until reboot)");
pw.println();
@@ -2201,13 +2241,23 @@ public class ShortcutService extends IShortcutService.Stub {
pw.println(" Unload a user from the memory");
pw.println(" (This should not affect any observable behavior)");
pw.println();
pw.println("cmd shortcut clear-shortcuts [--user USER_ID] PACKAGE");
pw.println(" Remove all shortcuts from a package, including pinned shortcuts");
pw.println();
}
private int handleResetThrottling() throws CommandException {
private void handleResetThrottling() throws CommandException {
parseOptions(/* takeUser =*/ true);
Slog.i(TAG, "cmd: handleResetThrottling");
resetThrottlingInner(mUserId);
return 0;
}
private void handleResetAllThrottling() {
Slog.i(TAG, "cmd: handleResetAllThrottling");
resetAllThrottlingInner();
}
private void handleResetPackageThrottling() throws CommandException {
@@ -2215,6 +2265,8 @@ public class ShortcutService extends IShortcutService.Stub {
final String packageName = getNextArgRequired();
Slog.i(TAG, "cmd: handleResetPackageThrottling: " + packageName);
synchronized (mLock) {
getPackageShortcutsLocked(packageName, mUserId).resetRateLimitingForCommandLine();
saveUserLocked(mUserId);
@@ -2224,6 +2276,8 @@ public class ShortcutService extends IShortcutService.Stub {
private void handleOverrideConfig() throws CommandException {
final String config = getNextArgRequired();
Slog.i(TAG, "cmd: handleOverrideConfig: " + config);
synchronized (mLock) {
if (!updateConfigurationLocked(config)) {
throw new CommandException("override-config failed. See logcat for details.");
@@ -2232,6 +2286,8 @@ public class ShortcutService extends IShortcutService.Stub {
}
private void handleResetConfig() {
Slog.i(TAG, "cmd: handleResetConfig");
synchronized (mLock) {
loadConfigurationLocked();
}
@@ -2276,8 +2332,20 @@ public class ShortcutService extends IShortcutService.Stub {
private void handleUnloadUser() throws CommandException {
parseOptions(/* takeUser =*/ true);
Slog.i(TAG, "cmd: handleUnloadUser: " + mUserId);
ShortcutService.this.handleCleanupUser(mUserId);
}
private void handleClearShortcuts() throws CommandException {
parseOptions(/* takeUser =*/ true);
final String packageName = getNextArgRequired();
Slog.i(TAG, "cmd: handleClearShortcuts: " + mUserId + ", " + packageName);
ShortcutService.this.handlePackageRemovedInner(packageName, mUserId,
/* forceForCommandLine= */ true);
}
}
// === Unit test support ===

View File

@@ -27,7 +27,9 @@ import android.util.Log;
import android.util.SparseArray;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

View File

@@ -19,7 +19,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
easymocklib \
guava \
android-support-test \
mockito-target
mockito-target \
ShortcutManagerTestUtils
LOCAL_JAVA_LIBRARIES := android.test.runner

View File

@@ -27,6 +27,7 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.*;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -608,14 +609,6 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
addPackage(packageName, uid, version, packageName);
}
private <T> List<T> list(T... array) {
return Arrays.asList(array);
}
private <T> Set<T> set(Set<T> in) {
return new ArraySet<T>(in);
}
private Signature[] genSignatures(String... signatures) {
final Signature[] sigs = new Signature[signatures.length];
for (int i = 0; i < signatures.length; i++){
@@ -799,33 +792,6 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
runTestOnUiThread(() -> {});
}
public static Bundle makeBundle(Object... keysAndValues) {
Preconditions.checkState((keysAndValues.length % 2) == 0);
if (keysAndValues.length == 0) {
return null;
}
final Bundle ret = new Bundle();
for (int i = keysAndValues.length - 2; i >= 0; i -= 2) {
final String key = keysAndValues[i].toString();
final Object value = keysAndValues[i + 1];
if (value == null) {
ret.putString(key, null);
} else if (value instanceof Integer) {
ret.putInt(key, (Integer) value);
} else if (value instanceof String) {
ret.putString(key, (String) value);
} else if (value instanceof Bundle) {
ret.putBundle(key, (Bundle) value);
} else {
fail("Type not supported yet: " + value.getClass().getName());
}
}
return ret;
}
/**
* Make a shortcut with an ID.
*/
@@ -923,20 +889,6 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
return new ComponentName(mClientContext, clazz);
}
private <T> Set<T> makeSet(T... values) {
final HashSet<T> ret = new HashSet<>();
for (T s : values) {
ret.add(s);
}
return ret;
}
private static void resetAll(Collection<?> mocks) {
for (Object o : mocks) {
reset(o);
}
}
@NonNull
private ShortcutInfo findById(List<ShortcutInfo> list, String id) {
for (ShortcutInfo s : list) {
@@ -957,94 +909,14 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
assertEquals(expectedNextResetTime, mService.getNextResetTimeLocked());
}
@NonNull
private List<ShortcutInfo> assertShortcutIds(@NonNull List<ShortcutInfo> actualShortcuts,
String... expectedIds) {
final HashSet<String> expected = new HashSet<>(list(expectedIds));
final HashSet<String> actual = new HashSet<>();
for (ShortcutInfo s : actualShortcuts) {
actual.add(s.getId());
}
// Compare the sets.
assertEquals(expected, actual);
return actualShortcuts;
}
@NonNull
private List<ShortcutInfo> assertAllHaveIntents(
@NonNull List<ShortcutInfo> actualShortcuts) {
for (ShortcutInfo s : actualShortcuts) {
assertNotNull("ID " + s.getId(), s.getIntent());
}
return actualShortcuts;
}
@NonNull
private List<ShortcutInfo> assertAllNotHaveIntents(
@NonNull List<ShortcutInfo> actualShortcuts) {
for (ShortcutInfo s : actualShortcuts) {
assertNull("ID " + s.getId(), s.getIntent());
}
return actualShortcuts;
}
@NonNull
private List<ShortcutInfo> assertAllHaveTitle(
@NonNull List<ShortcutInfo> actualShortcuts) {
for (ShortcutInfo s : actualShortcuts) {
assertNotNull("ID " + s.getId(), s.getTitle());
}
return actualShortcuts;
}
@NonNull
private List<ShortcutInfo> assertAllNotHaveTitle(
@NonNull List<ShortcutInfo> actualShortcuts) {
for (ShortcutInfo s : actualShortcuts) {
assertNull("ID " + s.getId(), s.getTitle());
}
return actualShortcuts;
}
@NonNull
private List<ShortcutInfo> assertAllNotHaveIcon(
@NonNull List<ShortcutInfo> actualShortcuts) {
public static List<ShortcutInfo> assertAllNotHaveIcon(
List<ShortcutInfo> actualShortcuts) {
for (ShortcutInfo s : actualShortcuts) {
assertNull("ID " + s.getId(), s.getIcon());
}
return actualShortcuts;
}
@NonNull
private List<ShortcutInfo> assertAllHaveIconResId(
@NonNull List<ShortcutInfo> actualShortcuts) {
for (ShortcutInfo s : actualShortcuts) {
assertTrue("ID " + s.getId() + " not have icon res ID", s.hasIconResource());
assertFalse("ID " + s.getId() + " shouldn't have icon FD", s.hasIconFile());
}
return actualShortcuts;
}
@NonNull
private List<ShortcutInfo> assertAllHaveIconFile(
@NonNull List<ShortcutInfo> actualShortcuts) {
for (ShortcutInfo s : actualShortcuts) {
assertFalse("ID " + s.getId() + " shouldn't have icon res ID", s.hasIconResource());
assertTrue("ID " + s.getId() + " not have icon FD", s.hasIconFile());
}
return actualShortcuts;
}
@NonNull
private List<ShortcutInfo> assertAllHaveIcon(
@NonNull List<ShortcutInfo> actualShortcuts) {
for (ShortcutInfo s : actualShortcuts) {
assertTrue("ID " + s.getId() + " has no icon ", s.hasIconFile() || s.hasIconResource());
}
return actualShortcuts;
}
@NonNull
private List<ShortcutInfo> assertAllHaveFlags(@NonNull List<ShortcutInfo> actualShortcuts,
int shortcutFlags) {
@@ -1055,87 +927,6 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
return actualShortcuts;
}
@NonNull
private List<ShortcutInfo> assertAllKeyFieldsOnly(
@NonNull List<ShortcutInfo> actualShortcuts) {
for (ShortcutInfo s : actualShortcuts) {
assertTrue("ID " + s.getId(), s.hasKeyFieldsOnly());
}
return actualShortcuts;
}
@NonNull
private List<ShortcutInfo> assertAllNotKeyFieldsOnly(
@NonNull List<ShortcutInfo> actualShortcuts) {
for (ShortcutInfo s : actualShortcuts) {
assertFalse("ID " + s.getId(), s.hasKeyFieldsOnly());
}
return actualShortcuts;
}
@NonNull
private List<ShortcutInfo> assertAllDynamic(@NonNull List<ShortcutInfo> actualShortcuts) {
return assertAllHaveFlags(actualShortcuts, ShortcutInfo.FLAG_DYNAMIC);
}
@NonNull
private List<ShortcutInfo> assertAllPinned(@NonNull List<ShortcutInfo> actualShortcuts) {
return assertAllHaveFlags(actualShortcuts, ShortcutInfo.FLAG_PINNED);
}
@NonNull
private List<ShortcutInfo> assertAllDynamicOrPinned(
@NonNull List<ShortcutInfo> actualShortcuts) {
for (ShortcutInfo s : actualShortcuts) {
assertTrue("ID " + s.getId(), s.isDynamic() || s.isPinned());
}
return actualShortcuts;
}
private void assertDynamicOnly(ShortcutInfo si) {
assertTrue(si.isDynamic());
assertFalse(si.isPinned());
}
private void assertPinnedOnly(ShortcutInfo si) {
assertFalse(si.isDynamic());
assertTrue(si.isPinned());
}
private void assertDynamicAndPinned(ShortcutInfo si) {
assertTrue(si.isDynamic());
assertTrue(si.isPinned());
}
private void assertBitmapSize(int expectedWidth, int expectedHeight, @NonNull Bitmap bitmap) {
assertEquals("width", expectedWidth, bitmap.getWidth());
assertEquals("height", expectedHeight, bitmap.getHeight());
}
private <T> void assertAllUnique(Collection<T> list) {
final Set<Object> set = new HashSet<>();
for (T item : list) {
if (set.contains(item)) {
fail("Duplicate item found: " + item + " (in the list: " + list + ")");
}
set.add(item);
}
}
@NonNull
private Bitmap pfdToBitmap(@NonNull ParcelFileDescriptor pfd) {
Preconditions.checkNotNull(pfd);
try {
return BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor());
} finally {
IoUtils.closeQuietly(pfd);
}
}
private void assertBundleEmpty(BaseBundle b) {
assertTrue(b == null || b.size() == 0);
}
private ShortcutInfo getPackageShortcut(String packageName, String shortcutId, int userId) {
return mService.getPackageShortcutForTest(packageName, shortcutId, userId);
}
@@ -1718,7 +1509,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
assertFalse(mManager.setDynamicShortcuts(list(si2)));
}
public void testIcons() {
public void testIcons() throws IOException {
final Icon res32x32 = Icon.createWithResource(getTestContext(), R.drawable.black_32x32);
final Icon res64x64 = Icon.createWithResource(getTestContext(), R.drawable.black_64x64);
final Icon res512x512 = Icon.createWithResource(getTestContext(), R.drawable.black_512x512);
@@ -2242,7 +2033,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
getCallingUser())),
"s1", "s3");
TestUtils.assertExpectException(
assertExpectException(
IllegalArgumentException.class, "package name must also be set", () -> {
mLauncherApps.getShortcuts(buildQuery(
/* time =*/ 0, /* package= */ null, list("id"),
@@ -3341,20 +3132,6 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
assertEquals(0, shortcuts.getValue().size());
}
private void assertCallbackNotReceived(LauncherApps.Callback mock) {
verify(mock, times(0)).onShortcutsChanged(anyString(), anyList(),
any(UserHandle.class));
}
private void assertCallbackReceived(LauncherApps.Callback mock,
UserHandle user, String packageName, String... ids) {
ArgumentCaptor<List> shortcutsCaptor = ArgumentCaptor.forClass(List.class);
verify(mock, times(1)).onShortcutsChanged(eq(packageName), shortcutsCaptor.capture(),
eq(user));
assertShortcutIds(shortcutsCaptor.getValue(), ids);
}
public void testLauncherCallback_crossProfile() throws Throwable {
prepareCrossProfileDataSet();
@@ -3724,18 +3501,18 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
// Check the registered packages.
dumpsysOnLogcat();
assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
set(user0.getAllPackages().keySet()));
assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
set(user10.getAllPackages().keySet()));
assertEquals(set(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
hashSet(user0.getAllPackages().keySet()));
assertEquals(set(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
hashSet(user10.getAllPackages().keySet()));
assertEquals(
makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
set(PackageWithUser.of(USER_0, LAUNCHER_1),
PackageWithUser.of(USER_0, LAUNCHER_2)),
set(user0.getAllLaunchers().keySet()));
hashSet(user0.getAllLaunchers().keySet()));
assertEquals(
makeSet(PackageWithUser.of(USER_10, LAUNCHER_1),
set(PackageWithUser.of(USER_10, LAUNCHER_1),
PackageWithUser.of(USER_10, LAUNCHER_2)),
set(user10.getAllLaunchers().keySet()));
hashSet(user10.getAllLaunchers().keySet()));
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
"s0_1", "s0_2");
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
@@ -3756,18 +3533,18 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
mService.cleanUpPackageLocked("abc", USER_0, USER_0);
// No changes.
assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
set(user0.getAllPackages().keySet()));
assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
set(user10.getAllPackages().keySet()));
assertEquals(set(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
hashSet(user0.getAllPackages().keySet()));
assertEquals(set(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
hashSet(user10.getAllPackages().keySet()));
assertEquals(
makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
set(PackageWithUser.of(USER_0, LAUNCHER_1),
PackageWithUser.of(USER_0, LAUNCHER_2)),
set(user0.getAllLaunchers().keySet()));
hashSet(user0.getAllLaunchers().keySet()));
assertEquals(
makeSet(PackageWithUser.of(USER_10, LAUNCHER_1),
set(PackageWithUser.of(USER_10, LAUNCHER_1),
PackageWithUser.of(USER_10, LAUNCHER_2)),
set(user10.getAllLaunchers().keySet()));
hashSet(user10.getAllLaunchers().keySet()));
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
"s0_1", "s0_2");
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
@@ -3787,18 +3564,18 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
uninstallPackage(USER_0, CALLING_PACKAGE_1);
mService.cleanUpPackageLocked(CALLING_PACKAGE_1, USER_0, USER_0);
assertEquals(makeSet(CALLING_PACKAGE_2),
set(user0.getAllPackages().keySet()));
assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
set(user10.getAllPackages().keySet()));
assertEquals(set(CALLING_PACKAGE_2),
hashSet(user0.getAllPackages().keySet()));
assertEquals(set(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
hashSet(user10.getAllPackages().keySet()));
assertEquals(
makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
set(PackageWithUser.of(USER_0, LAUNCHER_1),
PackageWithUser.of(USER_0, LAUNCHER_2)),
set(user0.getAllLaunchers().keySet()));
hashSet(user0.getAllLaunchers().keySet()));
assertEquals(
makeSet(PackageWithUser.of(USER_10, LAUNCHER_1),
set(PackageWithUser.of(USER_10, LAUNCHER_1),
PackageWithUser.of(USER_10, LAUNCHER_2)),
set(user10.getAllLaunchers().keySet()));
hashSet(user10.getAllLaunchers().keySet()));
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
"s0_2");
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
@@ -3818,17 +3595,17 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
uninstallPackage(USER_10, LAUNCHER_1);
mService.cleanUpPackageLocked(LAUNCHER_1, USER_10, USER_10);
assertEquals(makeSet(CALLING_PACKAGE_2),
set(user0.getAllPackages().keySet()));
assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
set(user10.getAllPackages().keySet()));
assertEquals(set(CALLING_PACKAGE_2),
hashSet(user0.getAllPackages().keySet()));
assertEquals(set(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
hashSet(user10.getAllPackages().keySet()));
assertEquals(
makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
set(PackageWithUser.of(USER_0, LAUNCHER_1),
PackageWithUser.of(USER_0, LAUNCHER_2)),
set(user0.getAllLaunchers().keySet()));
hashSet(user0.getAllLaunchers().keySet()));
assertEquals(
makeSet(PackageWithUser.of(USER_10, LAUNCHER_2)),
set(user10.getAllLaunchers().keySet()));
set(PackageWithUser.of(USER_10, LAUNCHER_2)),
hashSet(user10.getAllLaunchers().keySet()));
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
"s0_2");
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
@@ -3846,17 +3623,17 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
uninstallPackage(USER_10, CALLING_PACKAGE_2);
mService.cleanUpPackageLocked(CALLING_PACKAGE_2, USER_10, USER_10);
assertEquals(makeSet(CALLING_PACKAGE_2),
set(user0.getAllPackages().keySet()));
assertEquals(makeSet(CALLING_PACKAGE_1),
set(user10.getAllPackages().keySet()));
assertEquals(set(CALLING_PACKAGE_2),
hashSet(user0.getAllPackages().keySet()));
assertEquals(set(CALLING_PACKAGE_1),
hashSet(user10.getAllPackages().keySet()));
assertEquals(
makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
set(PackageWithUser.of(USER_0, LAUNCHER_1),
PackageWithUser.of(USER_0, LAUNCHER_2)),
set(user0.getAllLaunchers().keySet()));
hashSet(user0.getAllLaunchers().keySet()));
assertEquals(
makeSet(PackageWithUser.of(USER_10, LAUNCHER_2)),
set(user10.getAllLaunchers().keySet()));
set(PackageWithUser.of(USER_10, LAUNCHER_2)),
hashSet(user10.getAllLaunchers().keySet()));
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
"s0_2");
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
@@ -3874,17 +3651,17 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
uninstallPackage(USER_10, LAUNCHER_2);
mService.cleanUpPackageLocked(LAUNCHER_2, USER_10, USER_10);
assertEquals(makeSet(CALLING_PACKAGE_2),
set(user0.getAllPackages().keySet()));
assertEquals(makeSet(CALLING_PACKAGE_1),
set(user10.getAllPackages().keySet()));
assertEquals(set(CALLING_PACKAGE_2),
hashSet(user0.getAllPackages().keySet()));
assertEquals(set(CALLING_PACKAGE_1),
hashSet(user10.getAllPackages().keySet()));
assertEquals(
makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
set(PackageWithUser.of(USER_0, LAUNCHER_1),
PackageWithUser.of(USER_0, LAUNCHER_2)),
set(user0.getAllLaunchers().keySet()));
hashSet(user0.getAllLaunchers().keySet()));
assertEquals(
makeSet(),
set(user10.getAllLaunchers().keySet()));
set(),
hashSet(user10.getAllLaunchers().keySet()));
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
"s0_2");
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
@@ -3902,16 +3679,16 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
uninstallPackage(USER_10, CALLING_PACKAGE_1);
mService.cleanUpPackageLocked(CALLING_PACKAGE_1, USER_10, USER_10);
assertEquals(makeSet(CALLING_PACKAGE_2),
set(user0.getAllPackages().keySet()));
assertEquals(makeSet(),
set(user10.getAllPackages().keySet()));
assertEquals(set(CALLING_PACKAGE_2),
hashSet(user0.getAllPackages().keySet()));
assertEquals(set(),
hashSet(user10.getAllPackages().keySet()));
assertEquals(
makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
set(PackageWithUser.of(USER_0, LAUNCHER_1),
PackageWithUser.of(USER_0, LAUNCHER_2)),
set(user0.getAllLaunchers().keySet()));
assertEquals(makeSet(),
set(user10.getAllLaunchers().keySet()));
hashSet(user0.getAllLaunchers().keySet()));
assertEquals(set(),
hashSet(user10.getAllLaunchers().keySet()));
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
"s0_2");
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
@@ -5052,7 +4829,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
assertShortcutIds(
mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_P0)
/* empty */);
TestUtils.assertExpectException(
assertExpectException(
SecurityException.class, "", () -> {
mLauncherApps.getShortcuts(
buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10);
@@ -5131,7 +4908,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
assertShortcutIds(
mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0),
"s1", "s4");
TestUtils.assertExpectException(
assertExpectException(
SecurityException.class, "unrelated profile", () -> {
mLauncherApps.getShortcuts(
buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10);
@@ -5147,12 +4924,12 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
assertShortcutIds(
mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_10)
/* empty */);
TestUtils.assertExpectException(
assertExpectException(
SecurityException.class, "unrelated profile", () -> {
mLauncherApps.getShortcuts(
buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0);
});
TestUtils.assertExpectException(
assertExpectException(
SecurityException.class, "unrelated profile", () -> {
mLauncherApps.getShortcuts(
buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_P0);
@@ -5163,16 +4940,16 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
// ShortcutInfo tests
public void testShortcutInfoMissingMandatoryFields() {
TestUtils.assertExpectException(
assertExpectException(
IllegalArgumentException.class,
"ID must be provided",
() -> new ShortcutInfo.Builder(getTestContext()).build());
TestUtils.assertExpectException(
assertExpectException(
IllegalArgumentException.class,
"title must be provided",
() -> new ShortcutInfo.Builder(getTestContext()).setId("id").build()
.enforceMandatoryFields());
TestUtils.assertExpectException(
assertExpectException(
NullPointerException.class,
"Intent must be provided",
() -> new ShortcutInfo.Builder(getTestContext()).setId("id").setTitle("x").build()
@@ -5493,7 +5270,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
dumpsysOnLogcat("test1", /* force= */ true);
}
public void testDumpsys_withIcons() {
public void testDumpsys_withIcons() throws IOException {
testIcons();
// Dump after having some icons.
dumpsysOnLogcat("test1", /* force= */ true);

View File

@@ -0,0 +1,31 @@
# Copyright (C) 2016 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
$(call all-java-files-under, src)
LOCAL_STATIC_JAVA_LIBRARIES := \
mockito-target
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := ShortcutManagerTestUtils
LOCAL_SDK_VERSION := current
include $(BUILD_STATIC_JAVA_LIBRARY)

View File

@@ -0,0 +1,506 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.pm.shortcutmanagertest;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyList;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.app.Instrumentation;
import android.content.Context;
import android.content.pm.LauncherApps;
import android.content.pm.ShortcutInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.BaseBundle;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.UserHandle;
import android.test.MoreAsserts;
import android.util.Log;
import junit.framework.Assert;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.mockito.Mockito;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.BooleanSupplier;
import java.util.function.Function;
import java.util.function.Predicate;
public class ShortcutManagerTestUtils {
private static final String TAG = "ShortcutManagerUtils";
private static final boolean ENABLE_DUMPSYS = true; // DO NOT SUBMIT WITH true
private static final int STANDARD_TIMEOUT_SEC = 5;
private ShortcutManagerTestUtils() {
}
private static List<String> readAll(ParcelFileDescriptor pfd) {
try {
try {
final ArrayList<String> ret = new ArrayList<>();
try (BufferedReader r = new BufferedReader(
new FileReader(pfd.getFileDescriptor()))) {
String line;
while ((line = r.readLine()) != null) {
ret.add(line);
}
r.readLine();
}
return ret;
} finally {
pfd.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static String concatResult(List<String> result) {
final StringBuilder sb = new StringBuilder();
for (String s : result) {
sb.append(s);
sb.append("\n");
}
return sb.toString();
}
private static List<String> runCommand(Instrumentation instrumentation, String command) {
return runCommand(instrumentation, command, null);
}
private static List<String> runCommand(Instrumentation instrumentation, String command,
Predicate<List<String>> resultAsserter) {
Log.d(TAG, "Running command: " + command);
final List<String> result;
try {
result = readAll(
instrumentation.getUiAutomation().executeShellCommand(command));
} catch (Exception e) {
throw new RuntimeException(e);
}
if (resultAsserter != null && !resultAsserter.test(result)) {
fail("Command '" + command + "' failed, output was:\n" + concatResult(result));
}
return result;
}
private static void runCommandForNoOutput(Instrumentation instrumentation, String command) {
runCommand(instrumentation, command, result -> result.size() == 0);
}
private static List<String> runShortcutCommand(Instrumentation instrumentation, String command,
Predicate<List<String>> resultAsserter) {
return runCommand(instrumentation, "cmd shortcut " + command, resultAsserter);
}
public static List<String> runShortcutCommandForSuccess(Instrumentation instrumentation,
String command) {
return runShortcutCommand(instrumentation, command, result -> result.contains("Success"));
}
public static String getDefaultLauncher(Instrumentation instrumentation) {
final String PREFIX = "Launcher: ComponentInfo{";
final String POSTFIX = "}";
final List<String> result = runShortcutCommandForSuccess(
instrumentation, "get-default-launcher");
for (String s : result) {
if (s.startsWith(PREFIX) && s.endsWith(POSTFIX)) {
return s.substring(PREFIX.length(), s.length() - POSTFIX.length());
}
}
fail("Default launcher not found");
return null;
}
public static void setDefaultLauncher(Instrumentation instrumentation, String component) {
runCommandForNoOutput(instrumentation, "cmd package set-home-activity " + component);
}
public static void setDefaultLauncher(Instrumentation instrumentation, Context packageContext) {
setDefaultLauncher(instrumentation, packageContext.getPackageName()
+ "/android.content.pm.cts.shortcutmanager.packages.Launcher");
}
public static void overrideConfig(Instrumentation instrumentation, String config) {
runShortcutCommandForSuccess(instrumentation, "override-config " + config);
}
public static void resetConfig(Instrumentation instrumentation) {
runShortcutCommandForSuccess(instrumentation, "reset-config");
}
public static void resetThrottling(Instrumentation instrumentation) {
runShortcutCommandForSuccess(instrumentation, "reset-throttling");
}
public static void resetAllThrottling(Instrumentation instrumentation) {
runShortcutCommandForSuccess(instrumentation, "reset-all-throttling");
}
public static void clearShortcuts(Instrumentation instrumentation, int userId,
String packageName) {
runShortcutCommandForSuccess(instrumentation, "clear-shortcuts "
+ " --user " + userId + " " + packageName);
}
public static void dumpsysShortcut(Instrumentation instrumentation) {
if (!ENABLE_DUMPSYS) {
return;
}
for (String s : runCommand(instrumentation, "dumpsys shortcut")) {
Log.e(TAG, s);
}
}
public static Bundle makeBundle(Object... keysAndValues) {
assertTrue((keysAndValues.length % 2) == 0);
if (keysAndValues.length == 0) {
return null;
}
final Bundle ret = new Bundle();
for (int i = keysAndValues.length - 2; i >= 0; i -= 2) {
final String key = keysAndValues[i].toString();
final Object value = keysAndValues[i + 1];
if (value == null) {
ret.putString(key, null);
} else if (value instanceof Integer) {
ret.putInt(key, (Integer) value);
} else if (value instanceof String) {
ret.putString(key, (String) value);
} else if (value instanceof Bundle) {
ret.putBundle(key, (Bundle) value);
} else {
fail("Type not supported yet: " + value.getClass().getName());
}
}
return ret;
}
public static <T> List<T> list(T... array) {
return Arrays.asList(array);
}
public static <T> Set<T> hashSet(Set<T> in) {
return new HashSet<T>(in);
}
public static <T> Set<T> set(T... values) {
return set(v -> v, values);
}
public static <T, V> Set<T> set(Function<V, T> converter, V... values) {
return set(converter, Arrays.asList(values));
}
public static <T, V> Set<T> set(Function<V, T> converter, List<V> values) {
final HashSet<T> ret = new HashSet<>();
for (V v : values) {
ret.add(converter.apply(v));
}
return ret;
}
public static void resetAll(Collection<?> mocks) {
for (Object o : mocks) {
reset(o);
}
}
public static void assertExpectException(Class<? extends Throwable> expectedExceptionType,
String expectedExceptionMessageRegex, Runnable r) {
assertExpectException("", expectedExceptionType, expectedExceptionMessageRegex, r);
}
public static void assertDynamicShortcutCountExceeded(Runnable r) {
assertExpectException(IllegalArgumentException.class,
"Max number of dynamic shortcuts exceeded", r);
}
public static void assertExpectException(String message,
Class<? extends Throwable> expectedExceptionType,
String expectedExceptionMessageRegex, Runnable r) {
try {
r.run();
Assert.fail("Expected exception type " + expectedExceptionType.getName()
+ " was not thrown (message=" + message + ")");
} catch (Throwable e) {
Assert.assertTrue(
"Expected exception type was " + expectedExceptionType.getName()
+ " but caught " + e + " (message=" + message + ")",
expectedExceptionType.isAssignableFrom(e.getClass()));
if (expectedExceptionMessageRegex != null) {
MoreAsserts.assertContainsRegex(expectedExceptionMessageRegex, e.getMessage());
}
}
}
public static List<ShortcutInfo> assertShortcutIds(List<ShortcutInfo> actualShortcuts,
String... expectedIds) {
final HashSet<String> expected = new HashSet<>(list(expectedIds));
final HashSet<String> actual = new HashSet<>();
for (ShortcutInfo s : actualShortcuts) {
actual.add(s.getId());
}
// Compare the sets.
assertEquals(expected, actual);
return actualShortcuts;
}
public static List<ShortcutInfo> assertAllHaveIntents(
List<ShortcutInfo> actualShortcuts) {
for (ShortcutInfo s : actualShortcuts) {
assertNotNull("ID " + s.getId(), s.getIntent());
}
return actualShortcuts;
}
public static List<ShortcutInfo> assertAllNotHaveIntents(
List<ShortcutInfo> actualShortcuts) {
for (ShortcutInfo s : actualShortcuts) {
assertNull("ID " + s.getId(), s.getIntent());
}
return actualShortcuts;
}
public static List<ShortcutInfo> assertAllHaveTitle(
List<ShortcutInfo> actualShortcuts) {
for (ShortcutInfo s : actualShortcuts) {
assertNotNull("ID " + s.getId(), s.getTitle());
}
return actualShortcuts;
}
public static List<ShortcutInfo> assertAllNotHaveTitle(
List<ShortcutInfo> actualShortcuts) {
for (ShortcutInfo s : actualShortcuts) {
assertNull("ID " + s.getId(), s.getTitle());
}
return actualShortcuts;
}
public static List<ShortcutInfo> assertAllHaveIconResId(
List<ShortcutInfo> actualShortcuts) {
for (ShortcutInfo s : actualShortcuts) {
assertTrue("ID " + s.getId() + " not have icon res ID", s.hasIconResource());
assertFalse("ID " + s.getId() + " shouldn't have icon FD", s.hasIconFile());
}
return actualShortcuts;
}
public static List<ShortcutInfo> assertAllHaveIconFile(
List<ShortcutInfo> actualShortcuts) {
for (ShortcutInfo s : actualShortcuts) {
assertFalse("ID " + s.getId() + " shouldn't have icon res ID", s.hasIconResource());
assertTrue("ID " + s.getId() + " not have icon FD", s.hasIconFile());
}
return actualShortcuts;
}
public static List<ShortcutInfo> assertAllHaveIcon(
List<ShortcutInfo> actualShortcuts) {
for (ShortcutInfo s : actualShortcuts) {
assertTrue("ID " + s.getId() + " has no icon ", s.hasIconFile() || s.hasIconResource());
}
return actualShortcuts;
}
public static List<ShortcutInfo> assertAllKeyFieldsOnly(
List<ShortcutInfo> actualShortcuts) {
for (ShortcutInfo s : actualShortcuts) {
assertTrue("ID " + s.getId(), s.hasKeyFieldsOnly());
}
return actualShortcuts;
}
public static List<ShortcutInfo> assertAllNotKeyFieldsOnly(
List<ShortcutInfo> actualShortcuts) {
for (ShortcutInfo s : actualShortcuts) {
assertFalse("ID " + s.getId(), s.hasKeyFieldsOnly());
}
return actualShortcuts;
}
public static List<ShortcutInfo> assertAllDynamic(List<ShortcutInfo> actualShortcuts) {
for (ShortcutInfo s : actualShortcuts) {
assertTrue("ID " + s.getId(), s.isDynamic());
}
return actualShortcuts;
}
public static List<ShortcutInfo> assertAllPinned(List<ShortcutInfo> actualShortcuts) {
for (ShortcutInfo s : actualShortcuts) {
assertTrue("ID " + s.getId(), s.isPinned());
}
return actualShortcuts;
}
public static List<ShortcutInfo> assertAllDynamicOrPinned(
List<ShortcutInfo> actualShortcuts) {
for (ShortcutInfo s : actualShortcuts) {
assertTrue("ID " + s.getId(), s.isDynamic() || s.isPinned());
}
return actualShortcuts;
}
public static void assertDynamicOnly(ShortcutInfo si) {
assertTrue(si.isDynamic());
assertFalse(si.isPinned());
}
public static void assertPinnedOnly(ShortcutInfo si) {
assertFalse(si.isDynamic());
assertTrue(si.isPinned());
}
public static void assertDynamicAndPinned(ShortcutInfo si) {
assertTrue(si.isDynamic());
assertTrue(si.isPinned());
}
public static void assertBitmapSize(int expectedWidth, int expectedHeight, Bitmap bitmap) {
assertEquals("width", expectedWidth, bitmap.getWidth());
assertEquals("height", expectedHeight, bitmap.getHeight());
}
public static <T> void assertAllUnique(Collection<T> list) {
final Set<Object> set = new HashSet<>();
for (T item : list) {
if (set.contains(item)) {
fail("Duplicate item found: " + item + " (in the list: " + list + ")");
}
set.add(item);
}
}
public static Bitmap pfdToBitmap(ParcelFileDescriptor pfd) {
assertNotNull(pfd);
try {
try {
return BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor());
} finally {
pfd.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static void assertBundleEmpty(BaseBundle b) {
assertTrue(b == null || b.size() == 0);
}
public static void assertCallbackNotReceived(LauncherApps.Callback mock) {
verify(mock, times(0)).onShortcutsChanged(anyString(), anyList(),
any(UserHandle.class));
}
public static void assertCallbackReceived(LauncherApps.Callback mock,
UserHandle user, String packageName, String... ids) {
verify(mock).onShortcutsChanged(eq(packageName), checkShortcutIds(ids),
eq(user));
}
public static boolean checkAssertSuccess(Runnable r) {
try {
r.run();
return true;
} catch (AssertionError e) {
return false;
}
}
public static <T> T checkArgument(Predicate<T> checker, String description,
List<T> matchedCaptor) {
final Matcher<T> m = new BaseMatcher<T>() {
@Override
public boolean matches(Object item) {
if (item == null) {
return false;
}
final T value = (T) item;
if (!checker.test(value)) {
return false;
}
if (matchedCaptor != null) {
matchedCaptor.add(value);
}
return true;
}
@Override
public void describeTo(Description d) {
d.appendText(description);
}
};
return Mockito.argThat(m);
}
public static List<ShortcutInfo> checkShortcutIds(String... ids) {
return checkArgument((List<ShortcutInfo> list) -> {
final Set<String> actualSet = set(si -> si.getId(), list);
return actualSet.equals(set(ids));
}, "Shortcut IDs=[" + Arrays.toString(ids) + "]", null);
}
public static void waitUntil(String message, BooleanSupplier condition) {
waitUntil(message, condition, STANDARD_TIMEOUT_SEC);
}
public static void waitUntil(String message, BooleanSupplier condition, int timeoutSeconds) {
final long timeout = System.currentTimeMillis() + (timeoutSeconds * 1000L);
while (System.currentTimeMillis() < timeout) {
if (condition.getAsBoolean()) {
return;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
fail("Timed out for: " + message);
}
}