From 83892cc0768bd6d7f0827886e9e7a2eb3eed2b01 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Wed, 1 May 2013 16:53:33 -0700 Subject: Fixing issue where updating the visibility of one application can trigger all icons to disappear. (Bug 8757421) - Also queueing bindComponentsRemoved() and bindPackagesUpdated() to wait for resume (Bug 8594153) Change-Id: I44028fe79f6fa6bcd6b829e36f3f5b9ed756dc4d --- src/com/android/launcher2/ApplicationInfo.java | 6 -- .../android/launcher2/AppsCustomizePagedView.java | 24 +------- src/com/android/launcher2/DragController.java | 9 +-- src/com/android/launcher2/Launcher.java | 36 +++++++++-- src/com/android/launcher2/LauncherModel.java | 27 +++++---- src/com/android/launcher2/ShortcutInfo.java | 6 -- src/com/android/launcher2/Workspace.java | 69 +++++++++++++++++++--- 7 files changed, 114 insertions(+), 63 deletions(-) (limited to 'src/com/android') diff --git a/src/com/android/launcher2/ApplicationInfo.java b/src/com/android/launcher2/ApplicationInfo.java index a3040d4cd..eda8c2520 100644 --- a/src/com/android/launcher2/ApplicationInfo.java +++ b/src/com/android/launcher2/ApplicationInfo.java @@ -97,12 +97,6 @@ class ApplicationInfo extends ItemInfo { firstInstallTime = info.firstInstallTime; } - /** Returns the package name that the shortcut's intent will resolve to, or an empty string if - * none exists. */ - String getPackageName() { - return super.getPackageName(intent); - } - /** * Creates the application intent based on a component name and various launch flags. * Sets {@link #itemType} to {@link LauncherSettings.BaseLauncherColumns#ITEM_TYPE_APPLICATION}. diff --git a/src/com/android/launcher2/AppsCustomizePagedView.java b/src/com/android/launcher2/AppsCustomizePagedView.java index 5601169b8..901b661db 100644 --- a/src/com/android/launcher2/AppsCustomizePagedView.java +++ b/src/com/android/launcher2/AppsCustomizePagedView.java @@ -1556,16 +1556,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen } return -1; } - private int findAppByPackage(List list, String packageName) { - int length = list.size(); - for (int i = 0; i < length; ++i) { - ApplicationInfo info = list.get(i); - if (ItemInfo.getPackageName(info.intent).equals(packageName)) { - return i; - } - } - return -1; - } private void removeAppsWithoutInvalidate(ArrayList list) { // loop through all the apps and remove apps that have the same component int length = list.size(); @@ -1577,18 +1567,8 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen } } } - private void removeAppsWithPackageNameWithoutInvalidate(ArrayList packageNames) { - // loop through all the package names and remove apps that have the same package name - for (String pn : packageNames) { - int removeIndex = findAppByPackage(mApps, pn); - while (removeIndex > -1) { - mApps.remove(removeIndex); - removeIndex = findAppByPackage(mApps, pn); - } - } - } - public void removeApps(ArrayList packageNames) { - removeAppsWithPackageNameWithoutInvalidate(packageNames); + public void removeApps(ArrayList appInfos) { + removeAppsWithoutInvalidate(appInfos); updatePageCounts(); invalidateOnDataChange(); } diff --git a/src/com/android/launcher2/DragController.java b/src/com/android/launcher2/DragController.java index 78afe5704..d15cb6e06 100644 --- a/src/com/android/launcher2/DragController.java +++ b/src/com/android/launcher2/DragController.java @@ -328,18 +328,19 @@ public class DragController { } endDrag(); } - public void onAppsRemoved(ArrayList packageNames, Context context) { + public void onAppsRemoved(ArrayList appInfos, Context context) { // Cancel the current drag if we are removing an app that we are dragging if (mDragObject != null) { Object rawDragInfo = mDragObject.dragInfo; if (rawDragInfo instanceof ShortcutInfo) { ShortcutInfo dragInfo = (ShortcutInfo) rawDragInfo; - for (String pn : packageNames) { + for (ApplicationInfo info : appInfos) { // Added null checks to prevent NPE we've seen in the wild if (dragInfo != null && dragInfo.intent != null) { - boolean isSamePackage = dragInfo.getPackageName().equals(pn); - if (isSamePackage) { + boolean isSameComponent = + dragInfo.intent.getComponent().equals(info.componentName); + if (isSameComponent) { cancelDrag(); return; } diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java index 0aab2acaf..5ed7f6b78 100644 --- a/src/com/android/launcher2/Launcher.java +++ b/src/com/android/launcher2/Launcher.java @@ -3704,27 +3704,51 @@ public final class Launcher extends Activity } /** - * A package was uninstalled. + * A package was uninstalled. We take both the super set of packageNames + * in addition to specific applications to remove, the reason being that + * this can be called when a package is updated as well. In that scenario, + * we only remove specific components from the workspace, where as + * package-removal should clear all items by package name. * * Implementation of the method from LauncherModel.Callbacks. */ - public void bindAppsRemoved(ArrayList packageNames, boolean permanent) { - if (permanent) { - mWorkspace.removeItems(packageNames); + public void bindComponentsRemoved(final ArrayList packageNames, + final ArrayList appInfos, + final boolean matchPackageNamesOnly) { + if (waitUntilResume(new Runnable() { + public void run() { + bindComponentsRemoved(packageNames, appInfos, matchPackageNamesOnly); + } + })) { + return; + } + + if (matchPackageNamesOnly) { + mWorkspace.removeItemsByPackageName(packageNames); + } else { + mWorkspace.removeItemsByApplicationInfo(appInfos); } if (mAppsCustomizeContent != null) { - mAppsCustomizeContent.removeApps(packageNames); + mAppsCustomizeContent.removeApps(appInfos); } // Notify the drag controller - mDragController.onAppsRemoved(packageNames, this); + mDragController.onAppsRemoved(appInfos, this); } /** * A number of packages were updated. */ public void bindPackagesUpdated() { + if (waitUntilResume(new Runnable() { + public void run() { + bindPackagesUpdated(); + } + })) { + return; + } + if (mAppsCustomizeContent != null) { mAppsCustomizeContent.onPackagesUpdated(); } diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java index 99808a6ea..00770b28a 100644 --- a/src/com/android/launcher2/LauncherModel.java +++ b/src/com/android/launcher2/LauncherModel.java @@ -53,6 +53,7 @@ import com.android.launcher2.InstallWidgetReceiver.WidgetMimeTypeHandlerData; import java.lang.ref.WeakReference; import java.net.URISyntaxException; import java.text.Collator; +import java.util.Arrays; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -156,7 +157,9 @@ public class LauncherModel extends BroadcastReceiver { public void bindAllApplications(ArrayList apps); public void bindAppsAdded(ArrayList apps); public void bindAppsUpdated(ArrayList apps); - public void bindAppsRemoved(ArrayList packageNames, boolean permanent); + public void bindComponentsRemoved(ArrayList packageNames, + ArrayList appInfos, + boolean matchPackageNamesOnly); public void bindPackagesUpdated(); public boolean isAllAppsVisible(); public boolean isAllAppsButtonRank(int rank); @@ -2009,6 +2012,7 @@ public class LauncherModel extends BroadcastReceiver { ArrayList added = null; ArrayList modified = null; + final ArrayList removedApps = new ArrayList(); if (mBgAllAppsList.added.size() > 0) { added = new ArrayList(mBgAllAppsList.added); @@ -2018,16 +2022,9 @@ public class LauncherModel extends BroadcastReceiver { modified = new ArrayList(mBgAllAppsList.modified); mBgAllAppsList.modified.clear(); } - // We may be removing packages that have no associated launcher application, so we - // pass through the removed package names directly. - // NOTE: We flush the icon cache aggressively in removePackage() above. - final ArrayList removedPackageNames = new ArrayList(); if (mBgAllAppsList.removed.size() > 0) { + removedApps.addAll(mBgAllAppsList.removed); mBgAllAppsList.removed.clear(); - - for (int i = 0; i < N; ++i) { - removedPackageNames.add(packages[i]); - } } final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null; @@ -2058,13 +2055,19 @@ public class LauncherModel extends BroadcastReceiver { } }); } - if (!removedPackageNames.isEmpty()) { - final boolean permanent = mOp != OP_UNAVAILABLE; + // If a package has been removed, or an app has been removed as a result of + // an update (for example), make the removed callback. + if (mOp == OP_REMOVE || !removedApps.isEmpty()) { + final boolean permanent = (mOp == OP_REMOVE); + final ArrayList removedPackageNames = + new ArrayList(Arrays.asList(packages)); + mHandler.post(new Runnable() { public void run() { Callbacks cb = mCallbacks != null ? mCallbacks.get() : null; if (callbacks == cb && cb != null) { - callbacks.bindAppsRemoved(removedPackageNames, permanent); + callbacks.bindComponentsRemoved(removedPackageNames, + removedApps, permanent); } } }); diff --git a/src/com/android/launcher2/ShortcutInfo.java b/src/com/android/launcher2/ShortcutInfo.java index 968d3b836..ccb663a7f 100644 --- a/src/com/android/launcher2/ShortcutInfo.java +++ b/src/com/android/launcher2/ShortcutInfo.java @@ -93,12 +93,6 @@ class ShortcutInfo extends ItemInfo { return mIcon; } - /** Returns the package name that the shortcut's intent will resolve to, or an empty string if - * none exists. */ - String getPackageName() { - return super.getPackageName(intent); - } - public void updateIcon(IconCache iconCache) { mIcon = iconCache.getIcon(intent); usingFallbackIcon = iconCache.isDefaultIcon(mIcon); diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java index d4488db2e..ac4c3ddb4 100644 --- a/src/com/android/launcher2/Workspace.java +++ b/src/com/android/launcher2/Workspace.java @@ -3639,10 +3639,66 @@ public class Workspace extends SmoothPagedView } } - void removeItems(final ArrayList packages) { - final HashSet packageNames = new HashSet(); + // Removes ALL items that match a given package name, this is usually called when a package + // has been removed and we want to remove all components (widgets, shortcuts, apps) that + // belong to that package. + void removeItemsByPackageName(final ArrayList packages) { + HashSet packageNames = new HashSet(); packageNames.addAll(packages); + // Just create a hash table of all the specific components that this will affect + HashSet cns = new HashSet(); + ArrayList cellLayouts = getWorkspaceAndHotseatCellLayouts(); + for (CellLayout layoutParent : cellLayouts) { + ViewGroup layout = layoutParent.getShortcutsAndWidgets(); + int childCount = layout.getChildCount(); + for (int i = 0; i < childCount; ++i) { + View view = layout.getChildAt(i); + Object tag = view.getTag(); + + if (tag instanceof ShortcutInfo) { + ShortcutInfo info = (ShortcutInfo) tag; + ComponentName cn = info.intent.getComponent(); + if (packageNames.contains(cn.getPackageName())) { + cns.add(cn); + } + } else if (tag instanceof FolderInfo) { + FolderInfo info = (FolderInfo) tag; + for (ShortcutInfo s : info.contents) { + ComponentName cn = s.intent.getComponent(); + if (packageNames.contains(cn.getPackageName())) { + cns.add(cn); + } + } + } else if (tag instanceof LauncherAppWidgetInfo) { + LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) tag; + ComponentName cn = info.providerName; + if (packageNames.contains(cn.getPackageName())) { + cns.add(cn); + } + } + } + } + + // Remove all the things + removeItemsByComponentName(cns); + } + + // Removes items that match the application info specified, when applications are removed + // as a part of an update, this is called to ensure that other widgets and application + // shortcuts are not removed. + void removeItemsByApplicationInfo(final ArrayList appInfos) { + // Just create a hash table of all the specific components that this will affect + HashSet cns = new HashSet(); + for (ApplicationInfo info : appInfos) { + cns.add(info.componentName); + } + + // Remove all the things + removeItemsByComponentName(cns); + } + + void removeItemsByComponentName(final HashSet componentNames) { ArrayList cellLayouts = getWorkspaceAndHotseatCellLayouts(); for (final CellLayout layoutParent: cellLayouts) { final ViewGroup layout = layoutParent.getShortcutsAndWidgets(); @@ -3664,7 +3720,7 @@ public class Workspace extends SmoothPagedView final ComponentName name = intent.getComponent(); if (name != null) { - if (packageNames.contains(name.getPackageName())) { + if (componentNames.contains(name)) { LauncherModel.deleteItemFromDatabase(mLauncher, info); childrenToRemove.add(view); } @@ -3682,7 +3738,7 @@ public class Workspace extends SmoothPagedView final ComponentName name = intent.getComponent(); if (name != null) { - if (packageNames.contains(name.getPackageName())) { + if (componentNames.contains(name)) { appsToRemoveFromFolder.add(appInfo); } } @@ -3695,7 +3751,7 @@ public class Workspace extends SmoothPagedView final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) tag; final ComponentName provider = info.providerName; if (provider != null) { - if (packageNames.contains(provider.getPackageName())) { + if (componentNames.contains(provider)) { LauncherModel.deleteItemFromDatabase(mLauncher, info); childrenToRemove.add(view); } @@ -3740,8 +3796,7 @@ public class Workspace extends SmoothPagedView while (iter.hasNext()) { try { Intent intent = Intent.parseUri(iter.next(), 0); - String pn = ItemInfo.getPackageName(intent); - if (packageNames.contains(pn)) { + if (componentNames.contains(intent.getComponent())) { iter.remove(); } -- cgit v1.2.3