InstalledAppDetails.java revision 584b2b2bc17a4ccf42952b188722de1091c101be
1/**
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy
6 * of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations
14 * under the License.
15 */
16
17package com.android.settings.applications;
18
19import android.app.Activity;
20import android.app.ActivityManager;
21import android.app.AlertDialog;
22import android.app.LoaderManager.LoaderCallbacks;
23import android.content.BroadcastReceiver;
24import android.content.ComponentName;
25import android.content.Context;
26import android.content.DialogInterface;
27import android.content.Intent;
28import android.content.Loader;
29import android.content.pm.ApplicationInfo;
30import android.content.pm.PackageInfo;
31import android.content.pm.PackageManager;
32import android.content.pm.PackageManager.NameNotFoundException;
33import android.content.pm.ResolveInfo;
34import android.net.INetworkStatsService;
35import android.net.INetworkStatsSession;
36import android.net.NetworkTemplate;
37import android.net.TrafficStats;
38import android.net.Uri;
39import android.os.AsyncTask;
40import android.os.Bundle;
41import android.os.RemoteException;
42import android.os.ServiceManager;
43import android.os.UserHandle;
44import android.preference.Preference;
45import android.preference.Preference.OnPreferenceClickListener;
46import android.provider.Settings;
47import android.text.format.DateUtils;
48import android.text.format.Formatter;
49import android.view.Menu;
50import android.view.MenuInflater;
51import android.view.MenuItem;
52import android.view.View;
53import android.widget.Button;
54import android.widget.ImageView;
55import android.widget.TextView;
56
57import com.android.settings.DataUsageSummary;
58import com.android.settings.DataUsageSummary.AppItem;
59import com.android.settings.R;
60import com.android.settings.SettingsActivity;
61import com.android.settings.Utils;
62import com.android.settings.applications.ApplicationsState.AppEntry;
63import com.android.settings.net.ChartData;
64import com.android.settings.net.ChartDataLoader;
65import com.android.settings.notification.NotificationBackend;
66import com.android.settings.notification.NotificationBackend.AppRow;
67
68import java.lang.ref.WeakReference;
69import java.util.ArrayList;
70import java.util.HashSet;
71import java.util.List;
72
73/**
74 * Activity to display application information from Settings. This activity presents
75 * extended information associated with a package like code, data, total size, permissions
76 * used by the application and also the set of default launchable activities.
77 * For system applications, an option to clear user data is displayed only if data size is > 0.
78 * System applications that do not want clear user data do not have this option.
79 * For non-system applications, there is no option to clear data. Instead there is an option to
80 * uninstall the application.
81 */
82public class InstalledAppDetails extends AppInfoBase
83        implements View.OnClickListener, OnPreferenceClickListener {
84
85    // Menu identifiers
86    public static final int UNINSTALL_ALL_USERS_MENU = 1;
87    public static final int UNINSTALL_UPDATES = 2;
88
89    // Result code identifiers
90    public static final int REQUEST_UNINSTALL = 0;
91    private static final int SUB_INFO_FRAGMENT = 1;
92
93    private static final int LOADER_CHART_DATA = 2;
94
95    private static final int DLG_FORCE_STOP = DLG_BASE + 1;
96    private static final int DLG_DISABLE = DLG_BASE + 2;
97    private static final int DLG_SPECIAL_DISABLE = DLG_BASE + 3;
98    private static final int DLG_FACTORY_RESET = DLG_BASE + 4;
99
100    private static final String KEY_HEADER = "header_view";
101    private static final String KEY_NOTIFICATION = "notification_settings";
102    private static final String KEY_STORAGE = "storage_settings";
103    private static final String KEY_PERMISSION = "permission_settings";
104    private static final String KEY_DATA = "data_settings";
105    private static final String KEY_LAUNCH = "preferred_settings";
106
107    private final HashSet<String> mHomePackages = new HashSet<String>();
108
109    private boolean mInitialized;
110    private boolean mShowUninstalled;
111    private LayoutPreference mHeader;
112    private Button mUninstallButton;
113    private boolean mUpdatedSysApp = false;
114    private TextView mAppVersion;
115    private Button mForceStopButton;
116    private Preference mNotificationPreference;
117    private Preference mStoragePreference;
118    private Preference mPermissionsPreference;
119    private Preference mLaunchPreference;
120    private Preference mDataPreference;
121
122    private boolean mDisableAfterUninstall;
123    // Used for updating notification preference.
124    private final NotificationBackend mBackend = new NotificationBackend();
125
126    private ChartData mChartData;
127    private INetworkStatsSession mStatsSession;
128
129    private boolean handleDisableable(Button button) {
130        boolean disableable = false;
131        // Try to prevent the user from bricking their phone
132        // by not allowing disabling of apps signed with the
133        // system cert and any launcher app in the system.
134        if (mHomePackages.contains(mAppEntry.info.packageName)
135                || Utils.isSystemPackage(mPm, mPackageInfo)) {
136            // Disable button for core system applications.
137            button.setText(R.string.disable_text);
138        } else if (mAppEntry.info.enabled) {
139            button.setText(R.string.disable_text);
140            disableable = true;
141        } else {
142            button.setText(R.string.enable_text);
143            disableable = true;
144        }
145
146        return disableable;
147    }
148
149    private void initUninstallButtons() {
150        final boolean isBundled = (mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
151        boolean enabled = true;
152        if (isBundled) {
153            enabled = handleDisableable(mUninstallButton);
154        } else {
155            if ((mPackageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) == 0
156                    && mUserManager.getUsers().size() >= 2) {
157                // When we have multiple users, there is a separate menu
158                // to uninstall for all users.
159                enabled = false;
160            }
161            mUninstallButton.setText(R.string.uninstall_text);
162        }
163        // If this is a device admin, it can't be uninstalled or disabled.
164        // We do this here so the text of the button is still set correctly.
165        if (mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
166            enabled = false;
167        }
168
169        // Home apps need special handling.  Bundled ones we don't risk downgrading
170        // because that can interfere with home-key resolution.  Furthermore, we
171        // can't allow uninstallation of the only home app, and we don't want to
172        // allow uninstallation of an explicitly preferred one -- the user can go
173        // to Home settings and pick a different one, after which we'll permit
174        // uninstallation of the now-not-default one.
175        if (enabled && mHomePackages.contains(mPackageInfo.packageName)) {
176            if (isBundled) {
177                enabled = false;
178            } else {
179                ArrayList<ResolveInfo> homeActivities = new ArrayList<ResolveInfo>();
180                ComponentName currentDefaultHome  = mPm.getHomeActivities(homeActivities);
181                if (currentDefaultHome == null) {
182                    // No preferred default, so permit uninstall only when
183                    // there is more than one candidate
184                    enabled = (mHomePackages.size() > 1);
185                } else {
186                    // There is an explicit default home app -- forbid uninstall of
187                    // that one, but permit it for installed-but-inactive ones.
188                    enabled = !mPackageInfo.packageName.equals(currentDefaultHome.getPackageName());
189                }
190            }
191        }
192
193        if (mAppControlRestricted) {
194            enabled = false;
195        }
196
197        mUninstallButton.setEnabled(enabled);
198        if (enabled) {
199            // Register listener
200            mUninstallButton.setOnClickListener(this);
201        }
202    }
203
204    /** Called when the activity is first created. */
205    @Override
206    public void onCreate(Bundle icicle) {
207        super.onCreate(icicle);
208
209        setHasOptionsMenu(true);
210        addPreferencesFromResource(R.xml.installed_app_details);
211
212        INetworkStatsService statsService = INetworkStatsService.Stub.asInterface(
213                ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
214        try {
215            mStatsSession = statsService.openSession();
216        } catch (RemoteException e) {
217            throw new RuntimeException(e);
218        }
219    }
220
221    @Override
222    public void onResume() {
223        super.onResume();
224        AppItem app = new AppItem(mAppEntry.info.uid);
225        app.addUid(mAppEntry.info.uid);
226        getLoaderManager().restartLoader(LOADER_CHART_DATA,
227                ChartDataLoader.buildArgs(NetworkTemplate.buildTemplateMobileWildcard(), app),
228                mDataCallbacks);
229    }
230
231    @Override
232    public void onPause() {
233        getLoaderManager().destroyLoader(LOADER_CHART_DATA);
234        super.onPause();
235    }
236
237    @Override
238    public void onDestroy() {
239        TrafficStats.closeQuietly(mStatsSession);
240
241        super.onDestroy();
242    }
243
244    public void onActivityCreated(Bundle savedInstanceState) {
245        super.onActivityCreated(savedInstanceState);
246        handleHeader();
247
248        mNotificationPreference = findPreference(KEY_NOTIFICATION);
249        mNotificationPreference.setOnPreferenceClickListener(this);
250        mStoragePreference = findPreference(KEY_STORAGE);
251        mStoragePreference.setOnPreferenceClickListener(this);
252        mPermissionsPreference = findPreference(KEY_PERMISSION);
253        mPermissionsPreference.setOnPreferenceClickListener(this);
254        mLaunchPreference = findPreference(KEY_LAUNCH);
255        mLaunchPreference.setOnPreferenceClickListener(this);
256        mDataPreference = findPreference(KEY_DATA);
257        mDataPreference.setOnPreferenceClickListener(this);
258    }
259
260    private void handleHeader() {
261        mHeader = (LayoutPreference) findPreference(KEY_HEADER);
262
263        // Get Control button panel
264        View btnPanel = mHeader.findViewById(R.id.control_buttons_panel);
265        mForceStopButton = (Button) btnPanel.findViewById(R.id.right_button);
266        mForceStopButton.setText(R.string.force_stop);
267        mUninstallButton = (Button) btnPanel.findViewById(R.id.left_button);
268        mForceStopButton.setEnabled(false);
269    }
270
271    @Override
272    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
273        menu.add(0, UNINSTALL_UPDATES, 0, R.string.app_factory_reset)
274                .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
275        menu.add(0, UNINSTALL_ALL_USERS_MENU, 1, R.string.uninstall_all_users_text)
276                .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
277    }
278
279    @Override
280    public void onPrepareOptionsMenu(Menu menu) {
281        boolean showIt = true;
282        if (mUpdatedSysApp) {
283            showIt = false;
284        } else if (mAppEntry == null) {
285            showIt = false;
286        } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
287            showIt = false;
288        } else if (mPackageInfo == null || mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
289            showIt = false;
290        } else if (UserHandle.myUserId() != 0) {
291            showIt = false;
292        } else if (mUserManager.getUsers().size() < 2) {
293            showIt = false;
294        }
295        menu.findItem(UNINSTALL_ALL_USERS_MENU).setVisible(showIt);
296        mUpdatedSysApp = (mAppEntry.info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
297        menu.findItem(UNINSTALL_UPDATES).setVisible(mUpdatedSysApp && !mAppControlRestricted);
298    }
299
300    @Override
301    public boolean onOptionsItemSelected(MenuItem item) {
302        switch (item.getItemId()) {
303            case UNINSTALL_ALL_USERS_MENU:
304                uninstallPkg(mAppEntry.info.packageName, true, false);
305                return true;
306            case UNINSTALL_UPDATES:
307                showDialogInner(DLG_FACTORY_RESET, 0);
308                return true;
309        }
310        return false;
311    }
312
313    @Override
314    public void onActivityResult(int requestCode, int resultCode, Intent data) {
315        super.onActivityResult(requestCode, resultCode, data);
316        if (requestCode == REQUEST_UNINSTALL) {
317            if (mDisableAfterUninstall) {
318                mDisableAfterUninstall = false;
319                try {
320                    ApplicationInfo ainfo = getActivity().getPackageManager().getApplicationInfo(
321                            mAppEntry.info.packageName, PackageManager.GET_UNINSTALLED_PACKAGES
322                            | PackageManager.GET_DISABLED_COMPONENTS);
323                    if ((ainfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0) {
324                        new DisableChanger(this, mAppEntry.info,
325                                PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER)
326                                .execute((Object)null);
327                    }
328                } catch (NameNotFoundException e) {
329                }
330            }
331            if (!refreshUi()) {
332                setIntentAndFinish(true, true);
333            }
334        }
335    }
336
337    // Utility method to set application label and icon.
338    private void setAppLabelAndIcon(PackageInfo pkgInfo) {
339        final View appSnippet = mHeader.findViewById(R.id.app_snippet);
340        appSnippet.setPaddingRelative(0, appSnippet.getPaddingTop(), 0,
341                appSnippet.getPaddingBottom());
342
343        ImageView icon = (ImageView) appSnippet.findViewById(R.id.app_icon);
344        mState.ensureIcon(mAppEntry);
345        icon.setImageDrawable(mAppEntry.icon);
346        // Set application name.
347        TextView label = (TextView) appSnippet.findViewById(R.id.app_name);
348        label.setText(mAppEntry.label);
349        // Version number of application
350        mAppVersion = (TextView) appSnippet.findViewById(R.id.app_size);
351
352        if (pkgInfo != null && pkgInfo.versionName != null) {
353            mAppVersion.setVisibility(View.VISIBLE);
354            mAppVersion.setText(getActivity().getString(R.string.version_text,
355                    String.valueOf(pkgInfo.versionName)));
356        } else {
357            mAppVersion.setVisibility(View.INVISIBLE);
358        }
359    }
360
361    private boolean signaturesMatch(String pkg1, String pkg2) {
362        if (pkg1 != null && pkg2 != null) {
363            try {
364                final int match = mPm.checkSignatures(pkg1, pkg2);
365                if (match >= PackageManager.SIGNATURE_MATCH) {
366                    return true;
367                }
368            } catch (Exception e) {
369                // e.g. named alternate package not found during lookup;
370                // this is an expected case sometimes
371            }
372        }
373        return false;
374    }
375
376    @Override
377    protected boolean refreshUi() {
378        retrieveAppEntry();
379        if (mAppEntry == null) {
380            return false; // onCreate must have failed, make sure to exit
381        }
382
383        if (mPackageInfo == null) {
384            return false; // onCreate must have failed, make sure to exit
385        }
386
387        // Get list of "home" apps and trace through any meta-data references
388        List<ResolveInfo> homeActivities = new ArrayList<ResolveInfo>();
389        mPm.getHomeActivities(homeActivities);
390        mHomePackages.clear();
391        for (int i = 0; i< homeActivities.size(); i++) {
392            ResolveInfo ri = homeActivities.get(i);
393            final String activityPkg = ri.activityInfo.packageName;
394            mHomePackages.add(activityPkg);
395
396            // Also make sure to include anything proxying for the home app
397            final Bundle metadata = ri.activityInfo.metaData;
398            if (metadata != null) {
399                final String metaPkg = metadata.getString(ActivityManager.META_HOME_ALTERNATE);
400                if (signaturesMatch(metaPkg, activityPkg)) {
401                    mHomePackages.add(metaPkg);
402                }
403            }
404        }
405
406        checkForceStop();
407        setAppLabelAndIcon(mPackageInfo);
408        initUninstallButtons();
409
410        // Update the preference summaries.
411        Activity context = getActivity();
412        mStoragePreference.setSummary(AppStorageSettings.getSummary(mAppEntry, context));
413        mPermissionsPreference.setSummary(AppPermissionSettings.getSummary(mAppEntry, context));
414        mLaunchPreference.setSummary(AppLaunchSettings.getSummary(mAppEntry, mUsbManager,
415                mPm, context));
416        mNotificationPreference.setSummary(getNotificationSummary(mAppEntry, context,
417                mBackend));
418        mDataPreference.setSummary(getDataSummary());
419
420        if (!mInitialized) {
421            // First time init: are we displaying an uninstalled app?
422            mInitialized = true;
423            mShowUninstalled = (mAppEntry.info.flags&ApplicationInfo.FLAG_INSTALLED) == 0;
424        } else {
425            // All other times: if the app no longer exists then we want
426            // to go away.
427            try {
428                ApplicationInfo ainfo = context.getPackageManager().getApplicationInfo(
429                        mAppEntry.info.packageName, PackageManager.GET_UNINSTALLED_PACKAGES
430                        | PackageManager.GET_DISABLED_COMPONENTS);
431                if (!mShowUninstalled) {
432                    // If we did not start out with the app uninstalled, then
433                    // it transitioning to the uninstalled state for the current
434                    // user means we should go away as well.
435                    return (ainfo.flags&ApplicationInfo.FLAG_INSTALLED) != 0;
436                }
437            } catch (NameNotFoundException e) {
438                return false;
439            }
440        }
441
442        return true;
443    }
444
445    private CharSequence getDataSummary() {
446        if (mChartData != null) {
447            long totalBytes = mChartData.detail.getTotalBytes();
448            Context context = getActivity();
449            return getString(R.string.data_summary_format,
450                    Formatter.formatFileSize(context, totalBytes),
451                    DateUtils.formatDateTime(context, mChartData.detail.getStart(),
452                            DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH));
453        }
454        return getString(R.string.computing_size);
455    }
456
457    @Override
458    protected AlertDialog createDialog(int id, int errorCode) {
459        switch (id) {
460            case DLG_DISABLE:
461                return new AlertDialog.Builder(getActivity())
462                        .setTitle(getActivity().getText(R.string.app_disable_dlg_title))
463                        .setMessage(getActivity().getText(R.string.app_disable_dlg_text))
464                        .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
465                            public void onClick(DialogInterface dialog, int which) {
466                                // Disable the app
467                                new DisableChanger(InstalledAppDetails.this, mAppEntry.info,
468                                        PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER)
469                                .execute((Object)null);
470                            }
471                        })
472                        .setNegativeButton(R.string.dlg_cancel, null)
473                        .create();
474            case DLG_SPECIAL_DISABLE:
475                return new AlertDialog.Builder(getActivity())
476                        .setTitle(getActivity().getText(R.string.app_special_disable_dlg_title))
477                        .setMessage(getActivity().getText(R.string.app_special_disable_dlg_text))
478                        .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
479                            public void onClick(DialogInterface dialog, int which) {
480                                // Clear user data here
481                                uninstallPkg(mAppEntry.info.packageName,
482                                        false, true);
483                            }
484                        })
485                        .setNegativeButton(R.string.dlg_cancel, null)
486                        .create();
487            case DLG_FORCE_STOP:
488                return new AlertDialog.Builder(getActivity())
489                        .setTitle(getActivity().getText(R.string.force_stop_dlg_title))
490                        .setMessage(getActivity().getText(R.string.force_stop_dlg_text))
491                        .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
492                            public void onClick(DialogInterface dialog, int which) {
493                                // Force stop
494                                forceStopPackage(mAppEntry.info.packageName);
495                            }
496                        })
497                        .setNegativeButton(R.string.dlg_cancel, null)
498                        .create();
499            case DLG_FACTORY_RESET:
500                return new AlertDialog.Builder(getActivity())
501                        .setTitle(getActivity().getText(R.string.app_factory_reset_dlg_title))
502                        .setMessage(getActivity().getText(R.string.app_factory_reset_dlg_text))
503                        .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
504                            public void onClick(DialogInterface dialog, int which) {
505                                // Clear user data here
506                                uninstallPkg(mAppEntry.info.packageName,
507                                        false, false);
508                            }
509                        })
510                        .setNegativeButton(R.string.dlg_cancel, null)
511                        .create();
512        }
513        return null;
514    }
515
516    private void uninstallPkg(String packageName, boolean allUsers, boolean andDisable) {
517         // Create new intent to launch Uninstaller activity
518        Uri packageURI = Uri.parse("package:"+packageName);
519        Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageURI);
520        uninstallIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, allUsers);
521        startActivityForResult(uninstallIntent, REQUEST_UNINSTALL);
522        mDisableAfterUninstall = andDisable;
523    }
524
525    private void forceStopPackage(String pkgName) {
526        ActivityManager am = (ActivityManager)getActivity().getSystemService(
527                Context.ACTIVITY_SERVICE);
528        am.forceStopPackage(pkgName);
529        int userId = UserHandle.getUserId(mAppEntry.info.uid);
530        mState.invalidatePackage(pkgName, userId);
531        ApplicationsState.AppEntry newEnt = mState.getEntry(pkgName, userId);
532        if (newEnt != null) {
533            mAppEntry = newEnt;
534        }
535        checkForceStop();
536    }
537
538    private void updateForceStopButton(boolean enabled) {
539        if (mAppControlRestricted) {
540            mForceStopButton.setEnabled(false);
541        } else {
542            mForceStopButton.setEnabled(enabled);
543            mForceStopButton.setOnClickListener(InstalledAppDetails.this);
544        }
545    }
546
547    private void checkForceStop() {
548        if (mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
549            // User can't force stop device admin.
550            updateForceStopButton(false);
551        } else if ((mAppEntry.info.flags&ApplicationInfo.FLAG_STOPPED) == 0) {
552            // If the app isn't explicitly stopped, then always show the
553            // force stop button.
554            updateForceStopButton(true);
555        } else {
556            Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART,
557                    Uri.fromParts("package", mAppEntry.info.packageName, null));
558            intent.putExtra(Intent.EXTRA_PACKAGES, new String[] { mAppEntry.info.packageName });
559            intent.putExtra(Intent.EXTRA_UID, mAppEntry.info.uid);
560            intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(mAppEntry.info.uid));
561            getActivity().sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null,
562                    mCheckKillProcessesReceiver, null, Activity.RESULT_CANCELED, null, null);
563        }
564    }
565
566    private void startAppInfoFragment(Class<? extends AppInfoBase> fragment, CharSequence title) {
567        // start new fragment to display extended information
568        Bundle args = new Bundle();
569        args.putString(InstalledAppDetails.ARG_PACKAGE_NAME, mAppEntry.info.packageName);
570
571        SettingsActivity sa = (SettingsActivity) getActivity();
572        sa.startPreferencePanel(fragment.getName(), args, -1, title, this, SUB_INFO_FRAGMENT);
573    }
574
575    private void startNotifications() {
576        // start new fragment to display extended information
577        getActivity().startActivity(new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
578                .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
579                .putExtra(Settings.EXTRA_APP_PACKAGE, mAppEntry.info.packageName)
580                .putExtra(Settings.EXTRA_APP_UID, mAppEntry.info.uid));
581    }
582
583    /*
584     * Method implementing functionality of buttons clicked
585     * @see android.view.View.OnClickListener#onClick(android.view.View)
586     */
587    public void onClick(View v) {
588        String packageName = mAppEntry.info.packageName;
589        if(v == mUninstallButton) {
590            if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
591                if (mAppEntry.info.enabled) {
592                    if (mUpdatedSysApp) {
593                        showDialogInner(DLG_SPECIAL_DISABLE, 0);
594                    } else {
595                        showDialogInner(DLG_DISABLE, 0);
596                    }
597                } else {
598                    new DisableChanger(this, mAppEntry.info,
599                            PackageManager.COMPONENT_ENABLED_STATE_DEFAULT)
600                                    .execute((Object) null);
601                }
602            } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_INSTALLED) == 0) {
603                uninstallPkg(packageName, true, false);
604            } else {
605                uninstallPkg(packageName, false, false);
606            }
607        } else if (v == mForceStopButton) {
608            showDialogInner(DLG_FORCE_STOP, 0);
609            //forceStopPackage(mAppInfo.packageName);
610        }
611    }
612
613    @Override
614    public boolean onPreferenceClick(Preference preference) {
615        if (preference == mStoragePreference) {
616            startAppInfoFragment(AppStorageSettings.class, mStoragePreference.getTitle());
617        } else if (preference == mNotificationPreference) {
618            startNotifications();
619        } else if (preference == mPermissionsPreference) {
620            startAppInfoFragment(AppPermissionSettings.class, mPermissionsPreference.getTitle());
621        } else if (preference == mLaunchPreference) {
622            startAppInfoFragment(AppLaunchSettings.class, mLaunchPreference.getTitle());
623        } else if (preference == mDataPreference) {
624            Bundle args = new Bundle();
625            args.putString(DataUsageSummary.EXTRA_SHOW_APP_IMMEDIATE_PKG,
626                    mAppEntry.info.packageName);
627
628            SettingsActivity sa = (SettingsActivity) getActivity();
629            sa.startPreferencePanel(DataUsageSummary.class.getName(), args, -1,
630                    getString(R.string.app_data_usage), this, SUB_INFO_FRAGMENT);
631        } else {
632            return false;
633        }
634        return true;
635    }
636
637    public static CharSequence getNotificationSummary(AppEntry appEntry, Context context) {
638        return getNotificationSummary(appEntry, context, new NotificationBackend());
639    }
640
641    public static CharSequence getNotificationSummary(AppEntry appEntry, Context context,
642            NotificationBackend backend) {
643        AppRow appRow = backend.loadAppRow(context.getPackageManager(), appEntry.info);
644        return getNotificationSummary(appRow, context);
645    }
646
647    public static CharSequence getNotificationSummary(AppRow appRow, Context context) {
648        if (appRow.banned) {
649            return context.getString(R.string.notifications_disabled);
650        } else if (appRow.priority) {
651            if (appRow.sensitive) {
652                return context.getString(R.string.notifications_priority_sensitive);
653            }
654            return context.getString(R.string.notifications_priority);
655        } else if (appRow.sensitive) {
656            return context.getString(R.string.notifications_sensitive);
657        }
658        return context.getString(R.string.notifications_enabled);
659    }
660
661    static class DisableChanger extends AsyncTask<Object, Object, Object> {
662        final PackageManager mPm;
663        final WeakReference<InstalledAppDetails> mActivity;
664        final ApplicationInfo mInfo;
665        final int mState;
666
667        DisableChanger(InstalledAppDetails activity, ApplicationInfo info, int state) {
668            mPm = activity.mPm;
669            mActivity = new WeakReference<InstalledAppDetails>(activity);
670            mInfo = info;
671            mState = state;
672        }
673
674        @Override
675        protected Object doInBackground(Object... params) {
676            mPm.setApplicationEnabledSetting(mInfo.packageName, mState, 0);
677            return null;
678        }
679    }
680
681    private final LoaderCallbacks<ChartData> mDataCallbacks = new LoaderCallbacks<ChartData>() {
682
683        @Override
684        public Loader<ChartData> onCreateLoader(int id, Bundle args) {
685            return new ChartDataLoader(getActivity(), mStatsSession, args);
686        }
687
688        @Override
689        public void onLoadFinished(Loader<ChartData> loader, ChartData data) {
690            mChartData = data;
691            mDataPreference.setSummary(getDataSummary());
692        }
693
694        @Override
695        public void onLoaderReset(Loader<ChartData> loader) {
696            mChartData = null;
697            mDataPreference.setSummary(getDataSummary());
698        }
699    };
700
701    private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() {
702        @Override
703        public void onReceive(Context context, Intent intent) {
704            updateForceStopButton(getResultCode() != Activity.RESULT_CANCELED);
705        }
706    };
707}
708
709
710