diff options
Diffstat (limited to 'src/com')
4 files changed, 544 insertions, 13 deletions
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java index b01dc74..b966bc7 100644 --- a/src/com/android/settings/SecuritySettings.java +++ b/src/com/android/settings/SecuritySettings.java @@ -94,7 +94,6 @@ public class SecuritySettings extends SettingsPreferenceFragment private static final String LOCKSCREEN_QUICK_UNLOCK_CONTROL = "quick_unlock_control"; private static final String KEY_VIBRATE_PREF = "lockscreen_vibrate"; private static final String KEY_SMS_SECURITY_CHECK_PREF = "sms_security_check_limit"; - private static final String KEY_PRIVACY_GUARD_DEFAULT = "privacy_guard_default"; private static final String KEY_APP_SECURITY_CATEGORY = "app_security"; DevicePolicyManager mDPM; @@ -128,7 +127,6 @@ public class SecuritySettings extends SettingsPreferenceFragment private CheckBoxPreference mHomeUnlock; private CheckBoxPreference mQuickUnlockScreen; private ListPreference mSmsSecurityCheck; - private CheckBoxPreference mPrivacyGuardDefault; @Override public void onCreate(Bundle savedInstanceState) { @@ -410,14 +408,6 @@ public class SecuritySettings extends SettingsPreferenceFragment root.findPreference(KEY_APP_SECURITY_CATEGORY); appCategory.removePreference(mSmsSecurityCheck); } - - mPrivacyGuardDefault = (CheckBoxPreference) findPreference(KEY_PRIVACY_GUARD_DEFAULT); - try { - mPrivacyGuardDefault.setChecked(Settings.Secure.getInt(getContentResolver(), - Settings.Secure.PRIVACY_GUARD_DEFAULT) == 1); - } catch (SettingNotFoundException e) { - mPrivacyGuardDefault.setChecked(false); - } } return root; @@ -708,9 +698,6 @@ public class SecuritySettings extends SettingsPreferenceFragment } else if (KEY_TOGGLE_VERIFY_APPLICATIONS.equals(key)) { Settings.Global.putInt(getContentResolver(), Settings.Global.PACKAGE_VERIFIER_ENABLE, mToggleVerifyApps.isChecked() ? 1 : 0); - } else if (KEY_PRIVACY_GUARD_DEFAULT.equals(key)) { - Settings.Secure.putInt(getContentResolver(), Settings.Secure.PRIVACY_GUARD_DEFAULT, - mPrivacyGuardDefault.isChecked() ? 1 : 0); } else { // If we didn't handle it, let preferences handle it. return super.onPreferenceTreeClick(preferenceScreen, preference); diff --git a/src/com/android/settings/cyanogenmod/privacyguard/PrivacyGuardAppListAdapter.java b/src/com/android/settings/cyanogenmod/privacyguard/PrivacyGuardAppListAdapter.java new file mode 100644 index 0000000..4c7e815 --- /dev/null +++ b/src/com/android/settings/cyanogenmod/privacyguard/PrivacyGuardAppListAdapter.java @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2013 SlimRoms 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.cyanogenmod.privacyguard; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.graphics.drawable.Drawable; +import android.os.AsyncTask; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import com.android.settings.R; +import com.android.settings.cyanogenmod.privacyguard.PrivacyGuardManager.AppInfo; + +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +public class PrivacyGuardAppListAdapter extends BaseAdapter { + + private LayoutInflater mInflater; + private PackageManager mPm; + + private List<AppInfo> mApps; + private ConcurrentHashMap<String, Drawable> mIcons; + private Drawable mDefaultImg; + + private Context mContext; + + //constructor + public PrivacyGuardAppListAdapter(Context context, List<AppInfo> apps) { + mContext = context; + mInflater = LayoutInflater.from(mContext); + mPm = context.getPackageManager(); + mApps = apps; + + // set the default icon till the actual app icon is loaded in async task + mDefaultImg = mContext.getResources().getDrawable(android.R.mipmap.sym_def_app_icon); + mIcons = new ConcurrentHashMap<String, Drawable>(); + + new LoadIconsTask().execute(apps.toArray(new PrivacyGuardManager.AppInfo[]{})); + } + + @Override + public int getCount() { + return mApps.size(); + } + + @Override + public Object getItem(int position) { + return mApps.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + PrivacyGuardAppViewHolder appHolder; + + if (convertView == null) { + convertView = mInflater.inflate(R.layout.privacy_guard_manager_list_row, null); + + // creates a ViewHolder and children references + appHolder = new PrivacyGuardAppViewHolder(); + appHolder.title = (TextView) convertView.findViewById(R.id.app_title); + appHolder.icon = (ImageView) convertView.findViewById(R.id.app_icon); + appHolder.privacyGuardIcon = (ImageView) convertView.findViewById(R.id.app_privacy_guard_icon); + convertView.setTag(appHolder); + } else { + appHolder = (PrivacyGuardAppViewHolder) convertView.getTag(); + } + + PrivacyGuardManager.AppInfo app = mApps.get(position); + + appHolder.title.setText(app.title); + + Drawable icon = mIcons.get(app.packageName); + appHolder.icon.setImageDrawable(icon != null ? icon : mDefaultImg); + + int privacyGuardDrawableResId = app.privacyGuardEnabled + ? R.drawable.ic_privacy_guard : R.drawable.ic_privacy_guard_off; + appHolder.privacyGuardIcon.setImageResource(privacyGuardDrawableResId); + + return convertView; + } + + /** + * An asynchronous task to load the icons of the installed applications. + */ + private class LoadIconsTask extends AsyncTask<PrivacyGuardManager.AppInfo, Void, Void> { + @Override + protected Void doInBackground(PrivacyGuardManager.AppInfo... apps) { + for (PrivacyGuardManager.AppInfo app : apps) { + try { + Drawable icon = mPm.getApplicationIcon(app.packageName); + mIcons.put(app.packageName, icon); + publishProgress(); + } catch (PackageManager.NameNotFoundException e) { + // ignored; app will show up with default image + } + } + + return null; + } + + @Override + protected void onProgressUpdate(Void... progress) { + notifyDataSetChanged(); + } + } + + /** + * App view holder used to reuse the views inside the list. + */ + public static class PrivacyGuardAppViewHolder { + TextView title; + ImageView icon; + ImageView privacyGuardIcon; + } +} diff --git a/src/com/android/settings/cyanogenmod/privacyguard/PrivacyGuardManager.java b/src/com/android/settings/cyanogenmod/privacyguard/PrivacyGuardManager.java new file mode 100644 index 0000000..efb05a4 --- /dev/null +++ b/src/com/android/settings/cyanogenmod/privacyguard/PrivacyGuardManager.java @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2013 SlimRoms 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.cyanogenmod.privacyguard; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.app.Fragment; +import android.content.ActivityNotFoundException; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.SharedPreferences; +import android.net.Uri; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.AdapterView.OnItemLongClickListener; +import android.widget.ListView; +import android.widget.TextView; + +import com.android.settings.R; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +public class PrivacyGuardManager extends Fragment + implements OnItemClickListener, OnItemLongClickListener { + + private static final String TAG = "PrivacyGuardManager"; + + private TextView mNoUserAppsInstalled; + private ListView mAppsList; + private PrivacyGuardAppListAdapter mAdapter; + private List<AppInfo> mApps; + + private PackageManager mPm; + private Activity mActivity; + + private SharedPreferences mPreferences; + + // array of critical permissions where privacy guard + // can hide the information + private static final String[] PERMISSION_FILTER = new String[] { + android.Manifest.permission.ACCESS_COARSE_LOCATION, + android.Manifest.permission.ACCESS_FINE_LOCATION, + android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, + android.Manifest.permission.READ_HISTORY_BOOKMARKS, + android.Manifest.permission.WRITE_HISTORY_BOOKMARKS, + android.Manifest.permission.READ_CALENDAR, + android.Manifest.permission.WRITE_CALENDAR, + android.Manifest.permission.READ_CONTACTS, + android.Manifest.permission.WRITE_CONTACTS, + android.Manifest.permission.READ_CALL_LOG, + android.Manifest.permission.WRITE_CALL_LOG, + "com.android.voicemail.permission.READ_WRITE_ALL_VOICEMAIL", + android.Manifest.permission.READ_SMS, + android.Manifest.permission.RECEIVE_SMS, + android.Manifest.permission.SEND_SMS, + android.Manifest.permission.WRITE_SMS, + android.Manifest.permission.BROADCAST_SMS + }; + + // holder for package data passed into the adapter + public static final class AppInfo { + String title; + String packageName; + boolean privacyGuardEnabled; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + mActivity = getActivity(); + mPm = mActivity.getPackageManager(); + + return inflater.inflate(R.layout.privacy_guard_manager, container, false); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + mNoUserAppsInstalled = (TextView) mActivity.findViewById(R.id.error); + + mAppsList = (ListView) mActivity.findViewById(R.id.apps_list); + mAppsList.setOnItemClickListener(this); + mAppsList.setOnItemLongClickListener(this); + + // get shared preference + mPreferences = mActivity.getSharedPreferences("privacy_guard_manager", Activity.MODE_PRIVATE); + if (!mPreferences.getBoolean("first_help_shown", false)) { + showHelp(); + } + + // load apps and construct the list + loadApps(); + setHasOptionsMenu(true); + } + + private void loadApps() { + mApps = loadInstalledApps(); + + // if app list is empty inform the user + // else go ahead and construct the list + if (mApps == null || mApps.isEmpty()) { + if (shouldFilterByPermission()) { + mNoUserAppsInstalled.setText(R.string.privacy_guard_filter_does_not_match); + } else { + mNoUserAppsInstalled.setText(R.string.privacy_guard_no_user_apps); + } + mNoUserAppsInstalled.setVisibility(View.VISIBLE); + mAppsList.setVisibility(View.GONE); + } else { + mNoUserAppsInstalled.setVisibility(View.GONE); + mAppsList.setVisibility(View.VISIBLE); + mAdapter = new PrivacyGuardAppListAdapter(mActivity, mApps); + mAppsList.setAdapter(mAdapter); + } + } + + private void resetPrivacyGuard() { + if (mApps == null || mApps.isEmpty()) { + return; + } + // turn off privacy guard for all apps shown in the current list + for (AppInfo app : mApps) { + if (app.privacyGuardEnabled) { + mPm.setPrivacyGuardSetting(app.packageName, false); + app.privacyGuardEnabled = false; + } + } + mAdapter.notifyDataSetChanged(); + } + + @Override + public void onItemClick(AdapterView<?> parent, View view, int position, long id) { + // on click change the privacy guard status for this item + final AppInfo app = (AppInfo) parent.getItemAtPosition(position); + + app.privacyGuardEnabled = !app.privacyGuardEnabled; + mPm.setPrivacyGuardSetting(app.packageName, app.privacyGuardEnabled); + + mAdapter.notifyDataSetChanged(); + } + + @Override + public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { + // on long click open app details window + final AppInfo app = (AppInfo) parent.getItemAtPosition(position); + + try { + startActivity(new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS, + Uri.parse("package:" + app.packageName))); + } catch (ActivityNotFoundException e) { + Log.e(TAG, "Couldn't open app details activity", e); + } + + return true; + } + + /** + * Uses the package manager to query for all currently installed apps + * for the list. + * + * @return the complete List off installed applications (@code PrivacyGuardAppInfo) + */ + private List<AppInfo> loadInstalledApps() { + List<AppInfo> apps = new ArrayList<AppInfo>(); + List<PackageInfo> packages = mPm.getInstalledPackages(PackageManager.GET_PERMISSIONS); + boolean showSystemApps = shouldShowSystemApps(); + boolean filterByPermission = shouldFilterByPermission(); + + for (PackageInfo info : packages) { + final ApplicationInfo appInfo = info.applicationInfo; + + // skip system apps if they shall not be included + if (!showSystemApps && (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { + continue; + } + + if (filterByPermission) { + final String[] requestedPermissions = info.requestedPermissions; + if (requestedPermissions == null || !filterAppPermissions(requestedPermissions)) { + continue; + } + } + + AppInfo app = new AppInfo(); + app.title = appInfo.loadLabel(mPm).toString(); + app.packageName = info.packageName; + app.privacyGuardEnabled = mPm.getPrivacyGuardSetting(app.packageName); + apps.add(app); + } + + // sort the apps by title + Collections.sort(apps, new Comparator<AppInfo>() { + @Override + public int compare(AppInfo lhs, AppInfo rhs) { + return lhs.title.compareToIgnoreCase(rhs.title); + } + }); + + return apps; + } + + private boolean filterAppPermissions(final String[] requestedPermissions) { + for (String requested : requestedPermissions) { + for (String filtered : PERMISSION_FILTER) { + if (requested.equals(filtered)) { + return true; + } + } + } + return false; + } + + private boolean shouldShowSystemApps() { + return mPreferences.getBoolean("show_system_apps", false); + } + + private boolean shouldFilterByPermission() { + return mPreferences.getBoolean("filter_by_permission", true); + } + + private class HelpDialogFragment extends DialogFragment { + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + return new AlertDialog.Builder(getActivity()) + .setTitle(R.string.privacy_guard_help_title) + .setMessage(R.string.privacy_guard_help_text) + .setNegativeButton(android.R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }) + .create(); + } + + @Override + public void onCancel(DialogInterface dialog) { + mPreferences.edit().putBoolean("first_help_shown", true).commit(); + } + } + + private void showHelp() { + HelpDialogFragment fragment = new HelpDialogFragment(); + fragment.show(getFragmentManager(), "help_dialog"); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + inflater.inflate(R.menu.privacy_guard_manager, menu); + menu.findItem(R.id.show_system_apps).setChecked(shouldShowSystemApps()); + menu.findItem(R.id.filter_app_permissions).setChecked(shouldFilterByPermission()); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.help: + showHelp(); + return true; + case R.id.reset: + resetPrivacyGuard(); + return true; + case R.id.filter_app_permissions: + case R.id.show_system_apps: + final String prefName = item.getItemId() == R.id.filter_app_permissions + ? "filter_by_permission" : "show_system_apps"; + // set the menu checkbox and save it in + // shared preference and rebuild the list + item.setChecked(!item.isChecked()); + mPreferences.edit().putBoolean(prefName, item.isChecked()).commit(); + loadApps(); + return true; + default: + return super.onContextItemSelected(item); + } + } + + @Override + public void onResume() { + super.onResume(); + // rebuild the list; the user might have changed settings inbetween + loadApps(); + } +} diff --git a/src/com/android/settings/cyanogenmod/privacyguard/PrivacyGuardPrefs.java b/src/com/android/settings/cyanogenmod/privacyguard/PrivacyGuardPrefs.java new file mode 100644 index 0000000..6d18952 --- /dev/null +++ b/src/com/android/settings/cyanogenmod/privacyguard/PrivacyGuardPrefs.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2013 Slimroms + * + * 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.cyanogenmod.privacyguard; + +import android.app.Activity; +import android.content.Context; +import android.os.Bundle; +import android.preference.CheckBoxPreference; +import android.preference.Preference; +import android.preference.Preference.OnPreferenceChangeListener; +import android.preference.PreferenceScreen; +import android.provider.Settings; +import android.provider.Settings.SettingNotFoundException; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ListView; + +import com.android.settings.R; +import com.android.settings.SettingsPreferenceFragment; +import com.android.settings.Utils; + +public class PrivacyGuardPrefs extends SettingsPreferenceFragment implements + OnPreferenceChangeListener { + + private static final String TAG = "PrivacyGuardPrefs"; + + private static final String KEY_PRIVACY_GUARD_DEFAULT = "privacy_guard_default"; + + private CheckBoxPreference mPrivacyGuardDefault; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + addPreferencesFromResource(R.xml.privacy_guard_prefs); + PreferenceScreen prefSet = getPreferenceScreen(); + + mPrivacyGuardDefault = (CheckBoxPreference) findPreference(KEY_PRIVACY_GUARD_DEFAULT); + mPrivacyGuardDefault.setOnPreferenceChangeListener(this); + + try { + mPrivacyGuardDefault.setChecked(Settings.Secure.getInt(getContentResolver(), + Settings.Secure.PRIVACY_GUARD_DEFAULT) == 1); + } catch (SettingNotFoundException e) { + mPrivacyGuardDefault.setChecked(false); + } + } + + @Override + public View onCreateView(LayoutInflater inflater, + ViewGroup container, Bundle savedInstanceState) { + final View view = super.onCreateView(inflater, container, savedInstanceState); + final ListView list = (ListView) view.findViewById(android.R.id.list); + // our container already takes care of the padding + int paddingTop = list.getPaddingTop(); + int paddingBottom = list.getPaddingBottom(); + list.setPadding(0, paddingTop, 0, paddingBottom); + return view; + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + if (preference == mPrivacyGuardDefault) { + boolean value = (Boolean) newValue; + Settings.Secure.putInt(getContentResolver(), + Settings.Secure.PRIVACY_GUARD_DEFAULT, value ? 1 : 0); + return true; + } + return false; + } +} |