From 6a43e660cce2cda206f4fecf3ed4ecf9dce8f326 Mon Sep 17 00:00:00 2001 From: Flamefire Date: Tue, 1 Apr 2014 11:40:55 +0200 Subject: Re-Add hidden-apps setting Forward port from CM 10.2 PS3: Don't rename and incorporate changes from Devkota PS4: Update German translation PS5: Remove translations PS7: Hide widgets from widget list PS9: Remove debug output PS11: Rebase Change-Id: Ie06b288e22c2678fb09da1bf42d46922b8319e01 --- AndroidManifest.xml | 12 +- res/layout/hidden_apps_list.xml | 7 + res/layout/hidden_apps_list_item.xml | 33 +++ res/layout/tab_widget_indicator.xml | 19 -- res/values/cm_strings.xml | 14 + res/values/preferences_defaults.xml | 2 + res/xml/preferences_drawer.xml | 36 +++ res/xml/preferences_headers.xml | 20 +- .../android/launcher3/AppsCustomizePagedView.java | 150 +++++++++- src/com/android/launcher3/FastBitmapDrawable.java | 2 +- src/com/android/launcher3/LauncherModel.java | 100 ++++++- .../launcher3/settings/HiddenAppsActivity.java | 302 +++++++++++++++++++++ .../launcher3/settings/SettingsActivity.java | 9 + .../launcher3/settings/SettingsProvider.java | 3 + .../launcher3/widget/CheckableLinearLayout.java | 50 ++++ .../android/launcher3/widget/InertCheckBox.java | 69 +++++ 16 files changed, 783 insertions(+), 45 deletions(-) create mode 100644 res/layout/hidden_apps_list.xml create mode 100644 res/layout/hidden_apps_list_item.xml delete mode 100644 res/layout/tab_widget_indicator.xml create mode 100644 res/xml/preferences_drawer.xml create mode 100644 src/com/android/launcher3/settings/HiddenAppsActivity.java create mode 100644 src/com/android/launcher3/widget/CheckableLinearLayout.java create mode 100644 src/com/android/launcher3/widget/InertCheckBox.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index f33bb0b30..f8ef64f31 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -85,7 +85,7 @@ - @@ -94,6 +94,16 @@ + + + + + + + + \ No newline at end of file diff --git a/res/layout/hidden_apps_list_item.xml b/res/layout/hidden_apps_list_item.xml new file mode 100644 index 000000000..a00b07741 --- /dev/null +++ b/res/layout/hidden_apps_list_item.xml @@ -0,0 +1,33 @@ + + + + + + + + + + \ No newline at end of file diff --git a/res/layout/tab_widget_indicator.xml b/res/layout/tab_widget_indicator.xml deleted file mode 100644 index de7c50ec4..000000000 --- a/res/layout/tab_widget_indicator.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - diff --git a/res/values/cm_strings.xml b/res/values/cm_strings.xml index 33da3d2e9..73598a571 100644 --- a/res/values/cm_strings.xml +++ b/res/values/cm_strings.xml @@ -55,6 +55,14 @@ Drawer + Apps and widgets drawer + Apps + Hidden apps + Hide apps from the drawer + Remove shortcuts + Remove the shortcuts of hidden apps from the homescreen + Remove widgets + Remove the widgets of hidden apps from the homescreen Dock @@ -78,4 +86,10 @@ Customize your drawer Tap the page indicator to view additional configuration settings + + + Reset + + + Hidden apps diff --git a/res/values/preferences_defaults.xml b/res/values/preferences_defaults.xml index 288157381..daf28a3de 100644 --- a/res/values/preferences_defaults.xml +++ b/res/values/preferences_defaults.xml @@ -7,6 +7,8 @@ @bool/config_workspaceFadeAdjacentScreens stack false + true + true @bool/config_largeIcons sans-serif-condensed 0 diff --git a/res/xml/preferences_drawer.xml b/res/xml/preferences_drawer.xml new file mode 100644 index 000000000..c59d6b7fe --- /dev/null +++ b/res/xml/preferences_drawer.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/res/xml/preferences_headers.xml b/res/xml/preferences_headers.xml index bc919b2d5..42a08a9bd 100644 --- a/res/xml/preferences_headers.xml +++ b/res/xml/preferences_headers.xml @@ -20,20 +20,22 @@ android:fragment="com.android.launcher3.settings.SettingsActivity$HomescreenFragment" android:title="@string/preferences_interface_homescreen_title" /> - - +
- +
- + android:title="@string/preferences_application_title" /> +
+ android:summary="@string/application_copyright" /> diff --git a/src/com/android/launcher3/AppsCustomizePagedView.java b/src/com/android/launcher3/AppsCustomizePagedView.java index 28bc4e477..0cc540436 100644 --- a/src/com/android/launcher3/AppsCustomizePagedView.java +++ b/src/com/android/launcher3/AppsCustomizePagedView.java @@ -27,6 +27,7 @@ import android.appwidget.AppWidgetProviderInfo; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.content.res.TypedArray; @@ -175,6 +176,11 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen } private SortMode mSortMode = SortMode.Title; + private int mFilterApps = FILTER_APPS_SYSTEM_FLAG | FILTER_APPS_DOWNLOADED_FLAG; + + private static final int FILTER_APPS_SYSTEM_FLAG = 1; + private static final int FILTER_APPS_DOWNLOADED_FLAG = 2; + // Refs private Launcher mLauncher; private DragController mDragController; @@ -189,6 +195,11 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen private ArrayList mApps; private ArrayList mWidgets; + private ArrayList mFilteredApps; + private ArrayList mFilteredWidgets; + private ArrayList mHiddenApps; + private ArrayList mHiddenPackages; + // Cling private boolean mHasShownAllAppsCling; private int mClingFocusedX; @@ -279,7 +290,9 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen mLayoutInflater = LayoutInflater.from(context); mPackageManager = context.getPackageManager(); mApps = new ArrayList(); + mFilteredApps = new ArrayList(); mWidgets = new ArrayList(); + mFilteredWidgets = new ArrayList(); mIconCache = (LauncherAppState.getInstance()).getIconCache(); mCanvas = new Canvas(); mRunningTasks = new ArrayList(); @@ -309,6 +322,18 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) { setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); } + + String[] flattened = SettingsProvider.getStringCustomDefault(context, + SettingsProvider.SETTINGS_UI_DRAWER_HIDDEN_APPS, "").split("\\|"); + mHiddenApps = new ArrayList(flattened.length); + mHiddenPackages = new ArrayList(flattened.length); + for (String flat : flattened) { + ComponentName cmp = ComponentName.unflattenFromString(flat); + if (cmp != null) { + mHiddenApps.add(cmp); + mHiddenPackages.add(cmp.getPackageName()); + } + } } @Override @@ -351,7 +376,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen i = (currentPage * numItemsPerPage) + (childCount / 2); } } else if (mContentType == ContentType.Widgets) { - int numApps = mApps.size(); + int numApps = mFilteredApps.size(); PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(currentPage); int numItemsPerPage = mWidgetCountX * mWidgetCountY; int childCount = layout.getChildCount(); @@ -379,12 +404,12 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen int getPageForComponent(int index) { if (index < 0) return 0; - if (index < mApps.size()) { + if (index < mFilteredApps.size()) { int numItemsPerPage = mCellCountX * mCellCountY; return (index / numItemsPerPage); } else { int numItemsPerPage = mWidgetCountX * mWidgetCountY; - return (index - mApps.size()) / numItemsPerPage; + return (index - mFilteredApps.size()) / numItemsPerPage; } } @@ -395,9 +420,9 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen } private void updatePageCounts() { - mNumWidgetPages = (int) Math.ceil(mWidgets.size() / - (float) (mWidgetCountX * mWidgetCountY)); - mNumAppsPages = (int) Math.ceil((float) mApps.size() / (mCellCountX * mCellCountY)); + mNumWidgetPages = (int) Math.ceil((float) mFilteredWidgets.size() + / (mWidgetCountX * mWidgetCountY)); + mNumAppsPages = (int) Math.ceil((float) mFilteredApps.size() / (mCellCountX * mCellCountY)); } protected void onDataReady(int width, int height) { @@ -462,7 +487,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); if (!isDataReady()) { - if ((DISABLE_ALL_APPS || !mApps.isEmpty()) && !mWidgets.isEmpty()) { + if ((DISABLE_ALL_APPS || !mFilteredApps.isEmpty()) && !mFilteredWidgets.isEmpty()) { setDataIsReady(); setMeasuredDimension(width, height); onDataReady(width, height); @@ -507,7 +532,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen mWidgets.add(o); } } - updatePageCountsAndInvalidateData(); + filterWidgets(); } public void setBulkBind(boolean bulkBind) { @@ -1083,14 +1108,14 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen final boolean isRtl = isLayoutRtl(); int numCells = mCellCountX * mCellCountY; int startIndex = page * numCells; - int endIndex = Math.min(startIndex + numCells, mApps.size()); + int endIndex = Math.min(startIndex + numCells, mFilteredApps.size()); AppsCustomizeCellLayout layout = (AppsCustomizeCellLayout) getPageAt(page); layout.removeAllViewsOnPage(); ArrayList items = new ArrayList(); ArrayList images = new ArrayList(); for (int i = startIndex; i < endIndex; ++i) { - AppInfo info = mApps.get(i); + AppInfo info = mFilteredApps.get(i); PagedViewIcon icon = (PagedViewIcon) mLayoutInflater.inflate( R.layout.apps_customize_application, layout, false); icon.applyFromApplicationInfo(info, true, this); @@ -1239,8 +1264,8 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen // Prepare the set of widgets to load previews for in the background int offset = page * numItemsPerPage; - for (int i = offset; i < Math.min(offset + numItemsPerPage, mWidgets.size()); ++i) { - items.add(mWidgets.get(i)); + for (int i = offset; i < Math.min(offset + numItemsPerPage, mFilteredWidgets.size()); ++i) { + items.add(mFilteredWidgets.get(i)); } // Prepopulate the pages with the other widget info, and fill in the previews later @@ -1865,7 +1890,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen mSortMode = sortMode; - Collections.sort(mApps, getComparatorForSortMode()); + Collections.sort(mFilteredApps, getComparatorForSortMode()); if (mContentType == ContentType.Applications) { for (int i = 0; i < getChildCount(); i++) { @@ -1903,13 +1928,40 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen } } + public void setShowSystemApps(boolean show) { + if (show) { + mFilterApps |= FILTER_APPS_SYSTEM_FLAG; + } else { + mFilterApps &= ~FILTER_APPS_SYSTEM_FLAG; + } + filterApps(); + } + + public void setShowDownloadedApps(boolean show) { + if (show) { + mFilterApps |= FILTER_APPS_DOWNLOADED_FLAG; + } else { + mFilterApps &= ~FILTER_APPS_DOWNLOADED_FLAG; + } + filterApps(); + } + + public boolean getShowSystemApps() { + return (mFilterApps & FILTER_APPS_SYSTEM_FLAG) != 0; + } + + public boolean getShowDownloadedApps() { + return (mFilterApps & FILTER_APPS_DOWNLOADED_FLAG) != 0; + } + public void setApps(ArrayList list) { if (!DISABLE_ALL_APPS) { mApps = list; - Collections.sort(mApps, getComparatorForSortMode()); + filterAppsWithoutInvalidate(); updatePageCountsAndInvalidateData(); } } + private void addAppsWithoutInvalidate(ArrayList list) { // We add it in place, in alphabetical order int count = list.size(); @@ -1921,12 +1973,15 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen } } } + public void addApps(ArrayList list) { if (!DISABLE_ALL_APPS) { addAppsWithoutInvalidate(list); + filterAppsWithoutInvalidate(); updatePageCountsAndInvalidateData(); } } + private int findAppByComponent(List list, AppInfo item) { ComponentName removeComponent = item.intent.getComponent(); int length = list.size(); @@ -1938,6 +1993,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen } return -1; } + private void removeAppsWithoutInvalidate(ArrayList list) { // loop through all the apps and remove apps that have the same component int length = list.size(); @@ -1949,12 +2005,15 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen } } } + public void removeApps(ArrayList appInfos) { if (!DISABLE_ALL_APPS) { removeAppsWithoutInvalidate(appInfos); + filterAppsWithoutInvalidate(); updatePageCountsAndInvalidateData(); } } + public void updateApps(ArrayList list) { // We remove and re-add the updated applications list because it's properties may have // changed (ie. the title), and this will ensure that the items will be in their proper @@ -1962,10 +2021,73 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen if (!DISABLE_ALL_APPS) { removeAppsWithoutInvalidate(list); addAppsWithoutInvalidate(list); + filterAppsWithoutInvalidate(); updatePageCountsAndInvalidateData(); } } + public void filterAppsWithoutInvalidate() { + mFilteredApps = new ArrayList(mApps); + Iterator iterator = mFilteredApps.iterator(); + while (iterator.hasNext()) { + AppInfo appInfo = iterator.next(); + boolean system = (appInfo.flags & AppInfo.DOWNLOADED_FLAG) == 0; + if (mHiddenApps.contains(appInfo.componentName) || + (system && !getShowSystemApps()) || + (!system && !getShowDownloadedApps())) { + iterator.remove(); + } + } + Collections.sort(mFilteredApps, getComparatorForSortMode()); + } + + public void filterApps() { + filterAppsWithoutInvalidate(); + updatePageCountsAndInvalidateData(); + } + + public void filterWidgetsWithoutInvalidate() { + mFilteredWidgets = new ArrayList(mWidgets); + + Iterator iterator = mFilteredWidgets.iterator(); + while (iterator.hasNext()) { + Object o = iterator.next(); + + String packageName; + if (o instanceof AppWidgetProviderInfo) { + AppWidgetProviderInfo widgetInfo = (AppWidgetProviderInfo) o; + if (widgetInfo.provider == null) { + continue; + } + packageName = widgetInfo.provider.getPackageName(); + } else if (o instanceof ResolveInfo) { + ResolveInfo shortcut = (ResolveInfo) o; + packageName = shortcut.activityInfo.applicationInfo.packageName; + } else { + Log.w(TAG, "Unknown class in widgets list: " + o.getClass()); + continue; + } + + int flags; + try { + flags = AppInfo.initFlags(mPackageManager.getPackageInfo(packageName, 0)); + } catch (NameNotFoundException e) { + flags = 0; + } + boolean system = (flags & AppInfo.DOWNLOADED_FLAG) == 0; + if (mHiddenPackages.contains(packageName) || + (system && !getShowSystemApps()) || + (!system && !getShowDownloadedApps())) { + iterator.remove(); + } + } + } + + public void filterWidgets() { + filterWidgetsWithoutInvalidate(); + updatePageCountsAndInvalidateData(); + } + public void reset() { // If we have reset, then we should not continue to restore the previous state mSaveInstanceStateItemIndex = -1; diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java index 14760c7b6..8061c619d 100644 --- a/src/com/android/launcher3/FastBitmapDrawable.java +++ b/src/com/android/launcher3/FastBitmapDrawable.java @@ -32,7 +32,7 @@ class FastBitmapDrawable extends Drawable { private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG); FastBitmapDrawable(Bitmap b) { - mAlpha = 255; + mAlpha = 255; mBitmap = b; if (b != null) { mWidth = mBitmap.getWidth(); diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index bc97e0af2..e06fe5fb3 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -19,8 +19,16 @@ package com.android.launcher3; import android.app.SearchManager; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProviderInfo; -import android.content.*; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.ContentProviderClient; +import android.content.ContentProviderOperation; +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; import android.content.Intent.ShortcutIconResource; +import android.content.SharedPreferences; import android.content.pm.ActivityInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; @@ -42,7 +50,9 @@ import android.os.SystemClock; import android.provider.BaseColumns; import android.util.Log; import android.util.Pair; + import com.android.launcher3.InstallWidgetReceiver.WidgetMimeTypeHandlerData; +import com.android.launcher3.settings.SettingsProvider; import java.lang.ref.WeakReference; import java.net.URISyntaxException; @@ -2201,6 +2211,92 @@ public class LauncherModel extends BroadcastReceiver { runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE); } + private void removeHiddenAppsWorkspaceItems( + final ArrayList workspaceItems, + final ArrayList appWidgets, + final HashMap folders) { + + // Get hidden apps + ArrayList mHiddenApps = new ArrayList(); + ArrayList mHiddenAppsPackages = new ArrayList(); + Context context = mApp.getContext(); + String[] flattened = SettingsProvider.getStringCustomDefault(context, + SettingsProvider.SETTINGS_UI_DRAWER_HIDDEN_APPS, "").split("\\|"); + boolean hideShortcuts = SettingsProvider.getBoolean(context, + SettingsProvider.SETTINGS_UI_DRAWER_REMOVE_HIDDEN_APPS_SHORTCUTS, + R.bool.preferences_interface_drawer_remove_hidden_apps_shortcuts_default); + boolean hideWidgets = SettingsProvider.getBoolean(context, + SettingsProvider.SETTINGS_UI_DRAWER_REMOVE_HIDDEN_APPS_WIDGETS, + R.bool.preferences_interface_drawer_remove_hidden_apps_widgets_default); + + for (String flat : flattened) { + ComponentName cmp = ComponentName.unflattenFromString(flat); + if (cmp != null) { + mHiddenApps.add(cmp); + mHiddenAppsPackages.add(cmp.getPackageName()); + } + } + + // Shortcuts + if (hideShortcuts) { + int N = workspaceItems.size() - 1; + for (int i = N; i >= 0; i--) { + final ItemInfo item = workspaceItems.get(i); + if (item instanceof ShortcutInfo) { + ShortcutInfo shortcut = (ShortcutInfo)item; + if (shortcut.intent != null && shortcut.intent.getComponent() != null) { + if (mHiddenApps.contains(shortcut.intent.getComponent())) { + LauncherModel.deleteItemFromDatabase(mContext, shortcut); + workspaceItems.remove(i); + } + } + } else { + final FolderInfo folder = (FolderInfo)item; + List shortcuts = folder.contents; + int NN = shortcuts.size() - 1; + for (int j = NN; j >= 0; j--) { + ShortcutInfo sci = shortcuts.get(j); + if (sci.intent != null && sci.intent.getComponent() != null) { + if (mHiddenApps.contains(sci.intent.getComponent())) { + LauncherModel.deleteItemFromDatabase(mContext, sci); + folder.remove(sci); + } + } + } + + if (folder.contents.size() == 1 /*&& !(folder instanceof LiveFolderInfo)*/) { + ShortcutInfo finalItem = folder.contents.get(0); + finalItem.container = folder.container; + LauncherModel.deleteItemFromDatabase(mContext, folder); + LauncherModel.addOrMoveItemInDatabase(mContext, finalItem, folder.container, + folder.screenId, folder.cellX, folder.cellY); + workspaceItems.remove(i); + workspaceItems.add(finalItem); + folders.remove(Long.valueOf(item.id)); + } else if (folder.contents.size() == 0 /*&& !(folder instanceof LiveFolderInfo)*/) { + LauncherModel.deleteFolderContentsFromDatabase(mContext, folder); + workspaceItems.remove(i); + folders.remove(Long.valueOf(item.id)); + } + } + } + } + + // AppWidgets + if (hideWidgets) { + int N = appWidgets.size() - 1; + for (int i = N; i >= 0; i--) { + final LauncherAppWidgetInfo item = appWidgets.get(i); + if (item.providerName != null) { + if (mHiddenAppsPackages.contains(item.providerName.getPackageName())) { + LauncherModel.deleteItemFromDatabase(mContext, item); + appWidgets.remove(i); + } + } + } + } + } + private void bindWorkspaceItems(final Callbacks oldCallbacks, final ArrayList workspaceItems, final ArrayList appWidgets, @@ -2209,6 +2305,8 @@ public class LauncherModel extends BroadcastReceiver { final boolean postOnMainThread = (deferredBindRunnables != null); + removeHiddenAppsWorkspaceItems(workspaceItems, appWidgets, folders); + // Bind the workspace items int N = workspaceItems.size(); for (int i = 0; i < N; i += ITEMS_CHUNK) { diff --git a/src/com/android/launcher3/settings/HiddenAppsActivity.java b/src/com/android/launcher3/settings/HiddenAppsActivity.java new file mode 100644 index 000000000..57ea7bc36 --- /dev/null +++ b/src/com/android/launcher3/settings/HiddenAppsActivity.java @@ -0,0 +1,302 @@ +package com.android.launcher3.settings; + +import android.app.ListActivity; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.graphics.drawable.Drawable; +import android.os.AsyncTask; +import android.os.Bundle; +import android.util.Log; +import android.util.SparseBooleanArray; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; + +import com.android.launcher3.R; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +public class HiddenAppsActivity extends ListActivity { + + private boolean mSaved; + + private static final int MENU_RESET = 0; + + private PackageManager mPackageManager; + + private AppsAdapter mAppsAdapter; + + protected void onCreate(Bundle savedInstanceState) { + requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); + super.onCreate(savedInstanceState); + + setTitle(R.string.hidden_apps_title); + setContentView(R.layout.hidden_apps_list); + + getActionBar().setDisplayHomeAsUpEnabled(true); + setProgressBarIndeterminateVisibility(true); + setProgressBarIndeterminate(true); + + mPackageManager = getPackageManager(); + mAppsAdapter = new AppsAdapter(this, R.layout.hidden_apps_list_item); + mAppsAdapter.setNotifyOnChange(true); + + setListAdapter(mAppsAdapter); + + AsyncTask> refreshAppsTask = new AsyncTask>() { + + @Override + protected void onPostExecute(List apps) { + mAppsAdapter.clear(); + mAppsAdapter.addAll(apps); + restoreCheckedItems(); + setProgressBarIndeterminateVisibility(false); + setProgressBarIndeterminate(false); + } + + @Override + protected List doInBackground(Void... params) { + return refreshApps(); + } + }; + refreshAppsTask.execute(null, null, null); + } + + @Override + public void onPause() { + super.onPause(); + save(); + } + + private void save() { + if (mSaved) { + return; + } + String string = ""; + + SparseBooleanArray checked = getListView().getCheckedItemPositions(); + + AppsAdapter listAdapter = (AppsAdapter) getListAdapter(); + for (int i = 0; i < checked.size(); i++) { + if (checked.valueAt(i)) { + AppEntry app = listAdapter.getItem(checked.keyAt(i)); + if (!string.isEmpty()) + string += "|"; + string += app.componentName.flattenToString(); + } + } + + SharedPreferences.Editor editor = SettingsProvider.get(this).edit(); + editor.putString(SettingsProvider.SETTINGS_UI_DRAWER_HIDDEN_APPS, string); + editor.putBoolean(SettingsProvider.SETTINGS_CHANGED, true); + editor.apply(); + + mSaved = true; + } + + private void restoreCheckedItems() { + List apps = new ArrayList(); + String[] flattened = SettingsProvider.getStringCustomDefault(this, + SettingsProvider.SETTINGS_UI_DRAWER_HIDDEN_APPS, "").split("\\|"); + for (String flat : flattened) { + apps.add(ComponentName.unflattenFromString(flat)); + } + + AppsAdapter listAdapter = (AppsAdapter) getListAdapter(); + + for (int i = 0; i < listAdapter.getCount(); i++) { + AppEntry info = listAdapter.getItem(i); + if (apps.contains(info.componentName)) { + getListView().setItemChecked(i, true); + } + } + + mSaved = true; + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + menu.add(0, MENU_RESET, 0, R.string.menu_hidden_apps_delete) + .setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT); + + return true; + } + + private void reset() { + for (int i = 0; i < getListView().getCount(); i++) { + getListView().setItemChecked(i, false); + } + + mSaved = false; + } + + private List refreshApps() { + Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); + mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); + List apps = mPackageManager.queryIntentActivities(mainIntent, 0); + Collections.sort(apps, new ResolveInfo.DisplayNameComparator(mPackageManager)); + List appEntries = new ArrayList(apps.size()); + for (ResolveInfo info : apps) { + appEntries.add(new AppEntry(info)); + } + return appEntries; + } + + @Override + public boolean onMenuItemSelected(int featureId, MenuItem item) { + if (item.getItemId() == android.R.id.home) { + finish(); + return true; + } else if (item.getItemId() == MENU_RESET) { + reset(); + return true; + } + return super.onMenuItemSelected(featureId, item); + } + + @Override + protected void onListItemClick(ListView l, View v, int position, long id) { + mSaved = false; + } + + private final class AppEntry { + + public final ComponentName componentName; + public final String title; + + public AppEntry(ResolveInfo info) { + componentName = new ComponentName(info.activityInfo.packageName, info.activityInfo.name); + title = info.loadLabel(mPackageManager).toString(); + } + } + + /** + * App view holder used to reuse the views inside the list. + */ + private static class AppViewHolder { + public final TextView title; + public final ImageView icon; + + public AppViewHolder(View parentView) { + icon = (ImageView) parentView.findViewById(R.id.icon); + title = (TextView) parentView.findViewById(R.id.title); + } + } + + public class AppsAdapter extends ArrayAdapter { + + private final LayoutInflater mInflator; + + private ConcurrentHashMap mIcons; + private Drawable mDefaultImg; + private List mApps; + + public AppsAdapter(Context context, int textViewResourceId) { + super(context, textViewResourceId); + + mApps = new ArrayList(); + + mInflator = LayoutInflater.from(context); + + // set the default icon till the actual app icon is loaded in async + // task + mDefaultImg = context.getResources().getDrawable(android.R.mipmap.sym_def_app_icon); + mIcons = new ConcurrentHashMap(); + } + + @Override + public View getView(final int position, View convertView, ViewGroup parent) { + AppViewHolder viewHolder; + + if (convertView == null) { + convertView = mInflator.inflate(R.layout.hidden_apps_list_item, parent, false); + viewHolder = new AppViewHolder(convertView); + convertView.setTag(viewHolder); + } else { + viewHolder = (AppViewHolder) convertView.getTag(); + } + + AppEntry app = getItem(position); + + viewHolder.title.setText(app.title); + + Drawable icon = mIcons.get(app.componentName.getPackageName()); + viewHolder.icon.setImageDrawable(icon != null ? icon : mDefaultImg); + + return convertView; + } + + @Override + public boolean hasStableIds() { + return true; + } + + @Override + public void notifyDataSetChanged() { + super.notifyDataSetChanged(); + // If we have new items, we have to load their icons + // If items were deleted, remove them from our mApps + List newApps = new ArrayList(getCount()); + List oldApps = new ArrayList(getCount()); + for (int i = 0; i < getCount(); i++) { + AppEntry app = getItem(i); + if (mApps.contains(app)) { + oldApps.add(app); + } else { + newApps.add(app); + } + } + + if (newApps.size() > 0) { + new LoadIconsTask().execute(newApps.toArray(new AppEntry[] {})); + newApps.addAll(oldApps); + mApps = newApps; + } else { + mApps = oldApps; + } + } + + /** + * An asynchronous task to load the icons of the installed applications. + */ + private class LoadIconsTask extends AsyncTask { + @Override + protected Void doInBackground(AppEntry... apps) { + for (AppEntry app : apps) { + try { + if (mIcons.containsKey(app.componentName.getPackageName())) { + continue; + } + Drawable icon = mPackageManager.getApplicationIcon(app.componentName + .getPackageName()); + mIcons.put(app.componentName.getPackageName(), icon); + publishProgress(); + } catch (PackageManager.NameNotFoundException e) { + // ignored; app will show up with default image + } + } + + return null; + } + + @Override + protected void onProgressUpdate(Void... progress) { + notifyDataSetChanged(); + } + } + } +} diff --git a/src/com/android/launcher3/settings/SettingsActivity.java b/src/com/android/launcher3/settings/SettingsActivity.java index 182a6bff8..dbbf95f52 100644 --- a/src/com/android/launcher3/settings/SettingsActivity.java +++ b/src/com/android/launcher3/settings/SettingsActivity.java @@ -153,6 +153,15 @@ public class SettingsActivity extends PreferenceActivity } } + public static class DrawerFragment extends PreferenceFragment { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + addPreferencesFromResource(R.xml.preferences_drawer); + } + } + private static class HeaderAdapter extends ArrayAdapter
{ private static final int HEADER_TYPE_NORMAL = 0; private static final int HEADER_TYPE_CATEGORY = 1; diff --git a/src/com/android/launcher3/settings/SettingsProvider.java b/src/com/android/launcher3/settings/SettingsProvider.java index 8ef3c9c7f..3a211952a 100644 --- a/src/com/android/launcher3/settings/SettingsProvider.java +++ b/src/com/android/launcher3/settings/SettingsProvider.java @@ -32,6 +32,9 @@ public final class SettingsProvider { public static final String SETTINGS_UI_HOMESCREEN_SCROLLING_FADE_ADJACENT = "ui_homescreen_scrolling_fade_adjacent"; public static final String SETTINGS_UI_DRAWER_SCROLLING_TRANSITION_EFFECT = "ui_drawer_scrolling_transition_effect"; public static final String SETTINGS_UI_DRAWER_SCROLLING_FADE_ADJACENT = "ui_drawer_scrolling_fade_adjacent"; + public static final String SETTINGS_UI_DRAWER_HIDDEN_APPS = "ui_drawer_hidden_apps"; + public static final String SETTINGS_UI_DRAWER_REMOVE_HIDDEN_APPS_SHORTCUTS = "ui_drawer_remove_hidden_apps_shortcuts"; + public static final String SETTINGS_UI_DRAWER_REMOVE_HIDDEN_APPS_WIDGETS = "ui_drawer_remove_hidden_apps_widgets"; public static final String SETTINGS_UI_GENERAL_ICONS_LARGE = "ui_general_icons_large"; public static final String SETTINGS_UI_GENERAL_ICONS_TEXT_FONT_FAMILY = "ui_general_icons_text_font"; public static final String SETTINGS_UI_GENERAL_ICONS_TEXT_FONT_STYLE = "ui_general_icons_text_font_style"; diff --git a/src/com/android/launcher3/widget/CheckableLinearLayout.java b/src/com/android/launcher3/widget/CheckableLinearLayout.java new file mode 100644 index 000000000..f834c10b8 --- /dev/null +++ b/src/com/android/launcher3/widget/CheckableLinearLayout.java @@ -0,0 +1,50 @@ +package com.android.launcher3.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.CheckBox; +import android.widget.Checkable; +import android.widget.LinearLayout; + +import com.android.launcher3.R; + +/* + * This class is useful for using inside of ListView that needs to have checkable items. + */ +public class CheckableLinearLayout extends LinearLayout implements Checkable { + private CheckBox mCheckBox; + + public CheckableLinearLayout(Context context) { + super(context); + } + + public CheckableLinearLayout(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public CheckableLinearLayout(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + + mCheckBox = (CheckBox) findViewById(R.id.checkbox); + } + + @Override + public boolean isChecked() { + return mCheckBox.isChecked(); + } + + @Override + public void setChecked(boolean checked) { + mCheckBox.setChecked(checked); + } + + @Override + public void toggle() { + mCheckBox.toggle(); + } +} \ No newline at end of file diff --git a/src/com/android/launcher3/widget/InertCheckBox.java b/src/com/android/launcher3/widget/InertCheckBox.java new file mode 100644 index 000000000..e990a8b85 --- /dev/null +++ b/src/com/android/launcher3/widget/InertCheckBox.java @@ -0,0 +1,69 @@ +package com.android.launcher3.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.widget.CheckBox; + + +// CheckBox that does not react to any user event in order to let the container handle them. +public class InertCheckBox extends CheckBox { + + @SuppressWarnings("unused") + public InertCheckBox(Context context) { + super(context); + } + + @SuppressWarnings("unused") + public InertCheckBox(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @SuppressWarnings("unused") + public InertCheckBox(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + // Make the checkbox not respond to any user event + return false; + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + // Make the checkbox not respond to any user event + return false; + } + + @Override + public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { + // Make the checkbox not respond to any user event + return false; + } + + @Override + public boolean onKeyPreIme(int keyCode, KeyEvent event) { + // Make the checkbox not respond to any user event + return false; + } + + @Override + public boolean onKeyShortcut(int keyCode, KeyEvent event) { + // Make the checkbox not respond to any user event + return false; + } + + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + // Make the checkbox not respond to any user event + return false; + } + + @Override + public boolean onTrackballEvent(MotionEvent event) { + // Make the checkbox not respond to any user event + return false; + } +} \ No newline at end of file -- cgit v1.2.3