summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVineet Patil <vpatil@cyngn.com>2015-11-24 15:43:37 -0800
committerVineet Patil <vpatil@cyngn.com>2015-11-30 16:48:47 -0800
commit95dfdf845c3accc749609d8b955d55fc8df5adf1 (patch)
tree955c0257c7ac512371d118797f411541dfc83477
parentfe70926e116fca0d84b3642aae3fe6c68d6c7264 (diff)
downloadandroid_packages_apps_Trebuchet-95dfdf845c3accc749609d8b955d55fc8df5adf1.tar.gz
android_packages_apps_Trebuchet-95dfdf845c3accc749609d8b955d55fc8df5adf1.tar.bz2
android_packages_apps_Trebuchet-95dfdf845c3accc749609d8b955d55fc8df5adf1.zip
Re-Implementation of hidden folders
Change-Id: I2cdb881eb6a2608279d30a1cdfc1327a89ae7693
-rw-r--r--Android.mk3
-rw-r--r--AndroidManifest.xml2
-rw-r--r--res/color/listitem_text.xml21
-rw-r--r--res/drawable/ic_remove.xml29
-rw-r--r--res/drawable/listitem_bg.xml21
-rw-r--r--res/drawable/listitem_selector.xml21
-rw-r--r--res/layout/hidden_apps_list.xml22
-rw-r--r--res/layout/hidden_apps_list_item.xml48
-rw-r--r--res/layout/hidden_folder.xml69
-rw-r--r--res/layout/hidden_folder_apps_list_item.xml48
-rw-r--r--res/layout/user_folder.xml8
-rw-r--r--res/values/colors.xml6
-rw-r--r--res/values/dimens.xml9
-rw-r--r--src/com/android/launcher3/Folder.java103
-rw-r--r--src/com/android/launcher3/FolderIcon.java33
-rw-r--r--src/com/android/launcher3/FolderInfo.java4
-rw-r--r--src/com/android/launcher3/HiddenFolderFragment.java376
-rw-r--r--src/com/android/launcher3/Launcher.java69
-rw-r--r--src/com/android/launcher3/LauncherModel.java31
-rw-r--r--src/com/android/launcher3/LauncherProvider.java8
-rw-r--r--src/com/android/launcher3/LauncherSettings.java7
-rw-r--r--tests/Android.mk25
22 files changed, 926 insertions, 37 deletions
diff --git a/Android.mk b/Android.mk
index f9ed664e8..0d030dfb8 100644
--- a/Android.mk
+++ b/Android.mk
@@ -25,7 +25,8 @@ LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-v4 \
- android-support-v7-recyclerview
+ android-support-v7-recyclerview \
+ org.cyanogenmod.platform.internal
LOCAL_SRC_FILES := $(call all-java-files-under, src) \
$(call all-java-files-under, WallpaperPicker/src) \
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 80b059751..c8c0ec4b6 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -56,6 +56,7 @@
<uses-permission android:name="android.permission.SET_WALLPAPER_HINTS" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.BIND_APPWIDGET" />
+ <uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.BROADCAST_STICKY"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
@@ -65,6 +66,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:allowBackup="@bool/enable_backup"
diff --git a/res/color/listitem_text.xml b/res/color/listitem_text.xml
new file mode 100644
index 000000000..ce981439a
--- /dev/null
+++ b/res/color/listitem_text.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <item android:state_enabled="true"
+ android:state_pressed="true" android:color="@color/settings_bg_color" />
+ <item android:color="@android:color/white" />
+</selector>
diff --git a/res/drawable/ic_remove.xml b/res/drawable/ic_remove.xml
new file mode 100644
index 000000000..a37a64b82
--- /dev/null
+++ b/res/drawable/ic_remove.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#000000"
+ android:pathData="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59
+19 19 17.59 13.41 12z" />
+ <path
+ android:pathData="M0 0h24v24H0z" />
+</vector>
diff --git a/res/drawable/listitem_bg.xml b/res/drawable/listitem_bg.xml
index be1fedbe5..1a1e93d53 100644
--- a/res/drawable/listitem_bg.xml
+++ b/res/drawable/listitem_bg.xml
@@ -1,6 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_enabled="true"
- android:state_pressed="true" android:drawable="@android:color/white" />
- <item android:drawable="@color/slideup_panel_bg_color" />
-</selector> \ No newline at end of file
+ android:state_pressed="true" android:drawable="@android:color/white" />
+ <item android:drawable="@color/settings_bg_color" />
+</selector>
diff --git a/res/drawable/listitem_selector.xml b/res/drawable/listitem_selector.xml
new file mode 100644
index 000000000..1a1e93d53
--- /dev/null
+++ b/res/drawable/listitem_selector.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <item android:state_enabled="true"
+ android:state_pressed="true" android:drawable="@android:color/white" />
+ <item android:drawable="@color/settings_bg_color" />
+</selector>
diff --git a/res/layout/hidden_apps_list.xml b/res/layout/hidden_apps_list.xml
new file mode 100644
index 000000000..a639ae094
--- /dev/null
+++ b/res/layout/hidden_apps_list.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+<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" />
diff --git a/res/layout/hidden_apps_list_item.xml b/res/layout/hidden_apps_list_item.xml
new file mode 100644
index 000000000..7061b35c3
--- /dev/null
+++ b/res/layout/hidden_apps_list_item.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.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>
diff --git a/res/layout/hidden_folder.xml b/res/layout/hidden_folder.xml
new file mode 100644
index 000000000..529384737
--- /dev/null
+++ b/res/layout/hidden_folder.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:insettable="http://schemas.android.com/apk/res-auto"
+ 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"
+ insettable:layout_ignoreInsets="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_unlocked"
+ 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:layout_toStartOf="@id/folder_lock_icon"
+ 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..33f9fa572
--- /dev/null
+++ b/res/layout/hidden_folder_apps_list_item.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+<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">
+
+ <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" />
+
+ <ImageView android:id="@+id/remove"
+ android:layout_width="40dp"
+ android:layout_height="40dp"
+ android:layout_gravity="center"
+ android:src="@drawable/ic_remove"/>
+</LinearLayout>
diff --git a/res/layout/user_folder.xml b/res/layout/user_folder.xml
index 2152a9986..1a7e2d332 100644
--- a/res/layout/user_folder.xml
+++ b/res/layout/user_folder.xml
@@ -79,6 +79,14 @@
android:layout_gravity="center_vertical"
layout="@layout/page_indicator" />
+ <ImageView
+ android:id="@+id/folder_lock"
+ android:layout_width="@dimen/folder_lock_icon"
+ android:layout_height="@dimen/folder_lock_icon"
+ android:padding="@dimen/folder_name_padding"
+ android:layout_gravity="center_vertical"
+ android:src="@drawable/folder_unlocked" />
+
</LinearLayout>
</com.android.launcher3.Folder>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 0cad1cefc..80c0d6f6d 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -44,6 +44,12 @@
<color name="container_fastscroll_thumb_inactive_color">#009688</color>
<color name="container_fastscroll_thumb_active_color">#009688</color>
+ <color name="settings_header_text">#FF6cd2ea</color>
+ <color name="settings_bg_color">#FF485459</color>
+ <color name="settings_bg_header_color">#FFb2b0ab</color>
+ <color name="settings_bg_selected_color">#26000000</color>
+ <color name="settings_transition_selected_color">#50000000</color>
+
<!-- All Apps -->
<color name="all_apps_grid_section_text_color">#009688</color>
<color name="all_apps_grid_section_text_color_dark">#FFF</color>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 8c64ef0c5..95557d9c5 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -44,6 +44,15 @@
<!-- Workspace -->
<dimen name="workspace_max_gap">16dp</dimen>
+ <dimen name="workspace_overscroll_drawable_padding">0dp</dimen>
+ <dimen name="workspace_spring_loaded_page_spacing">15dp</dimen>
+ <dimen name="overview_panel_top_padding">20dp</dimen>
+ <dimen name="overview_panel_bottom_padding">50dp</dimen>
+ <dimen name="overview_panel_button_spacing">30dp</dimen>
+ <dimen name="overview_panel_list_padding">16dp</dimen>
+ <dimen name="overview_mode_page_offset">60dp</dimen>
+ <dimen name="sliding_panel_padding">175dp</dimen>
+ <dimen name="overview_scaling_padding">50dp</dimen>
<!-- QSB -->
<dimen name="toolbar_button_vertical_padding">4dip</dimen>
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index 1e0827e54..ccb12b62a 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -23,7 +23,9 @@ import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Point;
@@ -39,6 +41,7 @@ import android.text.Selection;
import android.text.Spannable;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.Pair;
import android.view.ActionMode;
import android.view.KeyEvent;
import android.view.Menu;
@@ -54,6 +57,7 @@ import android.view.animation.DecelerateInterpolator;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.FrameLayout;
+import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -67,9 +71,15 @@ import com.android.launcher3.settings.SettingsProvider;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.util.UiThreadCircularReveal;
+import static cyanogenmod.content.Intent.ACTION_PROTECTED;
+import static cyanogenmod.content.Intent.ACTION_PROTECTED_CHANGED;
+import static cyanogenmod.content.Intent.EXTRA_PROTECTED_COMPONENTS;
+import static cyanogenmod.content.Intent.EXTRA_PROTECTED_STATE;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import java.util.List;
/**
* Represents a set of icons chosen by the user or generated by the system.
@@ -161,6 +171,9 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
@Thunk float mFolderIconPivotY;
private boolean mIsEditingName = false;
+ ImageView mFolderLock;
+ private int mFolderLockHeight;
+
private boolean mDestroyed;
@Thunk Runnable mDeferredAction;
@@ -170,6 +183,8 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
// Folder scrolling
private int mScrollAreaOffset;
+ private boolean mHiddenFolder = false;
+
@Thunk int mScrollHintDir = DragController.SCROLL_NONE;
@Thunk int mCurrentScrollDir = DragController.SCROLL_NONE;
@@ -212,6 +227,10 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
mContent = (FolderPagedView) findViewById(R.id.folder_content);
mContent.setFolder(this);
+ // We find out how tall footer 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 = (ExtendedEditText) findViewById(R.id.folder_name);
mFolderName.setOnBackKeyListener(new ExtendedEditText.OnBackKeyListener() {
@Override
@@ -236,12 +255,13 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
if (hideLabels) {
mFolderName.setVisibility(View.GONE);
}
+ mFolderLock = (ImageView) findViewById(R.id.folder_lock);
+ mFolderLock.measure(measureSpec, measureSpec);
+ mFolderLock.setOnClickListener(this);
+ mFolderLockHeight = mFolderLock.getMeasuredHeight();
mFooter = findViewById(R.id.folder_footer);
- // We find out how tall footer 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;
mFooter.measure(measureSpec, measureSpec);
mFooterHeight = mFooter.getMeasuredHeight();
}
@@ -268,6 +288,49 @@ 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 List<Pair<ComponentName, CharSequence>> getComponents() {
+ int size = mItemsInReadingOrder.size();
+ List<Pair<ComponentName, CharSequence>> components =
+ new ArrayList<Pair<ComponentName, CharSequence>>();
+
+ for (int i = 0; i < size; i++) {
+ View v = mItemsInReadingOrder.get(i);
+ Object tag = v.getTag();
+ if (tag instanceof ShortcutInfo) {
+ ShortcutInfo shortcut = (ShortcutInfo) tag;
+ components.add(Pair.create(shortcut.getIntent().getComponent(), shortcut.title));
+ }
+ }
+
+ return components;
+ }
+
+ public void modifyProtectedApps(boolean protect) {
+ ArrayList<ComponentName> components = new ArrayList<ComponentName>();
+ for (Pair<ComponentName, CharSequence> item : getComponents()) {
+ if (item.first != null) {
+ components.add(item.first);
+ }
+ }
+
+ Intent intent = new Intent();
+ intent.setAction(ACTION_PROTECTED);
+ intent.putExtra(EXTRA_PROTECTED_STATE, protect);
+ intent.putExtra(EXTRA_PROTECTED_COMPONENTS, components);
+
+ mLauncher.sendBroadcast(intent);
}
public boolean onLongClick(View v) {
@@ -422,6 +485,10 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
updateTextViewFocus();
mInfo.addListener(this);
+ setFolderName();
+ }
+
+ public void setFolderName() {
if (!sDefaultFolderName.contentEquals(mInfo.title)) {
mFolderName.setText(mInfo.title);
} else {
@@ -1496,6 +1563,32 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
return mItemsInReadingOrder;
}
+ public ShortcutInfo getShortcutForComponent(ComponentName componentName) {
+ for (View v : mItemsInReadingOrder) {
+ Object tag = v.getTag();
+ if (tag instanceof ShortcutInfo) {
+ ComponentName cName = ((ShortcutInfo) tag).getIntent().getComponent();
+ if (cName.equals(componentName)) {
+ return (ShortcutInfo) tag;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public ShortcutInfo getShortcutForPosition(int position) {
+ if (position < 0 || position >= mItemsInReadingOrder.size()) {
+ return null;
+ }
+ View v = mItemsInReadingOrder.get(position);
+ Object tag = v.getTag();
+ if (tag instanceof ShortcutInfo) {
+ return (ShortcutInfo) tag;
+ }
+ return null;
+ }
+
public void getLocationInDragLayer(int[] loc) {
mLauncher.getDragLayer().getLocationInDragLayer(this, loc);
}
@@ -1513,6 +1606,10 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
outRect.right += mScrollAreaOffset;
}
+ public View getViewFromPosition(int position) {
+ return mItemsInReadingOrder.get(position);
+ }
+
@Override
public void fillInLaunchSourceData(Bundle sourceData) {
// Fill in from the folder icon's launch source provider first
diff --git a/src/com/android/launcher3/FolderIcon.java b/src/com/android/launcher3/FolderIcon.java
index 85e3c3333..9b6e3026b 100644
--- a/src/com/android/launcher3/FolderIcon.java
+++ b/src/com/android/launcher3/FolderIcon.java
@@ -378,13 +378,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);
}
@@ -423,6 +433,8 @@ public class FolderIcon extends FrameLayout implements FolderListener {
item = ((AppInfo) mDragInfo).makeShortcut();
item.spanX = 1;
item.spanY = 1;
+ } else if (mDragInfo instanceof FolderInfo) {
+ return;
} else {
// ShortcutInfo
item = (ShortcutInfo) mDragInfo;
@@ -690,6 +702,23 @@ public class FolderIcon extends FrameLayout implements FolderListener {
}
int nItemsInPreview = Math.min(items.size(), NUM_ITEMS_IN_PREVIEW);
+
+ // Hidden folder - don't display Preview
+ View folderLock = findViewById(R.id.folder_lock_image);
+ folderLock.setVisibility(mInfo.hidden ? VISIBLE : INVISIBLE);
+ View appView = findViewById(R.id.app_0);
+ appView.setVisibility(mInfo.hidden ? INVISIBLE : VISIBLE);
+ appView = findViewById(R.id.app_1);
+ appView.setVisibility(mInfo.hidden ? INVISIBLE : VISIBLE);
+ appView = findViewById(R.id.app_2);
+ appView.setVisibility(mInfo.hidden ? INVISIBLE : VISIBLE);
+ appView = findViewById(R.id.app_3);
+ appView.setVisibility(mInfo.hidden ? INVISIBLE : VISIBLE);
+
+ if (mInfo.hidden) {
+ return;
+ }
+
if (!mAnimating) {
for (int i = NUM_ITEMS_IN_PREVIEW; i >= 0; i--) {
d = null;
diff --git a/src/com/android/launcher3/FolderInfo.java b/src/com/android/launcher3/FolderInfo.java
index 32d752ac0..b8da8cb6a 100644
--- a/src/com/android/launcher3/FolderInfo.java
+++ b/src/com/android/launcher3/FolderInfo.java
@@ -54,9 +54,10 @@ public class FolderInfo extends ItemInfo {
public int options;
/**
- * The apps and shortcuts
+ * The apps and shortcuts and hidden status
*/
public ArrayList<ShortcutInfo> contents = new ArrayList<ShortcutInfo>();
+ public Boolean hidden = false;
ArrayList<FolderListener> listeners = new ArrayList<FolderListener>();
@@ -103,6 +104,7 @@ public class FolderInfo extends ItemInfo {
super.onAddToDatabase(context, values);
values.put(LauncherSettings.Favorites.TITLE, title.toString());
values.put(LauncherSettings.Favorites.OPTIONS, options);
+ 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..97c4dfd44
--- /dev/null
+++ b/src/com/android/launcher3/HiddenFolderFragment.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 2015 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 android.app.Fragment;
+import android.app.FragmentTransaction;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.media.Image;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.text.InputType;
+import android.util.Pair;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.ArrayAdapter;
+import android.widget.EditText;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+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 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_locked)
+ : getResources().getDrawable(R.drawable.folder_unlocked);
+ 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();
+ 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_locked)
+ : getResources().getDrawable(R.drawable.folder_unlocked);
+ mLock.setImageDrawable(mLockIcon);
+ mLock.setOnClickListener(mClicklistener);
+
+ mAppsAdapter = new AppsAdapter(mLauncher, R.layout.hidden_apps_list_item);
+ mAppsAdapter.setNotifyOnChange(true);
+ mAppEntries = loadApps(folder.getComponents());
+ mAppsAdapter.clear();
+ mAppsAdapter.addAll(mAppEntries);
+
+ mListView = (ListView) v.findViewById(R.id.hidden_apps_list);
+ mListView.setAdapter(mAppsAdapter);
+
+ // Apply insets
+ Launcher launcher = (Launcher) getActivity();
+ LinearLayout.LayoutParams llp =
+ (LinearLayout.LayoutParams) mListView.getLayoutParams();
+ // TODO: Uncomment this once the Settings for Trebuchet are merged
+ /*llp.bottomMargin += ((FrameLayout.LayoutParams) launcher.getOverviewPanel()
+ .findViewById(R.id.settings_container).getLayoutParams()).bottomMargin;*/
+ mListView.setLayoutParams(llp);
+
+ 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(List<Pair<ComponentName, CharSequence>> items) {
+ ArrayList<AppEntry> apps = new ArrayList<AppEntry>();
+ int pos = 0;
+ for (Pair<ComponentName, CharSequence> item : items) {
+ apps.add(new AppEntry(item.first, item.second, pos));
+ pos++;
+ }
+ return apps;
+ }
+
+ private void removeComponentFromFolder(AppEntry app) {
+ ShortcutInfo info;
+ if (app.componentName != null) {
+ info = mLauncher.mHiddenFolderIcon.getFolder()
+ .getShortcutForComponent(app.componentName);
+ } else {
+ // Shortcut does not have componentName, use position since it maps to
+ // reading order position in the folder
+ info = mLauncher.mHiddenFolderIcon.getFolder().getShortcutForPosition(app.position);
+ }
+ mLauncher.mHiddenFolderIcon.getFolderInfo().remove(info);
+
+ mAppEntries.remove(app);
+ mAppsAdapter.remove(app);
+ mAppsAdapter.notifyDataSetInvalidated();
+ }
+
+ 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) {
+ ShortcutInfo shortcut = (ShortcutInfo) tag;
+ mLauncher.startActivitySafely(v, shortcut.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();
+ }
+
+ final AppEntry app = getItem(position);
+
+ viewHolder.title.setText(app.title);
+
+ Drawable icon = null;
+ if (app.componentName != null) {
+ icon = mIcons.get(app.componentName.getPackageName());
+ }
+ viewHolder.icon.setImageDrawable(icon != null ? icon : mDefaultImg);
+ viewHolder.remove.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ removeComponentFromFolder(app);
+ }
+ });
+
+ convertView.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ saveHiddenFolderStatus(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 {
+ // Widget icons do not have a
+ if (app.componentName == null ||
+ 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 CharSequence title;
+ public final int position;
+
+ public AppEntry(ComponentName component, CharSequence title, int position) {
+ this.componentName = component;
+ this.title = title;
+ this.position = position;
+ }
+ }
+
+ private static class AppViewHolder {
+ public final TextView title;
+ public final ImageView icon;
+ public final ImageView remove;
+ public final int position;
+
+ public AppViewHolder(View parentView, int position) {
+ icon = (ImageView) parentView.findViewById(R.id.icon);
+ remove = (ImageView) parentView.findViewById(R.id.remove);
+ 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 454d77614..15373c20b 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -29,6 +29,10 @@ import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.AlertDialog;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
+import android.app.Dialog;
import android.app.SearchManager;
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetManager;
@@ -155,6 +159,8 @@ public class Launcher extends Activity
private static final int REQUEST_PERMISSION_CALL_PHONE = 13;
+ private static final int REQUEST_LOCK_PATTERN = 14;
+
private static final int WORKSPACE_BACKGROUND_GRADIENT = 0;
private static final int WORKSPACE_BACKGROUND_TRANSPARENT = 1;
private static final int WORKSPACE_BACKGROUND_BLACK = 2;
@@ -251,6 +257,7 @@ public class Launcher extends Activity
@Thunk DragLayer mDragLayer;
private DragController mDragController;
private View mWeightWatcher;
+ protected HiddenFolderFragment mHiddenFolderFragment;
private AppWidgetManagerCompat mAppWidgetManager;
private LauncherAppWidgetHost mAppWidgetHost;
@@ -261,6 +268,9 @@ public class Launcher extends Activity
private int[] mTmpAddItemCellCoordinates = new int[2];
+ protected FolderIcon mHiddenFolderIcon;
+ private boolean mHiddenFolderAuth = false;
+
@Thunk Hotseat mHotseat;
private ViewGroup mOverviewPanel;
OverviewSettingsPanel mOverviewSettingsPanel;
@@ -300,7 +310,7 @@ public class Launcher extends Activity
private Bundle mSavedInstanceState;
- private LauncherModel mModel;
+ protected LauncherModel mModel;
private IconCache mIconCache;
@Thunk boolean mUserPresent = true;
private boolean mVisible = false;
@@ -758,6 +768,23 @@ public class Launcher extends Activity
showWorkspace(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 ||
@@ -1094,6 +1121,18 @@ public class Launcher extends Activity
}
reloadLauncherIfNeeded();
+
+ //Close out Fragments
+ 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
@@ -2165,6 +2204,20 @@ public class Launcher extends Activity
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) {
onStartForResult(requestCode);
@@ -2560,6 +2613,15 @@ public class Launcher extends Activity
return;
}
+ Fragment f1 = getFragmentManager().findFragmentByTag(
+ HiddenFolderFragment.HIDDEN_FOLDER_FRAGMENT);
+ if (f1 != null) {
+ mHiddenFolderFragment.saveHiddenFolderStatus(-1);
+ FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
+ fragmentTransaction
+ .remove(mHiddenFolderFragment).commit();
+ }
+
if (isAppsViewVisible()) {
showWorkspace(true);
} else if (isWidgetsViewVisible()) {
@@ -3245,6 +3307,11 @@ public class Launcher extends Activity
FolderInfo info = folder.mInfo;
+ if (info.hidden) {
+ folder.startHiddenFolderManager();
+ return;
+ }
+
info.opened = true;
// While the folder is open, the position of the icon cannot change.
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index e3170e93b..c3ad6a8a1 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -109,6 +109,8 @@ public class LauncherModel extends BroadcastReceiver
@Thunk boolean mIsLoaderTaskRunning;
@Thunk boolean mHasLoaderCompletedOnce;
+ private volatile boolean mFlushingWorkerThread;
+
private static final String MIGRATE_AUTHORITY = "com.android.launcher2.settings";
@Thunk static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");
@@ -775,6 +777,35 @@ public class LauncherModel extends BroadcastReceiver
}
}
+ public void flushWorkerThread() {
+ mFlushingWorkerThread = true;
+ Runnable waiter = new Runnable() {
+ public void run() {
+ synchronized (this) {
+ notifyAll();
+ mFlushingWorkerThread = false;
+ }
+ }
+ };
+
+ synchronized(waiter) {
+ runOnWorkerThread(waiter);
+ if (mLoaderTask != null) {
+ synchronized(mLoaderTask) {
+ mLoaderTask.notify();
+ }
+ }
+ boolean success = false;
+ while (!success) {
+ try {
+ waiter.wait();
+ success = true;
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ }
+
/**
* Move an item in the DB to a new <container, screen, cellX, cellY>
*/
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 8791e9e57..fb99853f9 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -68,7 +68,7 @@ public class LauncherProvider extends ContentProvider {
private static final String TAG = "LauncherProvider";
private static final boolean LOGD = false;
- private static final int DATABASE_VERSION = 26;
+ private static final int DATABASE_VERSION = 27;
public static final String AUTHORITY = ProviderConfig.AUTHORITY;
@@ -537,6 +537,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" + "," +
"rank INTEGER NOT NULL DEFAULT 0," +
"options INTEGER NOT NULL DEFAULT 0" +
");");
@@ -718,7 +719,10 @@ public class LauncherProvider extends ContentProvider {
ManagedProfileHeuristic.markExistingUsersForNoFolderCreation(mContext);
case 25:
convertShortcutsToLauncherActivities(db);
- case 26: {
+ case 26:
+ // add hidden column
+ addIntegerColumn(db, "hidden", 0);
+ case 27: {
// DB Upgraded successfully
return;
}
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index 5cde2e588..2080bc643 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -40,7 +40,12 @@ public class LauncherSettings {
* <P>Type: TEXT</P>
*/
public static final String TITLE = "title";
-
+
+ /**
+ * Folder Hidden status
+ */
+ public 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
diff --git a/tests/Android.mk b/tests/Android.mk
index eba4ade48..e579af78b 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -12,26 +12,5 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-
-LOCAL_PATH := $(call my-dir)
-
-src_dirs := src
-res_dirs := res
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, $(res_dirs))
-LOCAL_AAPT_FLAGS := --auto-add-overlay
-
-LOCAL_SDK_VERSION := 21
-
-LOCAL_PACKAGE_NAME := Launcher3Tests
-
-LOCAL_INSTRUMENTATION_FOR := Launcher3
-
-include $(BUILD_PACKAGE)
+#LOCAL_PATH := $(call my-dir)
+#include $(call all-makefiles-under,$(LOCAL_PATH))