From e9d903cfbedfd971050e4a71059236c0264aa7e2 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. Issue-id: CYNGNOS-1344 Change-Id: I971483806b27e3a75ef0d5bb89d8dfb86f97511e --- res/values/cm_strings.xml | 3 + src/com/android/launcher3/Launcher.java | 45 +++++++++++++ src/com/android/launcher3/LauncherModel.java | 58 ++++++++++++++--- src/com/android/launcher3/Workspace.java | 97 ++++++++++++++++++++++++++++ 4 files changed, 195 insertions(+), 8 deletions(-) diff --git a/res/values/cm_strings.xml b/res/values/cm_strings.xml index 8d3527e9f..1c6aaf868 100644 --- a/res/values/cm_strings.xml +++ b/res/values/cm_strings.xml @@ -74,4 +74,7 @@ A search activity could not be found! + + + App not available diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 8879fea11..dbdc61e5b 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -3016,6 +3016,10 @@ public class Launcher extends Activity final Intent intent; if (tag instanceof ShortcutInfo) { shortcut = (ShortcutInfo) tag; + if (shortcut.isDisabled == 1) { + Toast.makeText(this, R.string.app_not_available, Toast.LENGTH_SHORT).show(); + return; + } intent = shortcut.intent; int[] pos = new int[2]; v.getLocationOnScreen(pos); @@ -4715,12 +4719,53 @@ 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); + } + HashSet cns = new HashSet<>(); + for (AppInfo appInfo : appInfos) { + cns.add(appInfo.componentName); + } + // Notify the drag controller + mDragController.onAppsRemoved(packageNames, cns); + mAppsView.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. + */ + private ArrayList mWidgetsAndShortcuts; private Runnable mBindPackagesUpdatedRunnable = new Runnable() { public void run() { bindAllPackages(mWidgetsModel); } }; + public void bindPackagesUpdated(final ArrayList widgetsAndShortcuts) { + if (waitUntilResume(mBindPackagesUpdatedRunnable, true)) { + mWidgetsAndShortcuts = widgetsAndShortcuts; + return; + } + } + @Override public void bindAllPackages(final WidgetsModel model) { if (waitUntilResume(mBindPackagesUpdatedRunnable, true)) { diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index 83b5d8209..d731d2231 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -207,8 +207,12 @@ public class LauncherModel extends BroadcastReceiver public void bindRestoreItemsChange(HashSet updates); public void bindComponentsRemoved(ArrayList packageNames, ArrayList appInfos, UserHandleCompat user, int reason); + public void bindPackagesUpdated(ArrayList widgetsAndShortcuts); public void bindAllPackages(WidgetsModel model); public void bindSearchProviderChanged(); + public void bindComponentsUnavailable(ArrayList packageNames, + ArrayList appInfos); + public void bindComponentsAvailable(ArrayList itemInfos); public boolean isAllAppsButtonRank(int rank); public void onPageBoundSynchronously(int page); public void dumpLogsToLocalData(); @@ -3218,6 +3222,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(); if (added != null) { + final ArrayList addedInfos = new ArrayList(added); addAppsToAllApps(context, added); for (AppInfo ai : added) { addedOrUpdatedApps.put(ai.componentName, ai); } + mHandler.post(new Runnable() { + public void run() { + Callbacks cb = mCallbacks != null ? mCallbacks.get() : null; + if (callbacks == cb && cb != null) { + if (DEBUG_LOADERS) Log.d(TAG, "bindComponentsAvailable: " + + addedInfos.size()); + callbacks.bindComponentsAvailable(addedInfos); + } + } + }); } if (modified != null) { @@ -3464,6 +3483,17 @@ public class LauncherModel extends BroadcastReceiver final int removeReason; if (mOp == OP_UNAVAILABLE) { removeReason = ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE; + // Call the packages-unavailable callback + mHandler.post(new Runnable() { + public void run() { + Callbacks cb = mCallbacks != null ? mCallbacks.get() : null; + if (callbacks == cb && cb != null) { + if (DEBUG_LOADERS) Log.d(TAG, "bindComponentsUnavailable: " + + removedApps.size()); + callbacks.bindComponentsUnavailable(unavailable, removedApps); + } + } + }); } else { // Remove all the components associated with this package for (String pn : removedPackageNames) { @@ -3479,16 +3509,28 @@ public class LauncherModel extends BroadcastReceiver // Remove any queued items from the install queue InstallShortcutReceiver.removeFromInstallQueue(context, removedPackageNames, mUser); - // Call the components-removed callback - mHandler.post(new Runnable() { - public void run() { - Callbacks cb = getCallback(); - if (callbacks == cb && cb != null) { - callbacks.bindComponentsRemoved( + 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.bindComponentsUnavailable(unavailable, removedApps); + } + } + }); + } else { + // Call the components-removed callback + mHandler.post(new Runnable() { + public void run() { + Callbacks cb = getCallback(); + if (callbacks == cb && cb != null) { + callbacks.bindComponentsRemoved( removedPackageNames, removedApps, mUser, removeReason); + } } - } - }); + }); + } } // Update widgets diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 54d153299..78dcdc949 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -28,6 +28,7 @@ import android.appwidget.AppWidgetHostView; import android.appwidget.AppWidgetProviderInfo; import android.content.ComponentName; import android.content.Context; +import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Resources; import android.content.res.TypedArray; @@ -4330,6 +4331,102 @@ public class Workspace extends PagedView 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 == 0) { + shortcut.isDisabled = 1; + ((BubbleTextView) view) + .applyFromShortcutInfo(shortcut, mIconCache, true); + } + } + } + } else if (view instanceof FolderIcon) { + final Folder folder = ((FolderIcon)view).getFolder(); + final FolderPagedView folderPagedView = (FolderPagedView)folder.getContent(); + final int N = folderPagedView.getItemCount(); + for (int page = 0; page < N; page++) { + final CellLayout cellLayout = folderPagedView.getPageAt(page); + updateUnvailableItemsInCellLayout(cellLayout, 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 == 1) { + shortcut.isDisabled = 0; + ((BubbleTextView) view) + .applyFromShortcutInfo(shortcut, mIconCache, true); + } + } + } + } + } else if (view instanceof FolderIcon) { + final Folder folder = ((FolderIcon) view).getFolder(); + final FolderPagedView folderPagedView = (FolderPagedView) folder.getContent(); + final int N = folderPagedView.getItemCount(); + for (int page = 0; page < N; page++) { + final CellLayout cellLayout = folderPagedView.getPageAt(page); + if (cellLayout != null) { + updateAvailabeItemsInCellLayout(cellLayout, 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