Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 07f8d94c authored by Makoto Onuki's avatar Makoto Onuki Committed by android-build-merger
Browse files

Merge "ShortcutManager: When app\'s data is cleared, remove all shortcuts," into nyc-dev

am: d1c30db5

* commit 'd1c30db5':
  ShortcutManager: When app's data is cleared, remove all shortcuts,

Change-Id: I53cf64a3c651824fb1bcf57dcf4541e7e29f8dfb
parents ec0229d7 d1c30db5
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
        sPackageFilt.addAction(Intent.ACTION_PACKAGE_CHANGED);
        sPackageFilt.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
        sPackageFilt.addAction(Intent.ACTION_PACKAGE_RESTARTED);
        sPackageFilt.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
        sPackageFilt.addDataScheme("package");
        sNonDataFilt.addAction(Intent.ACTION_UID_REMOVED);
        sNonDataFilt.addAction(Intent.ACTION_USER_STOPPED);
@@ -275,6 +276,9 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
    public void onFinishPackageChanges() {
    }

    public void onPackageDataCleared(String packageName, int uid) {
    }

    public int getChangingUserId() {
        return mChangeUserId;
    }
@@ -365,6 +369,12 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
                }
                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)) {
            mDisappearingPackages = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
            mChangeType = PACKAGE_TEMPORARY_CHANGE;
+27 −26
Original line number Diff line number Diff line
@@ -1561,48 +1561,46 @@ public class ShortcutService extends IShortcutService.Stub {

    // === House keeping ===

    @VisibleForTesting
    void cleanUpPackageLocked(String packageName, int owningUserId, int packageUserId) {
        cleanUpPackageLocked(packageName, owningUserId, packageUserId,
                /* forceForCommandLine= */ false);
    private void cleanUpPackageForAllLoadedUsers(String packageName, @UserIdInt int packageUserId) {
        synchronized (mLock) {
            forEachLoadedUserLocked(user ->
                    cleanUpPackageLocked(packageName, user.getUserId(), packageUserId));
        }
    }

    /**
     * Remove all the information associated with a package.  This will really remove all the
     * information, including the restore information (i.e. it'll remove packages even if they're
     * shadow).
     *
     * This is called when an app is uninstalled, or an app gets "clear data"ed.
     */
    private void cleanUpPackageLocked(String packageName, int owningUserId, int packageUserId,
            boolean forceForCommandLine) {
        if (!forceForCommandLine && isPackageInstalled(packageName, packageUserId)) {
            wtf("Package " + packageName + " is still installed for user " + packageUserId);
            return;
        }

    @VisibleForTesting
    void cleanUpPackageLocked(String packageName, int owningUserId, int packageUserId) {
        final boolean wasUserLoaded = isUserLoadedLocked(owningUserId);

        final ShortcutUser mUser = getUserShortcutsLocked(owningUserId);
        final ShortcutUser user = getUserShortcutsLocked(owningUserId);
        boolean doNotify = false;

        // First, remove the package from the package list (if the package is a publisher).
        if (packageUserId == owningUserId) {
            if (mUser.removePackage(this, packageName) != null) {
            if (user.removePackage(this, packageName) != null) {
                doNotify = true;
            }
        }

        // 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.
        final ArrayMap<PackageWithUser, ShortcutLauncher> launchers = mUser.getAllLaunchers();
        final ArrayMap<PackageWithUser, ShortcutLauncher> launchers = user.getAllLaunchers();
        for (int i = launchers.size() - 1; i >= 0; i--) {
            launchers.valueAt(i).cleanUpPackage(packageName, packageUserId);
        }
        // Now there may be orphan shortcuts because we removed pinned shortucts at the previous
        // step.  Remove them too.
        for (int i = mUser.getAllPackages().size() - 1; i >= 0; i--) {
            mUser.getAllPackages().valueAt(i).refreshPinnedFlags(this);
        for (int i = user.getAllPackages().size() - 1; i >= 0; i--) {
            user.getAllPackages().valueAt(i).refreshPinnedFlags(this);
        }

        scheduleSaveUser(owningUserId);
@@ -1842,6 +1840,11 @@ public class ShortcutService extends IShortcutService.Stub {
        public void onPackageRemoved(String packageName, int uid) {
            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,
                    packageUserId));
        }
        handlePackageRemovedInner(packageName, packageUserId, /* forceForCommandLine =*/ false);
        cleanUpPackageForAllLoadedUsers(packageName, packageUserId);
    }

    private void handlePackageRemovedInner(String packageName, @UserIdInt int packageUserId,
            boolean forceForCommandLine) {
        synchronized (mLock) {
            forEachLoadedUserLocked(user ->
                cleanUpPackageLocked(packageName, user.getUserId(), packageUserId,
                        forceForCommandLine));
    private void handlePackageDataCleared(String packageName, int packageUserId) {
        if (DEBUG) {
            Slog.d(TAG, String.format("handlePackageDataCleared: %s user=%d", packageName,
                    packageUserId));
        }
        cleanUpPackageForAllLoadedUsers(packageName, packageUserId);
    }

    // === PackageManager interaction ===
@@ -2390,8 +2392,7 @@ public class ShortcutService extends IShortcutService.Stub {

            Slog.i(TAG, "cmd: handleClearShortcuts: " + mUserId + ", " + packageName);

            ShortcutService.this.handlePackageRemovedInner(packageName, mUserId,
                    /* forceForCommandLine= */ true);
            ShortcutService.this.cleanUpPackageForAllLoadedUsers(packageName, mUserId);
        }
    }

+79 −0
Original line number Diff line number Diff line
@@ -1061,6 +1061,12 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
        i.putExtra(Intent.EXTRA_REPLACING, true);
        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) {
        Parcel p = Parcel.obtain();
@@ -4159,6 +4165,79 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
        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 {

        // Set up shortcuts and launchers.