summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorVineet Patil <vpatil@cyngn.com>2015-11-24 15:43:37 -0800
committerTom Powell <zifnab@zifnab06.net>2017-03-26 15:52:42 -0700
commit14e1bef375ccb9e719bac1877c53359fad8d9d47 (patch)
treec16d4ec2b9bfa92d6f41cce351e7b6a32a817a39 /src
parent466dd988f8b64651a3d0b3b517b2c2a24b160f41 (diff)
downloadandroid_packages_apps_Trebuchet-14e1bef375ccb9e719bac1877c53359fad8d9d47.tar.gz
android_packages_apps_Trebuchet-14e1bef375ccb9e719bac1877c53359fad8d9d47.tar.bz2
android_packages_apps_Trebuchet-14e1bef375ccb9e719bac1877c53359fad8d9d47.zip
Re-Implementation of hidden folders
Change-Id: I2cdb881eb6a2608279d30a1cdfc1327a89ae7693
Diffstat (limited to 'src')
-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
8 files changed, 621 insertions, 10 deletions
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