From e709bdd23575be9c951910ed2bea892f013afcc8 Mon Sep 17 00:00:00 2001 From: d34d Date: Fri, 17 Jul 2015 10:06:20 -0700 Subject: Show apps as unavailable when on unmounted storage This patch allows shortcuts to apps that are currently unavailable due to being on unmounted external storage to remain on the workspace and in folders. The icons will be disabled and grayed out until the external storage is mounted. Conflicts: res/values/cm_strings.xml Ticket: QRDL-991 Change-Id: I971483806b27e3a75ef0d5bb89d8dfb86f97511e --- res/values/cm_strings.xml | 3 + src/com/android/launcher3/Launcher.java | 40 ++++++++++++- src/com/android/launcher3/LauncherModel.java | 65 ++++++++++++++------- src/com/android/launcher3/Workspace.java | 84 ++++++++++++++++++++++++++++ 4 files changed, 171 insertions(+), 21 deletions(-) diff --git a/res/values/cm_strings.xml b/res/values/cm_strings.xml index 6f1899a9e..73ac3b1f6 100644 --- a/res/values/cm_strings.xml +++ b/res/values/cm_strings.xml @@ -85,4 +85,7 @@ Paged DISABLED + + + App not available diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 87a3d2483..b7a2c941d 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -3076,11 +3076,15 @@ public class Launcher extends Activity final Intent intent; if (tag instanceof ShortcutInfo) { shortcut = (ShortcutInfo) tag; + if (shortcut.isDisabled) { + Toast.makeText(this, R.string.app_not_available, Toast.LENGTH_SHORT).show(); + return; + } intent = shortcut.intent; int[] pos = new int[2]; v.getLocationOnScreen(pos); - intent.setSourceBounds(new Rect(pos[0], pos[1], - pos[0] + v.getWidth(), pos[1] + v.getHeight())); + intent.setSourceBounds( + new Rect(pos[0], pos[1], pos[0] + v.getWidth(), pos[1] + v.getHeight())); } else if (tag instanceof AppInfo) { shortcut = null; @@ -5473,6 +5477,38 @@ public class Launcher extends Activity } } + /** + * A package has become unavailable. + * + * Implementation of the method from LauncherModel.Callbacks. + */ + public void bindComponentsUnavailable(final ArrayList packageNames, + final ArrayList appInfos) { + if (!packageNames.isEmpty()) { + mWorkspace.updateUnavailableItemsByPackageName(packageNames); + } + // Notify the drag controller + mDragController.onAppsRemoved(packageNames, appInfos); + + // Update AllApps + if (!LauncherAppState.isDisableAllApps() && + mAppsCustomizeContent != null) { + mAppsCustomizeContent.removeApps(appInfos); + mAppDrawerAdapter.removeApps(appInfos); + } + } + + /** + * A package has become unavailable. + * + * Implementation of the method from LauncherModel.Callbacks. + */ + public void bindComponentsAvailable(final ArrayList itemInfos) { + if (!itemInfos.isEmpty()) { + mWorkspace.updateAvailableItems(itemInfos); + } + } + /** * A number of packages were updated. */ diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index abe96b2f9..d5672d5e3 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -209,6 +209,9 @@ public class LauncherModel extends BroadcastReceiver public void updatePackageBadge(String packageName); public void bindComponentsRemoved(ArrayList packageNames, ArrayList appInfos, UserHandleCompat user); + public void bindComponentsUnavailable(ArrayList packageNames, + ArrayList appInfos); + public void bindComponentsAvailable(ArrayList itemInfos); public void bindPackagesUpdated(ArrayList widgetsAndShortcuts); public void bindSearchablesChanged(); public boolean isAllAppsButtonRank(int rank); @@ -3299,6 +3302,7 @@ public class LauncherModel extends BroadcastReceiver final String[] packages = mPackages; final int N = packages.length; + final ArrayList unavailable = new ArrayList(); switch (mOp) { case OP_ADD: for (int i=0; i addedInfos = new ArrayList(added); // Ensure that we add all the workspace applications to the db if (LauncherAppState.isDisableAllApps()) { - final ArrayList addedInfos = new ArrayList(added); addAndBindAddedWorkspaceApps(context, addedInfos); } else { addAppsToAllApps(context, added); + mHandler.post(new Runnable() { + public void run() { + Callbacks cb = mCallbacks != null ? mCallbacks.get() : null; + if (callbacks == cb && cb != null) { + Log.d(TAG, "bindComponentsAvailable: " + addedInfos.size()); + callbacks.bindComponentsAvailable(addedInfos); + } + } + }); } } @@ -3391,6 +3407,32 @@ public class LauncherModel extends BroadcastReceiver if (mOp == OP_REMOVE) { // Mark all packages in the broadcast to be removed removedPackageNames.addAll(Arrays.asList(packages)); + // Remove all the components associated with this package + for (String pn : removedPackageNames) { + deletePackageFromDatabase(context, pn, mUser); + } + // Remove all the specific components + for (AppInfo a : removedApps) { + ArrayList infos = getItemInfoForComponentName(a.componentName, mUser); + deleteItemsFromDatabase(context, infos); + } + if (!removedPackageNames.isEmpty() || !removedApps.isEmpty()) { + // Remove any queued items from the install queue + String spKey = LauncherAppState.getSharedPreferencesKey(); + SharedPreferences sp = + context.getSharedPreferences(spKey, Context.MODE_PRIVATE); + InstallShortcutReceiver.removeFromInstallQueue(sp, removedPackageNames); + // Call the components-removed callback + mHandler.post(new Runnable() { + public void run() { + Callbacks cb = mCallbacks != null ? mCallbacks.get() : null; + if (callbacks == cb && cb != null) { + callbacks.bindComponentsRemoved(removedPackageNames, removedApps, + mUser); + } + } + }); + } } else if (mOp == OP_UPDATE) { // Mark disabled packages in the broadcast to be removed final PackageManager pm = context.getPackageManager(); @@ -3399,28 +3441,13 @@ public class LauncherModel extends BroadcastReceiver removedPackageNames.add(packages[i]); } } - } - // Remove all the components associated with this package - for (String pn : removedPackageNames) { - deletePackageFromDatabase(context, pn, mUser); - } - // Remove all the specific components - for (AppInfo a : removedApps) { - ArrayList infos = getItemInfoForComponentName(a.componentName, mUser); - deleteItemsFromDatabase(context, infos); - } - if (!removedPackageNames.isEmpty() || !removedApps.isEmpty()) { - // Remove any queued items from the install queue - String spKey = LauncherAppState.getSharedPreferencesKey(); - SharedPreferences sp = - context.getSharedPreferences(spKey, Context.MODE_PRIVATE); - InstallShortcutReceiver.removeFromInstallQueue(sp, removedPackageNames); - // Call the components-removed callback + } else if (mOp == OP_UNAVAILABLE) { + // Call the packages-unavailable callback mHandler.post(new Runnable() { public void run() { Callbacks cb = mCallbacks != null ? mCallbacks.get() : null; if (callbacks == cb && cb != null) { - callbacks.bindComponentsRemoved(removedPackageNames, removedApps, mUser); + callbacks.bindComponentsUnavailable(unavailable, removedApps); } } }); diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 1cfa6850f..8e5f868de 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -4948,6 +4948,90 @@ public class Workspace extends SmoothPagedView stripEmptyScreens(); } + void updateUnvailableItemsInCellLayout(CellLayout parent, ArrayList packages) { + final HashSet packageNames = new HashSet(); + packageNames.addAll(packages); + + ViewGroup layout = parent.getShortcutsAndWidgets(); + int childCount = layout.getChildCount(); + for (int i = 0; i < childCount; ++i) { + View view = layout.getChildAt(i); + if (view instanceof BubbleTextView) { + ItemInfo info = (ItemInfo) view.getTag(); + if (info instanceof ShortcutInfo) { + Intent intent = info.getIntent(); + ComponentName cn = intent != null ? intent.getComponent() : null; + if (cn != null && packageNames.contains(cn.getPackageName())) { + ShortcutInfo shortcut = (ShortcutInfo) info; + if (!shortcut.isDisabled) { + shortcut.isDisabled = true; + ((BubbleTextView) view) + .applyFromShortcutInfo(shortcut, mIconCache, true); + } + } + } + } else if (view instanceof FolderIcon) { + final Folder folder = ((FolderIcon)view).getFolder(); + updateUnvailableItemsInCellLayout(folder.getContent(), packages); + folder.invalidate(); + } + } + } + + void updateUnavailableItemsByPackageName(final ArrayList packages) { + ArrayList cellLayouts = getWorkspaceAndHotseatCellLayouts(); + for (CellLayout layoutParent : cellLayouts) { + updateUnvailableItemsInCellLayout(layoutParent, packages); + } + } + + /** + * Updates shortcuts to an app that was previously unavailable in the given cell layout + * @param parent CellLayout to check childen for shortcuts to the available app + * @param appInfos List of item infos. Items are assumed to be of type AppInfo + */ + void updateAvailabeItemsInCellLayout(CellLayout parent, final ArrayList appInfos) { + ViewGroup layout = parent.getShortcutsAndWidgets(); + int childCount = layout.getChildCount(); + for (int i = 0; i < childCount; ++i) { + View view = layout.getChildAt(i); + if (view instanceof BubbleTextView) { + ItemInfo info = (ItemInfo) view.getTag(); + if (info instanceof ShortcutInfo) { + Intent intent = info.getIntent(); + ComponentName cn = intent != null ? intent.getComponent() : null; + for (ItemInfo itemInfo : appInfos) { + AppInfo appInfo = (AppInfo) itemInfo; + if (cn != null && cn.getPackageName().equals( + appInfo.componentName.getPackageName())) { + ShortcutInfo shortcut = (ShortcutInfo) info; + if (shortcut.isDisabled) { + shortcut.isDisabled = false; + ((BubbleTextView) view) + .applyFromShortcutInfo(shortcut, mIconCache, true); + } + } + } + } + } else if (view instanceof FolderIcon) { + final Folder folder = ((FolderIcon)view).getFolder(); + updateAvailabeItemsInCellLayout(folder.getContent(), appInfos); + folder.invalidate(); + } + } + } + + /** + * Updates shortcuts to an app that was previously unavailable + * @param appInfos List of item infos. Items are assumed to be of type AppInfo + */ + void updateAvailableItems(final ArrayList appInfos) { + ArrayList cellLayouts = getWorkspaceAndHotseatCellLayouts(); + for (CellLayout layoutParent : cellLayouts) { + updateAvailabeItemsInCellLayout(layoutParent, appInfos); + } + } + interface ItemOperator { /** * Process the next itemInfo, possibly with side-effect on {@link ItemOperator#value}. -- cgit v1.2.3