From cf84500bd174148d4f7e6ce5a840c4f8f31cbabd Mon Sep 17 00:00:00 2001 From: Raj Yengisetty Date: Mon, 19 May 2014 18:39:10 -0700 Subject: 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 Change-Id: I41c295e7f2c9abc9b2e77e6e3d39b7ca60d47139 --- AndroidManifest.xml | 10 +- res/drawable-hdpi/folder_lock.png | Bin 0 -> 459 bytes res/drawable-hdpi/folder_lock_light.png | Bin 0 -> 461 bytes res/drawable-hdpi/folder_unlock.png | Bin 0 -> 480 bytes res/drawable-mdpi/folder_lock.png | Bin 0 -> 376 bytes res/drawable-mdpi/folder_lock_light.png | Bin 0 -> 372 bytes res/drawable-mdpi/folder_unlock.png | Bin 0 -> 383 bytes res/drawable-xhdpi/folder_lock.png | Bin 0 -> 601 bytes res/drawable-xhdpi/folder_lock_light.png | Bin 0 -> 601 bytes res/drawable-xhdpi/folder_unlock.png | Bin 0 -> 613 bytes res/drawable-xxhdpi/folder_lock.png | Bin 0 -> 750 bytes res/drawable-xxhdpi/folder_lock_light.png | Bin 0 -> 746 bytes res/drawable-xxhdpi/folder_unlock.png | Bin 0 -> 775 bytes res/drawable/lock.png | Bin 19461 -> 0 bytes res/layout/hidden_folder.xml | 51 ++++ res/layout/hidden_folder_apps_list_item.xml | 28 ++ res/layout/user_folder.xml | 50 +++- res/values/cm_strings.xml | 8 +- res/values/dimens.xml | 1 + res/values/preferences_defaults.xml | 4 +- .../android/launcher3/AppsCustomizePagedView.java | 41 ++- src/com/android/launcher3/Folder.java | 105 ++++++- src/com/android/launcher3/FolderIcon.java | 25 +- src/com/android/launcher3/FolderInfo.java | 4 +- .../android/launcher3/HiddenFolderFragment.java | 325 +++++++++++++++++++++ src/com/android/launcher3/Launcher.java | 87 +++++- src/com/android/launcher3/LauncherModel.java | 35 ++- src/com/android/launcher3/LauncherProvider.java | 10 +- src/com/android/launcher3/LauncherSettings.java | 5 + src/com/android/launcher3/Lists.java | 64 ++++ .../android/launcher3/OverviewSettingsPanel.java | 5 +- .../list/SettingsPinnedHeaderAdapter.java | 7 + .../launcher3/settings/HiddenAppsActivity.java | 302 ------------------- .../launcher3/settings/SettingsProvider.java | 1 - 34 files changed, 794 insertions(+), 374 deletions(-) create mode 100644 res/drawable-hdpi/folder_lock.png create mode 100644 res/drawable-hdpi/folder_lock_light.png create mode 100644 res/drawable-hdpi/folder_unlock.png create mode 100644 res/drawable-mdpi/folder_lock.png create mode 100644 res/drawable-mdpi/folder_lock_light.png create mode 100644 res/drawable-mdpi/folder_unlock.png create mode 100644 res/drawable-xhdpi/folder_lock.png create mode 100644 res/drawable-xhdpi/folder_lock_light.png create mode 100644 res/drawable-xhdpi/folder_unlock.png create mode 100644 res/drawable-xxhdpi/folder_lock.png create mode 100644 res/drawable-xxhdpi/folder_lock_light.png create mode 100644 res/drawable-xxhdpi/folder_unlock.png delete mode 100644 res/drawable/lock.png create mode 100644 res/layout/hidden_folder.xml create mode 100644 res/layout/hidden_folder_apps_list_item.xml create mode 100644 src/com/android/launcher3/HiddenFolderFragment.java create mode 100644 src/com/android/launcher3/Lists.java delete mode 100644 src/com/android/launcher3/settings/HiddenAppsActivity.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 066c1779c..9e8065d36 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -61,6 +61,7 @@ + - - - - - - - + + + + + + + + + + + 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 @@ + + + + + + + \ No newline at end of file diff --git a/res/layout/user_folder.xml b/res/layout/user_folder.xml index 5d5f33b1f..28476db69 100644 --- a/res/layout/user_folder.xml +++ b/res/layout/user_folder.xml @@ -34,21 +34,41 @@ android:hapticFeedbackEnabled="false" /> - + android:orientation="horizontal" > + + + + + + diff --git a/res/values/cm_strings.xml b/res/values/cm_strings.xml index 1d8034e3f..4d24dffcc 100644 --- a/res/values/cm_strings.xml +++ b/res/values/cm_strings.xml @@ -91,8 +91,6 @@ Hidden apps - - LAUNCHER SETTINGS HOME SCREEN SETTINGS DRAWER SETTINGS @@ -106,8 +104,14 @@ Larger icons Hide icon labels + + Protected apps ON OFF Themes + + + locked + unlocked diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 9d8fec048..6017b8eb6 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -107,6 +107,7 @@ 4dp 10dp + 50dp 48dp diff --git a/res/values/preferences_defaults.xml b/res/values/preferences_defaults.xml index 98d8bb7a8..28d8ce857 100644 --- a/res/values/preferences_defaults.xml +++ b/res/values/preferences_defaults.xml @@ -8,8 +8,8 @@ false stack false - false - false + true + true false @bool/config_largeIcons sans-serif-condensed diff --git a/src/com/android/launcher3/AppsCustomizePagedView.java b/src/com/android/launcher3/AppsCustomizePagedView.java index 136ac6574..0390f106a 100644 --- a/src/com/android/launcher3/AppsCustomizePagedView.java +++ b/src/com/android/launcher3/AppsCustomizePagedView.java @@ -40,6 +40,7 @@ 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; @@ -197,8 +198,8 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen private ArrayList mFilteredApps; private ArrayList mFilteredWidgets; - private ArrayList mHiddenApps; - private ArrayList mHiddenPackages; + private ArrayList mProtectedApps; + private ArrayList mProtectedPackages; // Cling private boolean mHasShownAllAppsCling; @@ -322,17 +323,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); } - String[] flattened = SettingsProvider.getStringCustomDefault(context, - SettingsProvider.SETTINGS_UI_DRAWER_HIDDEN_APPS, "").split("\\|"); - mHiddenApps = new ArrayList(flattened.length); - mHiddenPackages = new ArrayList(flattened.length); - for (String flat : flattened) { - ComponentName cmp = ComponentName.unflattenFromString(flat); - if (cmp != null) { - mHiddenApps.add(cmp); - mHiddenPackages.add(cmp.getPackageName()); - } - } + updateProtectedAppsList(context); } @Override @@ -2063,13 +2054,31 @@ 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(flattened.length); + mProtectedPackages = new ArrayList(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(mApps); Iterator iterator = mFilteredApps.iterator(); while (iterator.hasNext()) { AppInfo appInfo = iterator.next(); boolean system = (appInfo.flags & AppInfo.DOWNLOADED_FLAG) == 0; - if (mHiddenApps.contains(appInfo.componentName) || + if (mProtectedApps.contains(appInfo.componentName) || (system && !getShowSystemApps()) || (!system && !getShowDownloadedApps())) { iterator.remove(); @@ -2084,6 +2093,8 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen } public void filterWidgetsWithoutInvalidate() { + updateProtectedAppsList(mLauncher); + mFilteredWidgets = new ArrayList(mWidgets); Iterator iterator = mFilteredWidgets.iterator(); @@ -2112,7 +2123,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen flags = 0; } boolean system = (flags & AppInfo.DOWNLOADED_FLAG) == 0; - if (mHiddenPackages.contains(packageName) || + if (mProtectedPackages.contains(packageName) || (system && !getShowSystemApps()) || (!system && !getShowDownloadedApps())) { iterator.remove(); diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java index c7137b848..ef9791d52 100644 --- a/src/com/android/launcher3/Folder.java +++ b/src/com/android/launcher3/Folder.java @@ -20,10 +20,13 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; 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; @@ -42,7 +45,9 @@ import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; 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; @@ -61,6 +66,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; @@ -104,6 +115,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; @@ -130,6 +143,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. * @@ -178,6 +193,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; LauncherAppState app = LauncherAppState.getInstance(); DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); @@ -192,7 +208,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(); @@ -210,6 +225,12 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList 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() { @@ -234,6 +255,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) { @@ -272,6 +347,8 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList public void startEditingFolderName() { mFolderName.setHint(""); mIsEditingName = true; + + mInputMethodManager.showSoftInput(mFolderName, 0); } public void dismissEditingName() { @@ -411,6 +488,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 { @@ -1036,13 +1118,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); @@ -1057,8 +1142,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); } @@ -1347,4 +1436,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 122578381..51517548c 100644 --- a/src/com/android/launcher3/FolderIcon.java +++ b/src/com/android/launcher3/FolderIcon.java @@ -319,14 +319,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 || itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) && - !mFolder.isFull() && item != mInfo && !mInfo.opened); + !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); } @@ -611,6 +620,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 d45e4e47b..133bfd089 100644 --- a/src/com/android/launcher3/FolderInfo.java +++ b/src/com/android/launcher3/FolderInfo.java @@ -31,9 +31,10 @@ class FolderInfo extends ItemInfo { boolean opened; /** - * The apps and shortcuts + * The apps and shortcuts and hidden status */ ArrayList contents = new ArrayList(); + Boolean hidden = false; ArrayList listeners = new ArrayList(); @@ -78,6 +79,7 @@ class FolderInfo extends ItemInfo { void onAddToDatabase(ContentValues values) { super.onAddToDatabase(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 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 loadApps() { + ArrayList apps = new ArrayList(); + 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 { + + private final LayoutInflater mInflator; + + private ConcurrentHashMap mIcons; + private Drawable mDefaultImg; + private List mApps; + + public AppsAdapter(Context context, int textViewResourceId) { + super(context, textViewResourceId); + + mApps = new ArrayList(); + + mInflator = LayoutInflater.from(context); + + // set the default icon till the actual app icon is loaded in async + // task + mDefaultImg = context.getResources().getDrawable( + android.R.mipmap.sym_def_app_icon); + mIcons = new ConcurrentHashMap(); + } + + @Override + public View getView(final int position, View convertView, + ViewGroup parent) { + 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 newApps = new ArrayList(getCount()); + List oldApps = new ArrayList(getCount()); + for (int i = 0; i < getCount(); i++) { + AppEntry app = getItem(i); + if (mApps.contains(app)) { + oldApps.add(app); + } else { + newApps.add(app); + } + } + + if (newApps.size() > 0) { + new LoadIconsTask().execute(newApps.toArray(new AppEntry[] {})); + newApps.addAll(oldApps); + mApps = newApps; + } else { + mApps = oldApps; + } + } + + /** + * An asynchronous task to load the icons of the installed applications. + */ + private class LoadIconsTask extends AsyncTask { + @Override + protected Void doInBackground(AppEntry... apps) { + for (AppEntry app : apps) { + try { + if (mIcons.containsKey(app.componentName + .getPackageName())) { + continue; + } + Drawable icon = mPackageManager + .getApplicationIcon(app.componentName + .getPackageName()); + mIcons.put(app.componentName.getPackageName(), icon); + publishProgress(); + } catch (PackageManager.NameNotFoundException e) { + // ignored; app will show up with default image + } + } + + return null; + } + + @Override + protected void onProgressUpdate(Void... progress) { + notifyDataSetChanged(); + } + } + } + + 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 8a0fe6c05..1209355ea 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -66,7 +66,6 @@ import android.os.Handler; import android.os.Message; import android.os.StrictMode; import android.os.SystemClock; -import android.provider.Settings; import android.speech.RecognizerIntent; import android.text.Selection; import android.text.SpannableStringBuilder; @@ -102,7 +101,6 @@ import android.widget.Toast; import com.android.launcher3.DropTarget.DragObject; import com.android.launcher3.PagedView.TransitionEffect; -import com.android.launcher3.settings.SettingsActivity; import com.android.launcher3.settings.SettingsProvider; import java.io.DataInputStream; @@ -149,10 +147,11 @@ public class Launcher extends Activity private static final int REQUEST_PICK_WALLPAPER = 10; private static final int REQUEST_BIND_APPWIDGET = 11; - public static final int REQUEST_TRANSITION_EFFECTS = 14; 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. @@ -257,6 +256,7 @@ public class Launcher extends Activity private TransitionEffectsFragment mTransitionEffectsFragment; private LauncherClings mLauncherClings; + protected HiddenFolderFragment mHiddenFolderFragment; private AppWidgetManager mAppWidgetManager; private LauncherAppWidgetHost mAppWidgetHost; @@ -269,6 +269,9 @@ public class Launcher extends Activity private FolderInfo mFolderInfo; + protected FolderIcon mHiddenFolderIcon; + private boolean mHiddenFolderAuth = false; + private Hotseat mHotseat; private View mOverviewPanel; @@ -310,7 +313,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; @@ -411,6 +414,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) { @@ -512,6 +525,10 @@ public class Launcher extends Activity } else { mLauncherClings.removeFirstRunAndMigrationClings(); } + IntentFilter protectedAppsFilter = new IntentFilter( + "cyanogenmod.intent.action.PROTECTED_COMPONENT_UPDATE"); + registerReceiver(protectedAppsChangedReceiver, protectedAppsFilter, + "cyanogenmod.permission.PROTECTED_APP", null); } private void initializeDynamicGrid() { @@ -837,6 +854,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 || @@ -967,10 +1001,6 @@ public class Launcher extends Activity } super.onResume(); - if (settingsChanged()) { - android.os.Process.killProcess(android.os.Process.myPid()); - } - // Restore the previous launcher state if (mOnResumeState == State.WORKSPACE) { showWorkspace(false); @@ -1062,12 +1092,22 @@ public class Launcher extends Activity mWorkspace.onResume(); mAppsCustomizeContent.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 @@ -2140,12 +2180,28 @@ public class Launcher extends Activity mDragController = null; 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) mWaitingForResult = true; @@ -2488,6 +2544,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.isInOverviewMode()) { mAppsCustomizeContent.exitOverviewMode(true); @@ -2939,6 +3003,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 46bb6960f..9579272d7 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -49,6 +49,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; @@ -79,6 +80,7 @@ import java.util.concurrent.atomic.AtomicBoolean; public class LauncherModel extends BroadcastReceiver { static final boolean DEBUG_LOADERS = false; 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 @@ -912,6 +914,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)) { @@ -926,6 +929,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; } @@ -1873,8 +1877,9 @@ public class LauncherModel extends BroadcastReceiver { LauncherSettings.Favorites.SPANY); final int restoredIndex = c.getColumnIndexOrThrow( LauncherSettings.Favorites.RESTORED); - //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; @@ -2018,6 +2023,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); @@ -2385,8 +2391,11 @@ public class LauncherModel extends BroadcastReceiver { ArrayList mHiddenApps = new ArrayList(); ArrayList mHiddenAppsPackages = new ArrayList(); Context context = mApp.getContext(); - String[] flattened = SettingsProvider.getStringCustomDefault(context, - SettingsProvider.SETTINGS_UI_DRAWER_HIDDEN_APPS, "").split("\\|"); + // 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); @@ -2416,20 +2425,30 @@ public class LauncherModel extends BroadcastReceiver { } } } else { + // Only remove items from folders that aren't hidden final FolderInfo folder = (FolderInfo)item; List shortcuts = folder.contents; + int NN = shortcuts.size() - 1; for (int j = NN; j >= 0; j--) { ShortcutInfo sci = shortcuts.get(j); if (sci.intent != null && sci.intent.getComponent() != null) { - if (mHiddenApps.contains(sci.intent.getComponent())) { - LauncherModel.deleteItemFromDatabase(mContext, sci); - folder.remove(sci); + if (!folder.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 instanceof LiveFolderInfo)*/) { + if (folder.contents.size() == 1 && !folder.hidden) { ShortcutInfo finalItem = folder.contents.get(0); finalItem.container = folder.container; LauncherModel.deleteItemFromDatabase(mContext, folder); diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java index 46bf3882d..07f587fb5 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 = 19; + private static final int DATABASE_VERSION = 20; static final String OLD_AUTHORITY = "com.android.launcher2.settings"; static final String AUTHORITY = ProviderConfig.AUTHORITY; @@ -435,7 +435,8 @@ public class LauncherProvider extends ContentProvider { "displayMode INTEGER," + "appWidgetProvider TEXT," + "modified INTEGER NOT NULL DEFAULT 0," + - "restored INTEGER NOT NULL DEFAULT 0" + + "restored INTEGER NOT NULL DEFAULT 0," + + "hidden INTEGER DEFAULT 0" + ");"); addWorkspacesTable(db); @@ -856,6 +857,11 @@ public class LauncherProvider extends ContentProvider { version = 19; } + if (oldVersion < 20) { + db.execSQL("ALTER TABLE favorites ADD hidden INTEGER DEFAULT 0"); + version = 20; + } + 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 31b42fcc9..034ffbaa3 100644 --- a/src/com/android/launcher3/LauncherSettings.java +++ b/src/com/android/launcher3/LauncherSettings.java @@ -39,6 +39,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 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. + * + *

Note: if you only need an immutable empty List, use + * {@link Collections#emptyList} instead. + * + * @return a newly-created, initially-empty {@code ArrayList} + */ + public static ArrayList newArrayList() { + return new ArrayList(); + } + + /** + * Creates a resizable {@code ArrayList} instance containing the given + * elements. + * + *

Note: due to a bug in javac 1.5.0_06, we cannot support the + * following: + * + *

{@code List list = Lists.newArrayList(sub1, sub2);} + * + *

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: + * + *

{@code List list = Lists.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 ArrayList newArrayList(E... elements) { + int capacity = (elements.length * 110) / 100 + 5; + ArrayList list = new ArrayList(capacity); + Collections.addAll(list, elements); + return list; + } +} diff --git a/src/com/android/launcher3/OverviewSettingsPanel.java b/src/com/android/launcher3/OverviewSettingsPanel.java index 7ba1f76e0..fd8095f87 100644 --- a/src/com/android/launcher3/OverviewSettingsPanel.java +++ b/src/com/android/launcher3/OverviewSettingsPanel.java @@ -13,6 +13,8 @@ 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; @@ -46,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); diff --git a/src/com/android/launcher3/settings/HiddenAppsActivity.java b/src/com/android/launcher3/settings/HiddenAppsActivity.java deleted file mode 100644 index 57ea7bc36..000000000 --- a/src/com/android/launcher3/settings/HiddenAppsActivity.java +++ /dev/null @@ -1,302 +0,0 @@ -package com.android.launcher3.settings; - -import android.app.ListActivity; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.graphics.drawable.Drawable; -import android.os.AsyncTask; -import android.os.Bundle; -import android.util.Log; -import android.util.SparseBooleanArray; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.view.Window; -import android.widget.ArrayAdapter; -import android.widget.ImageView; -import android.widget.ListView; -import android.widget.TextView; - -import com.android.launcher3.R; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; - -public class HiddenAppsActivity extends ListActivity { - - private boolean mSaved; - - private static final int MENU_RESET = 0; - - private PackageManager mPackageManager; - - private AppsAdapter mAppsAdapter; - - protected void onCreate(Bundle savedInstanceState) { - requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); - super.onCreate(savedInstanceState); - - setTitle(R.string.hidden_apps_title); - setContentView(R.layout.hidden_apps_list); - - getActionBar().setDisplayHomeAsUpEnabled(true); - setProgressBarIndeterminateVisibility(true); - setProgressBarIndeterminate(true); - - mPackageManager = getPackageManager(); - mAppsAdapter = new AppsAdapter(this, R.layout.hidden_apps_list_item); - mAppsAdapter.setNotifyOnChange(true); - - setListAdapter(mAppsAdapter); - - AsyncTask> refreshAppsTask = new AsyncTask>() { - - @Override - protected void onPostExecute(List apps) { - mAppsAdapter.clear(); - mAppsAdapter.addAll(apps); - restoreCheckedItems(); - setProgressBarIndeterminateVisibility(false); - setProgressBarIndeterminate(false); - } - - @Override - protected List doInBackground(Void... params) { - return refreshApps(); - } - }; - refreshAppsTask.execute(null, null, null); - } - - @Override - public void onPause() { - super.onPause(); - save(); - } - - private void save() { - if (mSaved) { - return; - } - String string = ""; - - SparseBooleanArray checked = getListView().getCheckedItemPositions(); - - AppsAdapter listAdapter = (AppsAdapter) getListAdapter(); - for (int i = 0; i < checked.size(); i++) { - if (checked.valueAt(i)) { - AppEntry app = listAdapter.getItem(checked.keyAt(i)); - if (!string.isEmpty()) - string += "|"; - string += app.componentName.flattenToString(); - } - } - - SharedPreferences.Editor editor = SettingsProvider.get(this).edit(); - editor.putString(SettingsProvider.SETTINGS_UI_DRAWER_HIDDEN_APPS, string); - editor.putBoolean(SettingsProvider.SETTINGS_CHANGED, true); - editor.apply(); - - mSaved = true; - } - - private void restoreCheckedItems() { - List apps = new ArrayList(); - String[] flattened = SettingsProvider.getStringCustomDefault(this, - SettingsProvider.SETTINGS_UI_DRAWER_HIDDEN_APPS, "").split("\\|"); - for (String flat : flattened) { - apps.add(ComponentName.unflattenFromString(flat)); - } - - AppsAdapter listAdapter = (AppsAdapter) getListAdapter(); - - for (int i = 0; i < listAdapter.getCount(); i++) { - AppEntry info = listAdapter.getItem(i); - if (apps.contains(info.componentName)) { - getListView().setItemChecked(i, true); - } - } - - mSaved = true; - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - menu.add(0, MENU_RESET, 0, R.string.menu_hidden_apps_delete) - .setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT); - - return true; - } - - private void reset() { - for (int i = 0; i < getListView().getCount(); i++) { - getListView().setItemChecked(i, false); - } - - mSaved = false; - } - - private List refreshApps() { - Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); - mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); - List apps = mPackageManager.queryIntentActivities(mainIntent, 0); - Collections.sort(apps, new ResolveInfo.DisplayNameComparator(mPackageManager)); - List appEntries = new ArrayList(apps.size()); - for (ResolveInfo info : apps) { - appEntries.add(new AppEntry(info)); - } - return appEntries; - } - - @Override - public boolean onMenuItemSelected(int featureId, MenuItem item) { - if (item.getItemId() == android.R.id.home) { - finish(); - return true; - } else if (item.getItemId() == MENU_RESET) { - reset(); - return true; - } - return super.onMenuItemSelected(featureId, item); - } - - @Override - protected void onListItemClick(ListView l, View v, int position, long id) { - mSaved = false; - } - - private final class AppEntry { - - public final ComponentName componentName; - public final String title; - - public AppEntry(ResolveInfo info) { - componentName = new ComponentName(info.activityInfo.packageName, info.activityInfo.name); - title = info.loadLabel(mPackageManager).toString(); - } - } - - /** - * App view holder used to reuse the views inside the list. - */ - private static class AppViewHolder { - public final TextView title; - public final ImageView icon; - - public AppViewHolder(View parentView) { - icon = (ImageView) parentView.findViewById(R.id.icon); - title = (TextView) parentView.findViewById(R.id.title); - } - } - - public class AppsAdapter extends ArrayAdapter { - - private final LayoutInflater mInflator; - - private ConcurrentHashMap mIcons; - private Drawable mDefaultImg; - private List mApps; - - public AppsAdapter(Context context, int textViewResourceId) { - super(context, textViewResourceId); - - mApps = new ArrayList(); - - mInflator = LayoutInflater.from(context); - - // set the default icon till the actual app icon is loaded in async - // task - mDefaultImg = context.getResources().getDrawable(android.R.mipmap.sym_def_app_icon); - mIcons = new ConcurrentHashMap(); - } - - @Override - public View getView(final int position, View convertView, ViewGroup parent) { - AppViewHolder viewHolder; - - if (convertView == null) { - convertView = mInflator.inflate(R.layout.hidden_apps_list_item, parent, false); - viewHolder = new AppViewHolder(convertView); - convertView.setTag(viewHolder); - } else { - viewHolder = (AppViewHolder) convertView.getTag(); - } - - AppEntry app = getItem(position); - - viewHolder.title.setText(app.title); - - Drawable icon = mIcons.get(app.componentName.getPackageName()); - viewHolder.icon.setImageDrawable(icon != null ? icon : mDefaultImg); - - return convertView; - } - - @Override - public boolean hasStableIds() { - return true; - } - - @Override - public void notifyDataSetChanged() { - super.notifyDataSetChanged(); - // If we have new items, we have to load their icons - // If items were deleted, remove them from our mApps - List newApps = new ArrayList(getCount()); - List oldApps = new ArrayList(getCount()); - for (int i = 0; i < getCount(); i++) { - AppEntry app = getItem(i); - if (mApps.contains(app)) { - oldApps.add(app); - } else { - newApps.add(app); - } - } - - if (newApps.size() > 0) { - new LoadIconsTask().execute(newApps.toArray(new AppEntry[] {})); - newApps.addAll(oldApps); - mApps = newApps; - } else { - mApps = oldApps; - } - } - - /** - * An asynchronous task to load the icons of the installed applications. - */ - private class LoadIconsTask extends AsyncTask { - @Override - protected Void doInBackground(AppEntry... apps) { - for (AppEntry app : apps) { - try { - if (mIcons.containsKey(app.componentName.getPackageName())) { - continue; - } - Drawable icon = mPackageManager.getApplicationIcon(app.componentName - .getPackageName()); - mIcons.put(app.componentName.getPackageName(), icon); - publishProgress(); - } catch (PackageManager.NameNotFoundException e) { - // ignored; app will show up with default image - } - } - - return null; - } - - @Override - protected void onProgressUpdate(Void... progress) { - notifyDataSetChanged(); - } - } - } -} diff --git a/src/com/android/launcher3/settings/SettingsProvider.java b/src/com/android/launcher3/settings/SettingsProvider.java index abf4e1b67..5be13a44d 100644 --- a/src/com/android/launcher3/settings/SettingsProvider.java +++ b/src/com/android/launcher3/settings/SettingsProvider.java @@ -33,7 +33,6 @@ public final class SettingsProvider { public static final String SETTINGS_UI_HOMESCREEN_SCROLLING_FADE_ADJACENT = "ui_homescreen_scrolling_fade_adjacent"; public static final String SETTINGS_UI_DRAWER_SCROLLING_TRANSITION_EFFECT = "ui_drawer_scrolling_transition_effect"; public static final String SETTINGS_UI_DRAWER_SCROLLING_FADE_ADJACENT = "ui_drawer_scrolling_fade_adjacent"; - public static final String SETTINGS_UI_DRAWER_HIDDEN_APPS = "ui_drawer_hidden_apps"; public static final String SETTINGS_UI_DRAWER_REMOVE_HIDDEN_APPS_SHORTCUTS = "ui_drawer_remove_hidden_apps_shortcuts"; public static final String SETTINGS_UI_DRAWER_REMOVE_HIDDEN_APPS_WIDGETS = "ui_drawer_remove_hidden_apps_widgets"; public static final String SETTINGS_UI_DRAWER_HIDE_ICON_LABELS = "ui_drawer_hide_icon_labels"; -- cgit v1.2.3