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:
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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 ===
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -19,7 +19,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
|
||||
easymocklib \
|
||||
guava \
|
||||
android-support-test \
|
||||
mockito-target
|
||||
mockito-target \
|
||||
ShortcutManagerTestUtils
|
||||
|
||||
LOCAL_JAVA_LIBRARIES := android.test.runner
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
31
services/tests/shortcutmanagerutils/Android.mk
Normal file
31
services/tests/shortcutmanagerutils/Android.mk
Normal 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)
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user