summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AndroidManifest.xml12
-rw-r--r--res/layout/hidden_apps_list.xml7
-rw-r--r--res/layout/hidden_apps_list_item.xml33
-rw-r--r--res/layout/tab_widget_indicator.xml19
-rw-r--r--res/values/cm_strings.xml14
-rw-r--r--res/values/preferences_defaults.xml2
-rw-r--r--res/xml/preferences_drawer.xml36
-rw-r--r--res/xml/preferences_headers.xml20
-rw-r--r--src/com/android/launcher3/AppsCustomizePagedView.java150
-rw-r--r--src/com/android/launcher3/FastBitmapDrawable.java2
-rw-r--r--src/com/android/launcher3/LauncherModel.java100
-rw-r--r--src/com/android/launcher3/settings/HiddenAppsActivity.java302
-rw-r--r--src/com/android/launcher3/settings/SettingsActivity.java9
-rw-r--r--src/com/android/launcher3/settings/SettingsProvider.java3
-rw-r--r--src/com/android/launcher3/widget/CheckableLinearLayout.java50
-rw-r--r--src/com/android/launcher3/widget/InertCheckBox.java69
16 files changed, 783 insertions, 45 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index f33bb0b30..f8ef64f31 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -85,7 +85,7 @@
</intent-filter>
</activity>
- <activity android:name="com.android.launcher3.settings.SettingsActivity"
+ <activity android:name=".settings.SettingsActivity"
android:label="@string/preferences_title">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -95,6 +95,16 @@
</activity>
<activity
+ android:name=".settings.HiddenAppsActivity"
+ android:label="@string/hidden_apps_title"
+ android:exported="false">
+ <intent-filter>
+ <action android:name=".settings.HiddenAppsActivity" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
+ <activity
android:name="com.android.launcher3.ToggleWeightWatcher"
android:label="@string/toggle_weight_watcher"
android:enabled="@bool/debug_memory_enabled"
diff --git a/res/layout/hidden_apps_list.xml b/res/layout/hidden_apps_list.xml
new file mode 100644
index 000000000..fb0d4bffb
--- /dev/null
+++ b/res/layout/hidden_apps_list.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ListView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/list"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="5dp"
+ android:choiceMode="multipleChoice" /> \ 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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<com.android.launcher3.widget.CheckableLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="48dp"
+ android:gravity="center_vertical"
+ android:paddingRight="?android:attr/scrollbarSize"
+ android:background="?android:attr/selectableItemBackground"
+ android:descendantFocusability="blocksDescendants">
+
+ <ImageView android:id="@+id/icon"
+ android:layout_width="40dp"
+ android:layout_height="40dp"
+ android:layout_gravity="center" />
+
+ <TextView android:id="@+id/title"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="15dip"
+ android:layout_marginRight="6dip"
+ android:layout_marginTop="6dip"
+ android:layout_marginBottom="6dip"
+ android:layout_weight="1"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal" />
+
+ <com.android.launcher3.widget.InertCheckBox android:id="@+id/checkbox"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+</com.android.launcher3.widget.CheckableLinearLayout> \ 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 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<com.android.launcher3.AccessibleTabView
- xmlns:android="http://schemas.android.com/apk/res/android"
- style="@style/TabIndicator.AppsCustomize" />
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 -->
<string name="preferences_interface_drawer_title">Drawer</string>
+ <string name="preferences_interface_drawer_summary">Apps and widgets drawer</string>
+ <string name="preferences_interface_drawer_apps_category">Apps</string>
+ <string name="preferences_interface_drawer_hidden_apps_title">Hidden apps</string>
+ <string name="preferences_interface_drawer_hidden_apps_summary">Hide apps from the drawer</string>
+ <string name="preferences_interface_drawer_hidden_apps_shortcuts_title">Remove shortcuts</string>
+ <string name="preferences_interface_drawer_hidden_apps_shortcuts_summary">Remove the shortcuts of hidden apps from the homescreen</string>
+ <string name="preferences_interface_drawer_hidden_apps_widgets_title">Remove widgets</string>
+ <string name="preferences_interface_drawer_hidden_apps_widgets_summary">Remove the widgets of hidden apps from the homescreen</string>
<!-- Dock -->
<string name="preferences_interface_dock_title">Dock</string>
@@ -78,4 +86,10 @@
<string name="all_apps_cling_cm">Customize your drawer</string>
<!-- The description of how to access Trebuchet settings [CHAR_LIMIT=160] -->
<string name="all_apps_cling_summary">Tap the page indicator to view additional configuration settings</string>
+
+ <!-- Noun, menu item used to reset hidden apps list -->
+ <string name="menu_hidden_apps_delete">Reset</string>
+
+ <!-- Hidden apps -->
+ <string name="hidden_apps_title">Hidden apps</string>
</resources>
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 name="preferences_interface_homescreen_scrolling_fade_adjacent_default">@bool/config_workspaceFadeAdjacentScreens</bool>
<string name="preferences_interface_drawer_scrolling_transition_effect">stack</string>
<bool name="preferences_interface_drawer_scrolling_fade_adjacent_default">false</bool>
+ <bool name="preferences_interface_drawer_remove_hidden_apps_shortcuts_default">true</bool>
+ <bool name="preferences_interface_drawer_remove_hidden_apps_widgets_default">true</bool>
<bool name="preferences_interface_general_icons_large_default">@bool/config_largeIcons</bool>
<string name="preferences_interface_general_icons_text_font_family_default">sans-serif-condensed</string>
<integer name="preferences_interface_general_icons_text_font_style_default">0</integer>
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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher3"
+ android:key="ui_drawer"
+ android:title="@string/preferences_interface_drawer_title">
+ <PreferenceCategory android:title="@string/preferences_interface_drawer_apps_category">
+ <Preference android:key="ui_drawer_hidden_apps"
+ android:title="@string/preferences_interface_drawer_hidden_apps_title"
+ android:summary="@string/preferences_interface_drawer_hidden_apps_summary">
+ <intent android:action=".settings.HiddenAppsActivity"/>
+ </Preference>
+ <CheckBoxPreference android:key="ui_drawer_remove_hidden_apps_shortcuts"
+ android:title="@string/preferences_interface_drawer_hidden_apps_shortcuts_title"
+ android:summary="@string/preferences_interface_drawer_hidden_apps_shortcuts_summary"
+ android:defaultValue="@bool/preferences_interface_drawer_remove_hidden_apps_shortcuts_default" />
+ <CheckBoxPreference android:key="ui_drawer_remove_hidden_apps_widgets"
+ android:title="@string/preferences_interface_drawer_hidden_apps_widgets_title"
+ android:summary="@string/preferences_interface_drawer_hidden_apps_widgets_summary"
+ android:defaultValue="@bool/preferences_interface_drawer_remove_hidden_apps_widgets_default" />
+ </PreferenceCategory>
+</PreferenceScreen> \ 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" />
- <!--<header android:id="@+id/preferences_drawer_section"
- android:title="@string/preferences_interface_drawer_title" />
-
- <header android:id="@+id/preferences_dock_section"
+ <header android:id="@+id/preferences_drawer_section"
+ android:fragment="com.android.launcher3.settings.SettingsActivity$DrawerFragment"
+ android:title="@string/preferences_interface_drawer_title"
+ android:summary="@string/preferences_interface_drawer_summary" />
+
+ <!--<header android:id="@+id/preferences_dock_section"
android:title="@string/preferences_interface_dock_title" />-->
-
+
<header android:id="@+id/preferences_general_section"
android:fragment="com.android.launcher3.settings.SettingsActivity$GeneralFragment"
android:title="@string/preferences_interface_general_title" />
-
+
<header android:id="@+id/preferences_application_section"
- android:title="@string/preferences_application_title" />
-
+ android:title="@string/preferences_application_title" />
+
<header android:id="@+id/preferences_application_version"
- android:summary="@string/application_copyright" />
+ android:summary="@string/application_copyright" />
</preference-headers>
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<AppInfo> mApps;
private ArrayList<Object> mWidgets;
+ private ArrayList<AppInfo> mFilteredApps;
+ private ArrayList<Object> mFilteredWidgets;
+ private ArrayList<ComponentName> mHiddenApps;
+ private ArrayList<String> 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<AppInfo>();
+ mFilteredApps = new ArrayList<AppInfo>();
mWidgets = new ArrayList<Object>();
+ mFilteredWidgets = new ArrayList<Object>();
mIconCache = (LauncherAppState.getInstance()).getIconCache();
mCanvas = new Canvas();
mRunningTasks = new ArrayList<AppsCustomizeAsyncTask>();
@@ -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<ComponentName>(flattened.length);
+ mHiddenPackages = new ArrayList<String>(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<Object> items = new ArrayList<Object>();
ArrayList<Bitmap> images = new ArrayList<Bitmap>();
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<AppInfo> list) {
if (!DISABLE_ALL_APPS) {
mApps = list;
- Collections.sort(mApps, getComparatorForSortMode());
+ filterAppsWithoutInvalidate();
updatePageCountsAndInvalidateData();
}
}
+
private void addAppsWithoutInvalidate(ArrayList<AppInfo> 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<AppInfo> list) {
if (!DISABLE_ALL_APPS) {
addAppsWithoutInvalidate(list);
+ filterAppsWithoutInvalidate();
updatePageCountsAndInvalidateData();
}
}
+
private int findAppByComponent(List<AppInfo> 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<AppInfo> 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<AppInfo> appInfos) {
if (!DISABLE_ALL_APPS) {
removeAppsWithoutInvalidate(appInfos);
+ filterAppsWithoutInvalidate();
updatePageCountsAndInvalidateData();
}
}
+
public void updateApps(ArrayList<AppInfo> 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<AppInfo>(mApps);
+ Iterator<AppInfo> 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<Object>(mWidgets);
+
+ Iterator<Object> 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<ItemInfo> workspaceItems,
+ final ArrayList<LauncherAppWidgetInfo> appWidgets,
+ final HashMap<Long, FolderInfo> folders) {
+
+ // Get hidden apps
+ ArrayList<ComponentName> mHiddenApps = new ArrayList<ComponentName>();
+ ArrayList<String> mHiddenAppsPackages = new ArrayList<String>();
+ 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<ShortcutInfo> 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<ItemInfo> workspaceItems,
final ArrayList<LauncherAppWidgetInfo> 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<Void, Void, List<AppEntry>> refreshAppsTask = new AsyncTask<Void, Void, List<AppEntry>>() {
+
+ @Override
+ protected void onPostExecute(List<AppEntry> apps) {
+ mAppsAdapter.clear();
+ mAppsAdapter.addAll(apps);
+ restoreCheckedItems();
+ setProgressBarIndeterminateVisibility(false);
+ setProgressBarIndeterminate(false);
+ }
+
+ @Override
+ protected List<AppEntry> 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<ComponentName> apps = new ArrayList<ComponentName>();
+ 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<AppEntry> refreshApps() {
+ Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
+ mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+ List<ResolveInfo> apps = mPackageManager.queryIntentActivities(mainIntent, 0);
+ Collections.sort(apps, new ResolveInfo.DisplayNameComparator(mPackageManager));
+ List<AppEntry> appEntries = new ArrayList<AppEntry>(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<AppEntry> {
+
+ private final LayoutInflater mInflator;
+
+ private ConcurrentHashMap<String, Drawable> mIcons;
+ private Drawable mDefaultImg;
+ private List<AppEntry> mApps;
+
+ public AppsAdapter(Context context, int textViewResourceId) {
+ super(context, textViewResourceId);
+
+ mApps = new ArrayList<AppEntry>();
+
+ 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<String, Drawable>();
+ }
+
+ @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<AppEntry> newApps = new ArrayList<AppEntry>(getCount());
+ List<AppEntry> oldApps = new ArrayList<AppEntry>(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<AppEntry, Void, Void> {
+ @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<Header> {
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