summaryrefslogtreecommitdiffstats
path: root/src/com/android/settings/privacyguard
diff options
context:
space:
mode:
authorDiogo Ferreira <defer@cyngn.com>2015-01-14 16:06:23 +0000
committerRoman Birg <roman@cyngn.com>2015-11-03 12:21:36 -0800
commitbb303f0e1266e8d1a754f09103658c7212ccb239 (patch)
tree59dea88142e74856f564521c2d45f189094d1381 /src/com/android/settings/privacyguard
parentf788ff0f99b08b07bc3ec3426726b2a78649db39 (diff)
downloadpackages_apps_Settings-bb303f0e1266e8d1a754f09103658c7212ccb239.zip
packages_apps_Settings-bb303f0e1266e8d1a754f09103658c7212ccb239.tar.gz
packages_apps_Settings-bb303f0e1266e8d1a754f09103658c7212ccb239.tar.bz2
appops: Load the app list asynchronously
The AppList is pretty big and it is loading in the UI thread. This is noticeable even on high-end chips and there is a definite possibility that it throws an ANR on lower-end ones. This patchset adds an asynchronous loader and updates the privacy guard to use it. Change-Id: I81f3fb64604af07a351f8cbdfffa7454389e2cee
Diffstat (limited to 'src/com/android/settings/privacyguard')
-rw-r--r--src/com/android/settings/privacyguard/AppInfoLoader.java110
-rw-r--r--src/com/android/settings/privacyguard/PrivacyGuardManager.java101
2 files changed, 156 insertions, 55 deletions
diff --git a/src/com/android/settings/privacyguard/AppInfoLoader.java b/src/com/android/settings/privacyguard/AppInfoLoader.java
new file mode 100644
index 0000000..8e3ea5f
--- /dev/null
+++ b/src/com/android/settings/privacyguard/AppInfoLoader.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2015 The CyanogenMod 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.privacyguard;
+
+import android.app.AppOpsManager;
+import android.content.AsyncTaskLoader;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageInfo;
+
+import com.android.settings.privacyguard.PrivacyGuardManager.AppInfo;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * An asynchronous loader implementation that loads AppInfo structures.
+ */
+/* package */ class AppInfoLoader extends AsyncTaskLoader<List<AppInfo>> {
+ private PackageManager mPm;
+ private boolean mShowSystemApps;
+ private AppOpsManager mAppOps;
+
+ public AppInfoLoader(Context context, boolean showSystemApps) {
+ super(context);
+ mPm = context.getPackageManager();
+ mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
+ mShowSystemApps = showSystemApps;
+ }
+
+ @Override
+ public List<AppInfo> loadInBackground() {
+ return loadInstalledApps();
+ }
+
+ @Override
+ public void onStartLoading() {
+ forceLoad();
+ }
+
+ @Override
+ public void onStopLoading() {
+ cancelLoad();
+ }
+
+ @Override
+ protected void onReset() {
+ cancelLoad();
+ }
+
+ /**
+ * 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 | PackageManager.GET_SIGNATURES);
+
+ for (PackageInfo info : packages) {
+ final ApplicationInfo appInfo = info.applicationInfo;
+
+ // skip all system apps if they shall not be included
+ if (!mShowSystemApps && (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ continue;
+ }
+
+ AppInfo app = new AppInfo();
+ app.title = appInfo.loadLabel(mPm).toString();
+ app.packageName = info.packageName;
+ app.enabled = appInfo.enabled;
+ app.uid = info.applicationInfo.uid;
+ app.privacyGuardEnabled = mAppOps.getPrivacyGuardSettingForPackage(
+ app.uid, app.packageName);
+ apps.add(app);
+ }
+
+ // sort the apps by their enabled state, then by title
+ Collections.sort(apps, new Comparator<AppInfo>() {
+ @Override
+ public int compare(AppInfo lhs, AppInfo rhs) {
+ if (lhs.enabled != rhs.enabled) {
+ return lhs.enabled ? -1 : 1;
+ }
+ return lhs.title.compareToIgnoreCase(rhs.title);
+ }
+ });
+
+ return apps;
+ }
+
+}
diff --git a/src/com/android/settings/privacyguard/PrivacyGuardManager.java b/src/com/android/settings/privacyguard/PrivacyGuardManager.java
index 74eeee0..b187782 100644
--- a/src/com/android/settings/privacyguard/PrivacyGuardManager.java
+++ b/src/com/android/settings/privacyguard/PrivacyGuardManager.java
@@ -16,6 +16,7 @@
package com.android.settings.privacyguard;
+import android.view.animation.AnimationUtils;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AppOpsManager;
@@ -23,13 +24,12 @@ import android.app.Dialog;
import android.app.DialogFragment;
import android.app.Fragment;
import android.app.FragmentManager;
+import android.app.LoaderManager;
import android.content.ActivityNotFoundException;
import android.content.Context;
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.Loader;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
@@ -54,23 +54,24 @@ import com.android.settings.SubSettings;
import com.android.settings.applications.AppOpsDetails;
import com.android.settings.applications.AppOpsState;
import com.android.settings.applications.AppOpsState.OpsTemplate;
+import com.android.settings.privacyguard.AppInfoLoader;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.Comparator;
import java.util.List;
public class PrivacyGuardManager extends Fragment
- implements OnItemClickListener, OnItemLongClickListener {
+ implements OnItemClickListener, OnItemLongClickListener,
+ LoaderManager.LoaderCallbacks<List<PrivacyGuardManager.AppInfo>> {
private static final String TAG = "PrivacyGuardManager";
private TextView mNoUserAppsInstalled;
private ListView mAppsList;
+ private View mLoadingContainer;
private PrivacyGuardAppListAdapter mAdapter;
private List<AppInfo> mApps;
- private PackageManager mPm;
private Activity mActivity;
private SharedPreferences mPreferences;
@@ -97,7 +98,6 @@ public class PrivacyGuardManager extends Fragment
Bundle savedInstanceState) {
mActivity = getActivity();
- mPm = mActivity.getPackageManager();
mAppOps = (AppOpsManager)getActivity().getSystemService(Context.APP_OPS_SERVICE);
return inflater.inflate(R.layout.privacy_guard_manager, container, false);
@@ -123,6 +123,8 @@ public class PrivacyGuardManager extends Fragment
mAppsList.setOnItemClickListener(this);
mAppsList.setOnItemLongClickListener(this);
+ mLoadingContainer = mActivity.findViewById(R.id.loading_container);
+
// get shared preference
mPreferences = mActivity.getSharedPreferences("privacy_guard_manager", Activity.MODE_PRIVATE);
if (!mPreferences.getBoolean("first_help_shown", false)) {
@@ -139,7 +141,7 @@ public class PrivacyGuardManager extends Fragment
}
// load apps and construct the list
- loadApps();
+ scheduleAppsLoad();
setHasOptionsMenu(true);
}
@@ -174,7 +176,7 @@ public class PrivacyGuardManager extends Fragment
super.onResume();
// rebuild the list; the user might have changed settings inbetween
- loadApps();
+ scheduleAppsLoad();
if (mSavedFirstVisiblePosition != AdapterView.INVALID_POSITION) {
mAppsList.setSelectionFromTop(mSavedFirstVisiblePosition, mSavedFirstItemOffset);
@@ -182,9 +184,41 @@ public class PrivacyGuardManager extends Fragment
}
}
- private void loadApps() {
- mApps = loadInstalledApps();
+ @Override
+ public Loader<List<AppInfo>> onCreateLoader(int id, Bundle args) {
+ mLoadingContainer.startAnimation(AnimationUtils.loadAnimation(
+ mActivity, android.R.anim.fade_in));
+ mAppsList.startAnimation(AnimationUtils.loadAnimation(
+ mActivity, android.R.anim.fade_out));
+
+ mAppsList.setVisibility(View.INVISIBLE);
+ mLoadingContainer.setVisibility(View.VISIBLE);
+ return new AppInfoLoader(mActivity, shouldShowSystemApps());
+ }
+
+ @Override
+ public void onLoadFinished(Loader<List<AppInfo>> loader, List<AppInfo> apps) {
+ mApps = apps;
+ prepareAppAdapter();
+
+ mLoadingContainer.startAnimation(AnimationUtils.loadAnimation(
+ mActivity, android.R.anim.fade_out));
+ mAppsList.startAnimation(AnimationUtils.loadAnimation(
+ mActivity, android.R.anim.fade_in));
+
+ mLoadingContainer.setVisibility(View.INVISIBLE);
+ mAppsList.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void onLoaderReset(Loader<List<AppInfo>> loader) {
+ }
+
+ private void scheduleAppsLoad() {
+ getLoaderManager().restartLoader(0, null, this);
+ }
+ private void prepareAppAdapter() {
// if app list is empty inform the user
// else go ahead and construct the list
if (mApps == null || mApps.isEmpty()) {
@@ -265,49 +299,6 @@ public class PrivacyGuardManager extends Fragment
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 | PackageManager.GET_SIGNATURES);
- boolean showSystemApps = shouldShowSystemApps();
-
- for (PackageInfo info : packages) {
- final ApplicationInfo appInfo = info.applicationInfo;
-
- // skip all system apps if they shall not be included
- if (!showSystemApps && (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
- continue;
- }
-
- AppInfo app = new AppInfo();
- app.title = appInfo.loadLabel(mPm).toString();
- app.packageName = info.packageName;
- app.enabled = appInfo.enabled;
- app.uid = info.applicationInfo.uid;
- app.privacyGuardEnabled = mAppOps.getPrivacyGuardSettingForPackage(
- app.uid, app.packageName);
- apps.add(app);
- }
-
- // sort the apps by their enabled state, then by title
- Collections.sort(apps, new Comparator<AppInfo>() {
- @Override
- public int compare(AppInfo lhs, AppInfo rhs) {
- if (lhs.enabled != rhs.enabled) {
- return lhs.enabled ? -1 : 1;
- }
- return lhs.title.compareToIgnoreCase(rhs.title);
- }
- });
-
- return apps;
- }
private boolean shouldShowSystemApps() {
return mPreferences.getBoolean("show_system_apps", false);
@@ -393,7 +384,7 @@ public class PrivacyGuardManager extends Fragment
// shared preference and rebuild the list
item.setChecked(!item.isChecked());
mPreferences.edit().putBoolean(prefName, item.isChecked()).commit();
- loadApps();
+ scheduleAppsLoad();
return true;
case R.id.advanced:
Intent i = new Intent(Intent.ACTION_MAIN);