summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaj Yengisetty <rajesh@cyngn.com>2014-11-10 10:35:00 -0800
committerAdnan <adnan@cyngn.com>2014-11-19 15:53:56 -0800
commit4e4db4563a7ddf262993a9312781c66d34485ea4 (patch)
treeafdcf8ce885b656e42e062faca390fba0fb9c484
parentc2e0e2b87255a1fb002eadf7735e99614b7de656 (diff)
downloadandroid_packages_apps_Trebuchet-4e4db4563a7ddf262993a9312781c66d34485ea4.tar.gz
android_packages_apps_Trebuchet-4e4db4563a7ddf262993a9312781c66d34485ea4.tar.bz2
android_packages_apps_Trebuchet-4e4db4563a7ddf262993a9312781c66d34485ea4.zip
Protected App [3/3] Trebuchet - Protected Apps - Build fixed to work with LOCAL_SDK_VERSION - Fixed adding components to protected folders and adding protected folders to other folders - Fixed issues with EditText for FolderName - Adding support for Settings hooks - Uses Setting's LockPattern for Protected Apps - Add Read from Settings Secure DB (DO NOT WRITE!) - Protecting a folder updates Launcher without restart - Batch send component visibility
Conflicts: AndroidManifest.xml res/values/preferences_defaults.xml src/com/android/launcher3/AppsCustomizePagedView.java src/com/android/launcher3/Folder.java src/com/android/launcher3/FolderIcon.java src/com/android/launcher3/Launcher.java src/com/android/launcher3/LauncherModel.java src/com/android/launcher3/LauncherProvider.java src/com/android/launcher3/OverviewSettingsPanel.java Change-Id: I41c295e7f2c9abc9b2e77e6e3d39b7ca60d47139
-rw-r--r--AndroidManifest.xml1
-rw-r--r--res/drawable-hdpi/folder_lock.pngbin0 -> 459 bytes
-rw-r--r--res/drawable-hdpi/folder_lock_light.pngbin0 -> 461 bytes
-rw-r--r--res/drawable-hdpi/folder_unlock.pngbin0 -> 480 bytes
-rw-r--r--res/drawable-mdpi/folder_lock.pngbin0 -> 376 bytes
-rw-r--r--res/drawable-mdpi/folder_lock_light.pngbin0 -> 372 bytes
-rw-r--r--res/drawable-mdpi/folder_unlock.pngbin0 -> 383 bytes
-rw-r--r--res/drawable-xhdpi/folder_lock.pngbin0 -> 601 bytes
-rw-r--r--res/drawable-xhdpi/folder_lock_light.pngbin0 -> 601 bytes
-rw-r--r--res/drawable-xhdpi/folder_unlock.pngbin0 -> 613 bytes
-rw-r--r--res/drawable-xxhdpi/folder_lock.pngbin0 -> 750 bytes
-rw-r--r--res/drawable-xxhdpi/folder_lock_light.pngbin0 -> 746 bytes
-rw-r--r--res/drawable-xxhdpi/folder_unlock.pngbin0 -> 775 bytes
-rw-r--r--res/drawable/lock.pngbin19461 -> 0 bytes
-rw-r--r--res/layout/hidden_folder.xml51
-rw-r--r--res/layout/hidden_folder_apps_list_item.xml28
-rw-r--r--res/layout/user_folder.xml50
-rw-r--r--res/values/cm_strings.xml8
-rw-r--r--res/values/dimens.xml1
-rw-r--r--res/values/preferences_defaults.xml2
-rw-r--r--src/com/android/launcher3/AppsCustomizePagedView.java96
-rw-r--r--src/com/android/launcher3/Folder.java112
-rw-r--r--src/com/android/launcher3/FolderIcon.java28
-rw-r--r--src/com/android/launcher3/FolderInfo.java4
-rw-r--r--src/com/android/launcher3/HiddenFolderFragment.java325
-rw-r--r--src/com/android/launcher3/Launcher.java81
-rw-r--r--src/com/android/launcher3/LauncherModel.java107
-rw-r--r--src/com/android/launcher3/LauncherProvider.java8
-rw-r--r--src/com/android/launcher3/LauncherSettings.java5
-rw-r--r--src/com/android/launcher3/Lists.java64
-rw-r--r--src/com/android/launcher3/OverviewSettingsPanel.java8
-rw-r--r--src/com/android/launcher3/list/SettingsPinnedHeaderAdapter.java7
32 files changed, 956 insertions, 30 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 591d9b612..34780db53 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -69,6 +69,7 @@
<uses-permission android:name="com.android.launcher3.permission.WRITE_SETTINGS" />
<uses-permission android:name="com.android.launcher3.permission.RECEIVE_LAUNCH_BROADCASTS" />
<uses-permission android:name="com.android.launcher3.permission.RECEIVE_FIRST_LOAD_BROADCAST" />
+ <uses-permission android:name="cyanogenmod.permission.PROTECTED_APP" />
<application
android:name="com.android.launcher3.LauncherApplication"
diff --git a/res/drawable-hdpi/folder_lock.png b/res/drawable-hdpi/folder_lock.png
new file mode 100644
index 000000000..9d5ac426d
--- /dev/null
+++ b/res/drawable-hdpi/folder_lock.png
Binary files differ
diff --git a/res/drawable-hdpi/folder_lock_light.png b/res/drawable-hdpi/folder_lock_light.png
new file mode 100644
index 000000000..ca849e8d7
--- /dev/null
+++ b/res/drawable-hdpi/folder_lock_light.png
Binary files differ
diff --git a/res/drawable-hdpi/folder_unlock.png b/res/drawable-hdpi/folder_unlock.png
new file mode 100644
index 000000000..58524209c
--- /dev/null
+++ b/res/drawable-hdpi/folder_unlock.png
Binary files differ
diff --git a/res/drawable-mdpi/folder_lock.png b/res/drawable-mdpi/folder_lock.png
new file mode 100644
index 000000000..c44921a29
--- /dev/null
+++ b/res/drawable-mdpi/folder_lock.png
Binary files differ
diff --git a/res/drawable-mdpi/folder_lock_light.png b/res/drawable-mdpi/folder_lock_light.png
new file mode 100644
index 000000000..293444ec8
--- /dev/null
+++ b/res/drawable-mdpi/folder_lock_light.png
Binary files differ
diff --git a/res/drawable-mdpi/folder_unlock.png b/res/drawable-mdpi/folder_unlock.png
new file mode 100644
index 000000000..93e60fc45
--- /dev/null
+++ b/res/drawable-mdpi/folder_unlock.png
Binary files differ
diff --git a/res/drawable-xhdpi/folder_lock.png b/res/drawable-xhdpi/folder_lock.png
new file mode 100644
index 000000000..5d8610b2f
--- /dev/null
+++ b/res/drawable-xhdpi/folder_lock.png
Binary files differ
diff --git a/res/drawable-xhdpi/folder_lock_light.png b/res/drawable-xhdpi/folder_lock_light.png
new file mode 100644
index 000000000..4342c50f6
--- /dev/null
+++ b/res/drawable-xhdpi/folder_lock_light.png
Binary files differ
diff --git a/res/drawable-xhdpi/folder_unlock.png b/res/drawable-xhdpi/folder_unlock.png
new file mode 100644
index 000000000..a5b99c376
--- /dev/null
+++ b/res/drawable-xhdpi/folder_unlock.png
Binary files differ
diff --git a/res/drawable-xxhdpi/folder_lock.png b/res/drawable-xxhdpi/folder_lock.png
new file mode 100644
index 000000000..16726d395
--- /dev/null
+++ b/res/drawable-xxhdpi/folder_lock.png
Binary files differ
diff --git a/res/drawable-xxhdpi/folder_lock_light.png b/res/drawable-xxhdpi/folder_lock_light.png
new file mode 100644
index 000000000..4226f6af8
--- /dev/null
+++ b/res/drawable-xxhdpi/folder_lock_light.png
Binary files differ
diff --git a/res/drawable-xxhdpi/folder_unlock.png b/res/drawable-xxhdpi/folder_unlock.png
new file mode 100644
index 000000000..95c18cbc2
--- /dev/null
+++ b/res/drawable-xxhdpi/folder_unlock.png
Binary files differ
diff --git a/res/drawable/lock.png b/res/drawable/lock.png
deleted file mode 100644
index 132ad858a..000000000
--- a/res/drawable/lock.png
+++ /dev/null
Binary files differ
diff --git a/res/layout/hidden_folder.xml b/res/layout/hidden_folder.xml
new file mode 100644
index 000000000..ca06f6e48
--- /dev/null
+++ b/res/layout/hidden_folder.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/settings_bg_color"
+ android:orientation="vertical"
+ android:paddingLeft="@dimen/overview_panel_button_spacing"
+ android:paddingRight="@dimen/overview_panel_button_spacing"
+ android:paddingTop="@dimen/overview_panel_bottom_padding"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:clickable="true" >
+
+ <RelativeLayout
+ android:id="@+id/folder_title_lock"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <ImageView
+ android:id="@+id/folder_lock_icon"
+ android:layout_width="25dp"
+ android:layout_height="25dp"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true"
+ android:src="@drawable/folder_unlock"
+ android:background="@drawable/listitem_bg" />
+
+ <EditText
+ android:id="@+id/folder_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:paddingBottom="@dimen/folder_name_padding"
+ android:paddingTop="@dimen/folder_name_padding"
+ android:hint="@string/folder_hint_text"
+ android:textColor="@android:color/white"
+ android:textSize="20sp"
+ android:textColorHighlight="#ffCCCCCC"
+ android:textCursorDrawable="@null"
+ android:singleLine="true"
+ android:background="#00000000" />
+ </RelativeLayout>
+
+ <ListView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/hidden_apps_list"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="5dp" />
+
+</LinearLayout>
diff --git a/res/layout/hidden_folder_apps_list_item.xml b/res/layout/hidden_folder_apps_list_item.xml
new file mode 100644
index 000000000..13441941e
--- /dev/null
+++ b/res/layout/hidden_folder_apps_list_item.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout 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" />
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/user_folder.xml b/res/layout/user_folder.xml
index 4e5303ac0..3b1e5be7c 100644
--- a/res/layout/user_folder.xml
+++ b/res/layout/user_folder.xml
@@ -34,21 +34,41 @@
android:hapticFeedbackEnabled="false" />
</ScrollView>
- <com.android.launcher3.FolderEditText
- android:id="@+id/folder_name"
+ <RelativeLayout
+ android:id="@+id/folder_title_section"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_centerHorizontal="true"
- android:paddingTop="@dimen/folder_name_padding"
- android:paddingBottom="@dimen/folder_name_padding"
- android:background="#00000000"
- android:hint="@string/folder_hint_text"
- android:textSize="14sp"
- android:textColor="#ff777777"
- android:textColorHighlight="#ffCCCCCC"
- android:textCursorDrawable="@null"
- android:gravity="center_horizontal"
- android:singleLine="true"
- android:imeOptions="flagNoExtractUi"
- android:fontFamily="sans-serif-condensed"/>
+ android:orientation="horizontal" >
+
+ <ImageView
+ android:id="@+id/folder_lock"
+ android:layout_width="@dimen/folder_lock_icon"
+ android:layout_height="@dimen/folder_lock_icon"
+ android:paddingBottom="@dimen/folder_name_padding"
+ android:paddingTop="@dimen/folder_name_padding"
+ android:adjustViewBounds="true"
+ android:layout_alignParentRight="true"
+ android:src="@drawable/folder_unlock" />
+
+ <com.android.launcher3.FolderEditText
+ android:id="@+id/folder_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:background="#00000000"
+ android:fontFamily="sans-serif-condensed"
+ android:gravity="center_horizontal"
+ android:hint="@string/folder_hint_text"
+ android:imeOptions="flagNoExtractUi"
+ android:paddingBottom="@dimen/folder_name_padding"
+ android:paddingTop="@dimen/folder_name_padding"
+ android:singleLine="true"
+ android:textColor="#ff777777"
+ android:textColorHighlight="#ffCCCCCC"
+ android:textCursorDrawable="@null"
+ android:layout_alignParentLeft="true"
+ android:layout_toLeftOf="@id/folder_lock"
+ android:textSize="16sp" />
+ </RelativeLayout>
+
</com.android.launcher3.Folder>
diff --git a/res/values/cm_strings.xml b/res/values/cm_strings.xml
index 2fe669727..23077db1e 100644
--- a/res/values/cm_strings.xml
+++ b/res/values/cm_strings.xml
@@ -99,8 +99,6 @@
<!-- Hidden apps -->
<string name="hidden_apps_title">Hidden apps</string>
-
- <!-- Settings -->
<string name="launcher_settings">LAUNCHER SETTINGS</string>
<string name="home_screen_settings">HOME SCREEN SETTINGS</string>
<string name="drawer_settings">DRAWER SETTINGS</string>
@@ -114,8 +112,14 @@
<string name="larger_icons_text">Larger icons</string>
<!-- Text for hiding icon labels -->
<string name="hide_icon_labels">Hide icon labels</string>
+ <!-- Protected Apps -->
+ <string name="protected_app_settings">Protected apps</string>
<!-- Settings states -->
<string name="setting_state_on">ON</string>
<string name="setting_state_off">OFF</string>
<string name="themes_button_text">Themes</string>
+
+ <!-- Hidden states -->
+ <string name="hidden_folder">locked</string>
+ <string name="unhidden_folder">unlocked</string>
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index ce24d60b8..29a6c39e2 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -99,6 +99,7 @@
<!-- The amount that the preview contents are inset from the preview background -->
<dimen name="folder_preview_padding">4dp</dimen>
<dimen name="folder_name_padding">10dp</dimen>
+ <dimen name="folder_lock_icon">50dp</dimen>
<!-- Sizes for managed profile badges -->
<dimen name="profile_badge_size">24dp</dimen>
diff --git a/res/values/preferences_defaults.xml b/res/values/preferences_defaults.xml
index 6d6d1b29e..d60c0611e 100644
--- a/res/values/preferences_defaults.xml
+++ b/res/values/preferences_defaults.xml
@@ -8,6 +8,8 @@
<bool name="preferences_interface_homescreen_hide_icon_labels_default">false</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_drawer_hide_icon_labels_default">false</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>
diff --git a/src/com/android/launcher3/AppsCustomizePagedView.java b/src/com/android/launcher3/AppsCustomizePagedView.java
index eac84dde5..abccbb0da 100644
--- a/src/com/android/launcher3/AppsCustomizePagedView.java
+++ b/src/com/android/launcher3/AppsCustomizePagedView.java
@@ -35,6 +35,8 @@ import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Process;
+import android.provider.Settings;
+import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
@@ -202,6 +204,16 @@ 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> mProtectedApps;
+ private ArrayList<String> mProtectedPackages;
+
+ // Cling
+ private boolean mHasShownAllAppsCling;
+ private int mClingFocusedX;
+ private int mClingFocusedY;
+
// Caching
private IconCache mIconCache;
@@ -292,6 +304,8 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
}
setSinglePageInViewport();
+
+ updateProtectedAppsList(context);
}
@Override
@@ -1567,6 +1581,88 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
}
}
+ private void updateProtectedAppsList(Context context) {
+ String protectedComponents = Settings.Secure.getString(context.getContentResolver(),
+ LauncherModel.SETTINGS_PROTECTED_COMPONENTS);
+ protectedComponents = protectedComponents == null ? "" : protectedComponents;
+ String [] flattened = protectedComponents.split("\\|");
+ mProtectedApps = new ArrayList<ComponentName>(flattened.length);
+ mProtectedPackages = new ArrayList<String>(flattened.length);
+ for (String flat : flattened) {
+ ComponentName cmp = ComponentName.unflattenFromString(flat);
+ if (cmp != null) {
+ mProtectedApps.add(cmp);
+ mProtectedPackages.add(cmp.getPackageName());
+ }
+ }
+ }
+
+ public void filterAppsWithoutInvalidate() {
+ updateProtectedAppsList(mLauncher);
+
+ 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 (mProtectedApps.contains(appInfo.componentName) ||
+ (system && !getShowSystemApps()) ||
+ (!system && !getShowDownloadedApps())) {
+ iterator.remove();
+ }
+ }
+ Collections.sort(mFilteredApps, getComparatorForSortMode());
+ }
+
+ public void filterApps() {
+ filterAppsWithoutInvalidate();
+ updatePageCountsAndInvalidateData();
+ }
+
+ public void filterWidgetsWithoutInvalidate() {
+ updateProtectedAppsList(mLauncher);
+
+ 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 (mProtectedPackages.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/Folder.java b/src/com/android/launcher3/Folder.java
index 1890af47d..fa34e6327 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -21,10 +21,13 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.content.res.Resources;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.os.Bundle;
import android.os.SystemClock;
import android.support.v4.widget.AutoScrollHelper;
import android.text.InputType;
@@ -44,7 +47,9 @@ import android.view.accessibility.AccessibilityManager;
import android.view.animation.AccelerateInterpolator;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
+import android.widget.ImageView;
import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.TextView;
@@ -62,6 +67,12 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
View.OnFocusChangeListener {
private static final String TAG = "Launcher.Folder";
+ private static final String PROTECTED_ACTION = "cyanogenmod.intent.action.PACKAGE_PROTECTED";
+ private static final String PROTECTED_STATE =
+ "cyanogenmod.intent.action.PACKAGE_PROTECTED_STATE";
+ private static final String PROTECTED_COMPONENT =
+ "cyanogenmod.intent.action.PACKAGE_PROTECTED_COMPONENT";
+
protected DragController mDragController;
protected Launcher mLauncher;
protected FolderInfo mInfo;
@@ -107,6 +118,8 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
private boolean mSuppressFolderDeletion = false;
private boolean mItemAddedBackToSelfViaIcon = false;
FolderEditText mFolderName;
+ ImageView mFolderLock;
+ RelativeLayout mFolderTitleSection;
private float mFolderIconPivotX;
private float mFolderIconPivotY;
@@ -131,6 +144,8 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
private boolean mDeferDropAfterUninstall;
private boolean mUninstallSuccessful;
+ private boolean mHiddenFolder = false;
+
/**
* Used to inflate the Workspace from XML.
*
@@ -181,6 +196,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
super.onFinishInflate();
mScrollView = (ScrollView) findViewById(R.id.scroll_view);
mContent = (CellLayout) findViewById(R.id.folder_content);
+ int measureSpec = MeasureSpec.UNSPECIFIED;
mFocusIndicatorHandler = new FocusIndicatorView(getContext());
mContent.addView(mFocusIndicatorHandler, 0);
@@ -200,7 +216,6 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
// We find out how tall the text view wants to be (it is set to wrap_content), so that
// we can allocate the appropriate amount of space for it.
- int measureSpec = MeasureSpec.UNSPECIFIED;
mFolderName.measure(measureSpec, measureSpec);
mFolderNameHeight = mFolderName.getMeasuredHeight();
@@ -211,6 +226,19 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
mFolderName.setInputType(mFolderName.getInputType() |
InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS | InputType.TYPE_TEXT_FLAG_CAP_WORDS);
mAutoScrollHelper = new FolderAutoScrollHelper(mScrollView);
+
+ if (SettingsProvider.getBoolean(mLauncher,
+ SettingsProvider.SETTINGS_UI_HOMESCREEN_HIDE_ICON_LABELS,
+ R.bool.preferences_interface_homescreen_hide_icon_labels_default)) {
+ mFolderName.setVisibility(View.GONE);
+ mFolderNameHeight = getPaddingBottom();
+ }
+
+ mFolderLock = (ImageView) findViewById(R.id.folder_lock);
+ mFolderTitleSection = (RelativeLayout) findViewById(R.id.folder_title_section);
+ mFolderLock.measure(measureSpec, measureSpec);
+ mFolderLock.setOnClickListener(this);
+ mFolderTitleSection.measure(measureSpec, measureSpec);
}
private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
@@ -235,6 +263,60 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
if (tag instanceof ShortcutInfo) {
mLauncher.onClick(v);
}
+
+ if (v.getId() == R.id.folder_lock) {
+ startHiddenFolderManager();
+ }
+ }
+
+ public void startHiddenFolderManager() {
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(HiddenFolderFragment.HIDDEN_FOLDER_STATUS, mInfo.hidden);
+ mLauncher.validateLockForHiddenFolders(bundle, mFolderIcon);
+ }
+
+ public String[] getComponentTitles() {
+ int size = mItemsInReadingOrder.size();
+ String[] componentsTitles = new String[size];
+ for (int i = 0; i < size; i++) {
+ View v = mItemsInReadingOrder.get(i);
+ Object tag = v.getTag();
+ if (tag instanceof ShortcutInfo) {
+ componentsTitles[i] = ((ShortcutInfo) tag).title.toString();
+ }
+ }
+ return componentsTitles;
+ }
+
+ public String[] getComponents() {
+ String components = getComponentString();
+ return components.split("\\|");
+ }
+
+ public void modifyProtectedApps(boolean protect) {
+ String components = getComponentString();
+
+ Intent intent = new Intent();
+ intent.setAction(PROTECTED_ACTION);
+ intent.putExtra(PROTECTED_STATE, protect);
+ intent.putExtra(PROTECTED_COMPONENT, components);
+
+ mLauncher.sendBroadcast(intent);
+ }
+
+ private String getComponentString() {
+ int size = mItemsInReadingOrder.size();
+ String components = "";
+ for (int i = 0; i < size; i++) {
+ View v = mItemsInReadingOrder.get(i);
+ Object tag = v.getTag();
+ if (tag instanceof ShortcutInfo) {
+ ComponentName componentName = ((ShortcutInfo) tag).getIntent().getComponent();
+ components += componentName.flattenToString() + "|";
+ }
+ }
+
+ return components;
}
public boolean onLongClick(View v) {
@@ -270,6 +352,8 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
public void startEditingFolderName() {
mFolderName.setHint("");
mIsEditingName = true;
+
+ mInputMethodManager.showSoftInput(mFolderName, 0);
}
public void dismissEditingName() {
@@ -409,6 +493,11 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
updateTextViewFocus();
mInfo.addListener(this);
+ setFolderName();
+ updateItemLocationsInDatabase();
+ }
+
+ public void setFolderName() {
if (!sDefaultFolderName.contentEquals(mInfo.title)) {
mFolderName.setText(mInfo.title);
} else {
@@ -1085,13 +1174,16 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
}
private int getFolderHeight() {
- int height = getPaddingTop() + getPaddingBottom()
- + getContentAreaHeight() + mFolderNameHeight;
+ int height = getPaddingTop() + getPaddingBottom() + mFolderNameHeight
+ + getContentAreaHeight();
return height;
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int width = getPaddingLeft() + getPaddingRight() + mContent.getDesiredWidth();
+ int width = getPaddingLeft()
+ + getPaddingRight()
+ + Math.max(mContent.getDesiredWidth(),
+ mFolderTitleSection.getMeasuredWidth());
int height = getFolderHeight();
int contentAreaWidthSpec = MeasureSpec.makeMeasureSpec(getContentAreaWidth(),
MeasureSpec.EXACTLY);
@@ -1106,8 +1198,12 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
}
mScrollView.measure(contentAreaWidthSpec, contentAreaHeightSpec);
- mFolderName.measure(contentAreaWidthSpec,
- MeasureSpec.makeMeasureSpec(mFolderNameHeight, MeasureSpec.EXACTLY));
+ mFolderName.measure(contentAreaWidthSpec, MeasureSpec.makeMeasureSpec(
+ mFolderNameHeight, MeasureSpec.EXACTLY));
+ mFolderLock.measure(contentAreaWidthSpec, MeasureSpec.makeMeasureSpec(
+ mFolderNameHeight, MeasureSpec.EXACTLY));
+ mFolderTitleSection.measure(contentAreaWidthSpec, MeasureSpec
+ .makeMeasureSpec(mFolderNameHeight, MeasureSpec.EXACTLY));
setMeasuredDimension(width, height);
}
@@ -1392,4 +1488,8 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
public void getHitRectRelativeToDragLayer(Rect outRect) {
getHitRect(outRect);
}
+
+ public View getViewFromPosition(int position) {
+ return mItemsInReadingOrder.get(position);
+ }
}
diff --git a/src/com/android/launcher3/FolderIcon.java b/src/com/android/launcher3/FolderIcon.java
index a359f1180..ef31bcf99 100644
--- a/src/com/android/launcher3/FolderIcon.java
+++ b/src/com/android/launcher3/FolderIcon.java
@@ -322,13 +322,23 @@ public class FolderIcon extends FrameLayout implements FolderListener {
private boolean willAcceptItem(ItemInfo item) {
final int itemType = item.itemType;
+
+ boolean hidden = false;
+ if (item instanceof FolderInfo){
+ hidden = ((FolderInfo) item).hidden;
+ }
return ((itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
- itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) &&
- !mFolder.isFull() && item != mInfo && !mInfo.opened);
+ itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT ||
+ itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) &&
+ !mFolder.isFull() && item != mInfo && !mInfo.opened &&
+ !hidden);
}
public boolean acceptDrop(Object dragInfo) {
final ItemInfo item = (ItemInfo) dragInfo;
+ if (mInfo.hidden) {
+ return false;
+ }
return !mFolder.isDestroyed() && willAcceptItem(item);
}
@@ -619,6 +629,20 @@ public class FolderIcon extends FrameLayout implements FolderListener {
}
int nItemsInPreview = Math.min(items.size(), NUM_ITEMS_IN_PREVIEW);
+
+ // Hidden folder - don't display Preview
+ if (mInfo.hidden) {
+ mParams = computePreviewItemDrawingParams(NUM_ITEMS_IN_PREVIEW/2, mParams);
+ canvas.save();
+ canvas.translate(mParams.transX + mPreviewOffsetX, mParams.transY + mPreviewOffsetY);
+ canvas.scale(mParams.scale, mParams.scale);
+ Drawable lock = getResources().getDrawable(R.drawable.folder_lock);
+ lock.setBounds(0, 0, mIntrinsicIconSize, mIntrinsicIconSize);
+ lock.draw(canvas);
+ canvas.restore();
+ return;
+ }
+
if (!mAnimating) {
for (int i = nItemsInPreview - 1; i >= 0; i--) {
v = (TextView) items.get(i);
diff --git a/src/com/android/launcher3/FolderInfo.java b/src/com/android/launcher3/FolderInfo.java
index 85a792f4b..104bd6cc1 100644
--- a/src/com/android/launcher3/FolderInfo.java
+++ b/src/com/android/launcher3/FolderInfo.java
@@ -35,9 +35,10 @@ public class FolderInfo extends ItemInfo {
boolean opened;
/**
- * The apps and shortcuts
+ * The apps and shortcuts and hidden status
*/
ArrayList<ShortcutInfo> contents = new ArrayList<ShortcutInfo>();
+ Boolean hidden = false;
ArrayList<FolderListener> listeners = new ArrayList<FolderListener>();
@@ -83,6 +84,7 @@ public class FolderInfo extends ItemInfo {
void onAddToDatabase(Context context, ContentValues values) {
super.onAddToDatabase(context, values);
values.put(LauncherSettings.Favorites.TITLE, title.toString());
+ values.put(LauncherSettings.Favorites.HIDDEN, hidden ? 1 : 0);
}
void addListener(FolderListener listener) {
diff --git a/src/com/android/launcher3/HiddenFolderFragment.java b/src/com/android/launcher3/HiddenFolderFragment.java
new file mode 100644
index 000000000..d43f61d23
--- /dev/null
+++ b/src/com/android/launcher3/HiddenFolderFragment.java
@@ -0,0 +1,325 @@
+package com.android.launcher3;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+import android.app.Fragment;
+import android.app.FragmentTransaction;
+import android.media.Image;
+import android.text.InputType;
+import android.view.KeyEvent;
+import android.view.MenuItem;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.*;
+import com.android.launcher3.settings.SettingsProvider;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+
+public class HiddenFolderFragment extends Fragment {
+ public static final String HIDDEN_FOLDER_FRAGMENT = "hiddenFolderFragment";
+ public static final String HIDDEN_FOLDER_NAME = "hiddenFolderName";
+ public static final String HIDDEN_FOLDER_STATUS = "hiddenFolderStatus";
+ public static final String HIDDEN_FOLDER_INFO = "hiddenFolderInfo";
+ public static final String HIDDEN_FOLDER_INFO_TITLES = "hiddenFolderInfoTitles";
+ public static final String HIDDEN_FOLDER_LAUNCH = "hiddenFolderLaunchPosition";
+
+ private static final int REQ_LOCK_PATTERN = 1;
+
+ private String[] mComponentInfo;
+ private String[] mComponentTitles;
+ private boolean mHidden;
+ private PackageManager mPackageManager;
+ private AppsAdapter mAppsAdapter;
+ private ArrayList<AppEntry> mAppEntries;
+
+ private EditText mFolderName;
+ private ListView mListView;
+
+ private Launcher mLauncher;
+
+ private boolean mAuth = false;
+ private boolean mSent = false;
+
+ private OnClickListener mClicklistener = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mHidden = !mHidden;
+
+ ImageView mLock = (ImageView) v;
+ Drawable mLockIcon = mHidden ? getResources().getDrawable(R.drawable.folder_lock_light)
+ : getResources().getDrawable(R.drawable.folder_unlock);
+ mLock.setImageDrawable(mLockIcon);
+ }
+ };
+
+ @Override
+ public View onCreateView (LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View v = inflater.inflate(R.layout.hidden_folder, container, false);
+
+ mLauncher = (Launcher) getActivity();
+ mPackageManager = mLauncher.getPackageManager();
+
+ mHidden = getArguments().getBoolean(HIDDEN_FOLDER_STATUS);
+ Folder folder = mLauncher.mHiddenFolderIcon.getFolder();
+ mComponentInfo = folder.getComponents();
+ mComponentTitles = folder.getComponentTitles();
+ String title = mLauncher.mHiddenFolderIcon.getFolderInfo().title.toString();
+
+ mFolderName = (EditText) v.findViewById(R.id.folder_name);
+ mFolderName.setText(title);
+ mFolderName.setSelectAllOnFocus(true);
+ mFolderName.setInputType(mFolderName.getInputType() |
+ InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS | InputType.TYPE_TEXT_FLAG_CAP_WORDS);
+ mFolderName.setImeOptions(EditorInfo.IME_ACTION_DONE);
+ mFolderName.setOnEditorActionListener(new TextView.OnEditorActionListener() {
+ @Override
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ if (actionId == EditorInfo.IME_ACTION_DONE) {
+ doneEditingText(v);
+ return true;
+ }
+ return false;
+ }
+ });
+ mFolderName.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ if (!hasFocus) {
+ doneEditingText(v);
+ }
+ }
+ });
+
+ ImageView mLock = (ImageView) v.findViewById(R.id.folder_lock_icon);
+ Drawable mLockIcon = mHidden ? getResources().getDrawable(R.drawable.folder_lock_light)
+ : getResources().getDrawable(R.drawable.folder_unlock);
+ mLock.setImageDrawable(mLockIcon);
+ mLock.setOnClickListener(mClicklistener);
+
+ mAppsAdapter = new AppsAdapter(mLauncher, R.layout.hidden_apps_list_item);
+ mAppsAdapter.setNotifyOnChange(true);
+ mAppEntries = loadApps();
+ mAppsAdapter.clear();
+ mAppsAdapter.addAll(mAppEntries);
+
+ mListView = (ListView) v.findViewById(R.id.hidden_apps_list);
+ mListView.setAdapter(mAppsAdapter);
+
+ return v;
+ }
+
+ private void doneEditingText(View v) {
+ InputMethodManager mInputMethodManager = (InputMethodManager)
+ mLauncher.getSystemService(Context.INPUT_METHOD_SERVICE);
+ mInputMethodManager.hideSoftInputFromWindow(v.getWindowToken(), 0);
+
+ mListView.requestFocus();
+ }
+
+ private ArrayList<AppEntry> loadApps() {
+ ArrayList<AppEntry> apps = new ArrayList<AppEntry>();
+ int size = mComponentInfo.length;
+ for (int i = 0; i < size; i++) {
+ apps.add(new AppEntry(mComponentInfo[i], mComponentTitles[i]));
+ }
+ return apps;
+ }
+
+ public void saveHiddenFolderStatus(int position) {
+ String newTitle = mFolderName.getText().toString();
+ if (mLauncher.mHiddenFolderIcon != null) {
+ if (position != -1) {
+ Folder folder = mLauncher.mHiddenFolderIcon.getFolder();
+ View v = folder.getViewFromPosition(position);
+ Object tag = v.getTag();
+ if (tag instanceof ShortcutInfo) {
+ mLauncher.startActivitySafely(v,
+ ((ShortcutInfo) tag).getIntent(),
+ v.getTag());
+
+ return;
+ }
+ }
+
+ // Folder name
+ FolderInfo info = mLauncher.mHiddenFolderIcon.getFolderInfo();
+ if (!info.title.equals(newTitle)) {
+ info.setTitle(newTitle);
+ mLauncher.mHiddenFolderIcon.getFolder().setFolderName();
+ LauncherModel.updateItemInDatabase(mLauncher, info);
+ }
+
+ // Folder hidden status
+ if (info.hidden == mHidden) {
+ return;
+ } else {
+ info.hidden = mHidden;
+ // flip the boolean value to accomodate framework
+ // in framework "false" is "protected" and "true" is "visible"
+ mLauncher.mHiddenFolderIcon.getFolder().modifyProtectedApps(!info.hidden);
+
+ LauncherModel.updateItemInDatabase(mLauncher, info);
+ // We need to make sure this change gets written to the DB before
+ // OnResume restarts the process
+ mLauncher.mModel.flushWorkerThread();
+ }
+ }
+
+ FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
+ fragmentTransaction
+ .remove(mLauncher.mHiddenFolderFragment).commit();
+ }
+
+ 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) {
+ final AppViewHolder viewHolder;
+
+ if (convertView == null) {
+ convertView = mInflator.inflate(
+ R.layout.hidden_folder_apps_list_item, parent, false);
+ viewHolder = new AppViewHolder(convertView, position);
+ 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);
+
+ convertView.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ saveHiddenFolderStatus(viewHolder.position);
+ }
+ });
+
+ 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();
+ }
+ }
+ }
+
+ private final class AppEntry {
+
+ public final ComponentName componentName;
+ public final String title;
+
+ public AppEntry(String component, String title) {
+ componentName = ComponentName.unflattenFromString(component);
+ this.title = title;
+ }
+ }
+
+ private static class AppViewHolder {
+ public final TextView title;
+ public final ImageView icon;
+ public final int position;
+
+ public AppViewHolder(View parentView, int position) {
+ icon = (ImageView) parentView.findViewById(R.id.icon);
+ title = (TextView) parentView.findViewById(R.id.title);
+ this.position = position;
+ }
+ }
+}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index dcc87b83a..1c07194f7 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -168,6 +168,8 @@ public class Launcher extends Activity
static final int REQUEST_PICK_ICON = 13;
+ private static final int REQUEST_LOCK_PATTERN = 14;
+
/**
* IntentStarter uses request codes starting with this. This must be greater than all activity
* request codes used internally.
@@ -272,6 +274,8 @@ public class Launcher extends Activity
private DragController mDragController;
private View mWeightWatcher;
private TransitionEffectsFragment mTransitionEffectsFragment;
+ private LauncherClings mLauncherClings;
+ protected HiddenFolderFragment mHiddenFolderFragment;
private AppWidgetManagerCompat mAppWidgetManager;
private LauncherAppWidgetHost mAppWidgetHost;
@@ -284,6 +288,9 @@ public class Launcher extends Activity
private FolderInfo mFolderInfo;
+ protected FolderIcon mHiddenFolderIcon;
+ private boolean mHiddenFolderAuth = false;
+
private Hotseat mHotseat;
private ViewGroup mOverviewPanel;
private View mDarkPanel;
@@ -319,7 +326,7 @@ public class Launcher extends Activity
private Dialog mTransitionEffectDialog;
- private LauncherModel mModel;
+ protected LauncherModel mModel;
private IconCache mIconCache;
private boolean mUserPresent = true;
private boolean mVisible = false;
@@ -422,6 +429,16 @@ public class Launcher extends Activity
return Log.isLoggable(propertyName, Log.VERBOSE);
}
+ private BroadcastReceiver protectedAppsChangedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // Update the workspace
+ updateDynamicGrid();
+ mWorkspace.hideOutlines();
+ mSearchDropTargetBar.showSearchBar(false);
+ }
+ };
+
@Override
protected void onCreate(Bundle savedInstanceState) {
if (DEBUG_STRICT_MODE) {
@@ -514,6 +531,10 @@ public class Launcher extends Activity
showFirstRunActivity();
showFirstRunClings();
}
+ IntentFilter protectedAppsFilter = new IntentFilter(
+ "cyanogenmod.intent.action.PROTECTED_COMPONENT_UPDATE");
+ registerReceiver(protectedAppsChangedReceiver, protectedAppsFilter,
+ "cyanogenmod.permission.PROTECTED_APP", null);
}
@Override
@@ -822,6 +843,23 @@ public class Launcher extends Activity
mWorkspace.exitOverviewMode(false);
}
return;
+ } else if (requestCode == REQUEST_LOCK_PATTERN) {
+ mHiddenFolderAuth = true;
+ switch (resultCode) {
+ case RESULT_OK:
+ FragmentManager fragmentManager = getFragmentManager();
+ FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
+
+ fragmentTransaction.setCustomAnimations(0, 0);
+ fragmentTransaction.replace(R.id.launcher, mHiddenFolderFragment,
+ HiddenFolderFragment.HIDDEN_FOLDER_FRAGMENT);
+ fragmentTransaction.commit();
+ break;
+ case RESULT_CANCELED:
+ // User failed to enter/confirm a lock pattern, back out
+ break;
+ }
+ return;
}
boolean isWidgetDrop = (requestCode == REQUEST_PICK_APPWIDGET ||
@@ -1100,12 +1138,22 @@ public class Launcher extends Activity
PackageInstallerCompat.getInstance(this).onResume();
- //Close out TransitionEffects Fragment
+ //Close out Fragments
Fragment f = getFragmentManager().findFragmentByTag(
TransitionEffectsFragment.TRANSITION_EFFECTS_FRAGMENT);
if (f != null) {
mTransitionEffectsFragment.setEffect();
}
+ Fragment f1 = getFragmentManager().findFragmentByTag(
+ HiddenFolderFragment.HIDDEN_FOLDER_FRAGMENT);
+ if (f1 != null && !mHiddenFolderAuth) {
+ mHiddenFolderFragment.saveHiddenFolderStatus(-1);
+ FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
+ fragmentTransaction
+ .remove(mHiddenFolderFragment).commit();
+ } else {
+ mHiddenFolderAuth = false;
+ }
}
@Override
@@ -2190,12 +2238,28 @@ public class Launcher extends Activity
PackageInstallerCompat.getInstance(this).onStop();
LauncherAnimUtils.onDestroyActivity();
+
+ unregisterReceiver(protectedAppsChangedReceiver);
}
public DragController getDragController() {
return mDragController;
}
+ public void validateLockForHiddenFolders(Bundle bundle, FolderIcon info) {
+ // Validate Lock Pattern
+ Intent lockPatternActivity = new Intent();
+ lockPatternActivity.setClassName(
+ "com.android.settings",
+ "com.android.settings.applications.LockPatternActivity");
+ startActivityForResult(lockPatternActivity, REQUEST_LOCK_PATTERN);
+ mHiddenFolderAuth = false;
+
+ mHiddenFolderIcon = info;
+ mHiddenFolderFragment = new HiddenFolderFragment();
+ mHiddenFolderFragment.setArguments(bundle);
+ }
+
@Override
public void startActivityForResult(Intent intent, int requestCode) {
if (requestCode >= 0) {
@@ -2541,6 +2605,14 @@ public class Launcher extends Activity
@Override
public void onBackPressed() {
+ Fragment f1 = getFragmentManager().findFragmentByTag(
+ HiddenFolderFragment.HIDDEN_FOLDER_FRAGMENT);
+ if (f1 != null) {
+ mHiddenFolderFragment.saveHiddenFolderStatus(-1);
+ FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
+ fragmentTransaction
+ .remove(mHiddenFolderFragment).commit();
+ }
if (isAllAppsVisible()) {
if (mAppsCustomizeContent.getContentType() ==
AppsCustomizePagedView.ContentType.Applications) {
@@ -3145,6 +3217,11 @@ public class Launcher extends Activity
Folder folder = folderIcon.getFolder();
FolderInfo info = folder.mInfo;
+ if (info.hidden) {
+ folder.startHiddenFolderManager();
+ return;
+ }
+
info.opened = true;
// Just verify that the folder hasn't already been added to the DragLayer.
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 39035cdd8..80a488b8e 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -48,6 +48,7 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.provider.BaseColumns;
import android.text.TextUtils;
+import android.provider.Settings;
import android.util.Log;
import android.util.Pair;
@@ -89,6 +90,7 @@ public class LauncherModel extends BroadcastReceiver
private static final boolean REMOVE_UNRESTORED_ICONS = true;
static final String TAG = "Launcher.Model";
+ public static final String SETTINGS_PROTECTED_COMPONENTS = "protected_components";
// true = use a "More Apps" folder for non-workspace apps on upgrade
// false = strew non-workspace apps across the workspace on upgrade
@@ -979,6 +981,7 @@ public class LauncherModel extends BroadcastReceiver
final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
+ final int hiddenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.HIDDEN);
FolderInfo folderInfo = null;
switch (c.getInt(itemTypeIndex)) {
@@ -993,6 +996,7 @@ public class LauncherModel extends BroadcastReceiver
folderInfo.screenId = c.getInt(screenIndex);
folderInfo.cellX = c.getInt(cellXIndex);
folderInfo.cellY = c.getInt(cellYIndex);
+ folderInfo.hidden = c.getInt(hiddenIndex) > 0;
return folderInfo;
}
@@ -1956,6 +1960,9 @@ public class LauncherModel extends BroadcastReceiver
LauncherSettings.Favorites.PROFILE_ID);
//final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);
//final int displayModeIndex = c.getColumnIndexOrThrow(
+ final int hiddenIndex = c.getColumnIndexOrThrow(
+ LauncherSettings.Favorites.HIDDEN);
+ //final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI); //final int displayModeIndex = c.getColumnIndexOrThrow(
// LauncherSettings.Favorites.DISPLAY_MODE);
ShortcutInfo info;
@@ -2178,6 +2185,7 @@ public class LauncherModel extends BroadcastReceiver
folderInfo.cellY = c.getInt(cellYIndex);
folderInfo.spanX = 1;
folderInfo.spanY = 1;
+ folderInfo.hidden = c.getInt(hiddenIndex) > 0;
// check & update map of what's occupied
deleteOnInvalidPlacement.set(false);
@@ -2586,6 +2594,105 @@ 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();
+ // Since Trebuchet is compiled using the SDK we have to hardcode this string
+ String protectedComponents = Settings.Secure.getString(context.getContentResolver(),
+ SETTINGS_PROTECTED_COMPONENTS);
+ protectedComponents = protectedComponents == null ? "" : protectedComponents;
+ String[] flattened = protectedComponents.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 {
+ // Only remove items from folders that aren't hidden
+ 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 (!folder.hidden){
+ if (mHiddenApps.contains(sci.intent.getComponent())) {
+ LauncherModel.deleteItemFromDatabase(mContext, sci);
+ folder.remove(sci);
+ }
+ } else {
+ if (!mHiddenApps.contains(sci.intent.getComponent())) {
+ LauncherModel.deleteItemFromDatabase(mContext, sci);
+ folder.remove(sci);
+ }
+ }
+
+ }
+ }
+
+ if (folder.contents.size() == 1 && !folder.hidden) {
+ 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,
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 6cc1688de..8da3a2482 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -75,7 +75,7 @@ public class LauncherProvider extends ContentProvider {
private static final String DATABASE_NAME = "launcher.db";
- private static final int DATABASE_VERSION = 20;
+ private static final int DATABASE_VERSION = 21;
static final String OLD_AUTHORITY = "com.android.launcher2.settings";
static final String AUTHORITY = ProviderConfig.AUTHORITY;
@@ -496,6 +496,7 @@ public class LauncherProvider extends ContentProvider {
"modified INTEGER NOT NULL DEFAULT 0," +
"restored INTEGER NOT NULL DEFAULT 0," +
"profileId INTEGER DEFAULT " + userSerialNumber +
+ "hidden INTEGER DEFAULT 0" +
");");
addWorkspacesTable(db);
@@ -901,6 +902,11 @@ public class LauncherProvider extends ContentProvider {
// else old version remains, which means we wipe old data
}
+ if (oldVersion < 21) {
+ db.execSQL("ALTER TABLE favorites ADD hidden INTEGER DEFAULT 0");
+ version = 21;
+ }
+
if (version != DATABASE_VERSION) {
Log.w(TAG, "Destroying all old data.");
db.execSQL("DROP TABLE IF EXISTS " + TABLE_FAVORITES);
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index 355370283..357bac52d 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -40,6 +40,11 @@ class LauncherSettings {
static final String TITLE = "title";
/**
+ * Folder Hidden status
+ */
+ static final String HIDDEN = "hidden";
+
+ /**
* The Intent URL of the gesture, describing what it points to. This
* value is given to {@link android.content.Intent#parseUri(String, int)} to create
* an Intent that can be launched.
diff --git a/src/com/android/launcher3/Lists.java b/src/com/android/launcher3/Lists.java
new file mode 100644
index 000000000..51f5dc272
--- /dev/null
+++ b/src/com/android/launcher3/Lists.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+package com.android.launcher3;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * Provides static methods for creating {@code List} instances easily, and other
+ * utility methods for working with lists.
+ */
+public class Lists {
+
+ /**
+ * Creates an empty {@code ArrayList} instance.
+ *
+ * <p><b>Note:</b> if you only need an <i>immutable</i> empty List, use
+ * {@link Collections#emptyList} instead.
+ *
+ * @return a newly-created, initially-empty {@code ArrayList}
+ */
+ public static <E> ArrayList<E> newArrayList() {
+ return new ArrayList<E>();
+ }
+
+ /**
+ * Creates a resizable {@code ArrayList} instance containing the given
+ * elements.
+ *
+ * <p><b>Note:</b> due to a bug in javac 1.5.0_06, we cannot support the
+ * following:
+ *
+ * <p>{@code List<Base> list = Lists.newArrayList(sub1, sub2);}
+ *
+ * <p>where {@code sub1} and {@code sub2} are references to subtypes of
+ * {@code Base}, not of {@code Base} itself. To get around this, you must
+ * use:
+ *
+ * <p>{@code List<Base> list = Lists.<Base>newArrayList(sub1, sub2);}
+ *
+ * @param elements the elements that the list should contain, in order
+ * @return a newly-created {@code ArrayList} containing those elements
+ */
+ public static <E> ArrayList<E> newArrayList(E... elements) {
+ int capacity = (elements.length * 110) / 100 + 5;
+ ArrayList<E> list = new ArrayList<E>(capacity);
+ Collections.addAll(list, elements);
+ return list;
+ }
+}
diff --git a/src/com/android/launcher3/OverviewSettingsPanel.java b/src/com/android/launcher3/OverviewSettingsPanel.java
index dad2a503c..e104d202a 100644
--- a/src/com/android/launcher3/OverviewSettingsPanel.java
+++ b/src/com/android/launcher3/OverviewSettingsPanel.java
@@ -12,6 +12,11 @@ import com.android.launcher3.list.PinnedHeaderListView;
import com.android.launcher3.list.SettingsPinnedHeaderAdapter;
public class OverviewSettingsPanel {
+ public static final String ANDROID_SETTINGS = "com.android.settings";
+ public static final String ANDROID_PROTECTED_APPS =
+ "com.android.settings.applications.ProtectedAppsActivity";
+ public static final String THEME_SETTINGS =
+ "com.android.settings.Settings$ThemeSettingsActivity";
public static final int HOME_SETTINGS_POSITION = 0;
public static final int DRAWER_SETTINGS_POSITION = 1;
@@ -43,7 +48,8 @@ public class OverviewSettingsPanel {
String[] valuesDrawer = new String[] {
res.getString(R.string.scroll_effect_text),
res.getString(R.string.drawer_sorting_text),
- res.getString(R.string.hide_icon_labels)};
+ res.getString(R.string.hide_icon_labels),
+ res.getString(R.string.protected_app_settings)};
mSettingsAdapter = new SettingsPinnedHeaderAdapter(mLauncher);
mSettingsAdapter.setHeaders(headers);
diff --git a/src/com/android/launcher3/list/SettingsPinnedHeaderAdapter.java b/src/com/android/launcher3/list/SettingsPinnedHeaderAdapter.java
index 43d98c33e..499995375 100644
--- a/src/com/android/launcher3/list/SettingsPinnedHeaderAdapter.java
+++ b/src/com/android/launcher3/list/SettingsPinnedHeaderAdapter.java
@@ -1,6 +1,7 @@
package com.android.launcher3.list;
import android.content.Context;
+import android.content.Intent;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Typeface;
@@ -11,6 +12,7 @@ import android.view.ViewGroup;
import android.widget.TextView;
import com.android.launcher3.Launcher;
import com.android.launcher3.OverviewSettingsPanel;
+import com.android.launcher3.PagedView;
import com.android.launcher3.R;
import com.android.launcher3.settings.SettingsProvider;
import android.view.View.OnClickListener;
@@ -221,6 +223,11 @@ public class SettingsPinnedHeaderAdapter extends PinnedHeaderListAdapter {
SettingsProvider.SETTINGS_UI_DRAWER_HIDE_ICON_LABELS,
R.bool.preferences_interface_drawer_hide_icon_labels_default);
mLauncher.updateDynamicGrid();
+ } else if (value.equals(res.getString(R.string.protected_app_settings))) {
+ Intent intent = new Intent();
+ intent.setClassName(OverviewSettingsPanel.ANDROID_SETTINGS,
+ OverviewSettingsPanel.ANDROID_PROTECTED_APPS);
+ mLauncher.startActivity(intent);
}
View defaultHome = mLauncher.findViewById(R.id.default_home_screen_panel);