summaryrefslogtreecommitdiffstats
path: root/src/com/android/settings/applications
diff options
context:
space:
mode:
authorJason Monk <jmonk@google.com>2015-02-24 11:35:29 -0500
committerJason Monk <jmonk@google.com>2015-03-02 10:21:19 -0500
commitcd91128a2de5d111c59fe442c72b764d9a9acb3a (patch)
treedd1f7740f23a433b0ff6f3a95088d97d438caab5 /src/com/android/settings/applications
parenta330b1a093869194203bf4d40ea81676c7f6dbb3 (diff)
downloadpackages_apps_Settings-cd91128a2de5d111c59fe442c72b764d9a9acb3a.zip
packages_apps_Settings-cd91128a2de5d111c59fe442c72b764d9a9acb3a.tar.gz
packages_apps_Settings-cd91128a2de5d111c59fe442c72b764d9a9acb3a.tar.bz2
Split app info into several screens
The root screen now only has the uninstall/force stop/disable buttons and the rest has moved to sub screens listed in a preference list. The root screen as UI approximate to the new mocks, but the separated screens (storage, launch by default, etc.) have yet to receive their visual overhaul. Bug: 19511439 Change-Id: I4e01fbaefc69e0652edea2429d9e9b028c78e825
Diffstat (limited to 'src/com/android/settings/applications')
-rw-r--r--src/com/android/settings/applications/AppInfoBase.java188
-rw-r--r--src/com/android/settings/applications/AppInfoWithHeader.java40
-rw-r--r--src/com/android/settings/applications/AppLaunchSettings.java190
-rw-r--r--src/com/android/settings/applications/AppPermissionSettings.java221
-rw-r--r--src/com/android/settings/applications/AppStorageSettings.java501
-rw-r--r--src/com/android/settings/applications/HeaderPreference.java60
-rwxr-xr-xsrc/com/android/settings/applications/InstalledAppDetails.java1258
7 files changed, 1423 insertions, 1035 deletions
diff --git a/src/com/android/settings/applications/AppInfoBase.java b/src/com/android/settings/applications/AppInfoBase.java
new file mode 100644
index 0000000..2203a21
--- /dev/null
+++ b/src/com/android/settings/applications/AppInfoBase.java
@@ -0,0 +1,188 @@
+/*
+ * 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.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.hardware.usb.IUsbManager;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ServiceManager;
+import android.os.UserManager;
+import android.preference.PreferenceFragment;
+import android.util.Log;
+
+import com.android.settings.SettingsActivity;
+import com.android.settings.applications.ApplicationsState.AppEntry;
+
+import java.util.ArrayList;
+
+public abstract class AppInfoBase extends PreferenceFragment
+ implements ApplicationsState.Callbacks {
+
+ public static final String ARG_PACKAGE_NAME = "package";
+
+ protected static final String TAG = AppInfoBase.class.getSimpleName();
+ protected static final boolean localLOGV = false;
+
+ protected boolean mAppControlRestricted = false;
+
+ protected ApplicationsState mState;
+ private ApplicationsState.Session mSession;
+ protected ApplicationsState.AppEntry mAppEntry;
+ protected PackageInfo mPackageInfo;
+ protected String mPackageName;
+
+ protected IUsbManager mUsbManager;
+ protected DevicePolicyManager mDpm;
+ protected UserManager mUserManager;
+ protected PackageManager mPm;
+
+ // Dialog identifiers used in showDialog
+ protected static final int DLG_BASE = 0;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mState = ApplicationsState.getInstance(getActivity().getApplication());
+ mSession = mState.newSession(this);
+ Context context = getActivity();
+ mDpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ mPm = context.getPackageManager();
+ IBinder b = ServiceManager.getService(Context.USB_SERVICE);
+ mUsbManager = IUsbManager.Stub.asInterface(b);
+
+ // Need to make sure we have loaded applications at this point.
+ mSession.resume();
+
+ retrieveAppEntry();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mAppControlRestricted = mUserManager.hasUserRestriction(UserManager.DISALLOW_APPS_CONTROL);
+ mSession.resume();
+
+ if (!refreshUi()) {
+ setIntentAndFinish(true, true);
+ }
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ mSession.pause();
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ mSession.release();
+ }
+
+ protected String retrieveAppEntry() {
+ final Bundle args = getArguments();
+ mPackageName = (args != null) ? args.getString(ARG_PACKAGE_NAME) : null;
+ if (mPackageName == null) {
+ Intent intent = (args == null) ?
+ getActivity().getIntent() : (Intent) args.getParcelable("intent");
+ if (intent != null) {
+ mPackageName = intent.getData().getSchemeSpecificPart();
+ }
+ }
+ mAppEntry = mState.getEntry(mPackageName);
+ if (mAppEntry != null) {
+ // Get application info again to refresh changed properties of application
+ try {
+ mPackageInfo = mPm.getPackageInfo(mAppEntry.info.packageName,
+ PackageManager.GET_DISABLED_COMPONENTS |
+ PackageManager.GET_UNINSTALLED_PACKAGES |
+ PackageManager.GET_SIGNATURES);
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Exception when retrieving package:" + mAppEntry.info.packageName, e);
+ }
+ } else {
+ Log.w(TAG, "Missing AppEntry; maybe reinstalling?");
+ mPackageInfo = null;
+ }
+
+ return mPackageName;
+ }
+
+ protected void setIntentAndFinish(boolean finish, boolean appChanged) {
+ if (localLOGV) Log.i(TAG, "appChanged="+appChanged);
+ Intent intent = new Intent();
+ intent.putExtra(ManageApplications.APP_CHG, appChanged);
+ SettingsActivity sa = (SettingsActivity)getActivity();
+ sa.finishPreferencePanel(this, Activity.RESULT_OK, intent);
+ }
+
+ protected void showDialogInner(int id, int moveErrorCode) {
+ DialogFragment newFragment = new MyAlertDialogFragment(id, moveErrorCode);
+ newFragment.setTargetFragment(this, 0);
+ newFragment.show(getFragmentManager(), "dialog " + id);
+ }
+
+ protected abstract boolean refreshUi();
+ protected abstract AlertDialog createDialog(int id, int errorCode);
+
+ @Override
+ public void onRunningStateChanged(boolean running) { }
+ @Override
+ public void onRebuildComplete(ArrayList<AppEntry> apps) { }
+ @Override
+ public void onPackageIconChanged() { }
+ @Override
+ public void onPackageSizeChanged(String packageName) { }
+ @Override
+ public void onAllSizesComputed() { }
+
+ @Override
+ public void onPackageListChanged() {
+ refreshUi();
+ }
+
+ public class MyAlertDialogFragment extends DialogFragment {
+ public MyAlertDialogFragment(int id, int errorCode) {
+ Bundle args = new Bundle();
+ args.putInt("id", id);
+ args.putInt("moveError", errorCode);
+ setArguments(args);
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ int id = getArguments().getInt("id");
+ int errorCode = getArguments().getInt("moveError");
+ Dialog dialog = createDialog(id, errorCode);
+ if (dialog == null) {
+ throw new IllegalArgumentException("unknown id " + id);
+ }
+ return dialog;
+ }
+ }
+}
diff --git a/src/com/android/settings/applications/AppInfoWithHeader.java b/src/com/android/settings/applications/AppInfoWithHeader.java
new file mode 100644
index 0000000..f7546f2
--- /dev/null
+++ b/src/com/android/settings/applications/AppInfoWithHeader.java
@@ -0,0 +1,40 @@
+/*
+ * 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.os.Bundle;
+import android.util.Log;
+
+import com.android.settings.AppHeader;
+
+public abstract class AppInfoWithHeader extends AppInfoBase {
+
+ private boolean mCreated;
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ if (mCreated) {
+ Log.w(TAG, "onActivityCreated: ignoring duplicate call");
+ return;
+ }
+ mCreated = true;
+ if (mPackageInfo == null) return;
+ AppHeader.createAppHeader(getActivity(), mPackageInfo.applicationInfo.loadIcon(mPm),
+ mPackageInfo.applicationInfo.loadLabel(mPm), null);
+ }
+}
diff --git a/src/com/android/settings/applications/AppLaunchSettings.java b/src/com/android/settings/applications/AppLaunchSettings.java
new file mode 100644
index 0000000..6379102
--- /dev/null
+++ b/src/com/android/settings/applications/AppLaunchSettings.java
@@ -0,0 +1,190 @@
+/*
+ * 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.AlertDialog;
+import android.appwidget.AppWidgetManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.hardware.usb.IUsbManager;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.text.SpannableString;
+import android.text.TextUtils;
+import android.text.style.BulletSpan;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.applications.ApplicationsState.AppEntry;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class AppLaunchSettings extends AppInfoWithHeader implements OnClickListener {
+
+ private Button mActivitiesButton;
+ private AppWidgetManager mAppWidgetManager;
+
+ private View mRootView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mAppWidgetManager = AppWidgetManager.getInstance(getActivity());
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ final View view = inflater.inflate(R.layout.app_preferred_settings, container, false);
+
+ final ViewGroup allDetails = (ViewGroup) view.findViewById(R.id.all_details);
+ Utils.forceCustomPadding(allDetails, true /* additive padding */);
+
+ mActivitiesButton = (Button) view.findViewById(R.id.clear_activities_button);
+ mRootView = view;
+
+ return view;
+ }
+
+ @Override
+ protected boolean refreshUi() {
+ retrieveAppEntry();
+ boolean hasBindAppWidgetPermission =
+ mAppWidgetManager.hasBindAppWidgetPermission(mAppEntry.info.packageName);
+
+ TextView autoLaunchTitleView = (TextView) mRootView.findViewById(R.id.auto_launch_title);
+ TextView autoLaunchView = (TextView) mRootView.findViewById(R.id.auto_launch);
+ boolean autoLaunchEnabled = hasPreferredActivities(mPm, mPackageName)
+ || hasUsbDefaults(mUsbManager, mPackageName);
+ if (!autoLaunchEnabled && !hasBindAppWidgetPermission) {
+ resetLaunchDefaultsUi(autoLaunchTitleView, autoLaunchView);
+ } else {
+ boolean useBullets = hasBindAppWidgetPermission && autoLaunchEnabled;
+
+ if (hasBindAppWidgetPermission) {
+ autoLaunchTitleView.setText(R.string.auto_launch_label_generic);
+ } else {
+ autoLaunchTitleView.setText(R.string.auto_launch_label);
+ }
+
+ CharSequence text = null;
+ int bulletIndent = getResources()
+ .getDimensionPixelSize(R.dimen.installed_app_details_bullet_offset);
+ if (autoLaunchEnabled) {
+ CharSequence autoLaunchEnableText = getText(R.string.auto_launch_enable_text);
+ SpannableString s = new SpannableString(autoLaunchEnableText);
+ if (useBullets) {
+ s.setSpan(new BulletSpan(bulletIndent), 0, autoLaunchEnableText.length(), 0);
+ }
+ text = (text == null) ?
+ TextUtils.concat(s, "\n") : TextUtils.concat(text, "\n", s, "\n");
+ }
+ if (hasBindAppWidgetPermission) {
+ CharSequence alwaysAllowBindAppWidgetsText =
+ getText(R.string.always_allow_bind_appwidgets_text);
+ SpannableString s = new SpannableString(alwaysAllowBindAppWidgetsText);
+ if (useBullets) {
+ s.setSpan(new BulletSpan(bulletIndent),
+ 0, alwaysAllowBindAppWidgetsText.length(), 0);
+ }
+ text = (text == null) ?
+ TextUtils.concat(s, "\n") : TextUtils.concat(text, "\n", s, "\n");
+ }
+ autoLaunchView.setText(text);
+ mActivitiesButton.setEnabled(true);
+ mActivitiesButton.setOnClickListener(this);
+ }
+ return true;
+ }
+
+ private void resetLaunchDefaultsUi(TextView title, TextView autoLaunchView) {
+ title.setText(R.string.auto_launch_label);
+ autoLaunchView.setText(R.string.auto_launch_disable_text);
+ // Disable clear activities button
+ mActivitiesButton.setEnabled(false);
+ }
+
+ @Override
+ protected AlertDialog createDialog(int id, int errorCode) {
+ // No dialogs for preferred launch settings.
+ return null;
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v == mActivitiesButton) {
+ if (mUsbManager != null) {
+ mPm.clearPackagePreferredActivities(mPackageName);
+ try {
+ mUsbManager.clearDefaults(mPackageName, UserHandle.myUserId());
+ } catch (RemoteException e) {
+ Log.e(TAG, "mUsbManager.clearDefaults", e);
+ }
+ mAppWidgetManager.setBindAppWidgetPermission(mPackageName, false);
+ TextView autoLaunchTitleView =
+ (TextView) mRootView.findViewById(R.id.auto_launch_title);
+ TextView autoLaunchView = (TextView) mRootView.findViewById(R.id.auto_launch);
+ resetLaunchDefaultsUi(autoLaunchTitleView, autoLaunchView);
+ }
+ }
+ }
+
+ private static boolean hasUsbDefaults(IUsbManager usbManager, String packageName) {
+ try {
+ if (usbManager != null) {
+ return usbManager.hasDefaults(packageName, UserHandle.myUserId());
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "mUsbManager.hasDefaults", e);
+ }
+ return false;
+ }
+
+ private static boolean hasPreferredActivities(PackageManager pm, String packageName) {
+ // Get list of preferred activities
+ List<ComponentName> prefActList = Collections.emptyList();
+ // Intent list cannot be null. so pass empty list
+ List<IntentFilter> intentList = Collections.emptyList();
+ pm.getPreferredActivities(intentList, prefActList, packageName);
+ if (localLOGV) {
+ Log.i(TAG, "Have " + prefActList.size() + " number of activities in preferred list");
+ }
+ return prefActList.size() > 0;
+ }
+
+ public static CharSequence getSummary(AppEntry appEntry, IUsbManager usbManager,
+ PackageManager pm, Context context) {
+ String packageName = appEntry.info.packageName;
+ boolean hasPreferred = hasPreferredActivities(pm, packageName)
+ || hasUsbDefaults(usbManager, packageName);
+ return context.getString(hasPreferred
+ ? R.string.launch_defaults_some
+ : R.string.launch_defaults_none);
+ }
+
+}
diff --git a/src/com/android/settings/applications/AppPermissionSettings.java b/src/com/android/settings/applications/AppPermissionSettings.java
new file mode 100644
index 0000000..a5b4895
--- /dev/null
+++ b/src/com/android/settings/applications/AppPermissionSettings.java
@@ -0,0 +1,221 @@
+/*
+ * 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.AlertDialog;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AppSecurityPermissions;
+import android.widget.ArrayAdapter;
+import android.widget.LinearLayout;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import com.android.internal.telephony.ISms;
+import com.android.internal.telephony.SmsUsageMonitor;
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.applications.ApplicationsState.AppEntry;
+
+import java.util.ArrayList;
+
+public class AppPermissionSettings extends AppInfoWithHeader {
+
+ private ISms mSmsManager;
+ private View mRootView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mSmsManager = ISms.Stub.asInterface(ServiceManager.getService("isms"));
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ final View view = inflater.inflate(R.layout.permission_settings, container, false);
+
+ final ViewGroup allDetails = (ViewGroup) view.findViewById(R.id.all_details);
+ Utils.forceCustomPadding(allDetails, true /* additive padding */);
+
+ mRootView = view;
+ return view;
+ }
+
+ @Override
+ protected boolean refreshUi() {
+ retrieveAppEntry();
+ // Security permissions section
+ LinearLayout permsView = (LinearLayout) mRootView.findViewById(R.id.permissions_section);
+ AppSecurityPermissions asp = new AppSecurityPermissions(getActivity(), mPackageName);
+ int premiumSmsPermission = getPremiumSmsPermission(mPackageName);
+ // Premium SMS permission implies the app also has SEND_SMS permission, so the original
+ // application permissions list doesn't have to be shown/hidden separately. The premium
+ // SMS subsection should only be visible if the app has tried to send to a premium SMS.
+ if (asp.getPermissionCount() > 0
+ || premiumSmsPermission != SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN) {
+ permsView.setVisibility(View.VISIBLE);
+ } else {
+ permsView.setVisibility(View.GONE);
+ }
+ // Premium SMS permission subsection
+ TextView securityBillingDesc = (TextView) permsView.findViewById(
+ R.id.security_settings_billing_desc);
+ LinearLayout securityBillingList = (LinearLayout) permsView.findViewById(
+ R.id.security_settings_billing_list);
+ if (premiumSmsPermission != SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN) {
+ // Show the premium SMS permission selector
+ securityBillingDesc.setVisibility(View.VISIBLE);
+ securityBillingList.setVisibility(View.VISIBLE);
+ Spinner spinner = (Spinner) permsView.findViewById(
+ R.id.security_settings_premium_sms_list);
+ ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(getActivity(),
+ R.array.security_settings_premium_sms_values,
+ android.R.layout.simple_spinner_item);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ spinner.setAdapter(adapter);
+ // List items are in the same order as SmsUsageMonitor constants, offset by 1.
+ spinner.setSelection(premiumSmsPermission - 1);
+ spinner.setOnItemSelectedListener(new PremiumSmsSelectionListener(
+ mPackageName, mSmsManager));
+ } else {
+ // Hide the premium SMS permission selector
+ securityBillingDesc.setVisibility(View.GONE);
+ securityBillingList.setVisibility(View.GONE);
+ }
+ // App permissions subsection
+ if (asp.getPermissionCount() > 0) {
+ // Make the security sections header visible
+ LinearLayout securityList = (LinearLayout) permsView.findViewById(
+ R.id.security_settings_list);
+ securityList.removeAllViews();
+ securityList.addView(asp.getPermissionsViewWithRevokeButtons());
+ // If this app is running under a shared user ID with other apps,
+ // update the description to explain this.
+ String[] packages = mPm.getPackagesForUid(mPackageInfo.applicationInfo.uid);
+ if (packages != null && packages.length > 1) {
+ ArrayList<CharSequence> pnames = new ArrayList<CharSequence>();
+ for (int i=0; i<packages.length; i++) {
+ String pkg = packages[i];
+ if (mPackageInfo.packageName.equals(pkg)) {
+ continue;
+ }
+ try {
+ ApplicationInfo ainfo = mPm.getApplicationInfo(pkg, 0);
+ pnames.add(ainfo.loadLabel(mPm));
+ } catch (PackageManager.NameNotFoundException e) {
+ }
+ }
+ final int N = pnames.size();
+ if (N > 0) {
+ final Resources res = getActivity().getResources();
+ String appListStr;
+ if (N == 1) {
+ appListStr = pnames.get(0).toString();
+ } else if (N == 2) {
+ appListStr = res.getString(R.string.join_two_items, pnames.get(0),
+ pnames.get(1));
+ } else {
+ appListStr = pnames.get(N-2).toString();
+ for (int i=N-3; i>=0; i--) {
+ appListStr = res.getString(i == 0 ? R.string.join_many_items_first
+ : R.string.join_many_items_middle, pnames.get(i), appListStr);
+ }
+ appListStr = res.getString(R.string.join_many_items_last,
+ appListStr, pnames.get(N-1));
+ }
+ TextView descr = (TextView) mRootView.findViewById(
+ R.id.security_settings_desc);
+ descr.setText(res.getString(R.string.security_settings_desc_multi,
+ mPackageInfo.applicationInfo.loadLabel(mPm), appListStr));
+ }
+ }
+ }
+ return true;
+ }
+
+ private int getPremiumSmsPermission(String packageName) {
+ try {
+ if (mSmsManager != null) {
+ return mSmsManager.getPremiumSmsPermission(packageName);
+ }
+ } catch (RemoteException ex) {
+ // ignored
+ }
+ return SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN;
+ }
+
+ @Override
+ protected AlertDialog createDialog(int id, int errorCode) {
+ // No dialogs for Permissions screen.
+ return null;
+ }
+
+ public static CharSequence getSummary(AppEntry appEntry, Context context) {
+ AppSecurityPermissions asp = new AppSecurityPermissions(context,
+ appEntry.info.packageName);
+ int count = asp.getPermissionCount();
+ return context.getResources().getQuantityString(R.plurals.permissions_summary,
+ count, count);
+ }
+
+ private static class PremiumSmsSelectionListener implements AdapterView.OnItemSelectedListener {
+ private final String mPackageName;
+ private final ISms mSmsManager;
+
+ PremiumSmsSelectionListener(String packageName, ISms smsManager) {
+ mPackageName = packageName;
+ mSmsManager = smsManager;
+ }
+
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position,
+ long id) {
+ if (position >= 0 && position < 3) {
+ if (localLOGV) Log.d(TAG, "Selected premium SMS policy " + position);
+ setPremiumSmsPermission(mPackageName, (position + 1));
+ } else {
+ Log.e(TAG, "Error: unknown premium SMS policy " + position);
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ // Ignored
+ }
+
+ private void setPremiumSmsPermission(String packageName, int permission) {
+ try {
+ if (mSmsManager != null) {
+ mSmsManager.setPremiumSmsPermission(packageName, permission);
+ }
+ } catch (RemoteException ex) {
+ // ignored
+ }
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/com/android/settings/applications/AppStorageSettings.java b/src/com/android/settings/applications/AppStorageSettings.java
new file mode 100644
index 0000000..5ae5e8f
--- /dev/null
+++ b/src/com/android/settings/applications/AppStorageSettings.java
@@ -0,0 +1,501 @@
+/*
+ * 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.ActivityManager;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageDataObserver;
+import android.content.pm.IPackageMoveObserver;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.text.format.Formatter;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.applications.ApplicationsState.AppEntry;
+import com.android.settings.applications.ApplicationsState.Callbacks;
+
+public class AppStorageSettings extends AppInfoWithHeader implements OnClickListener, Callbacks {
+ private static final String TAG = "AppStorageSettings";
+
+ //internal constants used in Handler
+ private static final int OP_SUCCESSFUL = 1;
+ private static final int OP_FAILED = 2;
+ private static final int MSG_CLEAR_USER_DATA = 1;
+ private static final int MSG_CLEAR_CACHE = 3;
+ private static final int MSG_PACKAGE_MOVE = 4;
+
+ // invalid size value used initially and also when size retrieval through PackageManager
+ // fails for whatever reason
+ private static final int SIZE_INVALID = -1;
+
+ // Result code identifiers
+ public static final int REQUEST_MANAGE_SPACE = 2;
+
+ private static final int DLG_CLEAR_DATA = DLG_BASE + 1;
+ private static final int DLG_CANNOT_CLEAR_DATA = DLG_BASE + 2;
+ private static final int DLG_MOVE_FAILED = DLG_BASE + 3;
+
+ private CanBeOnSdCardChecker mCanBeOnSdCardChecker;
+ private TextView mTotalSize;
+ private TextView mAppSize;
+ private TextView mDataSize;
+ private TextView mExternalCodeSize;
+ private TextView mExternalDataSize;
+
+ // Views related to cache info
+ private TextView mCacheSize;
+ private Button mClearDataButton;
+ private Button mClearCacheButton;
+ private Button mMoveAppButton;
+ private boolean mMoveInProgress = false;
+
+ private boolean mCanClearData = true;
+ private boolean mHaveSizes = false;
+
+ private long mLastCodeSize = -1;
+ private long mLastDataSize = -1;
+ private long mLastExternalCodeSize = -1;
+ private long mLastExternalDataSize = -1;
+ private long mLastCacheSize = -1;
+ private long mLastTotalSize = -1;
+
+ private ClearCacheObserver mClearCacheObserver;
+ private ClearUserDataObserver mClearDataObserver;
+ private PackageMoveObserver mPackageMoveObserver;
+
+ // Resource strings
+ private CharSequence mInvalidSizeStr;
+ private CharSequence mComputingStr;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mCanBeOnSdCardChecker = new CanBeOnSdCardChecker();
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ final View view = inflater.inflate(R.layout.storage_settings, container, false);
+
+ final ViewGroup allDetails = (ViewGroup)view.findViewById(R.id.all_details);
+ Utils.forceCustomPadding(allDetails, true /* additive padding */);
+ mComputingStr = getActivity().getText(R.string.computing_size);
+ mInvalidSizeStr = getActivity().getText(R.string.invalid_size_value);
+
+ // Set default values on sizes
+ mTotalSize = (TextView)view.findViewById(R.id.total_size_text);
+ mAppSize = (TextView)view.findViewById(R.id.application_size_text);
+ mDataSize = (TextView)view.findViewById(R.id.data_size_text);
+ mExternalCodeSize = (TextView)view.findViewById(R.id.external_code_size_text);
+ mExternalDataSize = (TextView)view.findViewById(R.id.external_data_size_text);
+
+ if (Environment.isExternalStorageEmulated()) {
+ ((View)mExternalCodeSize.getParent()).setVisibility(View.GONE);
+ ((View)mExternalDataSize.getParent()).setVisibility(View.GONE);
+ }
+
+ // Initialize clear data and move install location buttons
+ View data_buttons_panel = view.findViewById(R.id.data_buttons_panel);
+ mMoveAppButton = (Button) data_buttons_panel.findViewById(R.id.left_button);
+
+ // Cache section
+ mCacheSize = (TextView)view.findViewById(R.id.cache_size_text);
+ mClearCacheButton = (Button)view.findViewById(R.id.clear_cache_button);
+ mClearDataButton = (Button) data_buttons_panel.findViewById(R.id.right_button);
+
+ return view;
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v == mClearCacheButton) {
+ // Lazy initialization of observer
+ if (mClearCacheObserver == null) {
+ mClearCacheObserver = new ClearCacheObserver();
+ }
+ mPm.deleteApplicationCacheFiles(mPackageName, mClearCacheObserver);
+ } else if(v == mClearDataButton) {
+ if (mAppEntry.info.manageSpaceActivityName != null) {
+ if (!Utils.isMonkeyRunning()) {
+ Intent intent = new Intent(Intent.ACTION_DEFAULT);
+ intent.setClassName(mAppEntry.info.packageName,
+ mAppEntry.info.manageSpaceActivityName);
+ startActivityForResult(intent, REQUEST_MANAGE_SPACE);
+ }
+ } else {
+ showDialogInner(DLG_CLEAR_DATA, 0);
+ }
+ } else if (v == mMoveAppButton) {
+ if (mPackageMoveObserver == null) {
+ mPackageMoveObserver = new PackageMoveObserver();
+ }
+ int moveFlags = (mAppEntry.info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0 ?
+ PackageManager.MOVE_INTERNAL : PackageManager.MOVE_EXTERNAL_MEDIA;
+ mMoveInProgress = true;
+ refreshButtons();
+ mPm.movePackage(mAppEntry.info.packageName, mPackageMoveObserver, moveFlags);
+ }
+ }
+
+ private String getSizeStr(long size) {
+ if (size == SIZE_INVALID) {
+ return mInvalidSizeStr.toString();
+ }
+ return Formatter.formatFileSize(getActivity(), size);
+ }
+
+ private void refreshSizeInfo() {
+ if (mAppEntry.size == ApplicationsState.SIZE_INVALID
+ || mAppEntry.size == ApplicationsState.SIZE_UNKNOWN) {
+ mLastCodeSize = mLastDataSize = mLastCacheSize = mLastTotalSize = -1;
+ if (!mHaveSizes) {
+ mAppSize.setText(mComputingStr);
+ mDataSize.setText(mComputingStr);
+ mCacheSize.setText(mComputingStr);
+ mTotalSize.setText(mComputingStr);
+ }
+ mClearDataButton.setEnabled(false);
+ mClearCacheButton.setEnabled(false);
+
+ } else {
+ mHaveSizes = true;
+ long codeSize = mAppEntry.codeSize;
+ long dataSize = mAppEntry.dataSize;
+ if (Environment.isExternalStorageEmulated()) {
+ codeSize += mAppEntry.externalCodeSize;
+ dataSize += mAppEntry.externalDataSize;
+ } else {
+ if (mLastExternalCodeSize != mAppEntry.externalCodeSize) {
+ mLastExternalCodeSize = mAppEntry.externalCodeSize;
+ mExternalCodeSize.setText(getSizeStr(mAppEntry.externalCodeSize));
+ }
+ if (mLastExternalDataSize != mAppEntry.externalDataSize) {
+ mLastExternalDataSize = mAppEntry.externalDataSize;
+ mExternalDataSize.setText(getSizeStr( mAppEntry.externalDataSize));
+ }
+ }
+ if (mLastCodeSize != codeSize) {
+ mLastCodeSize = codeSize;
+ mAppSize.setText(getSizeStr(codeSize));
+ }
+ if (mLastDataSize != dataSize) {
+ mLastDataSize = dataSize;
+ mDataSize.setText(getSizeStr(dataSize));
+ }
+ long cacheSize = mAppEntry.cacheSize + mAppEntry.externalCacheSize;
+ if (mLastCacheSize != cacheSize) {
+ mLastCacheSize = cacheSize;
+ mCacheSize.setText(getSizeStr(cacheSize));
+ }
+ if (mLastTotalSize != mAppEntry.size) {
+ mLastTotalSize = mAppEntry.size;
+ mTotalSize.setText(getSizeStr(mAppEntry.size));
+ }
+
+ if ((mAppEntry.dataSize+ mAppEntry.externalDataSize) <= 0 || !mCanClearData) {
+ mClearDataButton.setEnabled(false);
+ } else {
+ mClearDataButton.setEnabled(true);
+ mClearDataButton.setOnClickListener(this);
+ }
+ if (cacheSize <= 0) {
+ mClearCacheButton.setEnabled(false);
+ } else {
+ mClearCacheButton.setEnabled(true);
+ mClearCacheButton.setOnClickListener(this);
+ }
+ }
+ if (mAppControlRestricted) {
+ mClearCacheButton.setEnabled(false);
+ mClearDataButton.setEnabled(false);
+ }
+ }
+
+ @Override
+ protected boolean refreshUi() {
+ retrieveAppEntry();
+ refreshButtons();
+ refreshSizeInfo();
+ return true;
+ }
+
+ private void refreshButtons() {
+ if (!mMoveInProgress) {
+ initMoveButton();
+ initDataButtons();
+ } else {
+ mMoveAppButton.setText(R.string.moving);
+ mMoveAppButton.setEnabled(false);
+ }
+ }
+
+ private void initDataButtons() {
+ // If the app doesn't have its own space management UI
+ // And it's a system app that doesn't allow clearing user data or is an active admin
+ // Then disable the Clear Data button.
+ if (mAppEntry.info.manageSpaceActivityName == null
+ && ((mAppEntry.info.flags&(ApplicationInfo.FLAG_SYSTEM
+ | ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA))
+ == ApplicationInfo.FLAG_SYSTEM
+ || mDpm.packageHasActiveAdmins(mPackageName))) {
+ mClearDataButton.setText(R.string.clear_user_data_text);
+ mClearDataButton.setEnabled(false);
+ mCanClearData = false;
+ } else {
+ if (mAppEntry.info.manageSpaceActivityName != null) {
+ mClearDataButton.setText(R.string.manage_space_text);
+ } else {
+ mClearDataButton.setText(R.string.clear_user_data_text);
+ }
+ mClearDataButton.setOnClickListener(this);
+ }
+
+ if (mAppControlRestricted) {
+ mClearDataButton.setEnabled(false);
+ }
+ }
+
+ private void initMoveButton() {
+ if (Environment.isExternalStorageEmulated()) {
+ mMoveAppButton.setVisibility(View.INVISIBLE);
+ return;
+ }
+ boolean dataOnly = (mPackageInfo == null) && (mAppEntry != null);
+ boolean moveDisable = true;
+ if (dataOnly) {
+ mMoveAppButton.setText(R.string.move_app);
+ } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
+ mMoveAppButton.setText(R.string.move_app_to_internal);
+ // Always let apps move to internal storage from sdcard.
+ moveDisable = false;
+ } else {
+ mMoveAppButton.setText(R.string.move_app_to_sdcard);
+ mCanBeOnSdCardChecker.init();
+ moveDisable = !mCanBeOnSdCardChecker.check(mAppEntry.info);
+ }
+ if (moveDisable || mAppControlRestricted) {
+ mMoveAppButton.setEnabled(false);
+ } else {
+ mMoveAppButton.setOnClickListener(this);
+ mMoveAppButton.setEnabled(true);
+ }
+ }
+
+ /*
+ * Private method to initiate clearing user data when the user clicks the clear data
+ * button for a system package
+ */
+ private void initiateClearUserData() {
+ mClearDataButton.setEnabled(false);
+ // Invoke uninstall or clear user data based on sysPackage
+ String packageName = mAppEntry.info.packageName;
+ Log.i(TAG, "Clearing user data for package : " + packageName);
+ if (mClearDataObserver == null) {
+ mClearDataObserver = new ClearUserDataObserver();
+ }
+ ActivityManager am = (ActivityManager)
+ getActivity().getSystemService(Context.ACTIVITY_SERVICE);
+ boolean res = am.clearApplicationUserData(packageName, mClearDataObserver);
+ if (!res) {
+ // Clearing data failed for some obscure reason. Just log error for now
+ Log.i(TAG, "Couldnt clear application user data for package:"+packageName);
+ showDialogInner(DLG_CANNOT_CLEAR_DATA, 0);
+ } else {
+ mClearDataButton.setText(R.string.recompute_size);
+ }
+ }
+
+ private void processMoveMsg(Message msg) {
+ int result = msg.arg1;
+ String packageName = mAppEntry.info.packageName;
+ // Refresh the button attributes.
+ mMoveInProgress = false;
+ if (result == PackageManager.MOVE_SUCCEEDED) {
+ Log.i(TAG, "Moved resources for " + packageName);
+ // Refresh size information again.
+ mState.requestSize(mAppEntry.info.packageName);
+ } else {
+ showDialogInner(DLG_MOVE_FAILED, result);
+ }
+ refreshUi();
+ }
+
+ /*
+ * Private method to handle clear message notification from observer when
+ * the async operation from PackageManager is complete
+ */
+ private void processClearMsg(Message msg) {
+ int result = msg.arg1;
+ String packageName = mAppEntry.info.packageName;
+ mClearDataButton.setText(R.string.clear_user_data_text);
+ if(result == OP_SUCCESSFUL) {
+ Log.i(TAG, "Cleared user data for package : "+packageName);
+ mState.requestSize(mAppEntry.info.packageName);
+ } else {
+ mClearDataButton.setEnabled(true);
+ }
+ }
+
+ private CharSequence getMoveErrMsg(int errCode) {
+ switch (errCode) {
+ case PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE:
+ return getActivity().getString(R.string.insufficient_storage);
+ case PackageManager.MOVE_FAILED_DOESNT_EXIST:
+ return getActivity().getString(R.string.does_not_exist);
+ case PackageManager.MOVE_FAILED_FORWARD_LOCKED:
+ return getActivity().getString(R.string.app_forward_locked);
+ case PackageManager.MOVE_FAILED_INVALID_LOCATION:
+ return getActivity().getString(R.string.invalid_location);
+ case PackageManager.MOVE_FAILED_SYSTEM_PACKAGE:
+ return getActivity().getString(R.string.system_package);
+ case PackageManager.MOVE_FAILED_INTERNAL_ERROR:
+ return "";
+ }
+ return "";
+ }
+
+ @Override
+ protected AlertDialog createDialog(int id, int errorCode) {
+ switch (id) {
+ case DLG_CLEAR_DATA:
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(getActivity().getText(R.string.clear_data_dlg_title))
+ .setMessage(getActivity().getText(R.string.clear_data_dlg_text))
+ .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ // Clear user data here
+ initiateClearUserData();
+ }
+ })
+ .setNegativeButton(R.string.dlg_cancel, null)
+ .create();
+ case DLG_CANNOT_CLEAR_DATA:
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(getActivity().getText(R.string.clear_failed_dlg_title))
+ .setMessage(getActivity().getText(R.string.clear_failed_dlg_text))
+ .setNeutralButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ mClearDataButton.setEnabled(false);
+ //force to recompute changed value
+ setIntentAndFinish(false, false);
+ }
+ })
+ .create();
+ case DLG_MOVE_FAILED:
+ CharSequence msg = getActivity().getString(R.string.move_app_failed_dlg_text,
+ getMoveErrMsg(errorCode));
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(getActivity().getText(R.string.move_app_failed_dlg_title))
+ .setMessage(msg)
+ .setNeutralButton(R.string.dlg_ok, null)
+ .create();
+ }
+ return null;
+ }
+
+ @Override
+ public void onPackageSizeChanged(String packageName) {
+ if (packageName.equals(mAppEntry.info.packageName)) {
+ refreshSizeInfo();
+ }
+ }
+
+ private final Handler mHandler = new Handler() {
+ public void handleMessage(Message msg) {
+ if (getView() == null) {
+ return;
+ }
+ switch (msg.what) {
+ case MSG_CLEAR_USER_DATA:
+ processClearMsg(msg);
+ break;
+ case MSG_CLEAR_CACHE:
+ // Refresh size info
+ mState.requestSize(mPackageName);
+ break;
+ case MSG_PACKAGE_MOVE:
+ processMoveMsg(msg);
+ break;
+ }
+ }
+ };
+
+ public static CharSequence getSummary(AppEntry appEntry, Context context) {
+ if (appEntry.size == ApplicationsState.SIZE_INVALID
+ || appEntry.size == ApplicationsState.SIZE_UNKNOWN) {
+ return context.getText(R.string.computing_size);
+ } else {
+ CharSequence storageType = context.getString(
+ (appEntry.info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0
+ ? R.string.storage_type_external
+ : R.string.storage_type_internal);
+ return context.getString(R.string.storage_summary_format,
+ getSize(appEntry, context), storageType);
+ }
+ }
+
+ private static CharSequence getSize(AppEntry appEntry, Context context) {
+ long size = appEntry.size;
+ if (size == SIZE_INVALID) {
+ return context.getText(R.string.invalid_size_value);
+ }
+ return Formatter.formatFileSize(context, size);
+ }
+
+ class ClearCacheObserver extends IPackageDataObserver.Stub {
+ public void onRemoveCompleted(final String packageName, final boolean succeeded) {
+ final Message msg = mHandler.obtainMessage(MSG_CLEAR_CACHE);
+ msg.arg1 = succeeded ? OP_SUCCESSFUL : OP_FAILED;
+ mHandler.sendMessage(msg);
+ }
+ }
+
+ class ClearUserDataObserver extends IPackageDataObserver.Stub {
+ public void onRemoveCompleted(final String packageName, final boolean succeeded) {
+ final Message msg = mHandler.obtainMessage(MSG_CLEAR_USER_DATA);
+ msg.arg1 = succeeded?OP_SUCCESSFUL:OP_FAILED;
+ mHandler.sendMessage(msg);
+ }
+ }
+
+ class PackageMoveObserver extends IPackageMoveObserver.Stub {
+ public void packageMoved(String packageName, int returnCode) throws RemoteException {
+ final Message msg = mHandler.obtainMessage(MSG_PACKAGE_MOVE);
+ msg.arg1 = returnCode;
+ mHandler.sendMessage(msg);
+ }
+ }
+
+}
diff --git a/src/com/android/settings/applications/HeaderPreference.java b/src/com/android/settings/applications/HeaderPreference.java
new file mode 100644
index 0000000..57fe9f3
--- /dev/null
+++ b/src/com/android/settings/applications/HeaderPreference.java
@@ -0,0 +1,60 @@
+/*
+ * 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.content.Context;
+import android.content.res.TypedArray;
+import android.preference.Preference;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.settings.R;
+import com.android.settings.Utils;
+
+public class HeaderPreference extends Preference {
+
+ private View mRootView;
+
+ public HeaderPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ final TypedArray a = context.obtainStyledAttributes(
+ attrs, com.android.internal.R.styleable.Preference, 0, 0);
+ int layoutResource = a.getResourceId(com.android.internal.R.styleable.Preference_layout,
+ 0);
+ if (layoutResource == 0) {
+ throw new IllegalArgumentException("HeaderPreference requires a layout to be defined");
+ }
+ // Need to create view now so that findViewById can be called immediately.
+ final View view = LayoutInflater.from(getContext())
+ .inflate(layoutResource, null, false);
+
+ final ViewGroup allDetails = (ViewGroup) view.findViewById(R.id.all_details);
+ Utils.forceCustomPadding(allDetails, true /* additive padding */);
+ mRootView = view;
+ }
+
+ @Override
+ protected View onCreateView(ViewGroup parent) {
+ return mRootView;
+ }
+
+ public View findViewById(int id) {
+ return mRootView.findViewById(id);
+ }
+
+}
diff --git a/src/com/android/settings/applications/InstalledAppDetails.java b/src/com/android/settings/applications/InstalledAppDetails.java
index 3aa948d..d77d63f 100755
--- a/src/com/android/settings/applications/InstalledAppDetails.java
+++ b/src/com/android/settings/applications/InstalledAppDetails.java
@@ -16,75 +16,47 @@
package com.android.settings.applications;
-import com.android.internal.telephony.ISms;
-import com.android.internal.telephony.SmsUsageMonitor;
-import com.android.settings.R;
-import com.android.settings.SettingsActivity;
-import com.android.settings.Utils;
-import com.android.settings.applications.ApplicationsState.AppEntry;
-
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.DialogFragment;
-import android.app.Fragment;
-import android.app.INotificationManager;
-import android.app.admin.DevicePolicyManager;
-import android.appwidget.AppWidgetManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageDataObserver;
-import android.content.pm.IPackageMoveObserver;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.Resources;
-import android.hardware.usb.IUsbManager;
+import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
-import android.os.Environment;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
-import android.os.UserManager;
-import android.text.SpannableString;
-import android.text.TextUtils;
-import android.text.format.Formatter;
-import android.text.style.BulletSpan;
-import android.util.Log;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import android.view.LayoutInflater;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceClickListener;
+import android.provider.Settings;
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.AppSecurityPermissions;
-import android.widget.ArrayAdapter;
import android.widget.Button;
-import android.widget.CheckBox;
-import android.widget.CompoundButton;
import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.Spinner;
import android.widget.TextView;
+import com.android.settings.R;
+import com.android.settings.SettingsActivity;
+import com.android.settings.Utils;
+import com.android.settings.applications.ApplicationsState.AppEntry;
+import com.android.settings.notification.NotificationAppList;
+import com.android.settings.notification.NotificationAppList.AppRow;
+import com.android.settings.notification.NotificationAppList.Backend;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
/**
* Activity to display application information from Settings. This activity presents
* extended information associated with a package like code, data, total size, permissions
@@ -94,227 +66,48 @@ import android.widget.TextView;
* For non-system applications, there is no option to clear data. Instead there is an option to
* uninstall the application.
*/
-public class InstalledAppDetails extends Fragment
- implements View.OnClickListener, CompoundButton.OnCheckedChangeListener,
- ApplicationsState.Callbacks {
- private static final String TAG="InstalledAppDetails";
- private static final boolean localLOGV = false;
-
- public static final String ARG_PACKAGE_NAME = "package";
+public class InstalledAppDetails extends AppInfoBase
+ implements View.OnClickListener, OnPreferenceClickListener {
+
+ // Menu identifiers
+ public static final int UNINSTALL_ALL_USERS_MENU = 1;
+
+ // Result code identifiers
+ public static final int REQUEST_UNINSTALL = 0;
+ private static final int SUB_INFO_FRAGMENT = 1;
+
+ private static final int DLG_FORCE_STOP = DLG_BASE + 1;
+ private static final int DLG_DISABLE = DLG_BASE + 2;
+ private static final int DLG_SPECIAL_DISABLE = DLG_BASE + 3;
+ private static final int DLG_FACTORY_RESET = DLG_BASE + 4;
+
+ private static final String KEY_HEADER = "header_view";
+ private static final String KEY_NOTIFICATION = "notification_settings";
+ private static final String KEY_STORAGE = "storage_settings";
+ private static final String KEY_PERMISSION = "permission_settings";
+ private static final String KEY_DATA = "data_settings";
+ private static final String KEY_LAUNCH = "preferred_settings";
+
+ private final HashSet<String> mHomePackages = new HashSet<String>();
- private PackageManager mPm;
- private UserManager mUserManager;
- private IUsbManager mUsbManager;
- private AppWidgetManager mAppWidgetManager;
- private DevicePolicyManager mDpm;
- private ISms mSmsManager;
- private ApplicationsState mState;
- private ApplicationsState.Session mSession;
- private ApplicationsState.AppEntry mAppEntry;
private boolean mInitialized;
private boolean mShowUninstalled;
- private PackageInfo mPackageInfo;
- private CanBeOnSdCardChecker mCanBeOnSdCardChecker;
- private View mRootView;
+ private HeaderPreference mHeader;
private Button mUninstallButton;
private View mMoreControlButtons;
private Button mSpecialDisableButton;
- private boolean mMoveInProgress = false;
private boolean mUpdatedSysApp = false;
- private Button mActivitiesButton;
- private View mScreenCompatSection;
- private CheckBox mAskCompatibilityCB;
- private CheckBox mEnableCompatibilityCB;
- private boolean mCanClearData = true;
- private boolean mAppControlRestricted = false;
private TextView mAppVersion;
- private TextView mTotalSize;
- private TextView mAppSize;
- private TextView mDataSize;
- private TextView mExternalCodeSize;
- private TextView mExternalDataSize;
- private ClearUserDataObserver mClearDataObserver;
- // Views related to cache info
- private TextView mCacheSize;
- private Button mClearCacheButton;
- private ClearCacheObserver mClearCacheObserver;
private Button mForceStopButton;
- private Button mClearDataButton;
- private Button mMoveAppButton;
- private CompoundButton mNotificationSwitch;
-
- private PackageMoveObserver mPackageMoveObserver;
-
- private final HashSet<String> mHomePackages = new HashSet<String>();
+ private Preference mNotificationPreference;
+ private Preference mStoragePreference;
+ private Preference mPermissionsPreference;
+ private Preference mLaunchPreference;
+ private Preference mDataPreference;
private boolean mDisableAfterUninstall;
-
- private boolean mHaveSizes = false;
- private long mLastCodeSize = -1;
- private long mLastDataSize = -1;
- private long mLastExternalCodeSize = -1;
- private long mLastExternalDataSize = -1;
- private long mLastCacheSize = -1;
- private long mLastTotalSize = -1;
-
- //internal constants used in Handler
- private static final int OP_SUCCESSFUL = 1;
- private static final int OP_FAILED = 2;
- private static final int CLEAR_USER_DATA = 1;
- private static final int CLEAR_CACHE = 3;
- private static final int PACKAGE_MOVE = 4;
-
- // invalid size value used initially and also when size retrieval through PackageManager
- // fails for whatever reason
- private static final int SIZE_INVALID = -1;
-
- // Resource strings
- private CharSequence mInvalidSizeStr;
- private CharSequence mComputingStr;
-
- // Dialog identifiers used in showDialog
- private static final int DLG_BASE = 0;
- private static final int DLG_CLEAR_DATA = DLG_BASE + 1;
- private static final int DLG_FACTORY_RESET = DLG_BASE + 2;
- private static final int DLG_APP_NOT_FOUND = DLG_BASE + 3;
- private static final int DLG_CANNOT_CLEAR_DATA = DLG_BASE + 4;
- private static final int DLG_FORCE_STOP = DLG_BASE + 5;
- private static final int DLG_MOVE_FAILED = DLG_BASE + 6;
- private static final int DLG_DISABLE = DLG_BASE + 7;
- private static final int DLG_DISABLE_NOTIFICATIONS = DLG_BASE + 8;
- private static final int DLG_SPECIAL_DISABLE = DLG_BASE + 9;
-
- // Menu identifiers
- public static final int UNINSTALL_ALL_USERS_MENU = 1;
-
- // Result code identifiers
- public static final int REQUEST_UNINSTALL = 1;
- public static final int REQUEST_MANAGE_SPACE = 2;
-
- private Handler mHandler = new Handler() {
- public void handleMessage(Message msg) {
- // If the fragment is gone, don't process any more messages.
- if (getView() == null) {
- return;
- }
- switch (msg.what) {
- case CLEAR_USER_DATA:
- processClearMsg(msg);
- break;
- case CLEAR_CACHE:
- // Refresh size info
- mState.requestSize(mAppEntry.info.packageName);
- break;
- case PACKAGE_MOVE:
- processMoveMsg(msg);
- break;
- default:
- break;
- }
- }
- };
-
- class ClearUserDataObserver extends IPackageDataObserver.Stub {
- public void onRemoveCompleted(final String packageName, final boolean succeeded) {
- final Message msg = mHandler.obtainMessage(CLEAR_USER_DATA);
- msg.arg1 = succeeded?OP_SUCCESSFUL:OP_FAILED;
- mHandler.sendMessage(msg);
- }
- }
-
- class ClearCacheObserver extends IPackageDataObserver.Stub {
- public void onRemoveCompleted(final String packageName, final boolean succeeded) {
- final Message msg = mHandler.obtainMessage(CLEAR_CACHE);
- msg.arg1 = succeeded ? OP_SUCCESSFUL:OP_FAILED;
- mHandler.sendMessage(msg);
- }
- }
-
- class PackageMoveObserver extends IPackageMoveObserver.Stub {
- public void packageMoved(String packageName, int returnCode) throws RemoteException {
- final Message msg = mHandler.obtainMessage(PACKAGE_MOVE);
- msg.arg1 = returnCode;
- mHandler.sendMessage(msg);
- }
- }
-
- private String getSizeStr(long size) {
- if (size == SIZE_INVALID) {
- return mInvalidSizeStr.toString();
- }
- return Formatter.formatFileSize(getActivity(), size);
- }
-
- private void initDataButtons() {
- // If the app doesn't have its own space management UI
- // And it's a system app that doesn't allow clearing user data or is an active admin
- // Then disable the Clear Data button.
- if (mAppEntry.info.manageSpaceActivityName == null
- && ((mAppEntry.info.flags&(ApplicationInfo.FLAG_SYSTEM
- | ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA))
- == ApplicationInfo.FLAG_SYSTEM
- || mDpm.packageHasActiveAdmins(mPackageInfo.packageName))) {
- mClearDataButton.setText(R.string.clear_user_data_text);
- mClearDataButton.setEnabled(false);
- mCanClearData = false;
- } else {
- if (mAppEntry.info.manageSpaceActivityName != null) {
- mClearDataButton.setText(R.string.manage_space_text);
- } else {
- mClearDataButton.setText(R.string.clear_user_data_text);
- }
- mClearDataButton.setOnClickListener(this);
- }
-
- if (mAppControlRestricted) {
- mClearDataButton.setEnabled(false);
- }
- }
-
- private CharSequence getMoveErrMsg(int errCode) {
- switch (errCode) {
- case PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE:
- return getActivity().getString(R.string.insufficient_storage);
- case PackageManager.MOVE_FAILED_DOESNT_EXIST:
- return getActivity().getString(R.string.does_not_exist);
- case PackageManager.MOVE_FAILED_FORWARD_LOCKED:
- return getActivity().getString(R.string.app_forward_locked);
- case PackageManager.MOVE_FAILED_INVALID_LOCATION:
- return getActivity().getString(R.string.invalid_location);
- case PackageManager.MOVE_FAILED_SYSTEM_PACKAGE:
- return getActivity().getString(R.string.system_package);
- case PackageManager.MOVE_FAILED_INTERNAL_ERROR:
- return "";
- }
- return "";
- }
-
- private void initMoveButton() {
- if (Environment.isExternalStorageEmulated()) {
- mMoveAppButton.setVisibility(View.INVISIBLE);
- return;
- }
- boolean dataOnly = false;
- dataOnly = (mPackageInfo == null) && (mAppEntry != null);
- boolean moveDisable = true;
- if (dataOnly) {
- mMoveAppButton.setText(R.string.move_app);
- } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
- mMoveAppButton.setText(R.string.move_app_to_internal);
- // Always let apps move to internal storage from sdcard.
- moveDisable = false;
- } else {
- mMoveAppButton.setText(R.string.move_app_to_sdcard);
- mCanBeOnSdCardChecker.init();
- moveDisable = !mCanBeOnSdCardChecker.check(mAppEntry.info);
- }
- if (moveDisable || mAppControlRestricted) {
- mMoveAppButton.setEnabled(false);
- } else {
- mMoveAppButton.setOnClickListener(this);
- mMoveAppButton.setEnabled(true);
- }
- }
+ // Used for updating notification preference.
+ private final Backend mBackend = new Backend();
private boolean handleDisableable(Button button) {
boolean disableable = false;
@@ -407,108 +200,48 @@ public class InstalledAppDetails extends Fragment
}
}
- private void initNotificationButton() {
- INotificationManager nm = INotificationManager.Stub.asInterface(
- ServiceManager.getService(Context.NOTIFICATION_SERVICE));
- boolean enabled = true; // default on
- try {
- enabled = nm.areNotificationsEnabledForPackage(mAppEntry.info.packageName,
- mAppEntry.info.uid);
- } catch (android.os.RemoteException ex) {
- // this does not bode well
- }
- mNotificationSwitch.setChecked(enabled);
- if (Utils.isSystemPackage(mPm, mPackageInfo)) {
- mNotificationSwitch.setEnabled(false);
- } else if ((mPackageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) == 0) {
- // App is not installed on the current user
- mNotificationSwitch.setEnabled(false);
- } else {
- mNotificationSwitch.setEnabled(true);
- mNotificationSwitch.setOnCheckedChangeListener(this);
- }
- }
-
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
- mState = ApplicationsState.getInstance(getActivity().getApplication());
- mSession = mState.newSession(this);
- mPm = getActivity().getPackageManager();
- mUserManager = (UserManager)getActivity().getSystemService(Context.USER_SERVICE);
- IBinder b = ServiceManager.getService(Context.USB_SERVICE);
- mUsbManager = IUsbManager.Stub.asInterface(b);
- mAppWidgetManager = AppWidgetManager.getInstance(getActivity());
- mDpm = (DevicePolicyManager)getActivity().getSystemService(Context.DEVICE_POLICY_SERVICE);
- mSmsManager = ISms.Stub.asInterface(ServiceManager.getService("isms"));
-
- mCanBeOnSdCardChecker = new CanBeOnSdCardChecker();
-
- // Need to make sure we have loaded applications at this point.
- mSession.resume();
-
- retrieveAppEntry();
-
setHasOptionsMenu(true);
+ addPreferencesFromResource(R.xml.installed_app_details);
}
- @Override
- public View onCreateView(
- LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- final View view = inflater.inflate(R.layout.installed_app_details, container, false);
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ handleHeader();
- final ViewGroup allDetails = (ViewGroup) view.findViewById(R.id.all_details);
- Utils.forceCustomPadding(allDetails, true /* additive padding */);
-
- mRootView = view;
- mComputingStr = getActivity().getText(R.string.computing_size);
-
- // Set default values on sizes
- mTotalSize = (TextView) view.findViewById(R.id.total_size_text);
- mAppSize = (TextView) view.findViewById(R.id.application_size_text);
- mDataSize = (TextView) view.findViewById(R.id.data_size_text);
- mExternalCodeSize = (TextView) view.findViewById(R.id.external_code_size_text);
- mExternalDataSize = (TextView) view.findViewById(R.id.external_data_size_text);
+ mNotificationPreference = findPreference(KEY_NOTIFICATION);
+ mNotificationPreference.setOnPreferenceClickListener(this);
+ mStoragePreference = findPreference(KEY_STORAGE);
+ mStoragePreference.setOnPreferenceClickListener(this);
+ mPermissionsPreference = findPreference(KEY_PERMISSION);
+ mPermissionsPreference.setOnPreferenceClickListener(this);
+ mLaunchPreference = findPreference(KEY_LAUNCH);
+ mLaunchPreference.setOnPreferenceClickListener(this);
+ mDataPreference = findPreference(KEY_DATA);
+ mDataPreference.setOnPreferenceClickListener(this);
+ // Data isn't ready, lets just pull it for now.
+ getPreferenceScreen().removePreference(mDataPreference);
+ }
- if (Environment.isExternalStorageEmulated()) {
- ((View)mExternalCodeSize.getParent()).setVisibility(View.GONE);
- ((View)mExternalDataSize.getParent()).setVisibility(View.GONE);
- }
+ private void handleHeader() {
+ mHeader = (HeaderPreference) findPreference(KEY_HEADER);
// Get Control button panel
- View btnPanel = view.findViewById(R.id.control_buttons_panel);
- mForceStopButton = (Button) btnPanel.findViewById(R.id.left_button);
+ View btnPanel = mHeader.findViewById(R.id.control_buttons_panel);
+ mForceStopButton = (Button) btnPanel.findViewById(R.id.right_button);
mForceStopButton.setText(R.string.force_stop);
- mUninstallButton = (Button) btnPanel.findViewById(R.id.right_button);
+ mUninstallButton = (Button) btnPanel.findViewById(R.id.left_button);
mForceStopButton.setEnabled(false);
-
+
// Get More Control button panel
- mMoreControlButtons = view.findViewById(R.id.more_control_buttons_panel);
- mMoreControlButtons.findViewById(R.id.left_button).setVisibility(View.INVISIBLE);
- mSpecialDisableButton = (Button) mMoreControlButtons.findViewById(R.id.right_button);
+ mMoreControlButtons = mHeader.findViewById(R.id.more_control_buttons_panel);
+ mMoreControlButtons.findViewById(R.id.right_button).setVisibility(View.INVISIBLE);
+ mSpecialDisableButton = (Button) mMoreControlButtons.findViewById(R.id.left_button);
mMoreControlButtons.setVisibility(View.GONE);
-
- // Initialize clear data and move install location buttons
- View data_buttons_panel = view.findViewById(R.id.data_buttons_panel);
- mClearDataButton = (Button) data_buttons_panel.findViewById(R.id.right_button);
- mMoveAppButton = (Button) data_buttons_panel.findViewById(R.id.left_button);
-
- // Cache section
- mCacheSize = (TextView) view.findViewById(R.id.cache_size_text);
- mClearCacheButton = (Button) view.findViewById(R.id.clear_cache_button);
-
- mActivitiesButton = (Button) view.findViewById(R.id.clear_activities_button);
-
- // Screen compatibility control
- mScreenCompatSection = view.findViewById(R.id.screen_compatibility_section);
- mAskCompatibilityCB = (CheckBox) view.findViewById(R.id.ask_compatibility_cb);
- mEnableCompatibilityCB = (CheckBox) view.findViewById(R.id.enable_compatibility_cb);
-
- mNotificationSwitch = (CompoundButton) view.findViewById(R.id.notification_switch);
-
- return view;
}
@Override
@@ -572,8 +305,9 @@ public class InstalledAppDetails extends Fragment
// Utility method to set application label and icon.
private void setAppLabelAndIcon(PackageInfo pkgInfo) {
- final View appSnippet = mRootView.findViewById(R.id.app_snippet);
- appSnippet.setPaddingRelative(0, appSnippet.getPaddingTop(), 0, appSnippet.getPaddingBottom());
+ final View appSnippet = mHeader.findViewById(R.id.app_snippet);
+ appSnippet.setPaddingRelative(0, appSnippet.getPaddingTop(), 0,
+ appSnippet.getPaddingBottom());
ImageView icon = (ImageView) appSnippet.findViewById(R.id.app_icon);
mState.ensureIcon(mAppEntry);
@@ -593,86 +327,6 @@ public class InstalledAppDetails extends Fragment
}
}
- @Override
- public void onResume() {
- super.onResume();
-
- mAppControlRestricted = mUserManager.hasUserRestriction(UserManager.DISALLOW_APPS_CONTROL);
- mSession.resume();
- if (!refreshUi()) {
- setIntentAndFinish(true, true);
- }
- }
-
- @Override
- public void onPause() {
- super.onPause();
- mSession.pause();
- }
-
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- mSession.release();
- }
-
- @Override
- public void onAllSizesComputed() {
- }
-
- @Override
- public void onPackageIconChanged() {
- }
-
- @Override
- public void onPackageListChanged() {
- refreshUi();
- }
-
- @Override
- public void onRebuildComplete(ArrayList<AppEntry> apps) {
- }
-
- @Override
- public void onPackageSizeChanged(String packageName) {
- if (packageName.equals(mAppEntry.info.packageName)) {
- refreshSizeInfo();
- }
- }
-
- @Override
- public void onRunningStateChanged(boolean running) {
- }
-
- private String retrieveAppEntry() {
- final Bundle args = getArguments();
- String packageName = (args != null) ? args.getString(ARG_PACKAGE_NAME) : null;
- if (packageName == null) {
- Intent intent = (args == null) ?
- getActivity().getIntent() : (Intent) args.getParcelable("intent");
- if (intent != null) {
- packageName = intent.getData().getSchemeSpecificPart();
- }
- }
- mAppEntry = mState.getEntry(packageName);
- if (mAppEntry != null) {
- // Get application info again to refresh changed properties of application
- try {
- mPackageInfo = mPm.getPackageInfo(mAppEntry.info.packageName,
- PackageManager.GET_DISABLED_COMPONENTS |
- PackageManager.GET_UNINSTALLED_PACKAGES |
- PackageManager.GET_SIGNATURES);
- } catch (NameNotFoundException e) {
- Log.e(TAG, "Exception when retrieving package:" + mAppEntry.info.packageName, e);
- }
- } else {
- Log.w(TAG, "Missing AppEntry; maybe reinstalling?");
- mPackageInfo = null;
- }
-
- return packageName;
- }
-
private boolean signaturesMatch(String pkg1, String pkg2) {
if (pkg1 != null && pkg2 != null) {
try {
@@ -688,12 +342,9 @@ public class InstalledAppDetails extends Fragment
return false;
}
- private boolean refreshUi() {
- if (mMoveInProgress) {
- return true;
- }
- final String packageName = retrieveAppEntry();
-
+ @Override
+ protected boolean refreshUi() {
+ retrieveAppEntry();
if (mAppEntry == null) {
return false; // onCreate must have failed, make sure to exit
}
@@ -721,175 +372,18 @@ public class InstalledAppDetails extends Fragment
}
}
- // Get list of preferred activities
- List<ComponentName> prefActList = new ArrayList<ComponentName>();
-
- // Intent list cannot be null. so pass empty list
- List<IntentFilter> intentList = new ArrayList<IntentFilter>();
- mPm.getPreferredActivities(intentList, prefActList, packageName);
- if (localLOGV)
- Log.i(TAG, "Have " + prefActList.size() + " number of activities in preferred list");
- boolean hasUsbDefaults = false;
- try {
- if (mUsbManager != null) {
- hasUsbDefaults = mUsbManager.hasDefaults(packageName, UserHandle.myUserId());
- }
- } catch (RemoteException e) {
- Log.e(TAG, "mUsbManager.hasDefaults", e);
- }
- boolean hasBindAppWidgetPermission =
- mAppWidgetManager.hasBindAppWidgetPermission(mAppEntry.info.packageName);
-
- TextView autoLaunchTitleView = (TextView) mRootView.findViewById(R.id.auto_launch_title);
- TextView autoLaunchView = (TextView) mRootView.findViewById(R.id.auto_launch);
- boolean autoLaunchEnabled = prefActList.size() > 0 || hasUsbDefaults;
- if (!autoLaunchEnabled && !hasBindAppWidgetPermission) {
- resetLaunchDefaultsUi(autoLaunchTitleView, autoLaunchView);
- } else {
- boolean useBullets = hasBindAppWidgetPermission && autoLaunchEnabled;
-
- if (hasBindAppWidgetPermission) {
- autoLaunchTitleView.setText(R.string.auto_launch_label_generic);
- } else {
- autoLaunchTitleView.setText(R.string.auto_launch_label);
- }
-
- CharSequence text = null;
- int bulletIndent = getResources()
- .getDimensionPixelSize(R.dimen.installed_app_details_bullet_offset);
- if (autoLaunchEnabled) {
- CharSequence autoLaunchEnableText = getText(R.string.auto_launch_enable_text);
- SpannableString s = new SpannableString(autoLaunchEnableText);
- if (useBullets) {
- s.setSpan(new BulletSpan(bulletIndent), 0, autoLaunchEnableText.length(), 0);
- }
- text = (text == null) ?
- TextUtils.concat(s, "\n") : TextUtils.concat(text, "\n", s, "\n");
- }
- if (hasBindAppWidgetPermission) {
- CharSequence alwaysAllowBindAppWidgetsText =
- getText(R.string.always_allow_bind_appwidgets_text);
- SpannableString s = new SpannableString(alwaysAllowBindAppWidgetsText);
- if (useBullets) {
- s.setSpan(new BulletSpan(bulletIndent),
- 0, alwaysAllowBindAppWidgetsText.length(), 0);
- }
- text = (text == null) ?
- TextUtils.concat(s, "\n") : TextUtils.concat(text, "\n", s, "\n");
- }
- autoLaunchView.setText(text);
- mActivitiesButton.setEnabled(true);
- mActivitiesButton.setOnClickListener(this);
- }
-
- // Screen compatibility section.
- ActivityManager am = (ActivityManager)
- getActivity().getSystemService(Context.ACTIVITY_SERVICE);
- int compatMode = am.getPackageScreenCompatMode(packageName);
- // For now these are always off; this is the old UI model which we
- // are no longer using.
- if (false && (compatMode == ActivityManager.COMPAT_MODE_DISABLED
- || compatMode == ActivityManager.COMPAT_MODE_ENABLED)) {
- mScreenCompatSection.setVisibility(View.VISIBLE);
- mAskCompatibilityCB.setChecked(am.getPackageAskScreenCompat(packageName));
- mAskCompatibilityCB.setOnCheckedChangeListener(this);
- mEnableCompatibilityCB.setChecked(compatMode == ActivityManager.COMPAT_MODE_ENABLED);
- mEnableCompatibilityCB.setOnCheckedChangeListener(this);
- } else {
- mScreenCompatSection.setVisibility(View.GONE);
- }
-
- // Security permissions section
- LinearLayout permsView = (LinearLayout) mRootView.findViewById(R.id.permissions_section);
- AppSecurityPermissions asp = new AppSecurityPermissions(getActivity(), packageName);
- int premiumSmsPermission = getPremiumSmsPermission(packageName);
- // Premium SMS permission implies the app also has SEND_SMS permission, so the original
- // application permissions list doesn't have to be shown/hidden separately. The premium
- // SMS subsection should only be visible if the app has tried to send to a premium SMS.
- if (asp.getPermissionCount() > 0
- || premiumSmsPermission != SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN) {
- permsView.setVisibility(View.VISIBLE);
- } else {
- permsView.setVisibility(View.GONE);
- }
- // Premium SMS permission subsection
- TextView securityBillingDesc = (TextView) permsView.findViewById(
- R.id.security_settings_billing_desc);
- LinearLayout securityBillingList = (LinearLayout) permsView.findViewById(
- R.id.security_settings_billing_list);
- if (premiumSmsPermission != SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN) {
- // Show the premium SMS permission selector
- securityBillingDesc.setVisibility(View.VISIBLE);
- securityBillingList.setVisibility(View.VISIBLE);
- Spinner spinner = (Spinner) permsView.findViewById(
- R.id.security_settings_premium_sms_list);
- ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(getActivity(),
- R.array.security_settings_premium_sms_values,
- android.R.layout.simple_spinner_item);
- adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- spinner.setAdapter(adapter);
- // List items are in the same order as SmsUsageMonitor constants, offset by 1.
- spinner.setSelection(premiumSmsPermission - 1);
- spinner.setOnItemSelectedListener(new PremiumSmsSelectionListener(
- packageName, mSmsManager));
- } else {
- // Hide the premium SMS permission selector
- securityBillingDesc.setVisibility(View.GONE);
- securityBillingList.setVisibility(View.GONE);
- }
- // App permissions subsection
- if (asp.getPermissionCount() > 0) {
- // Make the security sections header visible
- LinearLayout securityList = (LinearLayout) permsView.findViewById(
- R.id.security_settings_list);
- securityList.removeAllViews();
- securityList.addView(asp.getPermissionsViewWithRevokeButtons());
- // If this app is running under a shared user ID with other apps,
- // update the description to explain this.
- String[] packages = mPm.getPackagesForUid(mPackageInfo.applicationInfo.uid);
- if (packages != null && packages.length > 1) {
- ArrayList<CharSequence> pnames = new ArrayList<CharSequence>();
- for (int i=0; i<packages.length; i++) {
- String pkg = packages[i];
- if (mPackageInfo.packageName.equals(pkg)) {
- continue;
- }
- try {
- ApplicationInfo ainfo = mPm.getApplicationInfo(pkg, 0);
- pnames.add(ainfo.loadLabel(mPm));
- } catch (PackageManager.NameNotFoundException e) {
- }
- }
- final int N = pnames.size();
- if (N > 0) {
- final Resources res = getActivity().getResources();
- String appListStr;
- if (N == 1) {
- appListStr = pnames.get(0).toString();
- } else if (N == 2) {
- appListStr = res.getString(R.string.join_two_items, pnames.get(0),
- pnames.get(1));
- } else {
- appListStr = pnames.get(N-2).toString();
- for (int i=N-3; i>=0; i--) {
- appListStr = res.getString(i == 0 ? R.string.join_many_items_first
- : R.string.join_many_items_middle, pnames.get(i), appListStr);
- }
- appListStr = res.getString(R.string.join_many_items_last,
- appListStr, pnames.get(N-1));
- }
- TextView descr = (TextView) mRootView.findViewById(
- R.id.security_settings_desc);
- descr.setText(res.getString(R.string.security_settings_desc_multi,
- mPackageInfo.applicationInfo.loadLabel(mPm), appListStr));
- }
- }
- }
-
checkForceStop();
setAppLabelAndIcon(mPackageInfo);
- refreshButtons();
- refreshSizeInfo();
+ initUninstallButtons();
+
+ // Update the preference summaries.
+ Activity context = getActivity();
+ mStoragePreference.setSummary(AppStorageSettings.getSummary(mAppEntry, context));
+ mPermissionsPreference.setSummary(AppPermissionSettings.getSummary(mAppEntry, context));
+ mLaunchPreference.setSummary(AppLaunchSettings.getSummary(mAppEntry, mUsbManager,
+ mPm, context));
+ mNotificationPreference.setSummary(getNotificationSummary(mAppEntry, context,
+ mBackend));
if (!mInitialized) {
// First time init: are we displaying an uninstalled app?
@@ -899,7 +393,7 @@ public class InstalledAppDetails extends Fragment
// All other times: if the app no longer exists then we want
// to go away.
try {
- ApplicationInfo ainfo = getActivity().getPackageManager().getApplicationInfo(
+ ApplicationInfo ainfo = context.getPackageManager().getApplicationInfo(
mAppEntry.info.packageName, PackageManager.GET_UNINSTALLED_PACKAGES
| PackageManager.GET_DISABLED_COMPONENTS);
if (!mShowUninstalled) {
@@ -916,344 +410,63 @@ public class InstalledAppDetails extends Fragment
return true;
}
- private static class PremiumSmsSelectionListener implements AdapterView.OnItemSelectedListener {
- private final String mPackageName;
- private final ISms mSmsManager;
-
- PremiumSmsSelectionListener(String packageName, ISms smsManager) {
- mPackageName = packageName;
- mSmsManager = smsManager;
- }
-
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position,
- long id) {
- if (position >= 0 && position < 3) {
- Log.d(TAG, "Selected premium SMS policy " + position);
- setPremiumSmsPermission(mPackageName, (position + 1));
- } else {
- Log.e(TAG, "Error: unknown premium SMS policy " + position);
- }
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- // Ignored
- }
-
- private void setPremiumSmsPermission(String packageName, int permission) {
- try {
- if (mSmsManager != null) {
- mSmsManager.setPremiumSmsPermission(packageName, permission);
- }
- } catch (RemoteException ex) {
- // ignored
- }
- }
- }
-
- private void resetLaunchDefaultsUi(TextView title, TextView autoLaunchView) {
- title.setText(R.string.auto_launch_label);
- autoLaunchView.setText(R.string.auto_launch_disable_text);
- // Disable clear activities button
- mActivitiesButton.setEnabled(false);
- }
-
- private void setIntentAndFinish(boolean finish, boolean appChanged) {
- if(localLOGV) Log.i(TAG, "appChanged="+appChanged);
- Intent intent = new Intent();
- intent.putExtra(ManageApplications.APP_CHG, appChanged);
- SettingsActivity sa = (SettingsActivity)getActivity();
- sa.finishPreferencePanel(this, Activity.RESULT_OK, intent);
- }
-
- private void refreshSizeInfo() {
- if (mAppEntry.size == ApplicationsState.SIZE_INVALID
- || mAppEntry.size == ApplicationsState.SIZE_UNKNOWN) {
- mLastCodeSize = mLastDataSize = mLastCacheSize = mLastTotalSize = -1;
- if (!mHaveSizes) {
- mAppSize.setText(mComputingStr);
- mDataSize.setText(mComputingStr);
- mCacheSize.setText(mComputingStr);
- mTotalSize.setText(mComputingStr);
- }
- mClearDataButton.setEnabled(false);
- mClearCacheButton.setEnabled(false);
-
- } else {
- mHaveSizes = true;
- long codeSize = mAppEntry.codeSize;
- long dataSize = mAppEntry.dataSize;
- if (Environment.isExternalStorageEmulated()) {
- codeSize += mAppEntry.externalCodeSize;
- dataSize += mAppEntry.externalDataSize;
- } else {
- if (mLastExternalCodeSize != mAppEntry.externalCodeSize) {
- mLastExternalCodeSize = mAppEntry.externalCodeSize;
- mExternalCodeSize.setText(getSizeStr(mAppEntry.externalCodeSize));
- }
- if (mLastExternalDataSize != mAppEntry.externalDataSize) {
- mLastExternalDataSize = mAppEntry.externalDataSize;
- mExternalDataSize.setText(getSizeStr( mAppEntry.externalDataSize));
- }
- }
- if (mLastCodeSize != codeSize) {
- mLastCodeSize = codeSize;
- mAppSize.setText(getSizeStr(codeSize));
- }
- if (mLastDataSize != dataSize) {
- mLastDataSize = dataSize;
- mDataSize.setText(getSizeStr(dataSize));
- }
- long cacheSize = mAppEntry.cacheSize + mAppEntry.externalCacheSize;
- if (mLastCacheSize != cacheSize) {
- mLastCacheSize = cacheSize;
- mCacheSize.setText(getSizeStr(cacheSize));
- }
- if (mLastTotalSize != mAppEntry.size) {
- mLastTotalSize = mAppEntry.size;
- mTotalSize.setText(getSizeStr(mAppEntry.size));
- }
-
- if ((mAppEntry.dataSize+ mAppEntry.externalDataSize) <= 0 || !mCanClearData) {
- mClearDataButton.setEnabled(false);
- } else {
- mClearDataButton.setEnabled(true);
- mClearDataButton.setOnClickListener(this);
- }
- if (cacheSize <= 0) {
- mClearCacheButton.setEnabled(false);
- } else {
- mClearCacheButton.setEnabled(true);
- mClearCacheButton.setOnClickListener(this);
- }
- }
- if (mAppControlRestricted) {
- mClearCacheButton.setEnabled(false);
- mClearDataButton.setEnabled(false);
- }
- }
-
- /*
- * Private method to handle clear message notification from observer when
- * the async operation from PackageManager is complete
- */
- private void processClearMsg(Message msg) {
- int result = msg.arg1;
- String packageName = mAppEntry.info.packageName;
- mClearDataButton.setText(R.string.clear_user_data_text);
- if(result == OP_SUCCESSFUL) {
- Log.i(TAG, "Cleared user data for package : "+packageName);
- mState.requestSize(mAppEntry.info.packageName);
- } else {
- mClearDataButton.setEnabled(true);
- }
- checkForceStop();
- }
-
- private void refreshButtons() {
- if (!mMoveInProgress) {
- initUninstallButtons();
- initDataButtons();
- initMoveButton();
- initNotificationButton();
- } else {
- mMoveAppButton.setText(R.string.moving);
- mMoveAppButton.setEnabled(false);
- mUninstallButton.setEnabled(false);
- mSpecialDisableButton.setEnabled(false);
- }
- }
-
- private void processMoveMsg(Message msg) {
- int result = msg.arg1;
- String packageName = mAppEntry.info.packageName;
- // Refresh the button attributes.
- mMoveInProgress = false;
- if (result == PackageManager.MOVE_SUCCEEDED) {
- Log.i(TAG, "Moved resources for " + packageName);
- // Refresh size information again.
- mState.requestSize(mAppEntry.info.packageName);
- } else {
- showDialogInner(DLG_MOVE_FAILED, result);
- }
- refreshUi();
- }
-
- /*
- * Private method to initiate clearing user data when the user clicks the clear data
- * button for a system package
- */
- private void initiateClearUserData() {
- mClearDataButton.setEnabled(false);
- // Invoke uninstall or clear user data based on sysPackage
- String packageName = mAppEntry.info.packageName;
- Log.i(TAG, "Clearing user data for package : " + packageName);
- if (mClearDataObserver == null) {
- mClearDataObserver = new ClearUserDataObserver();
- }
- ActivityManager am = (ActivityManager)
- getActivity().getSystemService(Context.ACTIVITY_SERVICE);
- boolean res = am.clearApplicationUserData(packageName, mClearDataObserver);
- if (!res) {
- // Clearing data failed for some obscure reason. Just log error for now
- Log.i(TAG, "Couldnt clear application user data for package:"+packageName);
- showDialogInner(DLG_CANNOT_CLEAR_DATA, 0);
- } else {
- mClearDataButton.setText(R.string.recompute_size);
- }
- }
-
- private void showDialogInner(int id, int moveErrorCode) {
- DialogFragment newFragment = MyAlertDialogFragment.newInstance(id, moveErrorCode);
- newFragment.setTargetFragment(this, 0);
- newFragment.show(getFragmentManager(), "dialog " + id);
- }
-
- public static class MyAlertDialogFragment extends DialogFragment {
-
- public static MyAlertDialogFragment newInstance(int id, int moveErrorCode) {
- MyAlertDialogFragment frag = new MyAlertDialogFragment();
- Bundle args = new Bundle();
- args.putInt("id", id);
- args.putInt("moveError", moveErrorCode);
- frag.setArguments(args);
- return frag;
- }
-
- InstalledAppDetails getOwner() {
- return (InstalledAppDetails)getTargetFragment();
- }
-
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- int id = getArguments().getInt("id");
- int moveErrorCode = getArguments().getInt("moveError");
- switch (id) {
- case DLG_CLEAR_DATA:
- return new AlertDialog.Builder(getActivity())
- .setTitle(getActivity().getText(R.string.clear_data_dlg_title))
- .setMessage(getActivity().getText(R.string.clear_data_dlg_text))
- .setPositiveButton(R.string.dlg_ok,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- // Clear user data here
- getOwner().initiateClearUserData();
- }
- })
- .setNegativeButton(R.string.dlg_cancel, null)
- .create();
- case DLG_FACTORY_RESET:
- return new AlertDialog.Builder(getActivity())
- .setTitle(getActivity().getText(R.string.app_factory_reset_dlg_title))
- .setMessage(getActivity().getText(R.string.app_factory_reset_dlg_text))
- .setPositiveButton(R.string.dlg_ok,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- // Clear user data here
- getOwner().uninstallPkg(getOwner().mAppEntry.info.packageName,
- false, false);
- }
- })
- .setNegativeButton(R.string.dlg_cancel, null)
- .create();
- case DLG_APP_NOT_FOUND:
- return new AlertDialog.Builder(getActivity())
- .setTitle(getActivity().getText(R.string.app_not_found_dlg_title))
- .setMessage(getActivity().getText(R.string.app_not_found_dlg_title))
- .setNeutralButton(getActivity().getText(R.string.dlg_ok),
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- //force to recompute changed value
- getOwner().setIntentAndFinish(true, true);
- }
- })
- .create();
- case DLG_CANNOT_CLEAR_DATA:
- return new AlertDialog.Builder(getActivity())
- .setTitle(getActivity().getText(R.string.clear_failed_dlg_title))
- .setMessage(getActivity().getText(R.string.clear_failed_dlg_text))
- .setNeutralButton(R.string.dlg_ok,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- getOwner().mClearDataButton.setEnabled(false);
- //force to recompute changed value
- getOwner().setIntentAndFinish(false, false);
- }
- })
- .create();
- case DLG_FORCE_STOP:
- return new AlertDialog.Builder(getActivity())
- .setTitle(getActivity().getText(R.string.force_stop_dlg_title))
- .setMessage(getActivity().getText(R.string.force_stop_dlg_text))
- .setPositiveButton(R.string.dlg_ok,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- // Force stop
- getOwner().forceStopPackage(getOwner().mAppEntry.info.packageName);
- }
- })
- .setNegativeButton(R.string.dlg_cancel, null)
- .create();
- case DLG_MOVE_FAILED:
- CharSequence msg = getActivity().getString(R.string.move_app_failed_dlg_text,
- getOwner().getMoveErrMsg(moveErrorCode));
- return new AlertDialog.Builder(getActivity())
- .setTitle(getActivity().getText(R.string.move_app_failed_dlg_title))
- .setMessage(msg)
- .setNeutralButton(R.string.dlg_ok, null)
- .create();
- case DLG_DISABLE:
- return new AlertDialog.Builder(getActivity())
- .setTitle(getActivity().getText(R.string.app_disable_dlg_title))
- .setMessage(getActivity().getText(R.string.app_disable_dlg_text))
- .setPositiveButton(R.string.dlg_ok,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- // Disable the app
- new DisableChanger(getOwner(), getOwner().mAppEntry.info,
- PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER)
- .execute((Object)null);
- }
- })
- .setNegativeButton(R.string.dlg_cancel, null)
- .create();
- case DLG_DISABLE_NOTIFICATIONS:
- return new AlertDialog.Builder(getActivity())
- .setTitle(getActivity().getText(R.string.app_disable_notifications_dlg_title))
- .setMessage(getActivity().getText(R.string.app_disable_notifications_dlg_text))
- .setPositiveButton(R.string.dlg_ok,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- // Disable the package's notifications
- getOwner().setNotificationsEnabled(false);
- }
- })
- .setNegativeButton(R.string.dlg_cancel,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- // Re-enable the checkbox
- getOwner().mNotificationSwitch.setChecked(true);
- }
- })
- .create();
- case DLG_SPECIAL_DISABLE:
- return new AlertDialog.Builder(getActivity())
- .setTitle(getActivity().getText(R.string.app_special_disable_dlg_title))
- .setMessage(getActivity().getText(R.string.app_special_disable_dlg_text))
- .setPositiveButton(R.string.dlg_ok,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- // Clear user data here
- getOwner().uninstallPkg(getOwner().mAppEntry.info.packageName,
- false, true);
- }
- })
- .setNegativeButton(R.string.dlg_cancel, null)
- .create();
- }
- throw new IllegalArgumentException("unknown id " + id);
- }
+ @Override
+ protected AlertDialog createDialog(int id, int errorCode) {
+ switch (id) {
+ case DLG_DISABLE:
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(getActivity().getText(R.string.app_disable_dlg_title))
+ .setMessage(getActivity().getText(R.string.app_disable_dlg_text))
+ .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ // Disable the app
+ new DisableChanger(InstalledAppDetails.this, mAppEntry.info,
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER)
+ .execute((Object)null);
+ }
+ })
+ .setNegativeButton(R.string.dlg_cancel, null)
+ .create();
+ case DLG_SPECIAL_DISABLE:
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(getActivity().getText(R.string.app_special_disable_dlg_title))
+ .setMessage(getActivity().getText(R.string.app_special_disable_dlg_text))
+ .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ // Clear user data here
+ uninstallPkg(mAppEntry.info.packageName,
+ false, true);
+ }
+ })
+ .setNegativeButton(R.string.dlg_cancel, null)
+ .create();
+ case DLG_FORCE_STOP:
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(getActivity().getText(R.string.force_stop_dlg_title))
+ .setMessage(getActivity().getText(R.string.force_stop_dlg_text))
+ .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ // Force stop
+ forceStopPackage(mAppEntry.info.packageName);
+ }
+ })
+ .setNegativeButton(R.string.dlg_cancel, null)
+ .create();
+ case DLG_FACTORY_RESET:
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(getActivity().getText(R.string.app_factory_reset_dlg_title))
+ .setMessage(getActivity().getText(R.string.app_factory_reset_dlg_text))
+ .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ // Clear user data here
+ uninstallPkg(mAppEntry.info.packageName,
+ false, false);
+ }
+ })
+ .setNegativeButton(R.string.dlg_cancel, null)
+ .create();
+ }
+ return null;
}
private void uninstallPkg(String packageName, boolean allUsers, boolean andDisable) {
@@ -1277,13 +490,6 @@ public class InstalledAppDetails extends Fragment
checkForceStop();
}
- private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- updateForceStopButton(getResultCode() != Activity.RESULT_CANCELED);
- }
- };
-
private void updateForceStopButton(boolean enabled) {
if (mAppControlRestricted) {
mForceStopButton.setEnabled(false);
@@ -1292,7 +498,7 @@ public class InstalledAppDetails extends Fragment
mForceStopButton.setOnClickListener(InstalledAppDetails.this);
}
}
-
+
private void checkForceStop() {
if (mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
// User can't force stop device admin.
@@ -1312,47 +518,21 @@ public class InstalledAppDetails extends Fragment
}
}
- static class DisableChanger extends AsyncTask<Object, Object, Object> {
- final PackageManager mPm;
- final WeakReference<InstalledAppDetails> mActivity;
- final ApplicationInfo mInfo;
- final int mState;
+ private void startAppInfoFragment(Class<? extends AppInfoBase> fragment, CharSequence title) {
+ // start new fragment to display extended information
+ Bundle args = new Bundle();
+ args.putString(InstalledAppDetails.ARG_PACKAGE_NAME, mAppEntry.info.packageName);
- DisableChanger(InstalledAppDetails activity, ApplicationInfo info, int state) {
- mPm = activity.mPm;
- mActivity = new WeakReference<InstalledAppDetails>(activity);
- mInfo = info;
- mState = state;
- }
-
- @Override
- protected Object doInBackground(Object... params) {
- mPm.setApplicationEnabledSetting(mInfo.packageName, mState, 0);
- return null;
- }
+ SettingsActivity sa = (SettingsActivity) getActivity();
+ sa.startPreferencePanel(fragment.getName(), args, -1, title, this, SUB_INFO_FRAGMENT);
}
- private void setNotificationsEnabled(boolean enabled) {
- String packageName = mAppEntry.info.packageName;
- INotificationManager nm = INotificationManager.Stub.asInterface(
- ServiceManager.getService(Context.NOTIFICATION_SERVICE));
- try {
- final boolean enable = mNotificationSwitch.isChecked();
- nm.setNotificationsEnabledForPackage(packageName, mAppEntry.info.uid, enabled);
- } catch (android.os.RemoteException ex) {
- mNotificationSwitch.setChecked(!enabled); // revert
- }
- }
-
- private int getPremiumSmsPermission(String packageName) {
- try {
- if (mSmsManager != null) {
- return mSmsManager.getPremiumSmsPermission(packageName);
- }
- } catch (RemoteException ex) {
- // ignored
- }
- return SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN;
+ private void startNotifications() {
+ // start new fragment to display extended information
+ getActivity().startActivity(new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
+ .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
+ .putExtra(Settings.EXTRA_APP_PACKAGE, mAppEntry.info.packageName)
+ .putExtra(Settings.EXTRA_APP_UID, mAppEntry.info.uid));
}
/*
@@ -1381,69 +561,77 @@ public class InstalledAppDetails extends Fragment
}
} else if(v == mSpecialDisableButton) {
showDialogInner(DLG_SPECIAL_DISABLE, 0);
- } else if(v == mActivitiesButton) {
- if (mUsbManager != null) {
- mPm.clearPackagePreferredActivities(packageName);
- try {
- mUsbManager.clearDefaults(packageName, UserHandle.myUserId());
- } catch (RemoteException e) {
- Log.e(TAG, "mUsbManager.clearDefaults", e);
- }
- mAppWidgetManager.setBindAppWidgetPermission(packageName, false);
- TextView autoLaunchTitleView =
- (TextView) mRootView.findViewById(R.id.auto_launch_title);
- TextView autoLaunchView = (TextView) mRootView.findViewById(R.id.auto_launch);
- resetLaunchDefaultsUi(autoLaunchTitleView, autoLaunchView);
- }
- } else if(v == mClearDataButton) {
- if (mAppEntry.info.manageSpaceActivityName != null) {
- if (!Utils.isMonkeyRunning()) {
- Intent intent = new Intent(Intent.ACTION_DEFAULT);
- intent.setClassName(mAppEntry.info.packageName,
- mAppEntry.info.manageSpaceActivityName);
- startActivityForResult(intent, REQUEST_MANAGE_SPACE);
- }
- } else {
- showDialogInner(DLG_CLEAR_DATA, 0);
- }
- } else if (v == mClearCacheButton) {
- // Lazy initialization of observer
- if (mClearCacheObserver == null) {
- mClearCacheObserver = new ClearCacheObserver();
- }
- mPm.deleteApplicationCacheFiles(packageName, mClearCacheObserver);
} else if (v == mForceStopButton) {
showDialogInner(DLG_FORCE_STOP, 0);
//forceStopPackage(mAppInfo.packageName);
- } else if (v == mMoveAppButton) {
- if (mPackageMoveObserver == null) {
- mPackageMoveObserver = new PackageMoveObserver();
- }
- int moveFlags = (mAppEntry.info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0 ?
- PackageManager.MOVE_INTERNAL : PackageManager.MOVE_EXTERNAL_MEDIA;
- mMoveInProgress = true;
- refreshButtons();
- mPm.movePackage(mAppEntry.info.packageName, mPackageMoveObserver, moveFlags);
}
}
@Override
- public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- String packageName = mAppEntry.info.packageName;
- ActivityManager am = (ActivityManager)
- getActivity().getSystemService(Context.ACTIVITY_SERVICE);
- if (buttonView == mAskCompatibilityCB) {
- am.setPackageAskScreenCompat(packageName, isChecked);
- } else if (buttonView == mEnableCompatibilityCB) {
- am.setPackageScreenCompatMode(packageName, isChecked ?
- ActivityManager.COMPAT_MODE_ENABLED : ActivityManager.COMPAT_MODE_DISABLED);
- } else if (buttonView == mNotificationSwitch) {
- if (!isChecked) {
- showDialogInner(DLG_DISABLE_NOTIFICATIONS, 0);
- } else {
- setNotificationsEnabled(true);
+ public boolean onPreferenceClick(Preference preference) {
+ if (preference == mStoragePreference) {
+ startAppInfoFragment(AppStorageSettings.class, mStoragePreference.getTitle());
+ } else if (preference == mNotificationPreference) {
+ startNotifications();
+ } else if (preference == mPermissionsPreference) {
+ startAppInfoFragment(AppPermissionSettings.class, mPermissionsPreference.getTitle());
+ } else if (preference == mLaunchPreference) {
+ startAppInfoFragment(AppLaunchSettings.class, mLaunchPreference.getTitle());
+ } else if (preference == mDataPreference) {
+ // Not yet.
+ } else {
+ return false;
+ }
+ return true;
+ }
+
+ public static CharSequence getNotificationSummary(AppEntry appEntry, Context context) {
+ return getNotificationSummary(appEntry, context, new Backend());
+ }
+
+ public static CharSequence getNotificationSummary(AppEntry appEntry, Context context,
+ Backend backend) {
+ AppRow appRow = NotificationAppList.loadAppRow(context.getPackageManager(), appEntry.info,
+ backend);
+ if (appRow.banned) {
+ return context.getString(R.string.notifications_disabled);
+ } else if (appRow.priority) {
+ if (appRow.sensitive) {
+ return context.getString(R.string.notifications_priority_sensitive);
}
+ return context.getString(R.string.notifications_priority);
+ } else if (appRow.sensitive) {
+ return context.getString(R.string.notifications_sensitive);
+ }
+ return context.getString(R.string.notifications_enabled);
+ }
+
+ static class DisableChanger extends AsyncTask<Object, Object, Object> {
+ final PackageManager mPm;
+ final WeakReference<InstalledAppDetails> mActivity;
+ final ApplicationInfo mInfo;
+ final int mState;
+
+ DisableChanger(InstalledAppDetails activity, ApplicationInfo info, int state) {
+ mPm = activity.mPm;
+ mActivity = new WeakReference<InstalledAppDetails>(activity);
+ mInfo = info;
+ mState = state;
+ }
+
+ @Override
+ protected Object doInBackground(Object... params) {
+ mPm.setApplicationEnabledSetting(mInfo.packageName, mState, 0);
+ return null;
}
}
+
+ private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ updateForceStopButton(getResultCode() != Activity.RESULT_CANCELED);
+ }
+ };
}
+