summaryrefslogtreecommitdiffstats
path: root/src/com/android/launcher3/HiddenFolderFragment.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/launcher3/HiddenFolderFragment.java')
-rw-r--r--src/com/android/launcher3/HiddenFolderFragment.java376
1 files changed, 376 insertions, 0 deletions
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;
+ }
+ }
+}