summaryrefslogtreecommitdiffstats
path: root/src/com/android/settings/applications/ProtectedAppsActivity.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/settings/applications/ProtectedAppsActivity.java')
-rw-r--r--src/com/android/settings/applications/ProtectedAppsActivity.java512
1 files changed, 512 insertions, 0 deletions
diff --git a/src/com/android/settings/applications/ProtectedAppsActivity.java b/src/com/android/settings/applications/ProtectedAppsActivity.java
new file mode 100644
index 0000000..7156c92
--- /dev/null
+++ b/src/com/android/settings/applications/ProtectedAppsActivity.java
@@ -0,0 +1,512 @@
+/*
+ * 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.settings.applications;
+
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Configuration;
+import android.graphics.drawable.Drawable;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.CheckBox;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+import com.android.settings.R;
+import com.android.settings.cyanogenmod.ProtectedAppsReceiver;
+
+import cyanogenmod.providers.CMSettings;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class ProtectedAppsActivity extends Activity {
+ private static final int REQ_ENTER_PATTERN = 1;
+ private static final int REQ_RESET_PATTERN = 2;
+
+ private static final String NEEDS_UNLOCK = "needs_unlock";
+ private static final String TARGET_INTENT = "target_intent";
+
+ private ListView mListView;
+
+ private static final int MENU_RESET = 0;
+ private static final int MENU_RESET_LOCK = 1;
+
+ private PackageManager mPackageManager;
+
+ private AppsAdapter mAppsAdapter;
+
+ private ArrayList<ComponentName> mProtect;
+
+ private boolean mWaitUserAuth = false;
+ private boolean mUserIsAuth = false;
+ private Intent mTargetIntent;
+ private int mOrientation;
+
+ private HashSet<ComponentName> mProtectedApps = new HashSet<ComponentName>();
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Handle incoming target activity
+ Intent incomingIntent = getIntent();
+ if (incomingIntent.hasExtra("com.android.settings.PROTECTED_APP_TARGET_INTENT")) {
+ mTargetIntent =
+ incomingIntent.getParcelableExtra(
+ "com.android.settings.PROTECTED_APP_TARGET_INTENT");
+ }
+
+ setTitle(R.string.protected_apps);
+ setContentView(R.layout.hidden_apps_list);
+
+ mPackageManager = getPackageManager();
+ mAppsAdapter = new AppsAdapter(this, R.layout.hidden_apps_list_item);
+ mAppsAdapter.setNotifyOnChange(true);
+
+ mListView = (ListView) findViewById(R.id.protected_apps_list);
+ mListView.setAdapter(mAppsAdapter);
+
+ mProtect = new ArrayList<ComponentName>();
+
+ if (savedInstanceState != null) {
+ mUserIsAuth = savedInstanceState.getBoolean(NEEDS_UNLOCK);
+ mTargetIntent = savedInstanceState.getParcelable(TARGET_INTENT);
+ } else {
+ if (!mUserIsAuth) {
+ // Require unlock
+ mWaitUserAuth = true;
+ Intent lockPattern = new Intent(this, LockPatternActivity.class);
+ startActivityForResult(lockPattern, REQ_ENTER_PATTERN);
+ } else {
+ //LAUNCH
+ if (mTargetIntent != null) {
+ launchTargetActivityInfoAndFinish();
+ }
+ }
+ }
+ mOrientation = getResources().getConfiguration().orientation;
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putBoolean(NEEDS_UNLOCK, mUserIsAuth);
+ outState.putParcelable(TARGET_INTENT, mTargetIntent);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ AsyncTask<Void, Void, List<AppEntry>> refreshAppsTask =
+ new AsyncTask<Void, Void, List<AppEntry>>() {
+
+ @Override
+ protected void onPostExecute(List<AppEntry> apps) {
+ mAppsAdapter.clear();
+ mAppsAdapter.addAll(apps);
+ }
+
+ @Override
+ protected List<AppEntry> doInBackground(Void... params) {
+ return refreshApps();
+ }
+ };
+ refreshAppsTask.execute(null, null, null);
+
+ getActionBar().setDisplayHomeAsUpEnabled(true);
+
+ // Update Protected Apps list
+ updateProtectedComponentsList();
+ }
+
+ private void updateProtectedComponentsList() {
+ String protectedComponents = CMSettings.Secure.getString(getContentResolver(),
+ CMSettings.Secure.PROTECTED_COMPONENTS);
+ protectedComponents = protectedComponents == null ? "" : protectedComponents;
+ String [] flattened = protectedComponents.split("\\|");
+ mProtectedApps = new HashSet<ComponentName>(flattened.length);
+ for (String flat : flattened) {
+ ComponentName cmp = ComponentName.unflattenFromString(flat);
+ if (cmp != null) {
+ mProtectedApps.add(cmp);
+ }
+ }
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+
+ // Close this app to prevent unauthorized access when
+ // 1) not waiting for authorization and
+ // 2) there is no portrait/landscape mode switching
+ if (!mWaitUserAuth && (mOrientation == getResources().getConfiguration().orientation)) {
+ finish();
+ }
+ }
+
+ private boolean getProtectedStateFromComponentName(ComponentName componentName) {
+ return mProtectedApps.contains(componentName);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ switch (requestCode) {
+ case REQ_ENTER_PATTERN:
+ mWaitUserAuth = false;
+ switch (resultCode) {
+ case RESULT_OK:
+ //Nothing to do, proceed!
+ mUserIsAuth = true;
+ if (mTargetIntent != null) {
+ launchTargetActivityInfoAndFinish();
+ }
+ break;
+ case RESULT_CANCELED:
+ // user failed to define a pattern, do not lock the folder
+ finish();
+ break;
+ }
+ break;
+ case REQ_RESET_PATTERN:
+ mWaitUserAuth = false;
+ mUserIsAuth = false;
+ }
+ }
+
+ private void launchTargetActivityInfoAndFinish() {
+ Intent launchIntent = mTargetIntent;
+ startActivity(launchIntent);
+ finish();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ menu.add(0, MENU_RESET, 0, R.string.menu_hidden_apps_delete)
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+ menu.add(0, MENU_RESET_LOCK, 0, R.string.menu_hidden_apps_reset_lock)
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+ return true;
+ }
+
+ private void reset() {
+ ArrayList<ComponentName> componentsList = new ArrayList<ComponentName>();
+
+ // Check to see if any components that have been protected that aren't present in
+ // the ListView. This can happen if there are components which have been protected
+ // but do not respond to the queryIntentActivities for Launcher Category
+ ContentResolver resolver = getContentResolver();
+ String hiddenComponents = CMSettings.Secure.getString(resolver,
+ CMSettings.Secure.PROTECTED_COMPONENTS);
+
+ if (hiddenComponents != null && !hiddenComponents.equals("")) {
+ for (String flattened : hiddenComponents.split("\\|")) {
+ ComponentName cmp = ComponentName.unflattenFromString(flattened);
+
+ if (!componentsList.contains(cmp)) {
+ componentsList.add(cmp);
+ }
+ }
+ }
+
+ AppProtectList list = new AppProtectList(componentsList,
+ PackageManager.COMPONENT_VISIBLE_STATUS);
+ StoreComponentProtectedStatus task = new StoreComponentProtectedStatus(this);
+ task.execute(list);
+ }
+
+ private void resetLock() {
+ mWaitUserAuth = true;
+ Intent lockPattern = new Intent(LockPatternActivity.RECREATE_PATTERN, null,
+ this, LockPatternActivity.class);
+ startActivityForResult(lockPattern, REQ_RESET_PATTERN);
+ }
+
+ private List<AppEntry> refreshApps() {
+ Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
+ mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+ List<ResolveInfo> apps = mPackageManager.queryIntentActivities(mainIntent, 0);
+ Collections.sort(apps, new ResolveInfo.DisplayNameComparator(mPackageManager));
+ List<AppEntry> appEntries = new ArrayList<AppEntry>(apps.size());
+ for (ResolveInfo info : apps) {
+ appEntries.add(new AppEntry(info));
+ }
+ return appEntries;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case MENU_RESET:
+ reset();
+ return true;
+ case MENU_RESET_LOCK:
+ resetLock();
+ return true;
+ case android.R.id.home:
+ finish();
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ private final class AppEntry {
+ public final ComponentName componentName;
+ public final String title;
+
+ public AppEntry(ResolveInfo info) {
+ ActivityInfo aInfo = info.activityInfo;
+ componentName = new ComponentName(aInfo.packageName, aInfo.name);
+ title = info.loadLabel(mPackageManager).toString();
+ }
+ }
+
+ private final class AppProtectList {
+ public final ArrayList<ComponentName> componentNames;
+ public final boolean state;
+
+ public AppProtectList(ArrayList<ComponentName> componentNames, boolean state) {
+ this.componentNames = new ArrayList<ComponentName>();
+ for (ComponentName cn : componentNames) {
+ this.componentNames.add(cn.clone());
+ }
+
+ this.state = state;
+ }
+ }
+
+ public class StoreComponentProtectedStatus extends AsyncTask<AppProtectList, Void, Void> {
+ private ProgressDialog mDialog;
+ private Context mContext;
+
+ public StoreComponentProtectedStatus(Context context) {
+ mContext = context;
+ mDialog = new ProgressDialog(mContext);
+ }
+
+ @Override
+ protected void onPreExecute() {
+ mDialog.setMessage(getResources().getString(R.string.saving_protected_components));
+ mDialog.setCancelable(false);
+ mDialog.setCanceledOnTouchOutside(false);
+ mDialog.show();
+ }
+
+ @Override
+ protected void onPostExecute(Void aVoid) {
+ if (mDialog.isShowing()) {
+ mDialog.dismiss();
+ }
+
+ mAppsAdapter.notifyDataSetChanged();
+ }
+
+ @Override
+ protected Void doInBackground(final AppProtectList... args) {
+ for (AppProtectList appList : args) {
+ ProtectedAppsReceiver.updateProtectedAppComponentsAndNotify(mContext,
+ appList.componentNames, appList.state);
+ }
+
+ updateProtectedComponentsList();
+ return null;
+ }
+ }
+
+ /**
+ * App view holder used to reuse the views inside the list.
+ */
+ private static class AppViewHolder {
+ public final View container;
+ public final TextView title;
+ public final ImageView icon;
+ public final View launch;
+ public final CheckBox checkBox;
+
+ public AppViewHolder(View parentView) {
+ container = parentView.findViewById(R.id.app_item);
+ icon = (ImageView) parentView.findViewById(R.id.icon);
+ title = (TextView) parentView.findViewById(R.id.title);
+ launch = parentView.findViewById(R.id.launch_app);
+ checkBox = (CheckBox) parentView.findViewById(R.id.checkbox);
+ }
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ }
+
+ 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) {
+ 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);
+
+ boolean state = getProtectedStateFromComponentName(app.componentName);
+ viewHolder.checkBox.setChecked(state);
+ if (state) {
+ viewHolder.launch.setVisibility(View.VISIBLE);
+ viewHolder.launch.setTag(app);
+ viewHolder.launch.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ ComponentName cName = ((AppEntry)v.getTag()).componentName;
+ Intent intent = new Intent();
+ intent.setClassName(cName.getPackageName(), cName.getClassName());
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(intent);
+ }
+ });
+ } else {
+ viewHolder.launch.setVisibility(View.GONE);
+ }
+
+ viewHolder.container.setTag(position);
+ viewHolder.container.setOnClickListener(mAppClickListener);
+ 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 {
+ String packageName = app.componentName.getPackageName();
+ if (mIcons.containsKey(packageName)) {
+ continue;
+ }
+ Drawable icon = mPackageManager.getApplicationIcon(packageName);
+ mIcons.put(packageName, icon);
+ publishProgress();
+ } catch (PackageManager.NameNotFoundException e) {
+ // ignored; app will show up with default image
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ protected void onProgressUpdate(Void... progress) {
+ notifyDataSetChanged();
+ }
+ }
+ }
+
+ private View.OnClickListener mAppClickListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ int position = (Integer) v.getTag();
+ ComponentName cn = mAppsAdapter.getItem(position).componentName;
+ ArrayList<ComponentName> componentsList = new ArrayList<ComponentName>();
+ componentsList.add(cn);
+ boolean state = getProtectedStateFromComponentName(cn);
+
+ AppProtectList list = new AppProtectList(componentsList, state);
+ StoreComponentProtectedStatus task =
+ new StoreComponentProtectedStatus(ProtectedAppsActivity.this);
+ task.execute(list);
+ }
+ };
+}