Merge "ShortcutManager: proper work profile support" into nyc-dev
am: d5b745a
* commit 'd5b745a9e64734483bc43c781ad809b2a75bd1ba':
ShortcutManager: proper work profile support
Change-Id: Ic31214205a5a93e37e5585829ae522bf4890b519
This commit is contained in:
@@ -47,4 +47,8 @@ interface IShortcutService {
|
|||||||
int getIconMaxDimensions(String packageName, int userId);
|
int getIconMaxDimensions(String packageName, int userId);
|
||||||
|
|
||||||
void resetThrottling(); // system only API for developer opsions
|
void resetThrottling(); // system only API for developer opsions
|
||||||
|
|
||||||
|
byte[] getBackupPayload(int user);
|
||||||
|
|
||||||
|
void applyRestore(in byte[] payload, int user);
|
||||||
}
|
}
|
||||||
@@ -32,7 +32,7 @@ import java.util.List;
|
|||||||
/**
|
/**
|
||||||
* Launcher information used by {@link ShortcutService}.
|
* Launcher information used by {@link ShortcutService}.
|
||||||
*/
|
*/
|
||||||
class ShortcutLauncher implements ShortcutPackageItem {
|
class ShortcutLauncher extends ShortcutPackageItem {
|
||||||
private static final String TAG = ShortcutService.TAG;
|
private static final String TAG = ShortcutService.TAG;
|
||||||
|
|
||||||
static final String TAG_ROOT = "launcher-pins";
|
static final String TAG_ROOT = "launcher-pins";
|
||||||
@@ -44,44 +44,34 @@ class ShortcutLauncher implements ShortcutPackageItem {
|
|||||||
private static final String ATTR_VALUE = "value";
|
private static final String ATTR_VALUE = "value";
|
||||||
private static final String ATTR_PACKAGE_NAME = "package-name";
|
private static final String ATTR_PACKAGE_NAME = "package-name";
|
||||||
|
|
||||||
@UserIdInt
|
private final int mOwnerUserId;
|
||||||
private final int mUserId;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final String mPackageName;
|
|
||||||
|
|
||||||
@UserIdInt
|
|
||||||
private final int mLauncherUserId;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Package name -> IDs.
|
* Package name -> IDs.
|
||||||
*/
|
*/
|
||||||
final private ArrayMap<String, ArraySet<String>> mPinnedShortcuts = new ArrayMap<>();
|
final private ArrayMap<String, ArraySet<String>> mPinnedShortcuts = new ArrayMap<>();
|
||||||
|
|
||||||
ShortcutLauncher(@UserIdInt int userId, @NonNull String packageName,
|
public ShortcutLauncher(@UserIdInt int ownerUserId, @NonNull String packageName,
|
||||||
|
@UserIdInt int launcherUserId, ShortcutPackageInfo spi) {
|
||||||
|
super(launcherUserId, packageName, spi != null ? spi : ShortcutPackageInfo.newEmpty());
|
||||||
|
mOwnerUserId = ownerUserId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShortcutLauncher(@UserIdInt int ownerUserId, @NonNull String packageName,
|
||||||
@UserIdInt int launcherUserId) {
|
@UserIdInt int launcherUserId) {
|
||||||
mUserId = userId;
|
this(launcherUserId, packageName, launcherUserId, null);
|
||||||
mPackageName = packageName;
|
|
||||||
mLauncherUserId = launcherUserId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@UserIdInt
|
@Override
|
||||||
public int getUserId() {
|
public int getOwnerUserId() {
|
||||||
return mUserId;
|
return mOwnerUserId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@UserIdInt
|
public void pinShortcuts(@NonNull ShortcutService s, @UserIdInt int packageUserId,
|
||||||
public int getLauncherUserId() {
|
@NonNull String packageName, @NonNull List<String> ids) {
|
||||||
return mLauncherUserId;
|
final ShortcutPackage packageShortcuts =
|
||||||
}
|
s.getPackageShortcutsLocked(packageName, packageUserId);
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public String getPackageName() {
|
|
||||||
return mPackageName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void pinShortcuts(@NonNull ShortcutService s, @NonNull String packageName,
|
|
||||||
@NonNull List<String> ids) {
|
|
||||||
final int idSize = ids.size();
|
final int idSize = ids.size();
|
||||||
if (idSize == 0) {
|
if (idSize == 0) {
|
||||||
mPinnedShortcuts.remove(packageName);
|
mPinnedShortcuts.remove(packageName);
|
||||||
@@ -91,8 +81,6 @@ class ShortcutLauncher implements ShortcutPackageItem {
|
|||||||
// Pin shortcuts. Make sure only pin the ones that were visible to the caller.
|
// 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.
|
// i.e. a non-dynamic, pinned shortcut by *other launchers* shouldn't be pinned here.
|
||||||
|
|
||||||
final ShortcutPackage packageShortcuts =
|
|
||||||
s.getPackageShortcutsLocked(packageName, mUserId);
|
|
||||||
final ArraySet<String> newSet = new ArraySet<>();
|
final ArraySet<String> newSet = new ArraySet<>();
|
||||||
|
|
||||||
for (int i = 0; i < idSize; i++) {
|
for (int i = 0; i < idSize; i++) {
|
||||||
@@ -107,7 +95,7 @@ class ShortcutLauncher implements ShortcutPackageItem {
|
|||||||
}
|
}
|
||||||
mPinnedShortcuts.put(packageName, newSet);
|
mPinnedShortcuts.put(packageName, newSet);
|
||||||
}
|
}
|
||||||
s.getPackageShortcutsLocked(packageName, mUserId).refreshPinnedFlags(s);
|
packageShortcuts.refreshPinnedFlags(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,15 +112,18 @@ class ShortcutLauncher implements ShortcutPackageItem {
|
|||||||
/**
|
/**
|
||||||
* Persist.
|
* Persist.
|
||||||
*/
|
*/
|
||||||
public void saveToXml(XmlSerializer out, boolean forBackup) throws IOException {
|
@Override
|
||||||
|
public void saveToXml(XmlSerializer out, boolean forBackup)
|
||||||
|
throws IOException {
|
||||||
final int size = mPinnedShortcuts.size();
|
final int size = mPinnedShortcuts.size();
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
return; // Nothing to write.
|
return; // Nothing to write.
|
||||||
}
|
}
|
||||||
|
|
||||||
out.startTag(null, TAG_ROOT);
|
out.startTag(null, TAG_ROOT);
|
||||||
ShortcutService.writeAttr(out, ATTR_PACKAGE_NAME, mPackageName);
|
ShortcutService.writeAttr(out, ATTR_PACKAGE_NAME, getPackageName());
|
||||||
ShortcutService.writeAttr(out, ATTR_LAUNCHER_USER_ID, mLauncherUserId);
|
ShortcutService.writeAttr(out, ATTR_LAUNCHER_USER_ID, getPackageUserId());
|
||||||
|
getPackageInfo().saveToXml(out);
|
||||||
|
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
out.startTag(null, TAG_PACKAGE);
|
out.startTag(null, TAG_PACKAGE);
|
||||||
@@ -153,16 +144,21 @@ class ShortcutLauncher implements ShortcutPackageItem {
|
|||||||
/**
|
/**
|
||||||
* Load.
|
* Load.
|
||||||
*/
|
*/
|
||||||
public static ShortcutLauncher loadFromXml(XmlPullParser parser, int ownerUserId)
|
public static ShortcutLauncher loadFromXml(XmlPullParser parser, int ownerUserId,
|
||||||
throws IOException, XmlPullParserException {
|
boolean fromBackup) throws IOException, XmlPullParserException {
|
||||||
final String launcherPackageName = ShortcutService.parseStringAttribute(parser,
|
final String launcherPackageName = ShortcutService.parseStringAttribute(parser,
|
||||||
ATTR_PACKAGE_NAME);
|
ATTR_PACKAGE_NAME);
|
||||||
final int launcherUserId = ShortcutService.parseIntAttribute(parser,
|
|
||||||
ATTR_LAUNCHER_USER_ID, ownerUserId);
|
// If restoring, just use the real user ID.
|
||||||
|
final int launcherUserId =
|
||||||
|
fromBackup ? ownerUserId
|
||||||
|
: ShortcutService.parseIntAttribute(parser, ATTR_LAUNCHER_USER_ID, ownerUserId);
|
||||||
|
|
||||||
final ShortcutLauncher ret = new ShortcutLauncher(launcherUserId, launcherPackageName,
|
final ShortcutLauncher ret = new ShortcutLauncher(launcherUserId, launcherPackageName,
|
||||||
launcherUserId);
|
launcherUserId);
|
||||||
|
|
||||||
|
ShortcutPackageInfo spi = null;
|
||||||
|
|
||||||
ArraySet<String> ids = null;
|
ArraySet<String> ids = null;
|
||||||
final int outerDepth = parser.getDepth();
|
final int outerDepth = parser.getDepth();
|
||||||
int type;
|
int type;
|
||||||
@@ -173,21 +169,33 @@ class ShortcutLauncher implements ShortcutPackageItem {
|
|||||||
}
|
}
|
||||||
final int depth = parser.getDepth();
|
final int depth = parser.getDepth();
|
||||||
final String tag = parser.getName();
|
final String tag = parser.getName();
|
||||||
switch (tag) {
|
if (depth == outerDepth + 1) {
|
||||||
case TAG_PACKAGE: {
|
switch (tag) {
|
||||||
final String packageName = ShortcutService.parseStringAttribute(parser,
|
case ShortcutPackageInfo.TAG_ROOT:
|
||||||
ATTR_PACKAGE_NAME);
|
spi = ShortcutPackageInfo.loadFromXml(parser);
|
||||||
ids = new ArraySet<>();
|
continue;
|
||||||
ret.mPinnedShortcuts.put(packageName, ids);
|
case TAG_PACKAGE: {
|
||||||
continue;
|
final String packageName = ShortcutService.parseStringAttribute(parser,
|
||||||
}
|
ATTR_PACKAGE_NAME);
|
||||||
case TAG_PIN: {
|
ids = new ArraySet<>();
|
||||||
ids.add(ShortcutService.parseStringAttribute(parser,
|
ret.mPinnedShortcuts.put(packageName, ids);
|
||||||
ATTR_VALUE));
|
continue;
|
||||||
continue;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw ShortcutService.throwForInvalidTag(depth, tag);
|
if (depth == outerDepth + 2) {
|
||||||
|
switch (tag) {
|
||||||
|
case TAG_PIN: {
|
||||||
|
ids.add(ShortcutService.parseStringAttribute(parser,
|
||||||
|
ATTR_VALUE));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ShortcutService.warnForInvalidTag(depth, tag);
|
||||||
|
}
|
||||||
|
if (spi != null) {
|
||||||
|
ret.replacePackageInfo(spi);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -197,9 +205,12 @@ class ShortcutLauncher implements ShortcutPackageItem {
|
|||||||
|
|
||||||
pw.print(prefix);
|
pw.print(prefix);
|
||||||
pw.print("Launcher: ");
|
pw.print("Launcher: ");
|
||||||
pw.print(mPackageName);
|
pw.print(getPackageName());
|
||||||
pw.print(" UserId: ");
|
pw.print(" Package user: ");
|
||||||
pw.print(mLauncherUserId);
|
pw.print(getPackageUserId());
|
||||||
|
pw.println();
|
||||||
|
|
||||||
|
getPackageInfo().dump(s, pw, prefix + " ");
|
||||||
pw.println();
|
pw.println();
|
||||||
|
|
||||||
final int size = mPinnedShortcuts.size();
|
final int size = mPinnedShortcuts.size();
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ package com.android.server.pm;
|
|||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.annotation.UserIdInt;
|
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.ShortcutInfo;
|
import android.content.pm.ShortcutInfo;
|
||||||
@@ -41,7 +40,7 @@ import java.util.function.Predicate;
|
|||||||
/**
|
/**
|
||||||
* Package information used by {@link ShortcutService}.
|
* Package information used by {@link ShortcutService}.
|
||||||
*/
|
*/
|
||||||
class ShortcutPackage implements ShortcutPackageItem {
|
class ShortcutPackage extends ShortcutPackageItem {
|
||||||
private static final String TAG = ShortcutService.TAG;
|
private static final String TAG = ShortcutService.TAG;
|
||||||
|
|
||||||
static final String TAG_ROOT = "package";
|
static final String TAG_ROOT = "package";
|
||||||
@@ -63,12 +62,6 @@ class ShortcutPackage implements ShortcutPackageItem {
|
|||||||
private static final String ATTR_ICON_RES = "icon-res";
|
private static final String ATTR_ICON_RES = "icon-res";
|
||||||
private static final String ATTR_BITMAP_PATH = "bitmap-path";
|
private static final String ATTR_BITMAP_PATH = "bitmap-path";
|
||||||
|
|
||||||
@UserIdInt
|
|
||||||
private final int mUserId;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final String mPackageName;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All the shortcuts from the package, keyed on IDs.
|
* All the shortcuts from the package, keyed on IDs.
|
||||||
*/
|
*/
|
||||||
@@ -89,19 +82,18 @@ class ShortcutPackage implements ShortcutPackageItem {
|
|||||||
*/
|
*/
|
||||||
private long mLastResetTime;
|
private long mLastResetTime;
|
||||||
|
|
||||||
ShortcutPackage(int userId, String packageName) {
|
public ShortcutPackage(int packageUserId, String packageName, ShortcutPackageInfo spi) {
|
||||||
mUserId = userId;
|
super(packageUserId, packageName, spi != null ? spi : ShortcutPackageInfo.newEmpty());
|
||||||
mPackageName = packageName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@UserIdInt
|
public ShortcutPackage(int packageUserId, String packageName) {
|
||||||
public int getUserId() {
|
this(packageUserId, packageName, null);
|
||||||
return mUserId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@Override
|
||||||
public String getPackageName() {
|
public int getOwnerUserId() {
|
||||||
return mPackageName;
|
// For packages, always owner user == package user.
|
||||||
|
return getPackageUserId();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -116,7 +108,7 @@ class ShortcutPackage implements ShortcutPackageItem {
|
|||||||
@NonNull String id) {
|
@NonNull String id) {
|
||||||
final ShortcutInfo shortcut = mShortcuts.remove(id);
|
final ShortcutInfo shortcut = mShortcuts.remove(id);
|
||||||
if (shortcut != null) {
|
if (shortcut != null) {
|
||||||
s.removeIcon(mUserId, shortcut);
|
s.removeIcon(getPackageUserId(), shortcut);
|
||||||
shortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_PINNED);
|
shortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_PINNED);
|
||||||
}
|
}
|
||||||
return shortcut;
|
return shortcut;
|
||||||
@@ -124,7 +116,7 @@ class ShortcutPackage implements ShortcutPackageItem {
|
|||||||
|
|
||||||
void addShortcut(@NonNull ShortcutService s, @NonNull ShortcutInfo newShortcut) {
|
void addShortcut(@NonNull ShortcutService s, @NonNull ShortcutInfo newShortcut) {
|
||||||
deleteShortcut(s, newShortcut.getId());
|
deleteShortcut(s, newShortcut.getId());
|
||||||
s.saveIconAndFixUpShortcut(mUserId, newShortcut);
|
s.saveIconAndFixUpShortcut(getPackageUserId(), newShortcut);
|
||||||
mShortcuts.put(newShortcut.getId(), newShortcut);
|
mShortcuts.put(newShortcut.getId(), newShortcut);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,11 +225,12 @@ class ShortcutPackage implements ShortcutPackageItem {
|
|||||||
|
|
||||||
// Then, for the pinned set for each launcher, set the pin flag one by one.
|
// Then, for the pinned set for each launcher, set the pin flag one by one.
|
||||||
final ArrayMap<ShortcutUser.PackageWithUser, ShortcutLauncher> launchers =
|
final ArrayMap<ShortcutUser.PackageWithUser, ShortcutLauncher> launchers =
|
||||||
s.getUserShortcutsLocked(mUserId).getAllLaunchers();
|
s.getUserShortcutsLocked(getPackageUserId()).getAllLaunchers();
|
||||||
|
|
||||||
for (int l = launchers.size() - 1; l >= 0; l--) {
|
for (int l = launchers.size() - 1; l >= 0; l--) {
|
||||||
final ShortcutLauncher launcherShortcuts = launchers.valueAt(l);
|
final ShortcutLauncher launcherShortcuts = launchers.valueAt(l);
|
||||||
final ArraySet<String> pinned = launcherShortcuts.getPinnedShortcutIds(mPackageName);
|
final ArraySet<String> pinned = launcherShortcuts.getPinnedShortcutIds(
|
||||||
|
getPackageName());
|
||||||
|
|
||||||
if (pinned == null || pinned.size() == 0) {
|
if (pinned == null || pinned.size() == 0) {
|
||||||
continue;
|
continue;
|
||||||
@@ -321,8 +314,8 @@ class ShortcutPackage implements ShortcutPackageItem {
|
|||||||
|
|
||||||
// Set of pinned shortcuts by the calling launcher.
|
// Set of pinned shortcuts by the calling launcher.
|
||||||
final ArraySet<String> pinnedByCallerSet = (callingLauncher == null) ? null
|
final ArraySet<String> pinnedByCallerSet = (callingLauncher == null) ? null
|
||||||
: s.getLauncherShortcuts(callingLauncher, mUserId, launcherUserId)
|
: s.getLauncherShortcuts(callingLauncher, getPackageUserId(), launcherUserId)
|
||||||
.getPinnedShortcutIds(mPackageName);
|
.getPinnedShortcutIds(getPackageName());
|
||||||
|
|
||||||
for (int i = 0; i < mShortcuts.size(); i++) {
|
for (int i = 0; i < mShortcuts.size(); i++) {
|
||||||
final ShortcutInfo si = mShortcuts.valueAt(i);
|
final ShortcutInfo si = mShortcuts.valueAt(i);
|
||||||
@@ -362,7 +355,7 @@ class ShortcutPackage implements ShortcutPackageItem {
|
|||||||
|
|
||||||
pw.print(prefix);
|
pw.print(prefix);
|
||||||
pw.print("Package: ");
|
pw.print("Package: ");
|
||||||
pw.print(mPackageName);
|
pw.print(getPackageName());
|
||||||
pw.println();
|
pw.println();
|
||||||
|
|
||||||
pw.print(prefix);
|
pw.print(prefix);
|
||||||
@@ -380,6 +373,9 @@ class ShortcutPackage implements ShortcutPackageItem {
|
|||||||
pw.print(s.formatTime(mLastResetTime));
|
pw.print(s.formatTime(mLastResetTime));
|
||||||
pw.println();
|
pw.println();
|
||||||
|
|
||||||
|
getPackageInfo().dump(s, pw, prefix + " ");
|
||||||
|
pw.println();
|
||||||
|
|
||||||
pw.println(" Shortcuts:");
|
pw.println(" Shortcuts:");
|
||||||
long totalBitmapSize = 0;
|
long totalBitmapSize = 0;
|
||||||
final ArrayMap<String, ShortcutInfo> shortcuts = mShortcuts;
|
final ArrayMap<String, ShortcutInfo> shortcuts = mShortcuts;
|
||||||
@@ -406,6 +402,7 @@ class ShortcutPackage implements ShortcutPackageItem {
|
|||||||
pw.println(")");
|
pw.println(")");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void saveToXml(@NonNull XmlSerializer out, boolean forBackup)
|
public void saveToXml(@NonNull XmlSerializer out, boolean forBackup)
|
||||||
throws IOException, XmlPullParserException {
|
throws IOException, XmlPullParserException {
|
||||||
final int size = mShortcuts.size();
|
final int size = mShortcuts.size();
|
||||||
@@ -416,10 +413,11 @@ class ShortcutPackage implements ShortcutPackageItem {
|
|||||||
|
|
||||||
out.startTag(null, TAG_ROOT);
|
out.startTag(null, TAG_ROOT);
|
||||||
|
|
||||||
ShortcutService.writeAttr(out, ATTR_NAME, mPackageName);
|
ShortcutService.writeAttr(out, ATTR_NAME, getPackageName());
|
||||||
ShortcutService.writeAttr(out, ATTR_DYNAMIC_COUNT, mDynamicShortcutCount);
|
ShortcutService.writeAttr(out, ATTR_DYNAMIC_COUNT, mDynamicShortcutCount);
|
||||||
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);
|
||||||
|
getPackageInfo().saveToXml(out);
|
||||||
|
|
||||||
for (int j = 0; j < size; j++) {
|
for (int j = 0; j < size; j++) {
|
||||||
saveShortcut(out, mShortcuts.valueAt(j), forBackup);
|
saveShortcut(out, mShortcuts.valueAt(j), forBackup);
|
||||||
@@ -464,13 +462,14 @@ class ShortcutPackage implements ShortcutPackageItem {
|
|||||||
out.endTag(null, TAG_SHORTCUT);
|
out.endTag(null, TAG_SHORTCUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShortcutPackage loadFromXml(XmlPullParser parser, int userId)
|
public static ShortcutPackage loadFromXml(ShortcutService s, XmlPullParser parser,
|
||||||
|
int ownerUserId, boolean fromBackup)
|
||||||
throws IOException, XmlPullParserException {
|
throws IOException, XmlPullParserException {
|
||||||
|
|
||||||
final String packageName = ShortcutService.parseStringAttribute(parser,
|
final String packageName = ShortcutService.parseStringAttribute(parser,
|
||||||
ATTR_NAME);
|
ATTR_NAME);
|
||||||
|
|
||||||
final ShortcutPackage ret = new ShortcutPackage(userId, packageName);
|
final ShortcutPackage ret = new ShortcutPackage(ownerUserId, packageName);
|
||||||
|
|
||||||
ret.mDynamicShortcutCount =
|
ret.mDynamicShortcutCount =
|
||||||
ShortcutService.parseIntAttribute(parser, ATTR_DYNAMIC_COUNT);
|
ShortcutService.parseIntAttribute(parser, ATTR_DYNAMIC_COUNT);
|
||||||
@@ -478,6 +477,7 @@ class ShortcutPackage implements ShortcutPackageItem {
|
|||||||
ShortcutService.parseIntAttribute(parser, ATTR_CALL_COUNT);
|
ShortcutService.parseIntAttribute(parser, ATTR_CALL_COUNT);
|
||||||
ret.mLastResetTime =
|
ret.mLastResetTime =
|
||||||
ShortcutService.parseLongAttribute(parser, ATTR_LAST_RESET);
|
ShortcutService.parseLongAttribute(parser, ATTR_LAST_RESET);
|
||||||
|
ShortcutPackageInfo spi = null;
|
||||||
|
|
||||||
final int outerDepth = parser.getDepth();
|
final int outerDepth = parser.getDepth();
|
||||||
int type;
|
int type;
|
||||||
@@ -488,15 +488,23 @@ class ShortcutPackage implements ShortcutPackageItem {
|
|||||||
}
|
}
|
||||||
final int depth = parser.getDepth();
|
final int depth = parser.getDepth();
|
||||||
final String tag = parser.getName();
|
final String tag = parser.getName();
|
||||||
switch (tag) {
|
if (depth == outerDepth + 1) {
|
||||||
case TAG_SHORTCUT:
|
switch (tag) {
|
||||||
final ShortcutInfo si = parseShortcut(parser, packageName);
|
case ShortcutPackageInfo.TAG_ROOT:
|
||||||
|
spi = ShortcutPackageInfo.loadFromXml(parser);
|
||||||
|
continue;
|
||||||
|
case TAG_SHORTCUT:
|
||||||
|
final ShortcutInfo si = parseShortcut(parser, packageName);
|
||||||
|
|
||||||
// Don't use addShortcut(), we don't need to save the icon.
|
// Don't use addShortcut(), we don't need to save the icon.
|
||||||
ret.mShortcuts.put(si.getId(), si);
|
ret.mShortcuts.put(si.getId(), si);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
throw ShortcutService.throwForInvalidTag(depth, tag);
|
ShortcutService.warnForInvalidTag(depth, tag);
|
||||||
|
}
|
||||||
|
if (spi != null) {
|
||||||
|
ret.replacePackageInfo(spi);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -522,8 +530,7 @@ class ShortcutPackage implements ShortcutPackageItem {
|
|||||||
title = ShortcutService.parseStringAttribute(parser, ATTR_TITLE);
|
title = ShortcutService.parseStringAttribute(parser, ATTR_TITLE);
|
||||||
intent = ShortcutService.parseIntentAttribute(parser, ATTR_INTENT);
|
intent = ShortcutService.parseIntentAttribute(parser, ATTR_INTENT);
|
||||||
weight = (int) ShortcutService.parseLongAttribute(parser, ATTR_WEIGHT);
|
weight = (int) ShortcutService.parseLongAttribute(parser, ATTR_WEIGHT);
|
||||||
lastChangedTimestamp = (int) ShortcutService.parseLongAttribute(parser,
|
lastChangedTimestamp = ShortcutService.parseLongAttribute(parser, ATTR_TIMESTAMP);
|
||||||
ATTR_TIMESTAMP);
|
|
||||||
flags = (int) ShortcutService.parseLongAttribute(parser, ATTR_FLAGS);
|
flags = (int) ShortcutService.parseLongAttribute(parser, ATTR_FLAGS);
|
||||||
iconRes = (int) ShortcutService.parseLongAttribute(parser, ATTR_ICON_RES);
|
iconRes = (int) ShortcutService.parseLongAttribute(parser, ATTR_ICON_RES);
|
||||||
bitmapPath = ShortcutService.parseStringAttribute(parser, ATTR_BITMAP_PATH);
|
bitmapPath = ShortcutService.parseStringAttribute(parser, ATTR_BITMAP_PATH);
|
||||||
|
|||||||
@@ -15,14 +15,11 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.server.pm;
|
package com.android.server.pm;
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
|
||||||
import android.annotation.UserIdInt;
|
import android.annotation.UserIdInt;
|
||||||
import android.content.pm.ApplicationInfo;
|
|
||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
import android.content.pm.Signature;
|
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
|
|
||||||
import com.android.internal.util.Preconditions;
|
import com.android.server.backup.BackupUtils;
|
||||||
|
|
||||||
import libcore.io.Base64;
|
import libcore.io.Base64;
|
||||||
import libcore.util.HexEncoding;
|
import libcore.util.HexEncoding;
|
||||||
@@ -33,32 +30,21 @@ import org.xmlpull.v1.XmlSerializer;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Package information used by {@link android.content.pm.ShortcutManager} for backup / restore.
|
* Package information used by {@link android.content.pm.ShortcutManager} for backup / restore.
|
||||||
*
|
|
||||||
* TODO: The methods about signature hashes are copied from BackupManagerService, which is not
|
|
||||||
* visible here. Unify the code.
|
|
||||||
*/
|
*/
|
||||||
class ShortcutPackageInfo implements ShortcutPackageItem {
|
class ShortcutPackageInfo {
|
||||||
private static final String TAG = ShortcutService.TAG;
|
private static final String TAG = ShortcutService.TAG;
|
||||||
|
|
||||||
static final String TAG_ROOT = "package-info";
|
static final String TAG_ROOT = "package-info";
|
||||||
private static final String ATTR_USER_ID = "user";
|
|
||||||
private static final String ATTR_NAME = "name";
|
|
||||||
private static final String ATTR_VERSION = "version";
|
private static final String ATTR_VERSION = "version";
|
||||||
private static final String ATTR_SHADOW = "shadow";
|
private static final String ATTR_SHADOW = "shadow";
|
||||||
|
|
||||||
private static final String TAG_SIGNATURE = "signature";
|
private static final String TAG_SIGNATURE = "signature";
|
||||||
private static final String ATTR_SIGNATURE_HASH = "hash";
|
private static final String ATTR_SIGNATURE_HASH = "hash";
|
||||||
|
|
||||||
private final String mPackageName;
|
|
||||||
private final int mUserId;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When true, this package information was restored from the previous device, and the app hasn't
|
* When true, this package information was restored from the previous device, and the app hasn't
|
||||||
* been installed yet.
|
* been installed yet.
|
||||||
@@ -67,22 +53,14 @@ class ShortcutPackageInfo implements ShortcutPackageItem {
|
|||||||
private int mVersionCode;
|
private int mVersionCode;
|
||||||
private ArrayList<byte[]> mSigHashes;
|
private ArrayList<byte[]> mSigHashes;
|
||||||
|
|
||||||
private ShortcutPackageInfo(String packageName, int userId,
|
private ShortcutPackageInfo(int versionCode, ArrayList<byte[]> sigHashes, boolean isShadow) {
|
||||||
int versionCode, ArrayList<byte[]> sigHashes, boolean isShadow) {
|
|
||||||
mPackageName = Preconditions.checkNotNull(packageName);
|
|
||||||
mUserId = userId;
|
|
||||||
mVersionCode = versionCode;
|
mVersionCode = versionCode;
|
||||||
mIsShadow = isShadow;
|
mIsShadow = isShadow;
|
||||||
mSigHashes = sigHashes;
|
mSigHashes = sigHashes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
public static ShortcutPackageInfo newEmpty() {
|
||||||
public String getPackageName() {
|
return new ShortcutPackageInfo(0, new ArrayList<>(0), /* isShadow */ false);
|
||||||
return mPackageName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getUserId() {
|
|
||||||
return mUserId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isShadow() {
|
public boolean isShadow() {
|
||||||
@@ -101,92 +79,13 @@ class ShortcutPackageInfo implements ShortcutPackageItem {
|
|||||||
return mVersionCode;
|
return mVersionCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] hashSignature(Signature sig) {
|
|
||||||
try {
|
|
||||||
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
|
||||||
digest.update(sig.toByteArray());
|
|
||||||
return digest.digest();
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
Slog.w(TAG, "No SHA-256 algorithm found!");
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ArrayList<byte[]> hashSignatureArray(Signature[] sigs) {
|
|
||||||
if (sigs == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
ArrayList<byte[]> hashes = new ArrayList<byte[]>(sigs.length);
|
|
||||||
for (Signature s : sigs) {
|
|
||||||
hashes.add(hashSignature(s));
|
|
||||||
}
|
|
||||||
return hashes;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean signaturesMatch(ArrayList<byte[]> storedSigHashes, PackageInfo target) {
|
|
||||||
if (target == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the target resides on the system partition, we allow it to restore
|
|
||||||
// data from the like-named package in a restore set even if the signatures
|
|
||||||
// do not match. (Unlike general applications, those flashed to the system
|
|
||||||
// partition will be signed with the device's platform certificate, so on
|
|
||||||
// different phones the same system app will have different signatures.)
|
|
||||||
if ((target.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allow unsigned apps, but not signed on one device and unsigned on the other
|
|
||||||
// !!! TODO: is this the right policy?
|
|
||||||
Signature[] deviceSigs = target.signatures;
|
|
||||||
if ((storedSigHashes == null || storedSigHashes.size() == 0)
|
|
||||||
&& (deviceSigs == null || deviceSigs.length == 0)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (storedSigHashes == null || deviceSigs == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// !!! TODO: this demands that every stored signature match one
|
|
||||||
// that is present on device, and does not demand the converse.
|
|
||||||
// Is this this right policy?
|
|
||||||
final int nStored = storedSigHashes.size();
|
|
||||||
final int nDevice = deviceSigs.length;
|
|
||||||
|
|
||||||
// hash each on-device signature
|
|
||||||
ArrayList<byte[]> deviceHashes = new ArrayList<byte[]>(nDevice);
|
|
||||||
for (int i = 0; i < nDevice; i++) {
|
|
||||||
deviceHashes.add(hashSignature(deviceSigs[i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
// now ensure that each stored sig (hash) matches an on-device sig (hash)
|
|
||||||
for (int n = 0; n < nStored; n++) {
|
|
||||||
boolean match = false;
|
|
||||||
final byte[] storedHash = storedSigHashes.get(n);
|
|
||||||
for (int i = 0; i < nDevice; i++) {
|
|
||||||
if (Arrays.equals(storedHash, deviceHashes.get(i))) {
|
|
||||||
match = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// match is false when no on-device sig matched one of the stored ones
|
|
||||||
if (!match) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean canRestoreTo(PackageInfo target) {
|
public boolean canRestoreTo(PackageInfo target) {
|
||||||
if (target.versionCode < mVersionCode) {
|
if (target.versionCode < mVersionCode) {
|
||||||
Slog.w(TAG, String.format("Package current version %d < backed up version %d",
|
Slog.w(TAG, String.format("Package current version %d < backed up version %d",
|
||||||
target.versionCode, mVersionCode));
|
target.versionCode, mVersionCode));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!signaturesMatch(mSigHashes, target)) {
|
if (!BackupUtils.signaturesMatch(mSigHashes, target)) {
|
||||||
Slog.w(TAG, "Package signature mismtach");
|
Slog.w(TAG, "Package signature mismtach");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -194,37 +93,34 @@ class ShortcutPackageInfo implements ShortcutPackageItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static ShortcutPackageInfo generateForInstalledPackage(
|
public static ShortcutPackageInfo generateForInstalledPackage(
|
||||||
ShortcutService s, String packageName, @UserIdInt int userId) {
|
ShortcutService s, String packageName, @UserIdInt int packageUserId) {
|
||||||
final PackageInfo pi = s.getPackageInfoWithSignatures(packageName, userId);
|
final PackageInfo pi = s.getPackageInfoWithSignatures(packageName, packageUserId);
|
||||||
if (pi.signatures == null || pi.signatures.length == 0) {
|
if (pi.signatures == null || pi.signatures.length == 0) {
|
||||||
Slog.e(TAG, "Can't get signatures: package=" + packageName);
|
Slog.e(TAG, "Can't get signatures: package=" + packageName);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final ShortcutPackageInfo ret = new ShortcutPackageInfo(packageName, userId, pi.versionCode,
|
final ShortcutPackageInfo ret = new ShortcutPackageInfo(pi.versionCode,
|
||||||
hashSignatureArray(pi.signatures), /* shadow=*/ false);
|
BackupUtils.hashSignatureArray(pi.signatures), /* shadow=*/ false);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void refreshAndSave(ShortcutService s, @UserIdInt int userId) {
|
public void refresh(ShortcutService s, ShortcutPackageItem pkg) {
|
||||||
final PackageInfo pi = s.getPackageInfoWithSignatures(mPackageName, userId);
|
// Note use mUserId here, rather than userId.
|
||||||
|
final PackageInfo pi = s.getPackageInfoWithSignatures(
|
||||||
|
pkg.getPackageName(), pkg.getPackageUserId());
|
||||||
if (pi == null) {
|
if (pi == null) {
|
||||||
Slog.w(TAG, "Package not found: " + mPackageName);
|
Slog.w(TAG, "Package not found: " + pkg.getPackageName());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mVersionCode = pi.versionCode;
|
mVersionCode = pi.versionCode;
|
||||||
mSigHashes = hashSignatureArray(pi.signatures);
|
mSigHashes = BackupUtils.hashSignatureArray(pi.signatures);
|
||||||
|
|
||||||
s.scheduleSaveUser(userId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveToXml(XmlSerializer out, boolean forBackup)
|
public void saveToXml(XmlSerializer out) throws IOException {
|
||||||
throws IOException, XmlPullParserException {
|
|
||||||
|
|
||||||
out.startTag(null, TAG_ROOT);
|
out.startTag(null, TAG_ROOT);
|
||||||
|
|
||||||
ShortcutService.writeAttr(out, ATTR_NAME, mPackageName);
|
|
||||||
ShortcutService.writeAttr(out, ATTR_USER_ID, mUserId);
|
|
||||||
ShortcutService.writeAttr(out, ATTR_VERSION, mVersionCode);
|
ShortcutService.writeAttr(out, ATTR_VERSION, mVersionCode);
|
||||||
ShortcutService.writeAttr(out, ATTR_SHADOW, mIsShadow);
|
ShortcutService.writeAttr(out, ATTR_SHADOW, mIsShadow);
|
||||||
|
|
||||||
@@ -236,11 +132,9 @@ class ShortcutPackageInfo implements ShortcutPackageItem {
|
|||||||
out.endTag(null, TAG_ROOT);
|
out.endTag(null, TAG_ROOT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShortcutPackageInfo loadFromXml(XmlPullParser parser, int ownerUserId)
|
public static ShortcutPackageInfo loadFromXml(XmlPullParser parser)
|
||||||
throws IOException, XmlPullParserException {
|
throws IOException, XmlPullParserException {
|
||||||
|
|
||||||
final String packageName = ShortcutService.parseStringAttribute(parser, ATTR_NAME);
|
|
||||||
final int userId = ShortcutService.parseIntAttribute(parser, ATTR_USER_ID, ownerUserId);
|
|
||||||
final int versionCode = ShortcutService.parseIntAttribute(parser, ATTR_VERSION);
|
final int versionCode = ShortcutService.parseIntAttribute(parser, ATTR_VERSION);
|
||||||
final boolean shadow = ShortcutService.parseBooleanAttribute(parser, ATTR_SHADOW);
|
final boolean shadow = ShortcutService.parseBooleanAttribute(parser, ATTR_SHADOW);
|
||||||
|
|
||||||
@@ -256,31 +150,27 @@ class ShortcutPackageInfo implements ShortcutPackageItem {
|
|||||||
}
|
}
|
||||||
final int depth = parser.getDepth();
|
final int depth = parser.getDepth();
|
||||||
final String tag = parser.getName();
|
final String tag = parser.getName();
|
||||||
switch (tag) {
|
|
||||||
case TAG_SIGNATURE: {
|
if (depth == outerDepth + 1) {
|
||||||
final String hash = ShortcutService.parseStringAttribute(
|
switch (tag) {
|
||||||
parser, ATTR_SIGNATURE_HASH);
|
case TAG_SIGNATURE: {
|
||||||
hashes.add(Base64.decode(hash.getBytes()));
|
final String hash = ShortcutService.parseStringAttribute(
|
||||||
continue;
|
parser, ATTR_SIGNATURE_HASH);
|
||||||
|
hashes.add(Base64.decode(hash.getBytes()));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw ShortcutService.throwForInvalidTag(depth, tag);
|
ShortcutService.warnForInvalidTag(depth, tag);
|
||||||
}
|
}
|
||||||
return new ShortcutPackageInfo(packageName, userId, versionCode, hashes, shadow);
|
return new ShortcutPackageInfo(versionCode, hashes, shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dump(ShortcutService s, PrintWriter pw, String prefix) {
|
public void dump(ShortcutService s, PrintWriter pw, String prefix) {
|
||||||
pw.println();
|
pw.println();
|
||||||
|
|
||||||
pw.print(prefix);
|
pw.print(prefix);
|
||||||
pw.print("PackageInfo: ");
|
pw.println("PackageInfo:");
|
||||||
pw.print(mPackageName);
|
|
||||||
pw.println();
|
|
||||||
|
|
||||||
pw.print(prefix);
|
|
||||||
pw.print(" User: ");
|
|
||||||
pw.print(mUserId);
|
|
||||||
pw.println();
|
|
||||||
|
|
||||||
pw.print(prefix);
|
pw.print(prefix);
|
||||||
pw.print(" IsShadow: ");
|
pw.print(" IsShadow: ");
|
||||||
|
|||||||
@@ -17,15 +17,69 @@ package com.android.server.pm;
|
|||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.android.internal.util.Preconditions;
|
||||||
|
|
||||||
import org.xmlpull.v1.XmlPullParserException;
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
import org.xmlpull.v1.XmlSerializer;
|
import org.xmlpull.v1.XmlSerializer;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public interface ShortcutPackageItem {
|
abstract class ShortcutPackageItem {
|
||||||
@NonNull
|
private final int mPackageUserId;
|
||||||
String getPackageName();
|
private final String mPackageName;
|
||||||
|
|
||||||
void saveToXml(@NonNull XmlSerializer out, boolean forBackup)
|
private ShortcutPackageInfo mPackageInfo;
|
||||||
|
|
||||||
|
protected ShortcutPackageItem(int packageUserId, @NonNull String packageName,
|
||||||
|
@NonNull ShortcutPackageInfo packageInfo) {
|
||||||
|
mPackageUserId = packageUserId;
|
||||||
|
mPackageName = Preconditions.checkStringNotEmpty(packageName);
|
||||||
|
mPackageInfo = Preconditions.checkNotNull(packageInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID of the user who actually has this package running on. For {@link ShortcutPackage},
|
||||||
|
* this is the same thing as {@link #getOwnerUserId}, but if it's a {@link ShortcutLauncher} and
|
||||||
|
* {@link #getOwnerUserId} is of a work profile, then this ID could be the user who owns the
|
||||||
|
* profile.
|
||||||
|
*/
|
||||||
|
public int getPackageUserId() {
|
||||||
|
return mPackageUserId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID of the user who sees the shortcuts from this instance.
|
||||||
|
*/
|
||||||
|
public abstract int getOwnerUserId();
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public String getPackageName() {
|
||||||
|
return mPackageName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShortcutPackageInfo getPackageInfo() {
|
||||||
|
return mPackageInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should be only used when loading from a file.o
|
||||||
|
*/
|
||||||
|
protected void replacePackageInfo(@NonNull ShortcutPackageInfo packageInfo) {
|
||||||
|
mPackageInfo = Preconditions.checkNotNull(packageInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void refreshPackageInfoAndSave(ShortcutService s) {
|
||||||
|
mPackageInfo.refresh(s, this);
|
||||||
|
s.scheduleSaveUser(getOwnerUserId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ensureNotShadowAndSave(ShortcutService s) {
|
||||||
|
if (mPackageInfo.isShadow()) {
|
||||||
|
mPackageInfo.setShadow(false);
|
||||||
|
s.scheduleSaveUser(getOwnerUserId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void saveToXml(@NonNull XmlSerializer out, boolean forBackup)
|
||||||
throws IOException, XmlPullParserException;
|
throws IOException, XmlPullParserException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,6 @@ import com.android.internal.annotations.GuardedBy;
|
|||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.content.PackageMonitor;
|
import com.android.internal.content.PackageMonitor;
|
||||||
import com.android.internal.os.BackgroundThread;
|
import com.android.internal.os.BackgroundThread;
|
||||||
import com.android.internal.util.ArrayUtils;
|
|
||||||
import com.android.internal.util.FastXmlSerializer;
|
import com.android.internal.util.FastXmlSerializer;
|
||||||
import com.android.internal.util.Preconditions;
|
import com.android.internal.util.Preconditions;
|
||||||
import com.android.server.LocalServices;
|
import com.android.server.LocalServices;
|
||||||
@@ -85,6 +84,10 @@ import org.xmlpull.v1.XmlPullParser;
|
|||||||
import org.xmlpull.v1.XmlPullParserException;
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
import org.xmlpull.v1.XmlSerializer;
|
import org.xmlpull.v1.XmlSerializer;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.BufferedOutputStream;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
@@ -92,6 +95,7 @@ import java.io.FileNotFoundException;
|
|||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
@@ -104,8 +108,6 @@ import java.util.function.Predicate;
|
|||||||
*
|
*
|
||||||
* - Default launcher check does take a few ms. Worth caching.
|
* - Default launcher check does take a few ms. Worth caching.
|
||||||
*
|
*
|
||||||
* - Don't backup launcher from different profile.
|
|
||||||
*
|
|
||||||
* - Clear data -> remove all dynamic? but not the pinned?
|
* - Clear data -> remove all dynamic? but not the pinned?
|
||||||
*
|
*
|
||||||
* - Scan and remove orphan bitmaps (just in case).
|
* - Scan and remove orphan bitmaps (just in case).
|
||||||
@@ -633,31 +635,45 @@ public class ShortcutService extends IShortcutService.Stub {
|
|||||||
}
|
}
|
||||||
path.mkdirs();
|
path.mkdirs();
|
||||||
final AtomicFile file = new AtomicFile(path);
|
final AtomicFile file = new AtomicFile(path);
|
||||||
FileOutputStream outs = null;
|
FileOutputStream os = null;
|
||||||
try {
|
try {
|
||||||
outs = file.startWrite();
|
os = file.startWrite();
|
||||||
|
|
||||||
// Write to XML
|
saveUserInternalLocked(userId, os, /* forBackup= */ false);
|
||||||
XmlSerializer out = new FastXmlSerializer();
|
|
||||||
out.setOutput(outs, StandardCharsets.UTF_8.name());
|
|
||||||
out.startDocument(null, true);
|
|
||||||
|
|
||||||
getUserShortcutsLocked(userId).saveToXml(this, out, /* forBackup= */ false);
|
file.finishWrite(os);
|
||||||
|
} catch (XmlPullParserException|IOException e) {
|
||||||
out.endDocument();
|
|
||||||
|
|
||||||
// Close.
|
|
||||||
file.finishWrite(outs);
|
|
||||||
} catch (IOException|XmlPullParserException e) {
|
|
||||||
Slog.e(TAG, "Failed to write to file " + file.getBaseFile(), e);
|
Slog.e(TAG, "Failed to write to file " + file.getBaseFile(), e);
|
||||||
file.failWrite(outs);
|
file.failWrite(os);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void saveUserInternalLocked(@UserIdInt int userId, OutputStream os,
|
||||||
|
boolean forBackup) throws IOException, XmlPullParserException {
|
||||||
|
|
||||||
|
final BufferedOutputStream bos = new BufferedOutputStream(os);
|
||||||
|
|
||||||
|
// Write to XML
|
||||||
|
XmlSerializer out = new FastXmlSerializer();
|
||||||
|
out.setOutput(bos, StandardCharsets.UTF_8.name());
|
||||||
|
out.startDocument(null, true);
|
||||||
|
|
||||||
|
getUserShortcutsLocked(userId).saveToXml(this, out, forBackup);
|
||||||
|
|
||||||
|
out.endDocument();
|
||||||
|
|
||||||
|
bos.flush();
|
||||||
|
os.flush();
|
||||||
|
}
|
||||||
|
|
||||||
static IOException throwForInvalidTag(int depth, String tag) throws IOException {
|
static IOException throwForInvalidTag(int depth, String tag) throws IOException {
|
||||||
throw new IOException(String.format("Invalid tag '%s' found at depth %d", tag, depth));
|
throw new IOException(String.format("Invalid tag '%s' found at depth %d", tag, depth));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void warnForInvalidTag(int depth, String tag) throws IOException {
|
||||||
|
Slog.w(TAG, String.format("Invalid tag '%s' found at depth %d", tag, depth));
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private ShortcutUser loadUserLocked(@UserIdInt int userId) {
|
private ShortcutUser loadUserLocked(@UserIdInt int userId) {
|
||||||
final File path = new File(injectUserDataPath(userId), FILENAME_USER_PACKAGES);
|
final File path = new File(injectUserDataPath(userId), FILENAME_USER_PACKAGES);
|
||||||
@@ -675,30 +691,8 @@ public class ShortcutService extends IShortcutService.Stub {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
ShortcutUser ret = null;
|
|
||||||
try {
|
try {
|
||||||
XmlPullParser parser = Xml.newPullParser();
|
return loadUserInternal(userId, in, /* forBackup= */ false);
|
||||||
parser.setInput(in, StandardCharsets.UTF_8.name());
|
|
||||||
|
|
||||||
int type;
|
|
||||||
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
|
|
||||||
if (type != XmlPullParser.START_TAG) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
final int depth = parser.getDepth();
|
|
||||||
|
|
||||||
final String tag = parser.getName();
|
|
||||||
if (DEBUG_LOAD) {
|
|
||||||
Slog.d(TAG, String.format("depth=%d type=%d name=%s",
|
|
||||||
depth, type, tag));
|
|
||||||
}
|
|
||||||
if ((depth == 1) && ShortcutUser.TAG_ROOT.equals(tag)) {
|
|
||||||
ret = ShortcutUser.loadFromXml(parser, userId);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
throwForInvalidTag(depth, tag);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
} catch (IOException|XmlPullParserException e) {
|
} catch (IOException|XmlPullParserException e) {
|
||||||
Slog.e(TAG, "Failed to read file " + file.getBaseFile(), e);
|
Slog.e(TAG, "Failed to read file " + file.getBaseFile(), e);
|
||||||
return null;
|
return null;
|
||||||
@@ -707,6 +701,36 @@ public class ShortcutService extends IShortcutService.Stub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ShortcutUser loadUserInternal(@UserIdInt int userId, InputStream is,
|
||||||
|
boolean fromBackup) throws XmlPullParserException, IOException {
|
||||||
|
|
||||||
|
final BufferedInputStream bis = new BufferedInputStream(is);
|
||||||
|
|
||||||
|
ShortcutUser ret = null;
|
||||||
|
XmlPullParser parser = Xml.newPullParser();
|
||||||
|
parser.setInput(bis, StandardCharsets.UTF_8.name());
|
||||||
|
|
||||||
|
int type;
|
||||||
|
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
|
||||||
|
if (type != XmlPullParser.START_TAG) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final int depth = parser.getDepth();
|
||||||
|
|
||||||
|
final String tag = parser.getName();
|
||||||
|
if (DEBUG_LOAD) {
|
||||||
|
Slog.d(TAG, String.format("depth=%d type=%d name=%s",
|
||||||
|
depth, type, tag));
|
||||||
|
}
|
||||||
|
if ((depth == 1) && ShortcutUser.TAG_ROOT.equals(tag)) {
|
||||||
|
ret = ShortcutUser.loadFromXml(this, parser, userId, fromBackup);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throwForInvalidTag(depth, tag);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
private void scheduleSaveBaseState() {
|
private void scheduleSaveBaseState() {
|
||||||
scheduleSaveInner(UserHandle.USER_NULL); // Special case -- use USER_NULL for base state.
|
scheduleSaveInner(UserHandle.USER_NULL); // Special case -- use USER_NULL for base state.
|
||||||
}
|
}
|
||||||
@@ -1042,6 +1066,10 @@ public class ShortcutService extends IShortcutService.Stub {
|
|||||||
Preconditions.checkState(isCallerShell(), "Caller must be shell");
|
Preconditions.checkState(isCallerShell(), "Caller must be shell");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void enforceSystem() {
|
||||||
|
Preconditions.checkState(isCallerSystem(), "Caller must be system");
|
||||||
|
}
|
||||||
|
|
||||||
private void verifyCaller(@NonNull String packageName, @UserIdInt int userId) {
|
private void verifyCaller(@NonNull String packageName, @UserIdInt int userId) {
|
||||||
Preconditions.checkStringNotEmpty(packageName, "packageName");
|
Preconditions.checkStringNotEmpty(packageName, "packageName");
|
||||||
|
|
||||||
@@ -1182,10 +1210,10 @@ public class ShortcutService extends IShortcutService.Stub {
|
|||||||
final int size = newShortcuts.size();
|
final int size = newShortcuts.size();
|
||||||
|
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
getUserShortcutsLocked(userId).ensurePackageInfo(this, packageName, userId);
|
|
||||||
|
|
||||||
final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
|
final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
|
||||||
|
|
||||||
|
ps.ensureNotShadowAndSave(this);
|
||||||
|
|
||||||
// Throttling.
|
// Throttling.
|
||||||
if (!ps.tryApiCall(this)) {
|
if (!ps.tryApiCall(this)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -1219,10 +1247,10 @@ public class ShortcutService extends IShortcutService.Stub {
|
|||||||
final int size = newShortcuts.size();
|
final int size = newShortcuts.size();
|
||||||
|
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
getUserShortcutsLocked(userId).ensurePackageInfo(this, packageName, userId);
|
|
||||||
|
|
||||||
final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
|
final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
|
||||||
|
|
||||||
|
ps.ensureNotShadowAndSave(this);
|
||||||
|
|
||||||
// Throttling.
|
// Throttling.
|
||||||
if (!ps.tryApiCall(this)) {
|
if (!ps.tryApiCall(this)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -1258,10 +1286,10 @@ public class ShortcutService extends IShortcutService.Stub {
|
|||||||
verifyCaller(packageName, userId);
|
verifyCaller(packageName, userId);
|
||||||
|
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
getUserShortcutsLocked(userId).ensurePackageInfo(this, packageName, userId);
|
|
||||||
|
|
||||||
final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
|
final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
|
||||||
|
|
||||||
|
ps.ensureNotShadowAndSave(this);
|
||||||
|
|
||||||
// Throttling.
|
// Throttling.
|
||||||
if (!ps.tryApiCall(this)) {
|
if (!ps.tryApiCall(this)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -1466,6 +1494,9 @@ public class ShortcutService extends IShortcutService.Stub {
|
|||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
void cleanUpPackageLocked(String packageName, int owningUserId, int packageUserId) {
|
void cleanUpPackageLocked(String packageName, int owningUserId, int packageUserId) {
|
||||||
|
|
||||||
|
// TODO Don't remove shadow packages' information.
|
||||||
|
|
||||||
final boolean wasUserLoaded = isUserLoadedLocked(owningUserId);
|
final boolean wasUserLoaded = isUserLoadedLocked(owningUserId);
|
||||||
|
|
||||||
final ShortcutUser mUser = getUserShortcutsLocked(owningUserId);
|
final ShortcutUser mUser = getUserShortcutsLocked(owningUserId);
|
||||||
@@ -1492,9 +1523,6 @@ public class ShortcutService extends IShortcutService.Stub {
|
|||||||
mUser.getPackages().valueAt(i).refreshPinnedFlags(this);
|
mUser.getPackages().valueAt(i).refreshPinnedFlags(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the package info too.
|
|
||||||
mUser.removePackageInfo(packageUserId, packageName);
|
|
||||||
|
|
||||||
scheduleSaveUser(owningUserId);
|
scheduleSaveUser(owningUserId);
|
||||||
|
|
||||||
if (doNotify) {
|
if (doNotify) {
|
||||||
@@ -1617,11 +1645,13 @@ public class ShortcutService extends IShortcutService.Stub {
|
|||||||
Preconditions.checkNotNull(shortcutIds, "shortcutIds");
|
Preconditions.checkNotNull(shortcutIds, "shortcutIds");
|
||||||
|
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
getUserShortcutsLocked(userId).ensurePackageInfo(
|
final ShortcutLauncher launcher =
|
||||||
ShortcutService.this, callingPackage, launcherUserId);
|
getLauncherShortcuts(callingPackage, userId, launcherUserId);
|
||||||
|
|
||||||
getLauncherShortcuts(callingPackage, userId, launcherUserId).pinShortcuts(
|
launcher.ensureNotShadowAndSave(ShortcutService.this);
|
||||||
ShortcutService.this, packageName, shortcutIds);
|
|
||||||
|
launcher.pinShortcuts(
|
||||||
|
ShortcutService.this, userId, packageName, shortcutIds);
|
||||||
}
|
}
|
||||||
userPackageChanged(packageName, userId);
|
userPackageChanged(packageName, userId);
|
||||||
}
|
}
|
||||||
@@ -1731,23 +1761,21 @@ public class ShortcutService extends IShortcutService.Stub {
|
|||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(TAG, "cleanupGonePackages() userId=" + userId);
|
Slog.d(TAG, "cleanupGonePackages() userId=" + userId);
|
||||||
}
|
}
|
||||||
ArrayList<PackageWithUser> gonePackages = null;
|
final ArrayList<PackageWithUser> gonePackages = new ArrayList<>();
|
||||||
|
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
final ShortcutUser user = getUserShortcutsLocked(userId);
|
final ShortcutUser user = getUserShortcutsLocked(userId);
|
||||||
final ArrayMap<PackageWithUser, ShortcutPackageInfo> infos = user.getAllPackageInfos();
|
|
||||||
for (int i = infos.size() -1; i >= 0; i--) {
|
user.forAllPackageItems(spi -> {
|
||||||
final ShortcutPackageInfo info = infos.valueAt(i);
|
if (spi.getPackageInfo().isShadow()) {
|
||||||
if (info.isShadow()) {
|
return; // Don't delete shadow information.
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
if (isPackageInstalled(info.getPackageName(), info.getUserId())) {
|
if (isPackageInstalled(spi.getPackageName(), spi.getPackageUserId())) {
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
gonePackages = ArrayUtils.add(gonePackages,
|
gonePackages.add(PackageWithUser.of(spi));
|
||||||
PackageWithUser.of(info.getUserId(), info.getPackageName()));
|
});
|
||||||
}
|
if (gonePackages.size() > 0) {
|
||||||
if (gonePackages != null) {
|
|
||||||
for (int i = gonePackages.size() - 1; i >= 0; i--) {
|
for (int i = gonePackages.size() - 1; i >= 0; i--) {
|
||||||
final PackageWithUser pu = gonePackages.get(i);
|
final PackageWithUser pu = gonePackages.get(i);
|
||||||
cleanUpPackageLocked(pu.packageName, userId, pu.userId);
|
cleanUpPackageLocked(pu.packageName, userId, pu.userId);
|
||||||
@@ -1761,25 +1789,18 @@ public class ShortcutService extends IShortcutService.Stub {
|
|||||||
Slog.d(TAG, String.format("handlePackageAdded: %s user=%d", packageName, userId));
|
Slog.d(TAG, String.format("handlePackageAdded: %s user=%d", packageName, userId));
|
||||||
}
|
}
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
final ShortcutPackageInfo existing = getUserShortcutsLocked(userId)
|
getUserShortcutsLocked(userId).unshadowPackage(this, packageName, userId);
|
||||||
.getPackageInfo(userId, packageName);
|
|
||||||
|
|
||||||
if (existing != null && existing.isShadow()) {
|
|
||||||
Slog.w(TAG, "handlePackageAdded: TODO Restore not implemented");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handlePackageUpdateFinished(String packageName, @UserIdInt int userId) {
|
private void handlePackageUpdateFinished(String packageName, @UserIdInt int userId) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(TAG, String.format("handlePackageUpdateFinished: %s user=%d", packageName, userId));
|
Slog.d(TAG, String.format("handlePackageUpdateFinished: %s user=%d",
|
||||||
|
packageName, userId));
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
final ShortcutPackageInfo spi =
|
getUserShortcutsLocked(userId).unshadowPackage(this, packageName, userId);
|
||||||
getUserShortcutsLocked(userId).getPackageInfo(userId, packageName);
|
|
||||||
if (spi != null) {
|
|
||||||
spi.refreshAndSave(this, userId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1792,13 +1813,14 @@ public class ShortcutService extends IShortcutService.Stub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// === Backup & restore ===
|
// === PackageManager interaction ===
|
||||||
|
|
||||||
PackageInfo getPackageInfoWithSignatures(String packageName, @UserIdInt int userId) {
|
PackageInfo getPackageInfoWithSignatures(String packageName, @UserIdInt int userId) {
|
||||||
return injectPackageInfo(packageName, userId, true);
|
return injectPackageInfo(packageName, userId, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
int injectGetPackageUid(@NonNull String packageName, @UserIdInt int userId) {
|
int injectGetPackageUid(@NonNull String packageName, @UserIdInt int userId) {
|
||||||
|
final long token = injectClearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
return mIPackageManager.getPackageUid(packageName, PACKAGE_MATCH_FLAGS
|
return mIPackageManager.getPackageUid(packageName, PACKAGE_MATCH_FLAGS
|
||||||
, userId);
|
, userId);
|
||||||
@@ -1806,12 +1828,15 @@ public class ShortcutService extends IShortcutService.Stub {
|
|||||||
// Shouldn't happen.
|
// Shouldn't happen.
|
||||||
Slog.wtf(TAG, "RemoteException", e);
|
Slog.wtf(TAG, "RemoteException", e);
|
||||||
return -1;
|
return -1;
|
||||||
|
} finally {
|
||||||
|
injectRestoreCallingIdentity(token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
PackageInfo injectPackageInfo(String packageName, @UserIdInt int userId,
|
PackageInfo injectPackageInfo(String packageName, @UserIdInt int userId,
|
||||||
boolean getSignatures) {
|
boolean getSignatures) {
|
||||||
|
final long token = injectClearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
return mIPackageManager.getPackageInfo(packageName, PACKAGE_MATCH_FLAGS
|
return mIPackageManager.getPackageInfo(packageName, PACKAGE_MATCH_FLAGS
|
||||||
| (getSignatures ? PackageManager.GET_SIGNATURES : 0)
|
| (getSignatures ? PackageManager.GET_SIGNATURES : 0)
|
||||||
@@ -1820,17 +1845,22 @@ public class ShortcutService extends IShortcutService.Stub {
|
|||||||
// Shouldn't happen.
|
// Shouldn't happen.
|
||||||
Slog.wtf(TAG, "RemoteException", e);
|
Slog.wtf(TAG, "RemoteException", e);
|
||||||
return null;
|
return null;
|
||||||
|
} finally {
|
||||||
|
injectRestoreCallingIdentity(token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
ApplicationInfo injectApplicationInfo(String packageName, @UserIdInt int userId) {
|
ApplicationInfo injectApplicationInfo(String packageName, @UserIdInt int userId) {
|
||||||
|
final long token = injectClearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
return mIPackageManager.getApplicationInfo(packageName, PACKAGE_MATCH_FLAGS, userId);
|
return mIPackageManager.getApplicationInfo(packageName, PACKAGE_MATCH_FLAGS, userId);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
// Shouldn't happen.
|
// Shouldn't happen.
|
||||||
Slog.wtf(TAG, "RemoteException", e);
|
Slog.wtf(TAG, "RemoteException", e);
|
||||||
return null;
|
return null;
|
||||||
|
} finally {
|
||||||
|
injectRestoreCallingIdentity(token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1839,12 +1869,61 @@ public class ShortcutService extends IShortcutService.Stub {
|
|||||||
return (ai != null) && ((ai.flags & flags) == flags);
|
return (ai != null) && ((ai.flags & flags) == flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isPackageInstalled(String packageName, int userId) {
|
||||||
|
return isApplicationFlagSet(packageName, userId, ApplicationInfo.FLAG_INSTALLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// === Backup & restore ===
|
||||||
|
|
||||||
boolean shouldBackupApp(String packageName, int userId) {
|
boolean shouldBackupApp(String packageName, int userId) {
|
||||||
return isApplicationFlagSet(packageName, userId, ApplicationInfo.FLAG_ALLOW_BACKUP);
|
return isApplicationFlagSet(packageName, userId, ApplicationInfo.FLAG_ALLOW_BACKUP);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isPackageInstalled(String packageName, int userId) {
|
@Override
|
||||||
return isApplicationFlagSet(packageName, userId, ApplicationInfo.FLAG_INSTALLED);
|
public byte[] getBackupPayload(@UserIdInt int userId) throws RemoteException {
|
||||||
|
enforceSystem();
|
||||||
|
if (DEBUG) {
|
||||||
|
Slog.d(TAG, "Backing up user " + userId);
|
||||||
|
}
|
||||||
|
synchronized (mLock) {
|
||||||
|
final ShortcutUser user = getUserShortcutsLocked(userId);
|
||||||
|
if (user == null) {
|
||||||
|
Slog.w(TAG, "Can't backup: user not found: id=" + userId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
user.forAllPackageItems(spi -> spi.refreshPackageInfoAndSave(this));
|
||||||
|
|
||||||
|
// Then save.
|
||||||
|
final ByteArrayOutputStream os = new ByteArrayOutputStream(32 * 1024);
|
||||||
|
try {
|
||||||
|
saveUserInternalLocked(userId, os, /* forBackup */ true);
|
||||||
|
} catch (XmlPullParserException|IOException e) {
|
||||||
|
// Shouldn't happen.
|
||||||
|
Slog.w(TAG, "Backup failed.", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return os.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void applyRestore(byte[] payload, @UserIdInt int userId) throws RemoteException {
|
||||||
|
enforceSystem();
|
||||||
|
if (DEBUG) {
|
||||||
|
Slog.d(TAG, "Restoring user " + userId);
|
||||||
|
}
|
||||||
|
final ShortcutUser user;
|
||||||
|
final ByteArrayInputStream is = new ByteArrayInputStream(payload);
|
||||||
|
try {
|
||||||
|
user = loadUserInternal(userId, is, /* fromBackup */ true);
|
||||||
|
} catch (XmlPullParserException|IOException e) {
|
||||||
|
Slog.w(TAG, "Restoration failed.", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
synchronized (mLock) {
|
||||||
|
mUsers.put(userId, user);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// === Dump ===
|
// === Dump ===
|
||||||
@@ -2202,19 +2281,4 @@ public class ShortcutService extends IShortcutService.Stub {
|
|||||||
return pkg.findShortcutById(shortcutId);
|
return pkg.findShortcutById(shortcutId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
ShortcutPackageInfo getPackageInfoForTest(String packageName, int userId) {
|
|
||||||
return getPackageInfoForTest(packageName, userId, userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
ShortcutPackageInfo getPackageInfoForTest(String packageName, int userId, int packageUserId) {
|
|
||||||
synchronized (mLock) {
|
|
||||||
final ShortcutUser user = mUsers.get(userId);
|
|
||||||
if (user == null) return null;
|
|
||||||
|
|
||||||
return user.getPackageInfo(packageUserId, packageName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import org.xmlpull.v1.XmlSerializer;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User information used by {@link ShortcutService}.
|
* User information used by {@link ShortcutService}.
|
||||||
@@ -56,6 +57,10 @@ class ShortcutUser {
|
|||||||
return new PackageWithUser(launcherUserId, packageName);
|
return new PackageWithUser(launcherUserId, packageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static PackageWithUser of(ShortcutPackageItem spi) {
|
||||||
|
return new PackageWithUser(spi.getPackageUserId(), spi.getPackageName());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return packageName.hashCode() ^ userId;
|
return packageName.hashCode() ^ userId;
|
||||||
@@ -84,8 +89,6 @@ class ShortcutUser {
|
|||||||
|
|
||||||
private final ArrayMap<PackageWithUser, ShortcutLauncher> mLaunchers = new ArrayMap<>();
|
private final ArrayMap<PackageWithUser, ShortcutLauncher> mLaunchers = new ArrayMap<>();
|
||||||
|
|
||||||
private final ArrayMap<PackageWithUser, ShortcutPackageInfo> mPackageInfos = new ArrayMap<>();
|
|
||||||
|
|
||||||
private ComponentName mLauncherComponent;
|
private ComponentName mLauncherComponent;
|
||||||
|
|
||||||
public ShortcutUser(int userId) {
|
public ShortcutUser(int userId) {
|
||||||
@@ -100,35 +103,14 @@ class ShortcutUser {
|
|||||||
return mLaunchers;
|
return mLaunchers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShortcutLauncher getLauncher(@UserIdInt int userId, @NonNull String packageName) {
|
|
||||||
return mLaunchers.get(PackageWithUser.of(userId, packageName));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addLauncher(ShortcutLauncher launcher) {
|
public void addLauncher(ShortcutLauncher launcher) {
|
||||||
mLaunchers.put(PackageWithUser.of(launcher.getUserId(), launcher.getPackageName()),
|
mLaunchers.put(PackageWithUser.of(launcher.getPackageUserId(),
|
||||||
launcher);
|
launcher.getPackageName()), launcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShortcutLauncher removeLauncher(
|
public ShortcutLauncher removeLauncher(
|
||||||
@UserIdInt int userId, @NonNull String packageName) {
|
@UserIdInt int packageUserId, @NonNull String packageName) {
|
||||||
return mLaunchers.remove(PackageWithUser.of(userId, packageName));
|
return mLaunchers.remove(PackageWithUser.of(packageUserId, packageName));
|
||||||
}
|
|
||||||
|
|
||||||
public ArrayMap<PackageWithUser, ShortcutPackageInfo> getAllPackageInfos() {
|
|
||||||
return mPackageInfos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ShortcutPackageInfo getPackageInfo(@UserIdInt int userId, @NonNull String packageName) {
|
|
||||||
return mPackageInfos.get(PackageWithUser.of(userId, packageName));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addPackageInfo(ShortcutPackageInfo spi) {
|
|
||||||
mPackageInfos.put(PackageWithUser.of(spi.getUserId(), spi.getPackageName()), spi);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ShortcutPackageInfo removePackageInfo(
|
|
||||||
@UserIdInt int userId, @NonNull String packageName) {
|
|
||||||
return mPackageInfos.remove(PackageWithUser.of(userId, packageName));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShortcutPackage getPackageShortcuts(@NonNull String packageName) {
|
public ShortcutPackage getPackageShortcuts(@NonNull String packageName) {
|
||||||
@@ -151,20 +133,37 @@ class ShortcutUser {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ensurePackageInfo(ShortcutService s, String packageName, @UserIdInt int userId) {
|
public void forAllPackageItems(Consumer<ShortcutPackageItem> callback) {
|
||||||
final PackageWithUser key = PackageWithUser.of(userId, packageName);
|
{
|
||||||
final ShortcutPackageInfo existing = mPackageInfos.get(key);
|
final int size = mLaunchers.size();
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
callback.accept(mLaunchers.valueAt(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
final int size = mPackages.size();
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
callback.accept(mPackages.valueAt(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (existing != null) {
|
public void unshadowPackage(ShortcutService s, @NonNull String packageName,
|
||||||
return;
|
@UserIdInt int packageUserId) {
|
||||||
}
|
forPackageItem(packageName, packageUserId, spi -> {
|
||||||
if (ShortcutService.DEBUG) {
|
Slog.i(TAG, String.format("Restoring for %s, user=%d", packageName, packageUserId));
|
||||||
Slog.d(TAG, String.format("Fetching package info: %s user=%d", packageName, userId));
|
spi.ensureNotShadowAndSave(s);
|
||||||
}
|
});
|
||||||
final ShortcutPackageInfo newSpi = ShortcutPackageInfo.generateForInstalledPackage(
|
}
|
||||||
s, packageName, userId);
|
|
||||||
mPackageInfos.put(key, newSpi);
|
public void forPackageItem(@NonNull String packageName, @UserIdInt int packageUserId,
|
||||||
s.scheduleSaveUser(mUserId);
|
Consumer<ShortcutPackageItem> callback) {
|
||||||
|
forAllPackageItems(spi -> {
|
||||||
|
if ((spi.getPackageUserId() == packageUserId)
|
||||||
|
&& spi.getPackageName().equals(packageName)) {
|
||||||
|
callback.accept(spi);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveToXml(ShortcutService s, XmlSerializer out, boolean forBackup)
|
public void saveToXml(ShortcutService s, XmlSerializer out, boolean forBackup)
|
||||||
@@ -174,12 +173,7 @@ class ShortcutUser {
|
|||||||
ShortcutService.writeTagValue(out, TAG_LAUNCHER,
|
ShortcutService.writeTagValue(out, TAG_LAUNCHER,
|
||||||
mLauncherComponent);
|
mLauncherComponent);
|
||||||
|
|
||||||
{
|
// Can't use forEachPackageItem due to the checked exceptions.
|
||||||
final int size = mPackageInfos.size();
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
saveShortcutPackageItem(s, out, mPackageInfos.valueAt(i), forBackup);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
final int size = mLaunchers.size();
|
final int size = mLaunchers.size();
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
@@ -198,14 +192,19 @@ class ShortcutUser {
|
|||||||
|
|
||||||
private void saveShortcutPackageItem(ShortcutService s, XmlSerializer out,
|
private void saveShortcutPackageItem(ShortcutService s, XmlSerializer out,
|
||||||
ShortcutPackageItem spi, boolean forBackup) throws IOException, XmlPullParserException {
|
ShortcutPackageItem spi, boolean forBackup) throws IOException, XmlPullParserException {
|
||||||
if (forBackup && !s.shouldBackupApp(spi.getPackageName(), mUserId)) {
|
if (forBackup) {
|
||||||
return; // Don't save.
|
if (!s.shouldBackupApp(spi.getPackageName(), spi.getPackageUserId())) {
|
||||||
|
return; // Don't save.
|
||||||
|
}
|
||||||
|
if (spi.getPackageUserId() != spi.getOwnerUserId()) {
|
||||||
|
return; // Don't save cross-user information.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
spi.saveToXml(out, forBackup);
|
spi.saveToXml(out, forBackup);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShortcutUser loadFromXml(XmlPullParser parser, int userId)
|
public static ShortcutUser loadFromXml(ShortcutService s, XmlPullParser parser, int userId,
|
||||||
throws IOException, XmlPullParserException {
|
boolean fromBackup) throws IOException, XmlPullParserException {
|
||||||
final ShortcutUser ret = new ShortcutUser(userId);
|
final ShortcutUser ret = new ShortcutUser(userId);
|
||||||
|
|
||||||
final int outerDepth = parser.getDepth();
|
final int outerDepth = parser.getDepth();
|
||||||
@@ -217,31 +216,30 @@ class ShortcutUser {
|
|||||||
}
|
}
|
||||||
final int depth = parser.getDepth();
|
final int depth = parser.getDepth();
|
||||||
final String tag = parser.getName();
|
final String tag = parser.getName();
|
||||||
switch (tag) {
|
|
||||||
case TAG_LAUNCHER: {
|
|
||||||
ret.mLauncherComponent = ShortcutService.parseComponentNameAttribute(
|
|
||||||
parser, ATTR_VALUE);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
case ShortcutPackage.TAG_ROOT: {
|
|
||||||
final ShortcutPackage shortcuts = ShortcutPackage.loadFromXml(parser, userId);
|
|
||||||
|
|
||||||
// Don't use addShortcut(), we don't need to save the icon.
|
if (depth == outerDepth + 1) {
|
||||||
ret.getPackages().put(shortcuts.getPackageName(), shortcuts);
|
switch (tag) {
|
||||||
continue;
|
case TAG_LAUNCHER: {
|
||||||
}
|
ret.mLauncherComponent = ShortcutService.parseComponentNameAttribute(
|
||||||
|
parser, ATTR_VALUE);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
case ShortcutPackage.TAG_ROOT: {
|
||||||
|
final ShortcutPackage shortcuts = ShortcutPackage.loadFromXml(
|
||||||
|
s, parser, userId, fromBackup);
|
||||||
|
|
||||||
case ShortcutLauncher.TAG_ROOT: {
|
// Don't use addShortcut(), we don't need to save the icon.
|
||||||
ret.addLauncher(ShortcutLauncher.loadFromXml(parser, userId));
|
ret.getPackages().put(shortcuts.getPackageName(), shortcuts);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ShortcutPackageInfo.TAG_ROOT: {
|
case ShortcutLauncher.TAG_ROOT: {
|
||||||
ret.addPackageInfo(ShortcutPackageInfo.loadFromXml(parser, userId));
|
ret.addLauncher(ShortcutLauncher.loadFromXml(parser, userId, fromBackup));
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw ShortcutService.throwForInvalidTag(depth, tag);
|
ShortcutService.warnForInvalidTag(depth, tag);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -283,9 +281,5 @@ class ShortcutUser {
|
|||||||
for (int i = 0; i < mPackages.size(); i++) {
|
for (int i = 0; i < mPackages.size(); i++) {
|
||||||
mPackages.valueAt(i).dump(s, pw, prefix + " ");
|
mPackages.valueAt(i).dump(s, pw, prefix + " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < mPackageInfos.size(); i++) {
|
|
||||||
mPackageInfos.valueAt(i).dump(s, pw, prefix + " ");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -797,7 +797,6 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
@NonNull
|
@NonNull
|
||||||
private List<ShortcutInfo> assertShortcutIds(@NonNull List<ShortcutInfo> actualShortcuts,
|
private List<ShortcutInfo> assertShortcutIds(@NonNull List<ShortcutInfo> actualShortcuts,
|
||||||
String... expectedIds) {
|
String... expectedIds) {
|
||||||
assertEquals(expectedIds.length, actualShortcuts.size());
|
|
||||||
final HashSet<String> expected = new HashSet<>(list(expectedIds));
|
final HashSet<String> expected = new HashSet<>(list(expectedIds));
|
||||||
final HashSet<String> actual = new HashSet<>();
|
final HashSet<String> actual = new HashSet<>();
|
||||||
for (ShortcutInfo s : actualShortcuts) {
|
for (ShortcutInfo s : actualShortcuts) {
|
||||||
@@ -973,18 +972,6 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
assertTrue(b == null || b.size() == 0);
|
assertTrue(b == null || b.size() == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertShortcutPackageInfo(String packageName, int userId, int expectedVersion) {
|
|
||||||
ShortcutPackageInfo spi = mService.getPackageInfoForTest(packageName, userId);
|
|
||||||
assertNotNull(spi);
|
|
||||||
assertEquals(expectedVersion, spi.getVersionCode());
|
|
||||||
|
|
||||||
assertTrue(spi.canRestoreTo(genPackage(packageName, /*uid*/ 0, 9999999, packageName)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertNoShortcutPackageInfo(String packageName, int userId) {
|
|
||||||
assertNull(mService.getPackageInfoForTest(packageName, userId));
|
|
||||||
}
|
|
||||||
|
|
||||||
private ShortcutInfo getPackageShortcut(String packageName, String shortcutId, int userId) {
|
private ShortcutInfo getPackageShortcut(String packageName, String shortcutId, int userId) {
|
||||||
return mService.getPackageShortcutForTest(packageName, shortcutId, userId);
|
return mService.getPackageShortcutForTest(packageName, shortcutId, userId);
|
||||||
}
|
}
|
||||||
@@ -1229,11 +1216,6 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
"shortcut1", "shortcut2");
|
"shortcut1", "shortcut2");
|
||||||
assertEquals(2, mManager.getRemainingCallCount());
|
assertEquals(2, mManager.getRemainingCallCount());
|
||||||
|
|
||||||
assertShortcutPackageInfo(CALLING_PACKAGE_1, USER_0, 1);
|
|
||||||
assertNoShortcutPackageInfo(CALLING_PACKAGE_2, USER_0);
|
|
||||||
assertNoShortcutPackageInfo(CALLING_PACKAGE_1, USER_10);
|
|
||||||
assertNoShortcutPackageInfo(CALLING_PACKAGE_2, USER_10);
|
|
||||||
|
|
||||||
// TODO: Check fields
|
// TODO: Check fields
|
||||||
|
|
||||||
assertTrue(mManager.setDynamicShortcuts(list(si1)));
|
assertTrue(mManager.setDynamicShortcuts(list(si1)));
|
||||||
@@ -1260,11 +1242,6 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
|
|
||||||
runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
|
runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
|
||||||
assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"))));
|
assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"))));
|
||||||
|
|
||||||
assertShortcutPackageInfo(CALLING_PACKAGE_1, USER_0, 1);
|
|
||||||
assertNoShortcutPackageInfo(CALLING_PACKAGE_2, USER_0);
|
|
||||||
assertNoShortcutPackageInfo(CALLING_PACKAGE_1, USER_10);
|
|
||||||
assertShortcutPackageInfo(CALLING_PACKAGE_2, USER_10, 2);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1302,7 +1279,6 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
|
|
||||||
runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
|
runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
|
||||||
assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
|
assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
|
||||||
assertShortcutPackageInfo(CALLING_PACKAGE_2, USER_10, 2);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1608,7 +1584,6 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
Bitmap bmp;
|
Bitmap bmp;
|
||||||
|
|
||||||
setCaller(LAUNCHER_1);
|
setCaller(LAUNCHER_1);
|
||||||
|
|
||||||
// Check hasIconResource()/hasIconFile().
|
// Check hasIconResource()/hasIconFile().
|
||||||
assertShortcutIds(assertAllHaveIconResId(mLauncherApps.getShortcutInfo(
|
assertShortcutIds(assertAllHaveIconResId(mLauncherApps.getShortcutInfo(
|
||||||
CALLING_PACKAGE_1, list("res32x32"),
|
CALLING_PACKAGE_1, list("res32x32"),
|
||||||
@@ -1898,12 +1873,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
// TODO Check bitmap removal too.
|
// TODO Check bitmap removal too.
|
||||||
|
|
||||||
runWithCaller(CALLING_PACKAGE_2, USER_11, () -> {
|
runWithCaller(CALLING_PACKAGE_2, USER_11, () -> {
|
||||||
assertNoShortcutPackageInfo(CALLING_PACKAGE_2, USER_11);
|
|
||||||
|
|
||||||
mManager.updateShortcuts(list());
|
mManager.updateShortcuts(list());
|
||||||
|
|
||||||
// Even an empty update call will populate the package info.
|
|
||||||
assertShortcutPackageInfo(CALLING_PACKAGE_2, USER_11, 2);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1940,7 +1910,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
assertTrue(mManager.setDynamicShortcuts(list(s2_2, s2_3, s2_4)));
|
assertTrue(mManager.setDynamicShortcuts(list(s2_2, s2_3, s2_4)));
|
||||||
|
|
||||||
setCaller(CALLING_PACKAGE_3);
|
setCaller(CALLING_PACKAGE_3);
|
||||||
final ShortcutInfo s3_2 = makeShortcutWithTimestamp("s3", 5000);
|
final ShortcutInfo s3_2 = makeShortcutWithTimestamp("s3", START_TIME + 5000);
|
||||||
assertTrue(mManager.setDynamicShortcuts(list(s3_2)));
|
assertTrue(mManager.setDynamicShortcuts(list(s3_2)));
|
||||||
|
|
||||||
setCaller(LAUNCHER_1);
|
setCaller(LAUNCHER_1);
|
||||||
@@ -2100,16 +2070,9 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
|
|
||||||
// Pin some.
|
// Pin some.
|
||||||
runWithCaller(LAUNCHER_1, USER_0, () -> {
|
runWithCaller(LAUNCHER_1, USER_0, () -> {
|
||||||
assertNoShortcutPackageInfo(LAUNCHER_1, USER_0);
|
|
||||||
|
|
||||||
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
|
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
|
||||||
list("s2", "s3"), getCallingUser());
|
list("s2", "s3"), getCallingUser());
|
||||||
|
|
||||||
assertShortcutPackageInfo(LAUNCHER_1, USER_0, 4);
|
|
||||||
assertNoShortcutPackageInfo(LAUNCHER_2, USER_0);
|
|
||||||
assertNoShortcutPackageInfo(LAUNCHER_1, USER_10);
|
|
||||||
assertNoShortcutPackageInfo(LAUNCHER_2, USER_10);
|
|
||||||
|
|
||||||
mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
|
mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
|
||||||
list("s3", "s4", "s5"), getCallingUser());
|
list("s3", "s4", "s5"), getCallingUser());
|
||||||
|
|
||||||
@@ -2170,19 +2133,11 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
|
|
||||||
dumpsysOnLogcat();
|
dumpsysOnLogcat();
|
||||||
|
|
||||||
assertNoShortcutPackageInfo(LAUNCHER_1, USER_0);
|
|
||||||
assertNoShortcutPackageInfo(LAUNCHER_2, USER_0);
|
|
||||||
assertNoShortcutPackageInfo(LAUNCHER_1, USER_10);
|
|
||||||
assertNoShortcutPackageInfo(LAUNCHER_2, USER_10);
|
|
||||||
|
|
||||||
// Pin some.
|
// Pin some.
|
||||||
runWithCaller(LAUNCHER_1, USER_0, () -> {
|
runWithCaller(LAUNCHER_1, USER_0, () -> {
|
||||||
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
|
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
|
||||||
list("s3", "s4"), getCallingUser());
|
list("s3", "s4"), getCallingUser());
|
||||||
|
|
||||||
assertShortcutPackageInfo(LAUNCHER_1, USER_0, 4);
|
|
||||||
assertNoShortcutPackageInfo(LAUNCHER_2, USER_0);
|
|
||||||
|
|
||||||
mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
|
mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
|
||||||
list("s1", "s2", "s4"), getCallingUser());
|
list("s1", "s2", "s4"), getCallingUser());
|
||||||
});
|
});
|
||||||
@@ -2256,16 +2211,10 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
| ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
|
| ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
|
||||||
"s2");
|
"s2");
|
||||||
|
|
||||||
assertNoShortcutPackageInfo(LAUNCHER_2, USER_0);
|
|
||||||
assertNoShortcutPackageInfo(LAUNCHER_2, USER_10);
|
|
||||||
|
|
||||||
// Now pin some.
|
// Now pin some.
|
||||||
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
|
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
|
||||||
list("s1", "s2"), getCallingUser());
|
list("s1", "s2"), getCallingUser());
|
||||||
|
|
||||||
assertShortcutPackageInfo(LAUNCHER_2, USER_0, 5);
|
|
||||||
assertNoShortcutPackageInfo(LAUNCHER_2, USER_10);
|
|
||||||
|
|
||||||
mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
|
mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
|
||||||
list("s1", "s2"), getCallingUser());
|
list("s1", "s2"), getCallingUser());
|
||||||
|
|
||||||
@@ -2283,12 +2232,6 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
"s2");
|
"s2");
|
||||||
});
|
});
|
||||||
|
|
||||||
assertShortcutPackageInfo(CALLING_PACKAGE_1, USER_0, 1);
|
|
||||||
assertShortcutPackageInfo(CALLING_PACKAGE_2, USER_0, 2);
|
|
||||||
assertNoShortcutPackageInfo(CALLING_PACKAGE_3, USER_0);
|
|
||||||
assertShortcutPackageInfo(LAUNCHER_1, USER_0, 4);
|
|
||||||
assertShortcutPackageInfo(LAUNCHER_2, USER_0, 5);
|
|
||||||
|
|
||||||
// Re-initialize and load from the files.
|
// Re-initialize and load from the files.
|
||||||
mService.saveDirtyInfo();
|
mService.saveDirtyInfo();
|
||||||
initService();
|
initService();
|
||||||
@@ -2297,12 +2240,6 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
mService.handleUnlockUser(USER_0);
|
mService.handleUnlockUser(USER_0);
|
||||||
|
|
||||||
// Make sure package info is restored too.
|
// Make sure package info is restored too.
|
||||||
assertShortcutPackageInfo(CALLING_PACKAGE_1, USER_0, 1);
|
|
||||||
assertShortcutPackageInfo(CALLING_PACKAGE_2, USER_0, 2);
|
|
||||||
assertNoShortcutPackageInfo(CALLING_PACKAGE_3, USER_0);
|
|
||||||
assertShortcutPackageInfo(LAUNCHER_1, USER_0, 4);
|
|
||||||
assertShortcutPackageInfo(LAUNCHER_2, USER_0, 5);
|
|
||||||
|
|
||||||
runWithCaller(LAUNCHER_1, USER_0, () -> {
|
runWithCaller(LAUNCHER_1, USER_0, () -> {
|
||||||
assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
|
assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
|
||||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
|
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
|
||||||
@@ -3234,10 +3171,6 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
mService.getShortcutsForTest().get(UserHandle.USER_SYSTEM).setLauncherComponent(
|
mService.getShortcutsForTest().get(UserHandle.USER_SYSTEM).setLauncherComponent(
|
||||||
mService, new ComponentName("pkg1", "class"));
|
mService, new ComponentName("pkg1", "class"));
|
||||||
|
|
||||||
assertShortcutPackageInfo(CALLING_PACKAGE_1, USER_0, 1);
|
|
||||||
assertShortcutPackageInfo(CALLING_PACKAGE_2, USER_0, 2);
|
|
||||||
assertNoShortcutPackageInfo(CALLING_PACKAGE_3, USER_0);
|
|
||||||
|
|
||||||
// Restore.
|
// Restore.
|
||||||
mService.saveDirtyInfo();
|
mService.saveDirtyInfo();
|
||||||
initService();
|
initService();
|
||||||
@@ -3248,10 +3181,6 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
// this will pre-load the per-user info.
|
// this will pre-load the per-user info.
|
||||||
mService.handleUnlockUser(UserHandle.USER_SYSTEM);
|
mService.handleUnlockUser(UserHandle.USER_SYSTEM);
|
||||||
|
|
||||||
assertShortcutPackageInfo(CALLING_PACKAGE_1, USER_0, 1);
|
|
||||||
assertShortcutPackageInfo(CALLING_PACKAGE_2, USER_0, 2);
|
|
||||||
assertNoShortcutPackageInfo(CALLING_PACKAGE_3, USER_0);
|
|
||||||
|
|
||||||
// Now it's loaded.
|
// Now it's loaded.
|
||||||
assertEquals(1, mService.getShortcutsForTest().size());
|
assertEquals(1, mService.getShortcutsForTest().size());
|
||||||
|
|
||||||
@@ -3394,11 +3323,6 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10);
|
assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10);
|
||||||
assertShortcutExists(CALLING_PACKAGE_2, "s10_2", USER_10);
|
assertShortcutExists(CALLING_PACKAGE_2, "s10_2", USER_10);
|
||||||
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_2, USER_0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_10));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_2, USER_10));
|
|
||||||
|
|
||||||
mService.saveDirtyInfo();
|
mService.saveDirtyInfo();
|
||||||
|
|
||||||
// Nonexistent package.
|
// Nonexistent package.
|
||||||
@@ -3430,11 +3354,6 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10);
|
assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10);
|
||||||
assertShortcutExists(CALLING_PACKAGE_2, "s10_2", USER_10);
|
assertShortcutExists(CALLING_PACKAGE_2, "s10_2", USER_10);
|
||||||
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_2, USER_0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_10));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_2, USER_10));
|
|
||||||
|
|
||||||
mService.saveDirtyInfo();
|
mService.saveDirtyInfo();
|
||||||
|
|
||||||
// Remove a package.
|
// Remove a package.
|
||||||
@@ -3465,11 +3384,6 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10);
|
assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10);
|
||||||
assertShortcutExists(CALLING_PACKAGE_2, "s10_2", USER_10);
|
assertShortcutExists(CALLING_PACKAGE_2, "s10_2", USER_10);
|
||||||
|
|
||||||
assertNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_2, USER_0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_10));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_2, USER_10));
|
|
||||||
|
|
||||||
mService.saveDirtyInfo();
|
mService.saveDirtyInfo();
|
||||||
|
|
||||||
// Remove a launcher.
|
// Remove a launcher.
|
||||||
@@ -3524,11 +3438,6 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10);
|
assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10);
|
||||||
assertShortcutNotExists(CALLING_PACKAGE_2, "s10_2", USER_10);
|
assertShortcutNotExists(CALLING_PACKAGE_2, "s10_2", USER_10);
|
||||||
|
|
||||||
assertNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_2, USER_0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_10));
|
|
||||||
assertNull(mService.getPackageInfoForTest(CALLING_PACKAGE_2, USER_10));
|
|
||||||
|
|
||||||
mService.saveDirtyInfo();
|
mService.saveDirtyInfo();
|
||||||
|
|
||||||
// Remove the other launcher from user 10 too.
|
// Remove the other launcher from user 10 too.
|
||||||
@@ -3585,6 +3494,97 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
mService.saveDirtyInfo();
|
mService.saveDirtyInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testSaveAndLoadUser_forBackup() {
|
||||||
|
// Create some shortcuts.
|
||||||
|
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
|
||||||
|
assertTrue(mManager.setDynamicShortcuts(list(
|
||||||
|
makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
|
||||||
|
});
|
||||||
|
runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
|
||||||
|
assertTrue(mManager.setDynamicShortcuts(list(
|
||||||
|
makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
|
||||||
|
});
|
||||||
|
runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
|
||||||
|
assertTrue(mManager.setDynamicShortcuts(list(
|
||||||
|
makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
|
||||||
|
});
|
||||||
|
runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
|
||||||
|
assertTrue(mManager.setDynamicShortcuts(list(
|
||||||
|
makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
|
||||||
|
});
|
||||||
|
|
||||||
|
assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
|
||||||
|
assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
|
||||||
|
assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
|
||||||
|
|
||||||
|
assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
|
||||||
|
assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
|
||||||
|
assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
|
||||||
|
|
||||||
|
assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
|
||||||
|
assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
|
||||||
|
assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
|
||||||
|
|
||||||
|
assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
|
||||||
|
assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
|
||||||
|
assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
|
||||||
|
|
||||||
|
// Pin some.
|
||||||
|
|
||||||
|
runWithCaller(LAUNCHER_1, USER_0, () -> {
|
||||||
|
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
|
||||||
|
list("s1"), HANDLE_USER_0);
|
||||||
|
|
||||||
|
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
|
||||||
|
list("s2"), UserHandle.of(USER_P0));
|
||||||
|
|
||||||
|
mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
|
||||||
|
list("s3"), HANDLE_USER_0);
|
||||||
|
});
|
||||||
|
|
||||||
|
runWithCaller(LAUNCHER_1, USER_P0, () -> {
|
||||||
|
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
|
||||||
|
list("s2"), HANDLE_USER_0);
|
||||||
|
|
||||||
|
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
|
||||||
|
list("s3"), UserHandle.of(USER_P0));
|
||||||
|
|
||||||
|
mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
|
||||||
|
list("s1"), HANDLE_USER_0);
|
||||||
|
});
|
||||||
|
|
||||||
|
runWithCaller(LAUNCHER_1, USER_10, () -> {
|
||||||
|
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
|
||||||
|
list("s3"), HANDLE_USER_10);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check the state.
|
||||||
|
|
||||||
|
assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
|
||||||
|
assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
|
||||||
|
assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
|
||||||
|
|
||||||
|
assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
|
||||||
|
assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
|
||||||
|
assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
|
||||||
|
|
||||||
|
assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
|
||||||
|
assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
|
||||||
|
assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
|
||||||
|
|
||||||
|
assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
|
||||||
|
assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
|
||||||
|
assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
|
||||||
|
|
||||||
|
// Make sure all the information is persisted.
|
||||||
|
mService.saveDirtyInfo();
|
||||||
|
initService();
|
||||||
|
mService.handleUnlockUser(USER_0);
|
||||||
|
mService.handleUnlockUser(USER_P0);
|
||||||
|
mService.handleUnlockUser(USER_10);
|
||||||
|
}
|
||||||
|
|
||||||
public void testHandleGonePackage_crossProfile() {
|
public void testHandleGonePackage_crossProfile() {
|
||||||
// Create some shortcuts.
|
// Create some shortcuts.
|
||||||
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
|
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
|
||||||
@@ -3667,20 +3667,6 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
|
assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
|
||||||
assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
|
assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
|
||||||
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_P0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_2, USER_0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_10));
|
|
||||||
|
|
||||||
// These two shouldn't exist
|
|
||||||
assertNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_P0, USER_0));
|
|
||||||
assertNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_0, USER_P0));
|
|
||||||
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_0, USER_0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_0, USER_P0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_P0, USER_0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_10, USER_10));
|
|
||||||
|
|
||||||
// Make sure all the information is persisted.
|
// Make sure all the information is persisted.
|
||||||
mService.saveDirtyInfo();
|
mService.saveDirtyInfo();
|
||||||
initService();
|
initService();
|
||||||
@@ -3704,21 +3690,6 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
|
assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
|
||||||
assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
|
assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
|
||||||
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_P0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_2, USER_0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_10));
|
|
||||||
|
|
||||||
// These two shouldn't exist
|
|
||||||
assertNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_P0, USER_0));
|
|
||||||
assertNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_0, USER_P0));
|
|
||||||
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_0, USER_0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_0, USER_P0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_P0, USER_0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_10, USER_10));
|
|
||||||
|
|
||||||
|
|
||||||
// Start uninstalling.
|
// Start uninstalling.
|
||||||
uninstallPackage(USER_10, LAUNCHER_1);
|
uninstallPackage(USER_10, LAUNCHER_1);
|
||||||
mService.cleanupGonePackages(USER_10);
|
mService.cleanupGonePackages(USER_10);
|
||||||
@@ -3739,16 +3710,6 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
|
assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
|
||||||
assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
|
assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
|
||||||
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_P0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_2, USER_0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_10));
|
|
||||||
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_0, USER_0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_0, USER_P0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_P0, USER_0));
|
|
||||||
assertNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_10, USER_10));
|
|
||||||
|
|
||||||
// Uninstall.
|
// Uninstall.
|
||||||
uninstallPackage(USER_10, CALLING_PACKAGE_1);
|
uninstallPackage(USER_10, CALLING_PACKAGE_1);
|
||||||
mService.cleanupGonePackages(USER_10);
|
mService.cleanupGonePackages(USER_10);
|
||||||
@@ -3769,17 +3730,6 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
|
assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
|
||||||
assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
|
assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
|
||||||
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_P0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_2, USER_0));
|
|
||||||
assertNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_10));
|
|
||||||
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_0, USER_0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_0, USER_P0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_P0, USER_0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_P0, USER_P0));
|
|
||||||
assertNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_10, USER_10));
|
|
||||||
|
|
||||||
uninstallPackage(USER_P0, LAUNCHER_1);
|
uninstallPackage(USER_P0, LAUNCHER_1);
|
||||||
mService.cleanupGonePackages(USER_0);
|
mService.cleanupGonePackages(USER_0);
|
||||||
|
|
||||||
@@ -3799,17 +3749,6 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
|
assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
|
||||||
assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
|
assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
|
||||||
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_P0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_2, USER_0));
|
|
||||||
assertNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_10));
|
|
||||||
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_0, USER_0));
|
|
||||||
assertNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_0, USER_P0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_P0, USER_0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_P0, USER_P0));
|
|
||||||
assertNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_10, USER_10));
|
|
||||||
|
|
||||||
mService.cleanupGonePackages(USER_P0);
|
mService.cleanupGonePackages(USER_P0);
|
||||||
|
|
||||||
assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
|
assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
|
||||||
@@ -3828,17 +3767,6 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
|
assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
|
||||||
assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
|
assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
|
||||||
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_P0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_2, USER_0));
|
|
||||||
assertNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_10));
|
|
||||||
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_0, USER_0));
|
|
||||||
assertNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_0, USER_P0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_P0, USER_0));
|
|
||||||
assertNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_P0, USER_P0));
|
|
||||||
assertNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_10, USER_10));
|
|
||||||
|
|
||||||
uninstallPackage(USER_P0, CALLING_PACKAGE_1);
|
uninstallPackage(USER_P0, CALLING_PACKAGE_1);
|
||||||
|
|
||||||
mService.saveDirtyInfo();
|
mService.saveDirtyInfo();
|
||||||
@@ -3863,17 +3791,6 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
|
assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
|
||||||
assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
|
assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
|
||||||
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_0));
|
|
||||||
assertNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_P0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_2, USER_0));
|
|
||||||
assertNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_10));
|
|
||||||
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_0, USER_0));
|
|
||||||
assertNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_0, USER_P0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_P0, USER_0));
|
|
||||||
assertNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_P0, USER_P0));
|
|
||||||
assertNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_10, USER_10));
|
|
||||||
|
|
||||||
// Uninstall
|
// Uninstall
|
||||||
uninstallPackage(USER_0, LAUNCHER_1);
|
uninstallPackage(USER_0, LAUNCHER_1);
|
||||||
|
|
||||||
@@ -3899,17 +3816,6 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
|
assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
|
||||||
assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
|
assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
|
||||||
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_0));
|
|
||||||
assertNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_P0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_2, USER_0));
|
|
||||||
assertNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_10));
|
|
||||||
|
|
||||||
assertNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_0, USER_0));
|
|
||||||
assertNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_0, USER_P0));
|
|
||||||
assertNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_P0, USER_0));
|
|
||||||
assertNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_P0, USER_P0));
|
|
||||||
assertNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_10, USER_10));
|
|
||||||
|
|
||||||
uninstallPackage(USER_0, CALLING_PACKAGE_2);
|
uninstallPackage(USER_0, CALLING_PACKAGE_2);
|
||||||
|
|
||||||
mService.saveDirtyInfo();
|
mService.saveDirtyInfo();
|
||||||
@@ -3933,17 +3839,6 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
|
assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
|
||||||
assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
|
assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
|
||||||
assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
|
assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
|
||||||
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_0));
|
|
||||||
assertNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_P0));
|
|
||||||
assertNull(mService.getPackageInfoForTest(CALLING_PACKAGE_2, USER_0));
|
|
||||||
assertNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_10));
|
|
||||||
|
|
||||||
assertNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_0, USER_0));
|
|
||||||
assertNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_0, USER_P0));
|
|
||||||
assertNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_P0, USER_0));
|
|
||||||
assertNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_P0, USER_P0));
|
|
||||||
assertNull(mService.getPackageInfoForTest(LAUNCHER_1, USER_10, USER_10));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Detailed test for hasShortcutPermissionInner().
|
// TODO Detailed test for hasShortcutPermissionInner().
|
||||||
@@ -3998,27 +3893,6 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
checkCanRestoreTo(false, spi2, 11, "x", "sig2x", "sig1", "y");
|
checkCanRestoreTo(false, spi2, 11, "x", "sig2x", "sig1", "y");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testShortcutPackageInfoRefresh() {
|
|
||||||
addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 10, "sig1");
|
|
||||||
|
|
||||||
final ShortcutPackageInfo spi1 = ShortcutPackageInfo.generateForInstalledPackage(
|
|
||||||
mService, CALLING_PACKAGE_1, USER_0);
|
|
||||||
|
|
||||||
checkCanRestoreTo(true, spi1, 10, "sig1");
|
|
||||||
|
|
||||||
addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 11, "sig1", "sig2");
|
|
||||||
|
|
||||||
spi1.refreshAndSave(mService, USER_0);
|
|
||||||
|
|
||||||
mService.handleCleanupUser(USER_0);
|
|
||||||
initService();
|
|
||||||
|
|
||||||
checkCanRestoreTo(false, spi1, 10, "sig1", "sig2");
|
|
||||||
checkCanRestoreTo(false, spi1, 11, "sig", "sig2");
|
|
||||||
checkCanRestoreTo(false, spi1, 11, "sig1", "sig");
|
|
||||||
checkCanRestoreTo(true, spi1, 11, "sig1", "sig2");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testHandlePackageDelete() {
|
public void testHandlePackageDelete() {
|
||||||
setCaller(CALLING_PACKAGE_1, USER_0);
|
setCaller(CALLING_PACKAGE_1, USER_0);
|
||||||
assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
|
assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
|
||||||
@@ -4038,73 +3912,56 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
setCaller(CALLING_PACKAGE_3, USER_10);
|
setCaller(CALLING_PACKAGE_3, USER_10);
|
||||||
assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
|
assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
|
||||||
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_0));
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_2, USER_0));
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_3, USER_0));
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_10));
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_2, USER_10));
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_3, USER_10));
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
|
||||||
|
|
||||||
mService.mPackageMonitor.onReceive(getTestContext(),
|
mService.mPackageMonitor.onReceive(getTestContext(),
|
||||||
genPackageDeleteIntent(CALLING_PACKAGE_1, USER_0));
|
genPackageDeleteIntent(CALLING_PACKAGE_1, USER_0));
|
||||||
|
|
||||||
assertNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_0));
|
assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_2, USER_0));
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_3, USER_0));
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_10));
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_2, USER_10));
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_3, USER_10));
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
|
||||||
|
|
||||||
mService.mPackageMonitor.onReceive(getTestContext(),
|
mService.mPackageMonitor.onReceive(getTestContext(),
|
||||||
genPackageDeleteIntent(CALLING_PACKAGE_2, USER_10));
|
genPackageDeleteIntent(CALLING_PACKAGE_2, USER_10));
|
||||||
|
|
||||||
assertNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_0));
|
assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_2, USER_0));
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_3, USER_0));
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_10));
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
|
||||||
assertNull(mService.getPackageInfoForTest(CALLING_PACKAGE_2, USER_10));
|
assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_3, USER_10));
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
|
||||||
|
|
||||||
mInjectedPackages.remove(CALLING_PACKAGE_1);
|
mInjectedPackages.remove(CALLING_PACKAGE_1);
|
||||||
mInjectedPackages.remove(CALLING_PACKAGE_3);
|
mInjectedPackages.remove(CALLING_PACKAGE_3);
|
||||||
|
|
||||||
mService.handleUnlockUser(USER_0);
|
mService.handleUnlockUser(USER_0);
|
||||||
assertNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_2, USER_0));
|
assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
|
||||||
assertNull(mService.getPackageInfoForTest(CALLING_PACKAGE_3, USER_0));
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_10));
|
assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
|
||||||
assertNull(mService.getPackageInfoForTest(CALLING_PACKAGE_2, USER_10));
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_3, USER_10));
|
assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
|
||||||
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
|
||||||
|
|
||||||
mService.handleUnlockUser(USER_10);
|
mService.handleUnlockUser(USER_10);
|
||||||
assertNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_0));
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_2, USER_0));
|
assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
|
||||||
assertNull(mService.getPackageInfoForTest(CALLING_PACKAGE_3, USER_0));
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
|
||||||
assertNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_10));
|
assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
|
||||||
assertNull(mService.getPackageInfoForTest(CALLING_PACKAGE_2, USER_10));
|
assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
|
||||||
assertNull(mService.getPackageInfoForTest(CALLING_PACKAGE_3, USER_10));
|
assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
|
||||||
|
assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testHandlePackageUpdate() {
|
public void testHandlePackageUpdate() {
|
||||||
setCaller(CALLING_PACKAGE_1, USER_0);
|
// TODO: Make sure unshadow is called.
|
||||||
assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
|
|
||||||
|
|
||||||
assertNotNull(mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_0));
|
|
||||||
assertEquals(1, mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_0).getVersionCode());
|
|
||||||
|
|
||||||
addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 123);
|
|
||||||
|
|
||||||
mService.mPackageMonitor.onReceive(getTestContext(),
|
|
||||||
genPackageUpdateIntent("abc", USER_0));
|
|
||||||
assertEquals(1, mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_0).getVersionCode());
|
|
||||||
|
|
||||||
mService.mPackageMonitor.onReceive(getTestContext(),
|
|
||||||
genPackageUpdateIntent("abc", USER_10));
|
|
||||||
assertEquals(1, mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_0).getVersionCode());
|
|
||||||
|
|
||||||
mService.mPackageMonitor.onReceive(getTestContext(),
|
|
||||||
genPackageUpdateIntent(CALLING_PACKAGE_1, USER_0));
|
|
||||||
assertEquals(123, mService.getPackageInfoForTest(CALLING_PACKAGE_1, USER_0)
|
|
||||||
.getVersionCode());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user