Merge "Properly protect ShortcutPackage#mShortcuts with synchronization lock." into tm-dev am: 645f51d337
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/18188747 Change-Id: Ie7669580df29be8a33a18febb2f484c9ab8879f7 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -166,18 +166,19 @@ class ShortcutPackage extends ShortcutPackageItem {
|
|||||||
* An in-memory copy of shortcuts for this package that was loaded from xml, keyed on IDs.
|
* An in-memory copy of shortcuts for this package that was loaded from xml, keyed on IDs.
|
||||||
*/
|
*/
|
||||||
@GuardedBy("mLock")
|
@GuardedBy("mLock")
|
||||||
final ArrayMap<String, ShortcutInfo> mShortcuts = new ArrayMap<>();
|
private final ArrayMap<String, ShortcutInfo> mShortcuts = new ArrayMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A temporary copy of shortcuts that are to be cleared once persisted into AppSearch, keyed on
|
* A temporary copy of shortcuts that are to be cleared once persisted into AppSearch, keyed on
|
||||||
* IDs.
|
* IDs.
|
||||||
*/
|
*/
|
||||||
@GuardedBy("mLock")
|
@GuardedBy("mLock")
|
||||||
private ArrayMap<String, ShortcutInfo> mTransientShortcuts = new ArrayMap<>(0);
|
private final ArrayMap<String, ShortcutInfo> mTransientShortcuts = new ArrayMap<>(0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All the share targets from the package
|
* All the share targets from the package
|
||||||
*/
|
*/
|
||||||
|
@GuardedBy("mLock")
|
||||||
private final ArrayList<ShareTargetInfo> mShareTargets = new ArrayList<>(0);
|
private final ArrayList<ShareTargetInfo> mShareTargets = new ArrayList<>(0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -231,7 +232,9 @@ class ShortcutPackage extends ShortcutPackageItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getShortcutCount() {
|
public int getShortcutCount() {
|
||||||
return mShortcuts.size();
|
synchronized (mLock) {
|
||||||
|
return mShortcuts.size();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -272,7 +275,9 @@ class ShortcutPackage extends ShortcutPackageItem {
|
|||||||
@Nullable
|
@Nullable
|
||||||
public ShortcutInfo findShortcutById(@Nullable final String id) {
|
public ShortcutInfo findShortcutById(@Nullable final String id) {
|
||||||
if (id == null) return null;
|
if (id == null) return null;
|
||||||
return mShortcuts.get(id);
|
synchronized (mLock) {
|
||||||
|
return mShortcuts.get(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isShortcutExistsAndInvisibleToPublisher(String id) {
|
public boolean isShortcutExistsAndInvisibleToPublisher(String id) {
|
||||||
@@ -347,11 +352,14 @@ class ShortcutPackage extends ShortcutPackageItem {
|
|||||||
* Delete a shortcut by ID. This will *always* remove it even if it's immutable or invisible.
|
* Delete a shortcut by ID. This will *always* remove it even if it's immutable or invisible.
|
||||||
*/
|
*/
|
||||||
private ShortcutInfo forceDeleteShortcutInner(@NonNull String id) {
|
private ShortcutInfo forceDeleteShortcutInner(@NonNull String id) {
|
||||||
final ShortcutInfo shortcut = mShortcuts.remove(id);
|
final ShortcutInfo shortcut;
|
||||||
if (shortcut != null) {
|
synchronized (mLock) {
|
||||||
removeIcon(shortcut);
|
shortcut = mShortcuts.remove(id);
|
||||||
shortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_PINNED
|
if (shortcut != null) {
|
||||||
| ShortcutInfo.FLAG_MANIFEST | ShortcutInfo.FLAG_CACHED_ALL);
|
removeIcon(shortcut);
|
||||||
|
shortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_PINNED
|
||||||
|
| ShortcutInfo.FLAG_MANIFEST | ShortcutInfo.FLAG_CACHED_ALL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return shortcut;
|
return shortcut;
|
||||||
}
|
}
|
||||||
@@ -524,14 +532,16 @@ class ShortcutPackage extends ShortcutPackageItem {
|
|||||||
public List<ShortcutInfo> deleteAllDynamicShortcuts() {
|
public List<ShortcutInfo> deleteAllDynamicShortcuts() {
|
||||||
final long now = mShortcutUser.mService.injectCurrentTimeMillis();
|
final long now = mShortcutUser.mService.injectCurrentTimeMillis();
|
||||||
boolean changed = false;
|
boolean changed = false;
|
||||||
for (int i = mShortcuts.size() - 1; i >= 0; i--) {
|
synchronized (mLock) {
|
||||||
ShortcutInfo si = mShortcuts.valueAt(i);
|
for (int i = mShortcuts.size() - 1; i >= 0; i--) {
|
||||||
if (si.isDynamic() && si.isVisibleToPublisher()) {
|
ShortcutInfo si = mShortcuts.valueAt(i);
|
||||||
changed = true;
|
if (si.isDynamic() && si.isVisibleToPublisher()) {
|
||||||
|
changed = true;
|
||||||
|
|
||||||
si.setTimestamp(now);
|
si.setTimestamp(now);
|
||||||
si.clearFlags(ShortcutInfo.FLAG_DYNAMIC);
|
si.clearFlags(ShortcutInfo.FLAG_DYNAMIC);
|
||||||
si.setRank(0); // It may still be pinned, so clear the rank.
|
si.setRank(0); // It may still be pinned, so clear the rank.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
removeAllShortcutsAsync();
|
removeAllShortcutsAsync();
|
||||||
@@ -874,59 +884,63 @@ class ShortcutPackage extends ShortcutPackageItem {
|
|||||||
*/
|
*/
|
||||||
public List<ShortcutManager.ShareShortcutInfo> getMatchingShareTargets(
|
public List<ShortcutManager.ShareShortcutInfo> getMatchingShareTargets(
|
||||||
@NonNull IntentFilter filter) {
|
@NonNull IntentFilter filter) {
|
||||||
final List<ShareTargetInfo> matchedTargets = new ArrayList<>();
|
synchronized (mLock) {
|
||||||
for (int i = 0; i < mShareTargets.size(); i++) {
|
final List<ShareTargetInfo> matchedTargets = new ArrayList<>();
|
||||||
final ShareTargetInfo target = mShareTargets.get(i);
|
for (int i = 0; i < mShareTargets.size(); i++) {
|
||||||
for (ShareTargetInfo.TargetData data : target.mTargetData) {
|
final ShareTargetInfo target = mShareTargets.get(i);
|
||||||
if (filter.hasDataType(data.mMimeType)) {
|
for (ShareTargetInfo.TargetData data : target.mTargetData) {
|
||||||
// Matched at least with one data type
|
if (filter.hasDataType(data.mMimeType)) {
|
||||||
matchedTargets.add(target);
|
// Matched at least with one data type
|
||||||
break;
|
matchedTargets.add(target);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (matchedTargets.isEmpty()) {
|
|
||||||
return new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the list of all dynamic shortcuts in this package.
|
|
||||||
final ArrayList<ShortcutInfo> shortcuts = new ArrayList<>();
|
|
||||||
// Pass callingLauncher to ensure pinned flag marked by system ui, e.g. ShareSheet, are
|
|
||||||
// included in the result
|
|
||||||
findAll(shortcuts, ShortcutInfo::isNonManifestVisible,
|
|
||||||
ShortcutInfo.CLONE_REMOVE_FOR_APP_PREDICTION,
|
|
||||||
mShortcutUser.mService.mContext.getPackageName(),
|
|
||||||
0, /*getPinnedByAnyLauncher=*/ false);
|
|
||||||
|
|
||||||
final List<ShortcutManager.ShareShortcutInfo> result = new ArrayList<>();
|
|
||||||
for (int i = 0; i < shortcuts.size(); i++) {
|
|
||||||
final Set<String> categories = shortcuts.get(i).getCategories();
|
|
||||||
if (categories == null || categories.isEmpty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (int j = 0; j < matchedTargets.size(); j++) {
|
|
||||||
// Shortcut must have all of share target categories
|
|
||||||
boolean hasAllCategories = true;
|
|
||||||
final ShareTargetInfo target = matchedTargets.get(j);
|
|
||||||
for (int q = 0; q < target.mCategories.length; q++) {
|
|
||||||
if (!categories.contains(target.mCategories[q])) {
|
|
||||||
hasAllCategories = false;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hasAllCategories) {
|
}
|
||||||
result.add(new ShortcutManager.ShareShortcutInfo(shortcuts.get(i),
|
|
||||||
new ComponentName(getPackageName(), target.mTargetClass)));
|
if (matchedTargets.isEmpty()) {
|
||||||
break;
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the list of all dynamic shortcuts in this package.
|
||||||
|
final ArrayList<ShortcutInfo> shortcuts = new ArrayList<>();
|
||||||
|
// Pass callingLauncher to ensure pinned flag marked by system ui, e.g. ShareSheet, are
|
||||||
|
// included in the result
|
||||||
|
findAll(shortcuts, ShortcutInfo::isNonManifestVisible,
|
||||||
|
ShortcutInfo.CLONE_REMOVE_FOR_APP_PREDICTION,
|
||||||
|
mShortcutUser.mService.mContext.getPackageName(),
|
||||||
|
0, /*getPinnedByAnyLauncher=*/ false);
|
||||||
|
|
||||||
|
final List<ShortcutManager.ShareShortcutInfo> result = new ArrayList<>();
|
||||||
|
for (int i = 0; i < shortcuts.size(); i++) {
|
||||||
|
final Set<String> categories = shortcuts.get(i).getCategories();
|
||||||
|
if (categories == null || categories.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (int j = 0; j < matchedTargets.size(); j++) {
|
||||||
|
// Shortcut must have all of share target categories
|
||||||
|
boolean hasAllCategories = true;
|
||||||
|
final ShareTargetInfo target = matchedTargets.get(j);
|
||||||
|
for (int q = 0; q < target.mCategories.length; q++) {
|
||||||
|
if (!categories.contains(target.mCategories[q])) {
|
||||||
|
hasAllCategories = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasAllCategories) {
|
||||||
|
result.add(new ShortcutManager.ShareShortcutInfo(shortcuts.get(i),
|
||||||
|
new ComponentName(getPackageName(), target.mTargetClass)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasShareTargets() {
|
public boolean hasShareTargets() {
|
||||||
return !mShareTargets.isEmpty();
|
synchronized (mLock) {
|
||||||
|
return !mShareTargets.isEmpty();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -935,38 +949,40 @@ class ShortcutPackage extends ShortcutPackageItem {
|
|||||||
* the app's Xml resource.
|
* the app's Xml resource.
|
||||||
*/
|
*/
|
||||||
int getSharingShortcutCount() {
|
int getSharingShortcutCount() {
|
||||||
if (mShareTargets.isEmpty()) {
|
synchronized (mLock) {
|
||||||
return 0;
|
if (mShareTargets.isEmpty()) {
|
||||||
}
|
return 0;
|
||||||
|
|
||||||
// Get the list of all dynamic shortcuts in this package
|
|
||||||
final ArrayList<ShortcutInfo> shortcuts = new ArrayList<>();
|
|
||||||
findAll(shortcuts, ShortcutInfo::isNonManifestVisible,
|
|
||||||
ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
|
|
||||||
|
|
||||||
int sharingShortcutCount = 0;
|
|
||||||
for (int i = 0; i < shortcuts.size(); i++) {
|
|
||||||
final Set<String> categories = shortcuts.get(i).getCategories();
|
|
||||||
if (categories == null || categories.isEmpty()) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
for (int j = 0; j < mShareTargets.size(); j++) {
|
|
||||||
// A SharingShortcut must have all of share target categories
|
// Get the list of all dynamic shortcuts in this package
|
||||||
boolean hasAllCategories = true;
|
final ArrayList<ShortcutInfo> shortcuts = new ArrayList<>();
|
||||||
final ShareTargetInfo target = mShareTargets.get(j);
|
findAll(shortcuts, ShortcutInfo::isNonManifestVisible,
|
||||||
for (int q = 0; q < target.mCategories.length; q++) {
|
ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
|
||||||
if (!categories.contains(target.mCategories[q])) {
|
|
||||||
hasAllCategories = false;
|
int sharingShortcutCount = 0;
|
||||||
|
for (int i = 0; i < shortcuts.size(); i++) {
|
||||||
|
final Set<String> categories = shortcuts.get(i).getCategories();
|
||||||
|
if (categories == null || categories.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (int j = 0; j < mShareTargets.size(); j++) {
|
||||||
|
// A SharingShortcut must have all of share target categories
|
||||||
|
boolean hasAllCategories = true;
|
||||||
|
final ShareTargetInfo target = mShareTargets.get(j);
|
||||||
|
for (int q = 0; q < target.mCategories.length; q++) {
|
||||||
|
if (!categories.contains(target.mCategories[q])) {
|
||||||
|
hasAllCategories = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasAllCategories) {
|
||||||
|
sharingShortcutCount++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hasAllCategories) {
|
|
||||||
sharingShortcutCount++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return sharingShortcutCount;
|
||||||
}
|
}
|
||||||
return sharingShortcutCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1090,19 +1106,25 @@ class ShortcutPackage extends ShortcutPackageItem {
|
|||||||
|
|
||||||
// Now prepare to publish manifest shortcuts.
|
// Now prepare to publish manifest shortcuts.
|
||||||
List<ShortcutInfo> newManifestShortcutList = null;
|
List<ShortcutInfo> newManifestShortcutList = null;
|
||||||
try {
|
final int shareTargetSize;
|
||||||
newManifestShortcutList = ShortcutParser.parseShortcuts(mShortcutUser.mService,
|
synchronized (mLock) {
|
||||||
getPackageName(), getPackageUserId(), mShareTargets);
|
try {
|
||||||
} catch (IOException|XmlPullParserException e) {
|
shareTargetSize = mShareTargets.size();
|
||||||
Slog.e(TAG, "Failed to load shortcuts from AndroidManifest.xml.", e);
|
newManifestShortcutList = ShortcutParser.parseShortcuts(mShortcutUser.mService,
|
||||||
|
getPackageName(), getPackageUserId(), mShareTargets);
|
||||||
|
} catch (IOException | XmlPullParserException e) {
|
||||||
|
Slog.e(TAG, "Failed to load shortcuts from AndroidManifest.xml.", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
final int manifestShortcutSize = newManifestShortcutList == null ? 0
|
final int manifestShortcutSize = newManifestShortcutList == null ? 0
|
||||||
: newManifestShortcutList.size();
|
: newManifestShortcutList.size();
|
||||||
if (ShortcutService.DEBUG || ShortcutService.DEBUG_REBOOT) {
|
if (ShortcutService.DEBUG || ShortcutService.DEBUG_REBOOT) {
|
||||||
Slog.d(TAG,
|
Slog.d(TAG,
|
||||||
String.format("Package %s has %d manifest shortcut(s), and %d share target(s)",
|
String.format(
|
||||||
getPackageName(), manifestShortcutSize, mShareTargets.size()));
|
"Package %s has %d manifest shortcut(s), and %d share target(s)",
|
||||||
|
getPackageName(), manifestShortcutSize, shareTargetSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isNewApp && (manifestShortcutSize == 0)) {
|
if (isNewApp && (manifestShortcutSize == 0)) {
|
||||||
// If it's a new app, and it doesn't have manifest shortcuts, then nothing to do.
|
// If it's a new app, and it doesn't have manifest shortcuts, then nothing to do.
|
||||||
|
|
||||||
@@ -1701,37 +1723,38 @@ class ShortcutPackage extends ShortcutPackageItem {
|
|||||||
@Override
|
@Override
|
||||||
public void saveToXml(@NonNull TypedXmlSerializer out, boolean forBackup)
|
public void saveToXml(@NonNull TypedXmlSerializer out, boolean forBackup)
|
||||||
throws IOException, XmlPullParserException {
|
throws IOException, XmlPullParserException {
|
||||||
final int size = mShortcuts.size();
|
synchronized (mLock) {
|
||||||
final int shareTargetSize = mShareTargets.size();
|
final int size = mShortcuts.size();
|
||||||
|
final int shareTargetSize = mShareTargets.size();
|
||||||
|
|
||||||
if (hasNoShortcut() && shareTargetSize == 0 && mApiCallCount == 0) {
|
if (hasNoShortcut() && shareTargetSize == 0 && mApiCallCount == 0) {
|
||||||
return; // nothing to write.
|
return; // nothing to write.
|
||||||
}
|
}
|
||||||
|
|
||||||
out.startTag(null, TAG_ROOT);
|
out.startTag(null, TAG_ROOT);
|
||||||
|
|
||||||
ShortcutService.writeAttr(out, ATTR_NAME, getPackageName());
|
ShortcutService.writeAttr(out, ATTR_NAME, getPackageName());
|
||||||
ShortcutService.writeAttr(out, ATTR_CALL_COUNT, mApiCallCount);
|
ShortcutService.writeAttr(out, ATTR_CALL_COUNT, mApiCallCount);
|
||||||
ShortcutService.writeAttr(out, ATTR_LAST_RESET, mLastResetTime);
|
ShortcutService.writeAttr(out, ATTR_LAST_RESET, mLastResetTime);
|
||||||
if (!forBackup) {
|
if (!forBackup) {
|
||||||
synchronized (mLock) {
|
ShortcutService.writeAttr(out, ATTR_SCHEMA_VERSON, mIsAppSearchSchemaUpToDate
|
||||||
ShortcutService.writeAttr(out, ATTR_SCHEMA_VERSON, (mIsAppSearchSchemaUpToDate)
|
|
||||||
? AppSearchShortcutInfo.SCHEMA_VERSION : 0);
|
? AppSearchShortcutInfo.SCHEMA_VERSION : 0);
|
||||||
}
|
}
|
||||||
}
|
getPackageInfo().saveToXml(mShortcutUser.mService, out, forBackup);
|
||||||
getPackageInfo().saveToXml(mShortcutUser.mService, out, forBackup);
|
|
||||||
|
|
||||||
for (int j = 0; j < size; j++) {
|
for (int j = 0; j < size; j++) {
|
||||||
saveShortcut(out, mShortcuts.valueAt(j), forBackup, getPackageInfo().isBackupAllowed());
|
saveShortcut(
|
||||||
}
|
out, mShortcuts.valueAt(j), forBackup, getPackageInfo().isBackupAllowed());
|
||||||
|
|
||||||
if (!forBackup) {
|
|
||||||
for (int j = 0; j < shareTargetSize; j++) {
|
|
||||||
mShareTargets.get(j).saveToXml(out);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
out.endTag(null, TAG_ROOT);
|
if (!forBackup) {
|
||||||
|
for (int j = 0; j < shareTargetSize; j++) {
|
||||||
|
mShareTargets.get(j).saveToXml(out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out.endTag(null, TAG_ROOT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveShortcut(TypedXmlSerializer out, ShortcutInfo si, boolean forBackup,
|
private void saveShortcut(TypedXmlSerializer out, ShortcutInfo si, boolean forBackup,
|
||||||
@@ -1917,38 +1940,38 @@ class ShortcutPackage extends ShortcutPackageItem {
|
|||||||
synchronized (ret.mLock) {
|
synchronized (ret.mLock) {
|
||||||
ret.mIsAppSearchSchemaUpToDate = ShortcutService.parseIntAttribute(
|
ret.mIsAppSearchSchemaUpToDate = ShortcutService.parseIntAttribute(
|
||||||
parser, ATTR_SCHEMA_VERSON, 0) == AppSearchShortcutInfo.SCHEMA_VERSION;
|
parser, ATTR_SCHEMA_VERSON, 0) == AppSearchShortcutInfo.SCHEMA_VERSION;
|
||||||
}
|
|
||||||
ret.mApiCallCount = ShortcutService.parseIntAttribute(parser, ATTR_CALL_COUNT);
|
|
||||||
ret.mLastResetTime = ShortcutService.parseLongAttribute(parser, ATTR_LAST_RESET);
|
|
||||||
|
|
||||||
|
ret.mApiCallCount = ShortcutService.parseIntAttribute(parser, ATTR_CALL_COUNT);
|
||||||
|
ret.mLastResetTime = ShortcutService.parseLongAttribute(parser, ATTR_LAST_RESET);
|
||||||
|
|
||||||
final int outerDepth = parser.getDepth();
|
final int outerDepth = parser.getDepth();
|
||||||
int type;
|
int type;
|
||||||
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
|
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
|
||||||
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
|
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
|
||||||
if (type != XmlPullParser.START_TAG) {
|
if (type != XmlPullParser.START_TAG) {
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
final int depth = parser.getDepth();
|
|
||||||
final String tag = parser.getName();
|
|
||||||
if (depth == outerDepth + 1) {
|
|
||||||
switch (tag) {
|
|
||||||
case ShortcutPackageInfo.TAG_ROOT:
|
|
||||||
ret.getPackageInfo().loadFromXml(parser, fromBackup);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
case TAG_SHORTCUT:
|
|
||||||
final ShortcutInfo si = parseShortcut(parser, packageName,
|
|
||||||
shortcutUser.getUserId(), fromBackup);
|
|
||||||
// Don't use addShortcut(), we don't need to save the icon.
|
|
||||||
ret.mShortcuts.put(si.getId(), si);
|
|
||||||
continue;
|
|
||||||
case TAG_SHARE_TARGET:
|
|
||||||
ret.mShareTargets.add(ShareTargetInfo.loadFromXml(parser));
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
final int depth = parser.getDepth();
|
||||||
|
final String tag = parser.getName();
|
||||||
|
if (depth == outerDepth + 1) {
|
||||||
|
switch (tag) {
|
||||||
|
case ShortcutPackageInfo.TAG_ROOT:
|
||||||
|
ret.getPackageInfo().loadFromXml(parser, fromBackup);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
case TAG_SHORTCUT:
|
||||||
|
final ShortcutInfo si = parseShortcut(parser, packageName,
|
||||||
|
shortcutUser.getUserId(), fromBackup);
|
||||||
|
// Don't use addShortcut(), we don't need to save the icon.
|
||||||
|
ret.mShortcuts.put(si.getId(), si);
|
||||||
|
continue;
|
||||||
|
case TAG_SHARE_TARGET:
|
||||||
|
ret.mShareTargets.add(ShareTargetInfo.loadFromXml(parser));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ShortcutService.warnForInvalidTag(depth, tag);
|
||||||
}
|
}
|
||||||
ShortcutService.warnForInvalidTag(depth, tag);
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -2152,7 +2175,9 @@ class ShortcutPackage extends ShortcutPackageItem {
|
|||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
List<ShareTargetInfo> getAllShareTargetsForTest() {
|
List<ShareTargetInfo> getAllShareTargetsForTest() {
|
||||||
return new ArrayList<>(mShareTargets);
|
synchronized (mLock) {
|
||||||
|
return new ArrayList<>(mShareTargets);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -2291,15 +2316,19 @@ class ShortcutPackage extends ShortcutPackageItem {
|
|||||||
|
|
||||||
private void saveShortcut(@NonNull final Collection<ShortcutInfo> shortcuts) {
|
private void saveShortcut(@NonNull final Collection<ShortcutInfo> shortcuts) {
|
||||||
Objects.requireNonNull(shortcuts);
|
Objects.requireNonNull(shortcuts);
|
||||||
for (ShortcutInfo si : shortcuts) {
|
synchronized (mLock) {
|
||||||
mShortcuts.put(si.getId(), si);
|
for (ShortcutInfo si : shortcuts) {
|
||||||
|
mShortcuts.put(si.getId(), si);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
List<ShortcutInfo> findAll(@NonNull final Collection<String> ids) {
|
List<ShortcutInfo> findAll(@NonNull final Collection<String> ids) {
|
||||||
return ids.stream().map(mShortcuts::get)
|
synchronized (mLock) {
|
||||||
.filter(Objects::nonNull).collect(Collectors.toList());
|
return ids.stream().map(mShortcuts::get)
|
||||||
|
.filter(Objects::nonNull).collect(Collectors.toList());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void forEachShortcut(@NonNull final Consumer<ShortcutInfo> cb) {
|
private void forEachShortcut(@NonNull final Consumer<ShortcutInfo> cb) {
|
||||||
@@ -2318,10 +2347,12 @@ class ShortcutPackage extends ShortcutPackageItem {
|
|||||||
|
|
||||||
private void forEachShortcutStopWhen(
|
private void forEachShortcutStopWhen(
|
||||||
@NonNull final Function<ShortcutInfo, Boolean> cb) {
|
@NonNull final Function<ShortcutInfo, Boolean> cb) {
|
||||||
for (int i = mShortcuts.size() - 1; i >= 0; i--) {
|
synchronized (mLock) {
|
||||||
final ShortcutInfo si = mShortcuts.valueAt(i);
|
for (int i = mShortcuts.size() - 1; i >= 0; i--) {
|
||||||
if (cb.apply(si)) {
|
final ShortcutInfo si = mShortcuts.valueAt(i);
|
||||||
return;
|
if (cb.apply(si)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2461,6 +2492,7 @@ class ShortcutPackage extends ShortcutPackageItem {
|
|||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GuardedBy("mLock")
|
||||||
@Override
|
@Override
|
||||||
void scheduleSaveToAppSearchLocked() {
|
void scheduleSaveToAppSearchLocked() {
|
||||||
final Map<String, ShortcutInfo> copy = new ArrayMap<>(mShortcuts);
|
final Map<String, ShortcutInfo> copy = new ArrayMap<>(mShortcuts);
|
||||||
|
|||||||
Reference in New Issue
Block a user