Merge "ShortcutManager: When app's data is cleared, remove all shortcuts," into nyc-dev
This commit is contained in:
@@ -45,6 +45,7 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
|
|||||||
sPackageFilt.addAction(Intent.ACTION_PACKAGE_CHANGED);
|
sPackageFilt.addAction(Intent.ACTION_PACKAGE_CHANGED);
|
||||||
sPackageFilt.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
|
sPackageFilt.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
|
||||||
sPackageFilt.addAction(Intent.ACTION_PACKAGE_RESTARTED);
|
sPackageFilt.addAction(Intent.ACTION_PACKAGE_RESTARTED);
|
||||||
|
sPackageFilt.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
|
||||||
sPackageFilt.addDataScheme("package");
|
sPackageFilt.addDataScheme("package");
|
||||||
sNonDataFilt.addAction(Intent.ACTION_UID_REMOVED);
|
sNonDataFilt.addAction(Intent.ACTION_UID_REMOVED);
|
||||||
sNonDataFilt.addAction(Intent.ACTION_USER_STOPPED);
|
sNonDataFilt.addAction(Intent.ACTION_USER_STOPPED);
|
||||||
@@ -275,6 +276,9 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
|
|||||||
public void onFinishPackageChanges() {
|
public void onFinishPackageChanges() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onPackageDataCleared(String packageName, int uid) {
|
||||||
|
}
|
||||||
|
|
||||||
public int getChangingUserId() {
|
public int getChangingUserId() {
|
||||||
return mChangeUserId;
|
return mChangeUserId;
|
||||||
}
|
}
|
||||||
@@ -365,6 +369,12 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
|
|||||||
}
|
}
|
||||||
onPackageModified(pkg);
|
onPackageModified(pkg);
|
||||||
}
|
}
|
||||||
|
} else if (Intent.ACTION_PACKAGE_DATA_CLEARED.equals(action)) {
|
||||||
|
String pkg = getPackageName(intent);
|
||||||
|
int uid = intent.getIntExtra(Intent.EXTRA_UID, 0);
|
||||||
|
if (pkg != null) {
|
||||||
|
onPackageDataCleared(pkg, uid);
|
||||||
|
}
|
||||||
} else if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) {
|
} else if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) {
|
||||||
mDisappearingPackages = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
|
mDisappearingPackages = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
|
||||||
mChangeType = PACKAGE_TEMPORARY_CHANGE;
|
mChangeType = PACKAGE_TEMPORARY_CHANGE;
|
||||||
|
|||||||
@@ -1561,48 +1561,46 @@ public class ShortcutService extends IShortcutService.Stub {
|
|||||||
|
|
||||||
// === House keeping ===
|
// === House keeping ===
|
||||||
|
|
||||||
@VisibleForTesting
|
private void cleanUpPackageForAllLoadedUsers(String packageName, @UserIdInt int packageUserId) {
|
||||||
void cleanUpPackageLocked(String packageName, int owningUserId, int packageUserId) {
|
synchronized (mLock) {
|
||||||
cleanUpPackageLocked(packageName, owningUserId, packageUserId,
|
forEachLoadedUserLocked(user ->
|
||||||
/* forceForCommandLine= */ false);
|
cleanUpPackageLocked(packageName, user.getUserId(), packageUserId));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove all the information associated with a package. This will really remove all the
|
* Remove all the information associated with a package. This will really remove all the
|
||||||
* information, including the restore information (i.e. it'll remove packages even if they're
|
* information, including the restore information (i.e. it'll remove packages even if they're
|
||||||
* shadow).
|
* shadow).
|
||||||
|
*
|
||||||
|
* This is called when an app is uninstalled, or an app gets "clear data"ed.
|
||||||
*/
|
*/
|
||||||
private void cleanUpPackageLocked(String packageName, int owningUserId, int packageUserId,
|
@VisibleForTesting
|
||||||
boolean forceForCommandLine) {
|
void cleanUpPackageLocked(String packageName, int owningUserId, int packageUserId) {
|
||||||
if (!forceForCommandLine && isPackageInstalled(packageName, packageUserId)) {
|
|
||||||
wtf("Package " + packageName + " is still installed for user " + packageUserId);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final boolean wasUserLoaded = isUserLoadedLocked(owningUserId);
|
final boolean wasUserLoaded = isUserLoadedLocked(owningUserId);
|
||||||
|
|
||||||
final ShortcutUser mUser = getUserShortcutsLocked(owningUserId);
|
final ShortcutUser user = getUserShortcutsLocked(owningUserId);
|
||||||
boolean doNotify = false;
|
boolean doNotify = false;
|
||||||
|
|
||||||
// First, remove the package from the package list (if the package is a publisher).
|
// First, remove the package from the package list (if the package is a publisher).
|
||||||
if (packageUserId == owningUserId) {
|
if (packageUserId == owningUserId) {
|
||||||
if (mUser.removePackage(this, packageName) != null) {
|
if (user.removePackage(this, packageName) != null) {
|
||||||
doNotify = true;
|
doNotify = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also remove from the launcher list (if the package is a launcher).
|
// Also remove from the launcher list (if the package is a launcher).
|
||||||
mUser.removeLauncher(packageUserId, packageName);
|
user.removeLauncher(packageUserId, packageName);
|
||||||
|
|
||||||
// Then remove pinned shortcuts from all launchers.
|
// Then remove pinned shortcuts from all launchers.
|
||||||
final ArrayMap<PackageWithUser, ShortcutLauncher> launchers = mUser.getAllLaunchers();
|
final ArrayMap<PackageWithUser, ShortcutLauncher> launchers = user.getAllLaunchers();
|
||||||
for (int i = launchers.size() - 1; i >= 0; i--) {
|
for (int i = launchers.size() - 1; i >= 0; i--) {
|
||||||
launchers.valueAt(i).cleanUpPackage(packageName, packageUserId);
|
launchers.valueAt(i).cleanUpPackage(packageName, packageUserId);
|
||||||
}
|
}
|
||||||
// Now there may be orphan shortcuts because we removed pinned shortucts at the previous
|
// Now there may be orphan shortcuts because we removed pinned shortucts at the previous
|
||||||
// step. Remove them too.
|
// step. Remove them too.
|
||||||
for (int i = mUser.getAllPackages().size() - 1; i >= 0; i--) {
|
for (int i = user.getAllPackages().size() - 1; i >= 0; i--) {
|
||||||
mUser.getAllPackages().valueAt(i).refreshPinnedFlags(this);
|
user.getAllPackages().valueAt(i).refreshPinnedFlags(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
scheduleSaveUser(owningUserId);
|
scheduleSaveUser(owningUserId);
|
||||||
@@ -1842,6 +1840,11 @@ public class ShortcutService extends IShortcutService.Stub {
|
|||||||
public void onPackageRemoved(String packageName, int uid) {
|
public void onPackageRemoved(String packageName, int uid) {
|
||||||
handlePackageRemoved(packageName, getChangingUserId());
|
handlePackageRemoved(packageName, getChangingUserId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPackageDataCleared(String packageName, int uid) {
|
||||||
|
handlePackageDataCleared(packageName, getChangingUserId());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1915,16 +1918,15 @@ public class ShortcutService extends IShortcutService.Stub {
|
|||||||
Slog.d(TAG, String.format("handlePackageRemoved: %s user=%d", packageName,
|
Slog.d(TAG, String.format("handlePackageRemoved: %s user=%d", packageName,
|
||||||
packageUserId));
|
packageUserId));
|
||||||
}
|
}
|
||||||
handlePackageRemovedInner(packageName, packageUserId, /* forceForCommandLine =*/ false);
|
cleanUpPackageForAllLoadedUsers(packageName, packageUserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handlePackageRemovedInner(String packageName, @UserIdInt int packageUserId,
|
private void handlePackageDataCleared(String packageName, int packageUserId) {
|
||||||
boolean forceForCommandLine) {
|
if (DEBUG) {
|
||||||
synchronized (mLock) {
|
Slog.d(TAG, String.format("handlePackageDataCleared: %s user=%d", packageName,
|
||||||
forEachLoadedUserLocked(user ->
|
packageUserId));
|
||||||
cleanUpPackageLocked(packageName, user.getUserId(), packageUserId,
|
|
||||||
forceForCommandLine));
|
|
||||||
}
|
}
|
||||||
|
cleanUpPackageForAllLoadedUsers(packageName, packageUserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// === PackageManager interaction ===
|
// === PackageManager interaction ===
|
||||||
@@ -2390,8 +2392,7 @@ public class ShortcutService extends IShortcutService.Stub {
|
|||||||
|
|
||||||
Slog.i(TAG, "cmd: handleClearShortcuts: " + mUserId + ", " + packageName);
|
Slog.i(TAG, "cmd: handleClearShortcuts: " + mUserId + ", " + packageName);
|
||||||
|
|
||||||
ShortcutService.this.handlePackageRemovedInner(packageName, mUserId,
|
ShortcutService.this.cleanUpPackageForAllLoadedUsers(packageName, mUserId);
|
||||||
/* forceForCommandLine= */ true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1061,6 +1061,12 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
i.putExtra(Intent.EXTRA_REPLACING, true);
|
i.putExtra(Intent.EXTRA_REPLACING, true);
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
private Intent genPackageDataClear(String packageName, int userId) {
|
||||||
|
Intent i = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED);
|
||||||
|
i.setData(Uri.parse("package:" + packageName));
|
||||||
|
i.putExtra(Intent.EXTRA_USER_HANDLE, userId);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
private ShortcutInfo parceled(ShortcutInfo si) {
|
private ShortcutInfo parceled(ShortcutInfo si) {
|
||||||
Parcel p = Parcel.obtain();
|
Parcel p = Parcel.obtain();
|
||||||
@@ -4159,6 +4165,79 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
|||||||
assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
|
assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Almost ame as testHandlePackageDelete, except it doesn't uninstall packages. */
|
||||||
|
public void testHandlePackageClearData() {
|
||||||
|
final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
|
||||||
|
getTestContext().getResources(), R.drawable.black_32x32));
|
||||||
|
setCaller(CALLING_PACKAGE_1, USER_0);
|
||||||
|
assertTrue(mManager.addDynamicShortcuts(list(
|
||||||
|
makeShortcutWithIcon("s1", bmp32x32), makeShortcutWithIcon("s2", bmp32x32)
|
||||||
|
)));
|
||||||
|
|
||||||
|
setCaller(CALLING_PACKAGE_2, USER_0);
|
||||||
|
assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32))));
|
||||||
|
|
||||||
|
setCaller(CALLING_PACKAGE_3, USER_0);
|
||||||
|
assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32))));
|
||||||
|
|
||||||
|
setCaller(CALLING_PACKAGE_1, USER_10);
|
||||||
|
assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32))));
|
||||||
|
|
||||||
|
setCaller(CALLING_PACKAGE_2, USER_10);
|
||||||
|
assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32))));
|
||||||
|
|
||||||
|
setCaller(CALLING_PACKAGE_3, USER_10);
|
||||||
|
assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32))));
|
||||||
|
|
||||||
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
|
||||||
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
|
||||||
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
|
||||||
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
|
||||||
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
|
||||||
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
|
||||||
|
|
||||||
|
assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0));
|
||||||
|
assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0));
|
||||||
|
assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0));
|
||||||
|
assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10));
|
||||||
|
assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10));
|
||||||
|
assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
|
||||||
|
|
||||||
|
mService.mPackageMonitor.onReceive(getTestContext(),
|
||||||
|
genPackageDataClear(CALLING_PACKAGE_1, USER_0));
|
||||||
|
|
||||||
|
assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
|
||||||
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
|
||||||
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
|
||||||
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
|
||||||
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
|
||||||
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
|
||||||
|
|
||||||
|
assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0));
|
||||||
|
assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0));
|
||||||
|
assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0));
|
||||||
|
assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10));
|
||||||
|
assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10));
|
||||||
|
assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
|
||||||
|
|
||||||
|
mService.mPackageMonitor.onReceive(getTestContext(),
|
||||||
|
genPackageDataClear(CALLING_PACKAGE_2, USER_10));
|
||||||
|
|
||||||
|
assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
|
||||||
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
|
||||||
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
|
||||||
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
|
||||||
|
assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
|
||||||
|
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
|
||||||
|
|
||||||
|
assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0));
|
||||||
|
assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0));
|
||||||
|
assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0));
|
||||||
|
assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10));
|
||||||
|
assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10));
|
||||||
|
assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
|
||||||
|
}
|
||||||
|
|
||||||
public void testHandlePackageUpdate() throws Throwable {
|
public void testHandlePackageUpdate() throws Throwable {
|
||||||
|
|
||||||
// Set up shortcuts and launchers.
|
// Set up shortcuts and launchers.
|
||||||
|
|||||||
Reference in New Issue
Block a user