Merge "Support multi-launcher" into nyc-dev
This commit is contained in:
@@ -524,7 +524,7 @@ public class ShortcutInfo implements Parcelable {
|
||||
}
|
||||
|
||||
/** @hide*/
|
||||
public void setFlags(@ShortcutFlags int flags) {
|
||||
public void replaceFlags(@ShortcutFlags int flags) {
|
||||
mFlags = flags;
|
||||
}
|
||||
|
||||
|
||||
@@ -159,6 +159,8 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
static final String TAG_EXTRAS = "extras";
|
||||
static final String TAG_SHORTCUT = "shortcut";
|
||||
static final String TAG_LAUNCHER = "launcher";
|
||||
static final String TAG_PIN = "pin";
|
||||
static final String TAG_LAUNCHER_PINS = "launcher-pins";
|
||||
|
||||
static final String ATTR_VALUE = "value";
|
||||
static final String ATTR_NAME = "name";
|
||||
@@ -174,6 +176,7 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
static final String ATTR_FLAGS = "flags";
|
||||
static final String ATTR_ICON_RES = "icon-res";
|
||||
static final String ATTR_BITMAP_PATH = "bitmap-path";
|
||||
static final String ATTR_PACKAGE_NAME = "package-name";
|
||||
|
||||
@VisibleForTesting
|
||||
interface ConfigConstants {
|
||||
@@ -723,7 +726,7 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
/** Return the per-user state. */
|
||||
@GuardedBy("mLock")
|
||||
@NonNull
|
||||
private UserShortcuts getUserShortcutsLocked(@UserIdInt int userId) {
|
||||
UserShortcuts getUserShortcutsLocked(@UserIdInt int userId) {
|
||||
UserShortcuts userPackages = mUsers.get(userId);
|
||||
if (userPackages == null) {
|
||||
userPackages = loadUserLocked(userId);
|
||||
@@ -738,15 +741,16 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
/** Return the per-user per-package state. */
|
||||
@GuardedBy("mLock")
|
||||
@NonNull
|
||||
private PackageShortcuts getPackageShortcutsLocked(
|
||||
PackageShortcuts getPackageShortcutsLocked(
|
||||
@NonNull String packageName, @UserIdInt int userId) {
|
||||
final UserShortcuts userPackages = getUserShortcutsLocked(userId);
|
||||
PackageShortcuts shortcuts = userPackages.getPackages().get(packageName);
|
||||
if (shortcuts == null) {
|
||||
shortcuts = new PackageShortcuts(userId, packageName);
|
||||
userPackages.getPackages().put(packageName, shortcuts);
|
||||
}
|
||||
return shortcuts;
|
||||
return getUserShortcutsLocked(userId).getPackageShortcuts(packageName);
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
@NonNull
|
||||
LauncherShortcuts getLauncherShortcuts(
|
||||
@NonNull String packageName, @UserIdInt int userId) {
|
||||
return getUserShortcutsLocked(userId).getLauncherShortcuts(packageName);
|
||||
}
|
||||
|
||||
// === Caller validation ===
|
||||
@@ -1057,7 +1061,7 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
validatePersistableBundleForXml(shortcut.getIntentPersistableExtras());
|
||||
validatePersistableBundleForXml(shortcut.getExtras());
|
||||
|
||||
shortcut.setFlags(0);
|
||||
shortcut.replaceFlags(0);
|
||||
}
|
||||
|
||||
// KXmlSerializer is strict and doesn't allow certain characters, so we disallow those
|
||||
@@ -1129,8 +1133,7 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
// Then, add/update all. We need to make sure to take over "pinned" flag.
|
||||
for (int i = 0; i < size; i++) {
|
||||
final ShortcutInfo newShortcut = newShortcuts.get(i);
|
||||
newShortcut.addFlags(ShortcutInfo.FLAG_DYNAMIC);
|
||||
ps.updateShortcutWithCapping(this, newShortcut);
|
||||
ps.addDynamicShortcut(this, newShortcut);
|
||||
}
|
||||
}
|
||||
userPackageChanged(packageName, userId);
|
||||
@@ -1194,8 +1197,7 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
fixUpIncomingShortcutInfo(newShortcut, /* forUpdate= */ false);
|
||||
|
||||
// Add it.
|
||||
newShortcut.addFlags(ShortcutInfo.FLAG_DYNAMIC);
|
||||
ps.updateShortcutWithCapping(this, newShortcut);
|
||||
ps.addDynamicShortcut(this, newShortcut);
|
||||
}
|
||||
userPackageChanged(packageName, userId);
|
||||
|
||||
@@ -1251,7 +1253,8 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
|
||||
final ArrayList<ShortcutInfo> ret = new ArrayList<>();
|
||||
|
||||
getPackageShortcutsLocked(packageName, userId).findAll(ret, query, cloneFlags);
|
||||
getPackageShortcutsLocked(packageName, userId).findAll(this, ret, query, cloneFlags,
|
||||
/* callingLauncher= */ null);
|
||||
|
||||
return new ParceledListSlice<>(ret);
|
||||
}
|
||||
@@ -1406,25 +1409,27 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
|
||||
synchronized (mLock) {
|
||||
if (packageName != null) {
|
||||
getShortcutsInnerLocked(packageName, changedSince, componentName, queryFlags,
|
||||
userId, ret, cloneFlag);
|
||||
getShortcutsInnerLocked(
|
||||
callingPackage, packageName, changedSince,
|
||||
componentName, queryFlags, userId, ret, cloneFlag);
|
||||
} else {
|
||||
final ArrayMap<String, PackageShortcuts> packages =
|
||||
getUserShortcutsLocked(userId).getPackages();
|
||||
for (int i = packages.size() - 1; i >= 0; i--) {
|
||||
getShortcutsInnerLocked(
|
||||
packages.keyAt(i),
|
||||
changedSince, componentName, queryFlags, userId, ret, cloneFlag);
|
||||
callingPackage, packages.keyAt(i), changedSince,
|
||||
componentName, queryFlags, userId, ret, cloneFlag);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private void getShortcutsInnerLocked(@Nullable String packageName,long changedSince,
|
||||
private void getShortcutsInnerLocked(@NonNull String callingPackage,
|
||||
@Nullable String packageName,long changedSince,
|
||||
@Nullable ComponentName componentName, int queryFlags,
|
||||
int userId, ArrayList<ShortcutInfo> ret, int cloneFlag) {
|
||||
getPackageShortcutsLocked(packageName, userId).findAll(ret,
|
||||
getPackageShortcutsLocked(packageName, userId).findAll(ShortcutService.this, ret,
|
||||
(ShortcutInfo si) -> {
|
||||
if (si.getLastChangedTimestamp() < changedSince) {
|
||||
return false;
|
||||
@@ -1435,12 +1440,12 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
}
|
||||
final boolean matchDynamic =
|
||||
((queryFlags & ShortcutQuery.FLAG_GET_DYNAMIC) != 0)
|
||||
&& si.isDynamic();
|
||||
&& si.isDynamic();
|
||||
final boolean matchPinned =
|
||||
((queryFlags & ShortcutQuery.FLAG_GET_PINNED) != 0)
|
||||
&& si.isPinned();
|
||||
return matchDynamic || matchPinned;
|
||||
}, cloneFlag);
|
||||
}, cloneFlag, callingPackage);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1453,9 +1458,10 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
final ArrayList<ShortcutInfo> ret = new ArrayList<>(ids.size());
|
||||
final ArraySet<String> idSet = new ArraySet<>(ids);
|
||||
synchronized (mLock) {
|
||||
getPackageShortcutsLocked(packageName, userId).findAll(ret,
|
||||
getPackageShortcutsLocked(packageName, userId).findAll(
|
||||
ShortcutService.this, ret,
|
||||
(ShortcutInfo si) -> idSet.contains(si.getId()),
|
||||
ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
|
||||
ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER, callingPackage);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -1468,8 +1474,8 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
Preconditions.checkNotNull(shortcutIds, "shortcutIds");
|
||||
|
||||
synchronized (mLock) {
|
||||
getPackageShortcutsLocked(packageName, userId).replacePinned(
|
||||
ShortcutService.this, callingPackage, shortcutIds);
|
||||
getLauncherShortcuts(callingPackage, userId).pinShortcuts(
|
||||
ShortcutService.this, packageName, shortcutIds);
|
||||
}
|
||||
userPackageChanged(packageName, userId);
|
||||
}
|
||||
@@ -1812,6 +1818,14 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
|
||||
final void wtf(String message) {
|
||||
Slog.wtf(TAG, message, /* exception= */ null);
|
||||
}
|
||||
|
||||
void wtf(String message, Exception e) {
|
||||
Slog.wtf(TAG, message, e);
|
||||
}
|
||||
|
||||
File injectSystemDataPath() {
|
||||
return Environment.getDataSystemDirectory();
|
||||
}
|
||||
@@ -1887,6 +1901,8 @@ class UserShortcuts {
|
||||
|
||||
private final ArrayMap<String, PackageShortcuts> mPackages = new ArrayMap<>();
|
||||
|
||||
private final ArrayMap<String, LauncherShortcuts> mLaunchers = new ArrayMap<>();
|
||||
|
||||
private ComponentName mLauncherComponent;
|
||||
|
||||
public UserShortcuts(int userId) {
|
||||
@@ -1897,13 +1913,41 @@ class UserShortcuts {
|
||||
return mPackages;
|
||||
}
|
||||
|
||||
public ArrayMap<String, LauncherShortcuts> getLaunchers() {
|
||||
return mLaunchers;
|
||||
}
|
||||
|
||||
public PackageShortcuts getPackageShortcuts(@NonNull String packageName) {
|
||||
PackageShortcuts ret = mPackages.get(packageName);
|
||||
if (ret == null) {
|
||||
ret = new PackageShortcuts(mUserId, packageName);
|
||||
mPackages.put(packageName, ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public LauncherShortcuts getLauncherShortcuts(@NonNull String packageName) {
|
||||
LauncherShortcuts ret = mLaunchers.get(packageName);
|
||||
if (ret == null) {
|
||||
ret = new LauncherShortcuts(mUserId, packageName);
|
||||
mLaunchers.put(packageName, ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
|
||||
out.startTag(null, ShortcutService.TAG_USER);
|
||||
|
||||
ShortcutService.writeTagValue(out, ShortcutService.TAG_LAUNCHER,
|
||||
mLauncherComponent);
|
||||
|
||||
for (int i = 0; i < mPackages.size(); i++) {
|
||||
final int lsize = mLaunchers.size();
|
||||
for (int i = 0; i < lsize; i++) {
|
||||
mLaunchers.valueAt(i).saveToXml(out);
|
||||
}
|
||||
|
||||
final int psize = mPackages.size();
|
||||
for (int i = 0; i < psize; i++) {
|
||||
mPackages.valueAt(i).saveToXml(out);
|
||||
}
|
||||
|
||||
@@ -1924,16 +1968,26 @@ class UserShortcuts {
|
||||
final int depth = parser.getDepth();
|
||||
final String tag = parser.getName();
|
||||
switch (tag) {
|
||||
case ShortcutService.TAG_LAUNCHER:
|
||||
case ShortcutService.TAG_LAUNCHER: {
|
||||
ret.mLauncherComponent = ShortcutService.parseComponentNameAttribute(
|
||||
parser, ShortcutService.ATTR_VALUE);
|
||||
continue;
|
||||
case ShortcutService.TAG_PACKAGE:
|
||||
}
|
||||
case ShortcutService.TAG_PACKAGE: {
|
||||
final PackageShortcuts shortcuts = PackageShortcuts.loadFromXml(parser, userId);
|
||||
|
||||
// Don't use addShortcut(), we don't need to save the icon.
|
||||
ret.getPackages().put(shortcuts.mPackageName, shortcuts);
|
||||
continue;
|
||||
}
|
||||
|
||||
case ShortcutService.TAG_LAUNCHER_PINS: {
|
||||
final LauncherShortcuts shortcuts =
|
||||
LauncherShortcuts.loadFromXml(parser, userId);
|
||||
|
||||
ret.getLaunchers().put(shortcuts.mPackageName, shortcuts);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
throw ShortcutService.throwForInvalidTag(depth, tag);
|
||||
}
|
||||
@@ -1970,12 +2024,166 @@ class UserShortcuts {
|
||||
pw.print(mLauncherComponent);
|
||||
pw.println();
|
||||
|
||||
for (int i = 0; i < mLaunchers.size(); i++) {
|
||||
mLaunchers.valueAt(i).dump(s, pw, prefix + " ");
|
||||
}
|
||||
|
||||
for (int i = 0; i < mPackages.size(); i++) {
|
||||
mPackages.valueAt(i).dump(s, pw, prefix + " ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class LauncherShortcuts {
|
||||
private static final String TAG = ShortcutService.TAG;
|
||||
|
||||
@UserIdInt
|
||||
final int mUserId;
|
||||
|
||||
@NonNull
|
||||
final String mPackageName;
|
||||
|
||||
/**
|
||||
* Package name -> IDs.
|
||||
*/
|
||||
final private ArrayMap<String, ArraySet<String>> mPinnedShortcuts = new ArrayMap<>();
|
||||
|
||||
LauncherShortcuts(@UserIdInt int userId, @NonNull String packageName) {
|
||||
mUserId = userId;
|
||||
mPackageName = packageName;
|
||||
}
|
||||
|
||||
public void pinShortcuts(@NonNull ShortcutService s, @NonNull String packageName,
|
||||
@NonNull List<String> ids) {
|
||||
final int idSize = ids.size();
|
||||
if (idSize == 0) {
|
||||
mPinnedShortcuts.remove(packageName);
|
||||
} else {
|
||||
final ArraySet<String> prevSet = mPinnedShortcuts.get(packageName);
|
||||
|
||||
// Pin shortcuts. Make sure only pin the ones that were visible to the caller.
|
||||
// i.e. a non-dynamic, pinned shortcut by *other launchers* shouldn't be pinned here.
|
||||
|
||||
final PackageShortcuts packageShortcuts =
|
||||
s.getPackageShortcutsLocked(packageName, mUserId);
|
||||
final ArraySet<String> newSet = new ArraySet<>();
|
||||
|
||||
for (int i = 0; i < idSize; i++) {
|
||||
final String id = ids.get(i);
|
||||
final ShortcutInfo si = packageShortcuts.findShortcutById(id);
|
||||
if (si == null) {
|
||||
continue;
|
||||
}
|
||||
if (si.isDynamic() || (prevSet != null && prevSet.contains(id))) {
|
||||
newSet.add(id);
|
||||
}
|
||||
}
|
||||
mPinnedShortcuts.put(packageName, newSet);
|
||||
}
|
||||
s.getPackageShortcutsLocked(packageName, mUserId).refreshPinnedFlags(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the pinned shortcut IDs for the publisher package.
|
||||
*/
|
||||
public ArraySet<String> getPinnedShortcutIds(@NonNull String packageName) {
|
||||
return mPinnedShortcuts.get(packageName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist.
|
||||
*/
|
||||
public void saveToXml(XmlSerializer out) throws IOException {
|
||||
out.startTag(null, ShortcutService.TAG_LAUNCHER_PINS);
|
||||
ShortcutService.writeAttr(out, ShortcutService.ATTR_PACKAGE_NAME,
|
||||
mPackageName);
|
||||
|
||||
final int size = mPinnedShortcuts.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
out.startTag(null, ShortcutService.TAG_PACKAGE);
|
||||
ShortcutService.writeAttr(out, ShortcutService.ATTR_PACKAGE_NAME,
|
||||
mPinnedShortcuts.keyAt(i));
|
||||
|
||||
final ArraySet<String> ids = mPinnedShortcuts.valueAt(i);
|
||||
final int idSize = ids.size();
|
||||
for (int j = 0; j < idSize; j++) {
|
||||
ShortcutService.writeTagValue(out, ShortcutService.TAG_PIN, ids.valueAt(j));
|
||||
}
|
||||
out.endTag(null, ShortcutService.TAG_PACKAGE);
|
||||
}
|
||||
|
||||
out.endTag(null, ShortcutService.TAG_LAUNCHER_PINS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load.
|
||||
*/
|
||||
public static LauncherShortcuts loadFromXml(XmlPullParser parser, int userId)
|
||||
throws IOException, XmlPullParserException {
|
||||
final String launcherPackageName = ShortcutService.parseStringAttribute(parser,
|
||||
ShortcutService.ATTR_PACKAGE_NAME);
|
||||
|
||||
final LauncherShortcuts ret = new LauncherShortcuts(userId, launcherPackageName);
|
||||
|
||||
ArraySet<String> ids = null;
|
||||
final int outerDepth = parser.getDepth();
|
||||
int type;
|
||||
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
|
||||
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
|
||||
if (type != XmlPullParser.START_TAG) {
|
||||
continue;
|
||||
}
|
||||
final int depth = parser.getDepth();
|
||||
final String tag = parser.getName();
|
||||
switch (tag) {
|
||||
case ShortcutService.TAG_PACKAGE: {
|
||||
final String packageName = ShortcutService.parseStringAttribute(parser,
|
||||
ShortcutService.ATTR_PACKAGE_NAME);
|
||||
ids = new ArraySet<>();
|
||||
ret.mPinnedShortcuts.put(packageName, ids);
|
||||
continue;
|
||||
}
|
||||
case ShortcutService.TAG_PIN: {
|
||||
ids.add(ShortcutService.parseStringAttribute(parser,
|
||||
ShortcutService.ATTR_VALUE));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
throw ShortcutService.throwForInvalidTag(depth, tag);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void dump(@NonNull ShortcutService s, @NonNull PrintWriter pw, @NonNull String prefix) {
|
||||
pw.println();
|
||||
|
||||
pw.print(prefix);
|
||||
pw.print("Launcher: ");
|
||||
pw.print(mPackageName);
|
||||
pw.println();
|
||||
|
||||
final int size = mPinnedShortcuts.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
pw.println();
|
||||
|
||||
pw.print(prefix);
|
||||
pw.print(" ");
|
||||
pw.print("Package: ");
|
||||
pw.println(mPinnedShortcuts.keyAt(i));
|
||||
|
||||
final ArraySet<String> ids = mPinnedShortcuts.valueAt(i);
|
||||
final int idSize = ids.size();
|
||||
|
||||
for (int j = 0; j < idSize; j++) {
|
||||
pw.print(prefix);
|
||||
pw.print(" ");
|
||||
pw.print(ids.valueAt(j));
|
||||
pw.println();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* All the information relevant to shortcuts from a single package (per-user).
|
||||
*/
|
||||
@@ -2039,27 +2247,34 @@ class PackageShortcuts {
|
||||
*
|
||||
* It checks the max number of dynamic shortcuts.
|
||||
*/
|
||||
public void updateShortcutWithCapping(@NonNull ShortcutService s,
|
||||
public void addDynamicShortcut(@NonNull ShortcutService s,
|
||||
@NonNull ShortcutInfo newShortcut) {
|
||||
newShortcut.addFlags(ShortcutInfo.FLAG_DYNAMIC);
|
||||
|
||||
final ShortcutInfo oldShortcut = mShortcuts.get(newShortcut.getId());
|
||||
|
||||
int oldFlags = 0;
|
||||
int newDynamicCount = mDynamicShortcutCount;
|
||||
final boolean wasPinned;
|
||||
final int newDynamicCount;
|
||||
|
||||
if (oldShortcut != null) {
|
||||
oldFlags = oldShortcut.getFlags();
|
||||
if (oldShortcut == null) {
|
||||
wasPinned = false;
|
||||
newDynamicCount = mDynamicShortcutCount + 1; // adding a dynamic shortcut.
|
||||
} else {
|
||||
wasPinned = oldShortcut.isPinned();
|
||||
if (oldShortcut.isDynamic()) {
|
||||
newDynamicCount--;
|
||||
newDynamicCount = mDynamicShortcutCount; // not adding a dynamic shortcut.
|
||||
} else {
|
||||
newDynamicCount = mDynamicShortcutCount + 1; // adding a dynamic shortcut.
|
||||
}
|
||||
}
|
||||
if (newShortcut.isDynamic()) {
|
||||
newDynamicCount++;
|
||||
}
|
||||
|
||||
// Make sure there's still room.
|
||||
s.enforceMaxDynamicShortcuts(newDynamicCount);
|
||||
|
||||
// Okay, make it dynamic and add.
|
||||
newShortcut.addFlags(oldFlags);
|
||||
if (wasPinned) {
|
||||
newShortcut.addFlags(ShortcutInfo.FLAG_PINNED);
|
||||
}
|
||||
|
||||
addShortcut(s, newShortcut);
|
||||
mDynamicShortcutCount = newDynamicCount;
|
||||
@@ -2088,6 +2303,9 @@ class PackageShortcuts {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all dynamic shortcuts.
|
||||
*/
|
||||
public void deleteAllDynamicShortcuts(@NonNull ShortcutService s) {
|
||||
for (int i = mShortcuts.size() - 1; i >= 0; i--) {
|
||||
mShortcuts.valueAt(i).clearFlags(ShortcutInfo.FLAG_DYNAMIC);
|
||||
@@ -2096,6 +2314,9 @@ class PackageShortcuts {
|
||||
mDynamicShortcutCount = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a dynamic shortcut by ID.
|
||||
*/
|
||||
public void deleteDynamicWithId(@NonNull ShortcutService s, @NonNull String shortcutId) {
|
||||
final ShortcutInfo oldShortcut = mShortcuts.get(shortcutId);
|
||||
|
||||
@@ -2112,24 +2333,40 @@ class PackageShortcuts {
|
||||
}
|
||||
}
|
||||
|
||||
public void replacePinned(@NonNull ShortcutService s, String launcherPackage,
|
||||
List<String> shortcutIds) {
|
||||
|
||||
// TODO Should be per launcherPackage.
|
||||
|
||||
/**
|
||||
* Called after a launcher updates the pinned set. For each shortcut in this package,
|
||||
* set FLAG_PINNED if any launcher has pinned it. Otherwise, clear it.
|
||||
*
|
||||
* <p>Then remove all shortcuts that are not dynamic and no longer pinned either.
|
||||
*/
|
||||
public void refreshPinnedFlags(@NonNull ShortcutService s) {
|
||||
// First, un-pin all shortcuts
|
||||
for (int i = mShortcuts.size() - 1; i >= 0; i--) {
|
||||
mShortcuts.valueAt(i).clearFlags(ShortcutInfo.FLAG_PINNED);
|
||||
}
|
||||
|
||||
// Then pin ALL
|
||||
for (int i = shortcutIds.size() - 1; i >= 0; i--) {
|
||||
final ShortcutInfo shortcut = mShortcuts.get(shortcutIds.get(i));
|
||||
if (shortcut != null) {
|
||||
shortcut.addFlags(ShortcutInfo.FLAG_PINNED);
|
||||
// Then, for the pinned set for each launcher, set the pin flag one by one.
|
||||
final ArrayMap<String, LauncherShortcuts> launchers =
|
||||
s.getUserShortcutsLocked(mUserId).getLaunchers();
|
||||
|
||||
for (int l = launchers.size() - 1; l >= 0; l--) {
|
||||
final LauncherShortcuts launcherShortcuts = launchers.valueAt(l);
|
||||
final ArraySet<String> pinned = launcherShortcuts.getPinnedShortcutIds(mPackageName);
|
||||
|
||||
if (pinned == null || pinned.size() == 0) {
|
||||
continue;
|
||||
}
|
||||
for (int i = pinned.size() - 1; i >= 0; i--) {
|
||||
final ShortcutInfo si = mShortcuts.get(pinned.valueAt(i));
|
||||
if (si == null) {
|
||||
s.wtf("Shortcut not found");
|
||||
} else {
|
||||
si.addFlags(ShortcutInfo.FLAG_PINNED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Lastly, remove the ones that are no longer pinned nor dynamic.
|
||||
removeOrphans(s);
|
||||
}
|
||||
|
||||
@@ -2173,12 +2410,40 @@ class PackageShortcuts {
|
||||
/**
|
||||
* Find all shortcuts that match {@code query}.
|
||||
*/
|
||||
public void findAll(@NonNull List<ShortcutInfo> result,
|
||||
@Nullable Predicate<ShortcutInfo> query, int cloneFlag) {
|
||||
public void findAll(@NonNull ShortcutService s, @NonNull List<ShortcutInfo> result,
|
||||
@Nullable Predicate<ShortcutInfo> query, int cloneFlag,
|
||||
@Nullable String callingLauncher) {
|
||||
|
||||
// Set of pinned shortcuts by the calling launcher.
|
||||
final ArraySet<String> pinnedByCallerSet = (callingLauncher == null) ? null
|
||||
: s.getLauncherShortcuts(callingLauncher, mUserId)
|
||||
.getPinnedShortcutIds(mPackageName);
|
||||
|
||||
for (int i = 0; i < mShortcuts.size(); i++) {
|
||||
final ShortcutInfo si = mShortcuts.valueAt(i);
|
||||
if (query == null || query.test(si)) {
|
||||
result.add(si.clone(cloneFlag));
|
||||
|
||||
// If it's called by non-launcher (i.e. publisher, always include -> true.
|
||||
// Otherwise, only include non-dynamic pinned one, if the calling launcher has pinned
|
||||
// it.
|
||||
final boolean isPinnedByCaller = (callingLauncher == null)
|
||||
|| ((pinnedByCallerSet != null) && pinnedByCallerSet.contains(si.getId()));
|
||||
if (!si.isDynamic()) {
|
||||
if (!si.isPinned()) {
|
||||
s.wtf("Shortcut not pinned here");
|
||||
continue;
|
||||
}
|
||||
if (!isPinnedByCaller) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
final ShortcutInfo clone = si.clone(cloneFlag);
|
||||
// Fix up isPinned for the caller. Note we need to do it before the "test" callback,
|
||||
// since it may check isPinned.
|
||||
if (!isPinnedByCaller) {
|
||||
clone.clearFlags(ShortcutInfo.FLAG_PINNED);
|
||||
}
|
||||
if (query == null || query.test(clone)) {
|
||||
result.add(clone);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2188,6 +2453,8 @@ class PackageShortcuts {
|
||||
}
|
||||
|
||||
public void dump(@NonNull ShortcutService s, @NonNull PrintWriter pw, @NonNull String prefix) {
|
||||
pw.println();
|
||||
|
||||
pw.print(prefix);
|
||||
pw.print("Package: ");
|
||||
pw.print(mPackageName);
|
||||
|
||||
@@ -57,6 +57,7 @@ import android.test.InstrumentationTestCase;
|
||||
import android.test.mock.MockContext;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.frameworks.servicestests.R;
|
||||
import com.android.internal.util.Preconditions;
|
||||
@@ -250,6 +251,12 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
||||
r.run();
|
||||
mContext.injectRestoreCallingIdentity(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
void wtf(String message, Exception e) {
|
||||
// During tests, WTF is fatal.
|
||||
fail(message + " exception: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
/** ShortcutManager with injection override methods. */
|
||||
@@ -1752,68 +1759,320 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
||||
|
||||
public void testPinShortcutAndGetPinnedShortcuts() {
|
||||
// Create some shortcuts.
|
||||
setCaller(CALLING_PACKAGE_1);
|
||||
final ShortcutInfo s1_1 = makeShortcutWithTimestamp("s1", 1000);
|
||||
final ShortcutInfo s1_2 = makeShortcutWithTimestamp("s2", 2000);
|
||||
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
|
||||
final ShortcutInfo s1_1 = makeShortcutWithTimestamp("s1", 1000);
|
||||
final ShortcutInfo s1_2 = makeShortcutWithTimestamp("s2", 2000);
|
||||
|
||||
assertTrue(mManager.setDynamicShortcuts(Arrays.asList(s1_1, s1_2)));
|
||||
assertTrue(mManager.setDynamicShortcuts(Arrays.asList(s1_1, s1_2)));
|
||||
});
|
||||
|
||||
setCaller(CALLING_PACKAGE_2);
|
||||
final ShortcutInfo s2_2 = makeShortcutWithTimestamp("s2", 1500);
|
||||
final ShortcutInfo s2_3 = makeShortcutWithTimestamp("s3", 3000);
|
||||
final ShortcutInfo s2_4 = makeShortcutWithTimestamp("s4", 500);
|
||||
assertTrue(mManager.setDynamicShortcuts(Arrays.asList(s2_2, s2_3, s2_4)));
|
||||
runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
|
||||
final ShortcutInfo s2_2 = makeShortcutWithTimestamp("s2", 1500);
|
||||
final ShortcutInfo s2_3 = makeShortcutWithTimestamp("s3", 3000);
|
||||
final ShortcutInfo s2_4 = makeShortcutWithTimestamp("s4", 500);
|
||||
assertTrue(mManager.setDynamicShortcuts(Arrays.asList(s2_2, s2_3, s2_4)));
|
||||
});
|
||||
|
||||
setCaller(CALLING_PACKAGE_3);
|
||||
final ShortcutInfo s3_2 = makeShortcutWithTimestamp("s2", 1000);
|
||||
assertTrue(mManager.setDynamicShortcuts(Arrays.asList(s2_2)));
|
||||
runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
|
||||
final ShortcutInfo s3_2 = makeShortcutWithTimestamp("s2", 1000);
|
||||
assertTrue(mManager.setDynamicShortcuts(Arrays.asList(s3_2)));
|
||||
});
|
||||
|
||||
// Pin some.
|
||||
setCaller(LAUNCHER_1);
|
||||
runWithCaller(LAUNCHER_1, USER_0, () -> {
|
||||
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
|
||||
Arrays.asList("s2", "s3"), getCallingUser());
|
||||
|
||||
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
|
||||
Arrays.asList("s2", "s3"), getCallingUser());
|
||||
mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
|
||||
Arrays.asList("s3", "s4", "s5"), getCallingUser());
|
||||
|
||||
mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
|
||||
Arrays.asList("s3", "s4", "s5"), getCallingUser());
|
||||
|
||||
mLauncherApps.pinShortcuts(CALLING_PACKAGE_3,
|
||||
Arrays.asList("s3"), getCallingUser()); // Note ID doesn't exist
|
||||
mLauncherApps.pinShortcuts(CALLING_PACKAGE_3,
|
||||
Arrays.asList("s3"), getCallingUser()); // Note ID doesn't exist
|
||||
});
|
||||
|
||||
// Delete some.
|
||||
setCaller(CALLING_PACKAGE_1);
|
||||
assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
|
||||
mManager.deleteDynamicShortcut("s2");
|
||||
assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
|
||||
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
|
||||
assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
|
||||
mManager.deleteDynamicShortcut("s2");
|
||||
assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
|
||||
});
|
||||
|
||||
setCaller(CALLING_PACKAGE_2);
|
||||
assertShortcutIds(mManager.getPinnedShortcuts(), "s3", "s4");
|
||||
mManager.deleteDynamicShortcut("s3");
|
||||
assertShortcutIds(mManager.getPinnedShortcuts(), "s3", "s4");
|
||||
runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
|
||||
assertShortcutIds(mManager.getPinnedShortcuts(), "s3", "s4");
|
||||
mManager.deleteDynamicShortcut("s3");
|
||||
assertShortcutIds(mManager.getPinnedShortcuts(), "s3", "s4");
|
||||
});
|
||||
|
||||
setCaller(CALLING_PACKAGE_3);
|
||||
assertShortcutIds(mManager.getPinnedShortcuts() /* none */);
|
||||
mManager.deleteDynamicShortcut("s2");
|
||||
assertShortcutIds(mManager.getPinnedShortcuts() /* none */);
|
||||
runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
|
||||
assertShortcutIds(mManager.getPinnedShortcuts() /* none */);
|
||||
mManager.deleteDynamicShortcut("s2");
|
||||
assertShortcutIds(mManager.getPinnedShortcuts() /* none */);
|
||||
});
|
||||
|
||||
// Get pinned shortcuts from launcher
|
||||
setCaller(LAUNCHER_1);
|
||||
runWithCaller(LAUNCHER_1, USER_0, () -> {
|
||||
// CALLING_PACKAGE_1 deleted s2, but it's pinned, so it still exists.
|
||||
assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
|
||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
|
||||
"s2");
|
||||
|
||||
// CALLING_PACKAGE_1 deleted s2, but it's pinned, so it still exists.
|
||||
assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
|
||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
|
||||
"s2");
|
||||
assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
|
||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
|
||||
"s3", "s4");
|
||||
|
||||
assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
|
||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
|
||||
"s3", "s4");
|
||||
assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
|
||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_3,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser())))
|
||||
/* none */);
|
||||
});
|
||||
}
|
||||
|
||||
assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
|
||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_3,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser())))
|
||||
/* none */);
|
||||
public void testPinShortcutAndGetPinnedShortcuts_multi() {
|
||||
// Create some shortcuts.
|
||||
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
|
||||
assertTrue(mManager.setDynamicShortcuts(Arrays.asList(
|
||||
makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
|
||||
});
|
||||
|
||||
runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
|
||||
assertTrue(mManager.setDynamicShortcuts(Arrays.asList(
|
||||
makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
|
||||
});
|
||||
|
||||
dumpsysOnLogcat();
|
||||
|
||||
// Pin some.
|
||||
runWithCaller(LAUNCHER_1, USER_0, () -> {
|
||||
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
|
||||
Arrays.asList("s3", "s4"), getCallingUser());
|
||||
|
||||
mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
|
||||
Arrays.asList("s1", "s2", "s4"), getCallingUser());
|
||||
});
|
||||
|
||||
dumpsysOnLogcat();
|
||||
|
||||
// Delete some.
|
||||
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
|
||||
assertShortcutIds(mManager.getPinnedShortcuts(), "s3");
|
||||
mManager.deleteDynamicShortcut("s3");
|
||||
assertShortcutIds(mManager.getPinnedShortcuts(), "s3");
|
||||
});
|
||||
|
||||
dumpsysOnLogcat();
|
||||
|
||||
runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
|
||||
assertShortcutIds(mManager.getPinnedShortcuts(), "s1", "s2");
|
||||
mManager.deleteDynamicShortcut("s1");
|
||||
mManager.deleteDynamicShortcut("s3");
|
||||
assertShortcutIds(mManager.getPinnedShortcuts(), "s1", "s2");
|
||||
});
|
||||
|
||||
dumpsysOnLogcat();
|
||||
|
||||
// Get pinned shortcuts from launcher
|
||||
runWithCaller(LAUNCHER_1, USER_0, () -> {
|
||||
assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
|
||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
|
||||
"s3");
|
||||
|
||||
assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
|
||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
|
||||
"s1", "s2");
|
||||
|
||||
assertShortcutIds(assertAllDynamicOrPinned(
|
||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
|
||||
| ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
|
||||
"s1", "s2", "s3");
|
||||
|
||||
assertShortcutIds(assertAllDynamicOrPinned(
|
||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
|
||||
| ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
|
||||
"s1", "s2");
|
||||
});
|
||||
|
||||
dumpsysOnLogcat();
|
||||
|
||||
runWithCaller(LAUNCHER_2, USER_0, () -> {
|
||||
// Launcher2 still has no pinned ones.
|
||||
assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
|
||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser())))
|
||||
/* none */);
|
||||
assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
|
||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser())))
|
||||
/* none */);
|
||||
|
||||
assertShortcutIds(assertAllDynamic(
|
||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
|
||||
| ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
|
||||
"s1", "s2");
|
||||
assertShortcutIds(assertAllDynamic(
|
||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
|
||||
| ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
|
||||
"s2");
|
||||
|
||||
// Now pin some.
|
||||
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
|
||||
Arrays.asList("s1", "s2"), getCallingUser());
|
||||
|
||||
mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
|
||||
Arrays.asList("s1", "s2"), getCallingUser());
|
||||
|
||||
assertShortcutIds(assertAllDynamic(
|
||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
|
||||
| ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
|
||||
"s1", "s2");
|
||||
|
||||
// S1 was not visible to it, so shouldn't be pinned.
|
||||
assertShortcutIds(assertAllDynamic(
|
||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
|
||||
| ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
|
||||
"s2");
|
||||
});
|
||||
|
||||
// Re-initialize and load from the files.
|
||||
initService();
|
||||
|
||||
runWithCaller(LAUNCHER_1, USER_0, () -> {
|
||||
assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
|
||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
|
||||
"s3");
|
||||
assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
|
||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
|
||||
"s1", "s2");
|
||||
});
|
||||
runWithCaller(LAUNCHER_2, USER_0, () -> {
|
||||
assertShortcutIds(assertAllDynamic(
|
||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
|
||||
| ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
|
||||
"s1", "s2");
|
||||
assertShortcutIds(assertAllDynamic(
|
||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
|
||||
| ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
|
||||
"s2");
|
||||
});
|
||||
|
||||
// Delete all dynamic.
|
||||
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
|
||||
mManager.deleteAllDynamicShortcuts();
|
||||
|
||||
assertEquals(0, mManager.getDynamicShortcuts().size());
|
||||
assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s1", "s2", "s3");
|
||||
});
|
||||
runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
|
||||
mManager.deleteAllDynamicShortcuts();
|
||||
|
||||
assertEquals(0, mManager.getDynamicShortcuts().size());
|
||||
assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s2", "s1");
|
||||
});
|
||||
|
||||
runWithCaller(LAUNCHER_1, USER_0, () -> {
|
||||
assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
|
||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
|
||||
"s3");
|
||||
|
||||
assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
|
||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
|
||||
"s1", "s2");
|
||||
|
||||
// from all packages.
|
||||
assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
|
||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, null,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
|
||||
"s1", "s2", "s3");
|
||||
|
||||
// Update pined. Note s2 and s3 are actually available, but not visible to this
|
||||
// launcher, so still can't be pinned.
|
||||
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, Arrays.asList("s1", "s2", "s3", "s4"),
|
||||
getCallingUser());
|
||||
|
||||
assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
|
||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
|
||||
"s3");
|
||||
});
|
||||
// Re-publish s1.
|
||||
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
|
||||
assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
|
||||
|
||||
assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()), "s1");
|
||||
assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s1", "s2", "s3");
|
||||
});
|
||||
runWithCaller(LAUNCHER_1, USER_0, () -> {
|
||||
assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
|
||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
|
||||
"s3");
|
||||
|
||||
// Now "s1" is visible, so can be pinned.
|
||||
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, Arrays.asList("s1", "s2", "s3", "s4"),
|
||||
getCallingUser());
|
||||
|
||||
assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
|
||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
|
||||
"s1", "s3");
|
||||
});
|
||||
|
||||
// Now clear pinned shortcuts. First, from launcher 1.
|
||||
runWithCaller(LAUNCHER_1, USER_0, () -> {
|
||||
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, Arrays.asList(), getCallingUser());
|
||||
mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, Arrays.asList(), getCallingUser());
|
||||
|
||||
assertEquals(0,
|
||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()).size());
|
||||
assertEquals(0,
|
||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()).size());
|
||||
});
|
||||
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
|
||||
assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()), "s1");
|
||||
assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s1", "s2");
|
||||
});
|
||||
runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
|
||||
assertEquals(0, mManager.getDynamicShortcuts().size());
|
||||
assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s2");
|
||||
});
|
||||
|
||||
// Clear all pins from launcher 2.
|
||||
runWithCaller(LAUNCHER_2, USER_0, () -> {
|
||||
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, Arrays.asList(), getCallingUser());
|
||||
mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, Arrays.asList(), getCallingUser());
|
||||
|
||||
assertEquals(0,
|
||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()).size());
|
||||
assertEquals(0,
|
||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()).size());
|
||||
});
|
||||
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
|
||||
assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()), "s1");
|
||||
assertEquals(0, mManager.getPinnedShortcuts().size());
|
||||
});
|
||||
runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
|
||||
assertEquals(0, mManager.getDynamicShortcuts().size());
|
||||
assertEquals(0, mManager.getPinnedShortcuts().size());
|
||||
});
|
||||
}
|
||||
|
||||
public void testCreateShortcutIntent() {
|
||||
@@ -1880,8 +2139,11 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
||||
}
|
||||
|
||||
public void testLauncherCallback() throws Throwable {
|
||||
LauncherApps.Callback c0 = mock(LauncherApps.Callback.class);
|
||||
|
||||
// TODO Add "multi" version -- run the test with two launchers and make sure the callback
|
||||
// argument only contains the ones that are actually visible to each launcher.
|
||||
|
||||
LauncherApps.Callback c0 = mock(LauncherApps.Callback.class);
|
||||
|
||||
// Set listeners
|
||||
|
||||
|
||||
Reference in New Issue
Block a user