InstalledAppDetails.java revision 3465b67740e17711af2b36b09e2250a02275d860
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 com.android.internal.telephony.ISms;
20import com.android.internal.telephony.SmsUsageMonitor;
21import com.android.settings.R;
22import com.android.settings.Utils;
23import com.android.settings.applications.ApplicationsState.AppEntry;
24
25import android.app.Activity;
26import android.app.ActivityManager;
27import android.app.AlertDialog;
28import android.app.Dialog;
29import android.app.DialogFragment;
30import android.app.Fragment;
31import android.app.INotificationManager;
32import android.app.admin.DevicePolicyManager;
33import android.appwidget.AppWidgetManager;
34import android.content.BroadcastReceiver;
35import android.content.ComponentName;
36import android.content.Context;
37import android.content.DialogInterface;
38import android.content.Intent;
39import android.content.IntentFilter;
40import android.content.pm.ApplicationInfo;
41import android.content.pm.IPackageDataObserver;
42import android.content.pm.IPackageMoveObserver;
43import android.content.pm.PackageInfo;
44import android.content.pm.PackageManager;
45import android.content.pm.ResolveInfo;
46import android.content.pm.PackageManager.NameNotFoundException;
47import android.content.res.Resources;
48import android.hardware.usb.IUsbManager;
49import android.net.Uri;
50import android.os.AsyncTask;
51import android.os.Bundle;
52import android.os.Environment;
53import android.os.Handler;
54import android.os.IBinder;
55import android.os.Message;
56import android.os.RemoteException;
57import android.os.ServiceManager;
58import android.preference.PreferenceActivity;
59import android.text.SpannableString;
60import android.text.TextUtils;
61import android.text.format.Formatter;
62import android.text.style.BulletSpan;
63import android.util.Log;
64
65import java.lang.ref.WeakReference;
66import java.util.ArrayList;
67import java.util.List;
68import android.view.LayoutInflater;
69import android.view.View;
70import android.view.ViewGroup;
71import android.widget.AdapterView;
72import android.widget.AppSecurityPermissions;
73import android.widget.ArrayAdapter;
74import android.widget.Button;
75import android.widget.CheckBox;
76import android.widget.CompoundButton;
77import android.widget.ImageView;
78import android.widget.LinearLayout;
79import android.widget.Spinner;
80import android.widget.TextView;
81
82/**
83 * Activity to display application information from Settings. This activity presents
84 * extended information associated with a package like code, data, total size, permissions
85 * used by the application and also the set of default launchable activities.
86 * For system applications, an option to clear user data is displayed only if data size is > 0.
87 * System applications that do not want clear user data do not have this option.
88 * For non-system applications, there is no option to clear data. Instead there is an option to
89 * uninstall the application.
90 */
91public class InstalledAppDetails extends Fragment
92        implements View.OnClickListener, CompoundButton.OnCheckedChangeListener,
93        ApplicationsState.Callbacks {
94    private static final String TAG="InstalledAppDetails";
95    static final boolean SUPPORT_DISABLE_APPS = true;
96    private static final boolean localLOGV = false;
97
98    public static final String ARG_PACKAGE_NAME = "package";
99
100    private PackageManager mPm;
101    private IUsbManager mUsbManager;
102    private AppWidgetManager mAppWidgetManager;
103    private DevicePolicyManager mDpm;
104    private ISms mSmsManager;
105    private ApplicationsState mState;
106    private ApplicationsState.Session mSession;
107    private ApplicationsState.AppEntry mAppEntry;
108    private PackageInfo mPackageInfo;
109    private CanBeOnSdCardChecker mCanBeOnSdCardChecker;
110    private View mRootView;
111    private Button mUninstallButton;
112    private boolean mMoveInProgress = false;
113    private boolean mUpdatedSysApp = false;
114    private Button mActivitiesButton;
115    private View mScreenCompatSection;
116    private CheckBox mAskCompatibilityCB;
117    private CheckBox mEnableCompatibilityCB;
118    private boolean mCanClearData = true;
119    private TextView mAppVersion;
120    private TextView mTotalSize;
121    private TextView mAppSize;
122    private TextView mDataSize;
123    private TextView mExternalCodeSize;
124    private TextView mExternalDataSize;
125    private ClearUserDataObserver mClearDataObserver;
126    // Views related to cache info
127    private TextView mCacheSize;
128    private Button mClearCacheButton;
129    private ClearCacheObserver mClearCacheObserver;
130    private Button mForceStopButton;
131    private Button mClearDataButton;
132    private Button mMoveAppButton;
133    private CompoundButton mNotificationSwitch;
134
135    private PackageMoveObserver mPackageMoveObserver;
136
137    private boolean mHaveSizes = false;
138    private long mLastCodeSize = -1;
139    private long mLastDataSize = -1;
140    private long mLastExternalCodeSize = -1;
141    private long mLastExternalDataSize = -1;
142    private long mLastCacheSize = -1;
143    private long mLastTotalSize = -1;
144
145    //internal constants used in Handler
146    private static final int OP_SUCCESSFUL = 1;
147    private static final int OP_FAILED = 2;
148    private static final int CLEAR_USER_DATA = 1;
149    private static final int CLEAR_CACHE = 3;
150    private static final int PACKAGE_MOVE = 4;
151
152    // invalid size value used initially and also when size retrieval through PackageManager
153    // fails for whatever reason
154    private static final int SIZE_INVALID = -1;
155
156    // Resource strings
157    private CharSequence mInvalidSizeStr;
158    private CharSequence mComputingStr;
159
160    // Dialog identifiers used in showDialog
161    private static final int DLG_BASE = 0;
162    private static final int DLG_CLEAR_DATA = DLG_BASE + 1;
163    private static final int DLG_FACTORY_RESET = DLG_BASE + 2;
164    private static final int DLG_APP_NOT_FOUND = DLG_BASE + 3;
165    private static final int DLG_CANNOT_CLEAR_DATA = DLG_BASE + 4;
166    private static final int DLG_FORCE_STOP = DLG_BASE + 5;
167    private static final int DLG_MOVE_FAILED = DLG_BASE + 6;
168    private static final int DLG_DISABLE = DLG_BASE + 7;
169    private static final int DLG_DISABLE_NOTIFICATIONS = DLG_BASE + 8;
170
171    private Handler mHandler = new Handler() {
172        public void handleMessage(Message msg) {
173            // If the fragment is gone, don't process any more messages.
174            if (getView() == null) {
175                return;
176            }
177            switch (msg.what) {
178                case CLEAR_USER_DATA:
179                    processClearMsg(msg);
180                    break;
181                case CLEAR_CACHE:
182                    // Refresh size info
183                    mState.requestSize(mAppEntry.info.packageName);
184                    break;
185                case PACKAGE_MOVE:
186                    processMoveMsg(msg);
187                    break;
188                default:
189                    break;
190            }
191        }
192    };
193
194    class ClearUserDataObserver extends IPackageDataObserver.Stub {
195       public void onRemoveCompleted(final String packageName, final boolean succeeded) {
196           final Message msg = mHandler.obtainMessage(CLEAR_USER_DATA);
197           msg.arg1 = succeeded?OP_SUCCESSFUL:OP_FAILED;
198           mHandler.sendMessage(msg);
199        }
200    }
201
202    class ClearCacheObserver extends IPackageDataObserver.Stub {
203        public void onRemoveCompleted(final String packageName, final boolean succeeded) {
204            final Message msg = mHandler.obtainMessage(CLEAR_CACHE);
205            msg.arg1 = succeeded ? OP_SUCCESSFUL:OP_FAILED;
206            mHandler.sendMessage(msg);
207         }
208     }
209
210    class PackageMoveObserver extends IPackageMoveObserver.Stub {
211        public void packageMoved(String packageName, int returnCode) throws RemoteException {
212            final Message msg = mHandler.obtainMessage(PACKAGE_MOVE);
213            msg.arg1 = returnCode;
214            mHandler.sendMessage(msg);
215        }
216    }
217
218    private String getSizeStr(long size) {
219        if (size == SIZE_INVALID) {
220            return mInvalidSizeStr.toString();
221        }
222        return Formatter.formatFileSize(getActivity(), size);
223    }
224
225    private void initDataButtons() {
226        if ((mAppEntry.info.flags&(ApplicationInfo.FLAG_SYSTEM
227                | ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA))
228                == ApplicationInfo.FLAG_SYSTEM
229                || mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
230            mClearDataButton.setText(R.string.clear_user_data_text);
231            mClearDataButton.setEnabled(false);
232            mCanClearData = false;
233        } else {
234            if (mAppEntry.info.manageSpaceActivityName != null) {
235                mClearDataButton.setText(R.string.manage_space_text);
236            } else {
237                mClearDataButton.setText(R.string.clear_user_data_text);
238            }
239            mClearDataButton.setOnClickListener(this);
240        }
241    }
242
243    private CharSequence getMoveErrMsg(int errCode) {
244        switch (errCode) {
245            case PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE:
246                return getActivity().getString(R.string.insufficient_storage);
247            case PackageManager.MOVE_FAILED_DOESNT_EXIST:
248                return getActivity().getString(R.string.does_not_exist);
249            case PackageManager.MOVE_FAILED_FORWARD_LOCKED:
250                return getActivity().getString(R.string.app_forward_locked);
251            case PackageManager.MOVE_FAILED_INVALID_LOCATION:
252                return getActivity().getString(R.string.invalid_location);
253            case PackageManager.MOVE_FAILED_SYSTEM_PACKAGE:
254                return getActivity().getString(R.string.system_package);
255            case PackageManager.MOVE_FAILED_INTERNAL_ERROR:
256                return "";
257        }
258        return "";
259    }
260
261    private void initMoveButton() {
262        if (Environment.isExternalStorageEmulated()) {
263            mMoveAppButton.setVisibility(View.INVISIBLE);
264            return;
265        }
266        boolean dataOnly = false;
267        dataOnly = (mPackageInfo == null) && (mAppEntry != null);
268        boolean moveDisable = true;
269        if (dataOnly) {
270            mMoveAppButton.setText(R.string.move_app);
271        } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
272            mMoveAppButton.setText(R.string.move_app_to_internal);
273            // Always let apps move to internal storage from sdcard.
274            moveDisable = false;
275        } else {
276            mMoveAppButton.setText(R.string.move_app_to_sdcard);
277            mCanBeOnSdCardChecker.init();
278            moveDisable = !mCanBeOnSdCardChecker.check(mAppEntry.info);
279        }
280        if (moveDisable) {
281            mMoveAppButton.setEnabled(false);
282        } else {
283            mMoveAppButton.setOnClickListener(this);
284            mMoveAppButton.setEnabled(true);
285        }
286    }
287
288    private boolean isThisASystemPackage() {
289        try {
290            PackageInfo sys = mPm.getPackageInfo("android", PackageManager.GET_SIGNATURES);
291            return (mPackageInfo != null && mPackageInfo.signatures != null &&
292                    sys.signatures[0].equals(mPackageInfo.signatures[0]));
293        } catch (PackageManager.NameNotFoundException e) {
294            return false;
295        }
296    }
297
298    private void initUninstallButtons() {
299        mUpdatedSysApp = (mAppEntry.info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
300        boolean enabled = true;
301        if (mUpdatedSysApp) {
302            mUninstallButton.setText(R.string.app_factory_reset);
303        } else {
304            if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
305                enabled = false;
306                if (SUPPORT_DISABLE_APPS) {
307                    try {
308                        // Try to prevent the user from bricking their phone
309                        // by not allowing disabling of apps signed with the
310                        // system cert and any launcher app in the system.
311                        PackageInfo sys = mPm.getPackageInfo("android",
312                                PackageManager.GET_SIGNATURES);
313                        Intent intent = new Intent(Intent.ACTION_MAIN);
314                        intent.addCategory(Intent.CATEGORY_HOME);
315                        intent.setPackage(mAppEntry.info.packageName);
316                        List<ResolveInfo> homes = mPm.queryIntentActivities(intent, 0);
317                        if ((homes != null && homes.size() > 0) || isThisASystemPackage()) {
318                            // Disable button for core system applications.
319                            mUninstallButton.setText(R.string.disable_text);
320                        } else if (mAppEntry.info.enabled) {
321                            mUninstallButton.setText(R.string.disable_text);
322                            enabled = true;
323                        } else {
324                            mUninstallButton.setText(R.string.enable_text);
325                            enabled = true;
326                        }
327                    } catch (PackageManager.NameNotFoundException e) {
328                        Log.w(TAG, "Unable to get package info", e);
329                    }
330                }
331            } else if ((mPackageInfo.applicationInfo.flags
332                    & ApplicationInfo.FLAG_INSTALLED) == 0) {
333                mUninstallButton.setText(R.string.install_text);
334            } else {
335                mUninstallButton.setText(R.string.uninstall_text);
336            }
337        }
338        // If this is a device admin, it can't be uninstall or disabled.
339        // We do this here so the text of the button is still set correctly.
340        if (mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
341            enabled = false;
342        }
343        mUninstallButton.setEnabled(enabled);
344        if (enabled) {
345            // Register listener
346            mUninstallButton.setOnClickListener(this);
347        }
348    }
349
350    private void initNotificationButton() {
351        INotificationManager nm = INotificationManager.Stub.asInterface(
352                ServiceManager.getService(Context.NOTIFICATION_SERVICE));
353        boolean enabled = true; // default on
354        try {
355            enabled = nm.areNotificationsEnabledForPackage(mAppEntry.info.packageName);
356        } catch (android.os.RemoteException ex) {
357            // this does not bode well
358        }
359        mNotificationSwitch.setChecked(enabled);
360        if (isThisASystemPackage()) {
361            mNotificationSwitch.setEnabled(false);
362        } else {
363            mNotificationSwitch.setEnabled(true);
364            mNotificationSwitch.setOnCheckedChangeListener(this);
365        }
366    }
367
368    /** Called when the activity is first created. */
369    @Override
370    public void onCreate(Bundle icicle) {
371        super.onCreate(icicle);
372
373        mState = ApplicationsState.getInstance(getActivity().getApplication());
374        mSession = mState.newSession(this);
375        mPm = getActivity().getPackageManager();
376        IBinder b = ServiceManager.getService(Context.USB_SERVICE);
377        mUsbManager = IUsbManager.Stub.asInterface(b);
378        mAppWidgetManager = AppWidgetManager.getInstance(getActivity());
379        mDpm = (DevicePolicyManager)getActivity().getSystemService(Context.DEVICE_POLICY_SERVICE);
380        mSmsManager = ISms.Stub.asInterface(ServiceManager.getService("isms"));
381
382        mCanBeOnSdCardChecker = new CanBeOnSdCardChecker();
383    }
384
385    @Override
386    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
387        View view = mRootView = inflater.inflate(R.layout.installed_app_details, null);
388
389        mComputingStr = getActivity().getText(R.string.computing_size);
390
391        // Set default values on sizes
392        mTotalSize = (TextView)view.findViewById(R.id.total_size_text);
393        mAppSize = (TextView)view.findViewById(R.id.application_size_text);
394        mDataSize = (TextView)view.findViewById(R.id.data_size_text);
395        mExternalCodeSize = (TextView)view.findViewById(R.id.external_code_size_text);
396        mExternalDataSize = (TextView)view.findViewById(R.id.external_data_size_text);
397
398        if (Environment.isExternalStorageEmulated()) {
399            ((View)mExternalCodeSize.getParent()).setVisibility(View.GONE);
400            ((View)mExternalDataSize.getParent()).setVisibility(View.GONE);
401        }
402
403        // Get Control button panel
404        View btnPanel = view.findViewById(R.id.control_buttons_panel);
405        mForceStopButton = (Button) btnPanel.findViewById(R.id.left_button);
406        mForceStopButton.setText(R.string.force_stop);
407        mUninstallButton = (Button)btnPanel.findViewById(R.id.right_button);
408        mForceStopButton.setEnabled(false);
409
410        // Initialize clear data and move install location buttons
411        View data_buttons_panel = view.findViewById(R.id.data_buttons_panel);
412        mClearDataButton = (Button) data_buttons_panel.findViewById(R.id.right_button);
413        mMoveAppButton = (Button) data_buttons_panel.findViewById(R.id.left_button);
414
415        // Cache section
416        mCacheSize = (TextView) view.findViewById(R.id.cache_size_text);
417        mClearCacheButton = (Button) view.findViewById(R.id.clear_cache_button);
418
419        mActivitiesButton = (Button)view.findViewById(R.id.clear_activities_button);
420
421        // Screen compatibility control
422        mScreenCompatSection = view.findViewById(R.id.screen_compatibility_section);
423        mAskCompatibilityCB = (CheckBox)view.findViewById(R.id.ask_compatibility_cb);
424        mEnableCompatibilityCB = (CheckBox)view.findViewById(R.id.enable_compatibility_cb);
425
426        mNotificationSwitch = (CompoundButton) view.findViewById(R.id.notification_switch);
427
428        return view;
429    }
430
431    // Utility method to set applicaiton label and icon.
432    private void setAppLabelAndIcon(PackageInfo pkgInfo) {
433        View appSnippet = mRootView.findViewById(R.id.app_snippet);
434        ImageView icon = (ImageView) appSnippet.findViewById(R.id.app_icon);
435        mState.ensureIcon(mAppEntry);
436        icon.setImageDrawable(mAppEntry.icon);
437        // Set application name.
438        TextView label = (TextView) appSnippet.findViewById(R.id.app_name);
439        label.setText(mAppEntry.label);
440        // Version number of application
441        mAppVersion = (TextView) appSnippet.findViewById(R.id.app_size);
442
443        if (pkgInfo != null && pkgInfo.versionName != null) {
444            mAppVersion.setVisibility(View.VISIBLE);
445            mAppVersion.setText(getActivity().getString(R.string.version_text,
446                    String.valueOf(pkgInfo.versionName)));
447        } else {
448            mAppVersion.setVisibility(View.INVISIBLE);
449        }
450    }
451
452    @Override
453    public void onResume() {
454        super.onResume();
455
456        mSession.resume();
457        if (!refreshUi()) {
458            setIntentAndFinish(true, true);
459        }
460    }
461
462    @Override
463    public void onPause() {
464        super.onPause();
465        mSession.pause();
466    }
467
468    @Override
469    public void onAllSizesComputed() {
470    }
471
472    @Override
473    public void onPackageIconChanged() {
474    }
475
476    @Override
477    public void onPackageListChanged() {
478        refreshUi();
479    }
480
481    @Override
482    public void onRebuildComplete(ArrayList<AppEntry> apps) {
483    }
484
485    @Override
486    public void onPackageSizeChanged(String packageName) {
487        if (packageName.equals(mAppEntry.info.packageName)) {
488            refreshSizeInfo();
489        }
490    }
491
492    @Override
493    public void onRunningStateChanged(boolean running) {
494    }
495
496    private boolean refreshUi() {
497        if (mMoveInProgress) {
498            return true;
499        }
500        final Bundle args = getArguments();
501        String packageName = (args != null) ? args.getString(ARG_PACKAGE_NAME) : null;
502        if (packageName == null) {
503            Intent intent = (args == null) ?
504                    getActivity().getIntent() : (Intent) args.getParcelable("intent");
505            if (intent != null) {
506                packageName = intent.getData().getSchemeSpecificPart();
507            }
508        }
509        mAppEntry = mState.getEntry(packageName);
510
511        if (mAppEntry == null) {
512            return false; // onCreate must have failed, make sure to exit
513        }
514
515        // Get application info again to refresh changed properties of application
516        try {
517            mPackageInfo = mPm.getPackageInfo(mAppEntry.info.packageName,
518                    PackageManager.GET_DISABLED_COMPONENTS |
519                    PackageManager.GET_UNINSTALLED_PACKAGES |
520                    PackageManager.GET_SIGNATURES);
521        } catch (NameNotFoundException e) {
522            Log.e(TAG, "Exception when retrieving package:" + mAppEntry.info.packageName, e);
523            return false; // onCreate must have failed, make sure to exit
524        }
525
526        // Get list of preferred activities
527        List<ComponentName> prefActList = new ArrayList<ComponentName>();
528
529        // Intent list cannot be null. so pass empty list
530        List<IntentFilter> intentList = new ArrayList<IntentFilter>();
531        mPm.getPreferredActivities(intentList, prefActList, packageName);
532        if (localLOGV)
533            Log.i(TAG, "Have " + prefActList.size() + " number of activities in preferred list");
534        boolean hasUsbDefaults = false;
535        try {
536            hasUsbDefaults = mUsbManager.hasDefaults(packageName);
537        } catch (RemoteException e) {
538            Log.e(TAG, "mUsbManager.hasDefaults", e);
539        }
540        boolean hasBindAppWidgetPermission =
541                mAppWidgetManager.hasBindAppWidgetPermission(mAppEntry.info.packageName);
542
543        TextView autoLaunchTitleView = (TextView) mRootView.findViewById(R.id.auto_launch_title);
544        TextView autoLaunchView = (TextView) mRootView.findViewById(R.id.auto_launch);
545        boolean autoLaunchEnabled = prefActList.size() > 0 || hasUsbDefaults;
546        if (!autoLaunchEnabled && !hasBindAppWidgetPermission) {
547            resetLaunchDefaultsUi(autoLaunchTitleView, autoLaunchView);
548        } else {
549            boolean useBullets = hasBindAppWidgetPermission && autoLaunchEnabled;
550
551            if (hasBindAppWidgetPermission) {
552                autoLaunchTitleView.setText(R.string.auto_launch_label_generic);
553            } else {
554                autoLaunchTitleView.setText(R.string.auto_launch_label);
555            }
556
557            CharSequence text = null;
558            int bulletIndent = getResources()
559                    .getDimensionPixelSize(R.dimen.installed_app_details_bullet_offset);
560            if (autoLaunchEnabled) {
561                CharSequence autoLaunchEnableText = getText(R.string.auto_launch_enable_text);
562                SpannableString s = new SpannableString(autoLaunchEnableText);
563                if (useBullets) {
564                    s.setSpan(new BulletSpan(bulletIndent), 0, autoLaunchEnableText.length(), 0);
565                }
566                text = (text == null) ?
567                        TextUtils.concat(s, "\n") : TextUtils.concat(text, "\n", s, "\n");
568            }
569            if (hasBindAppWidgetPermission) {
570                CharSequence alwaysAllowBindAppWidgetsText =
571                        getText(R.string.always_allow_bind_appwidgets_text);
572                SpannableString s = new SpannableString(alwaysAllowBindAppWidgetsText);
573                if (useBullets) {
574                    s.setSpan(new BulletSpan(bulletIndent),
575                            0, alwaysAllowBindAppWidgetsText.length(), 0);
576                }
577                text = (text == null) ?
578                        TextUtils.concat(s, "\n") : TextUtils.concat(text, "\n", s, "\n");
579            }
580            autoLaunchView.setText(text);
581            mActivitiesButton.setEnabled(true);
582            mActivitiesButton.setOnClickListener(this);
583        }
584
585        // Screen compatibility section.
586        ActivityManager am = (ActivityManager)
587                getActivity().getSystemService(Context.ACTIVITY_SERVICE);
588        int compatMode = am.getPackageScreenCompatMode(packageName);
589        // For now these are always off; this is the old UI model which we
590        // are no longer using.
591        if (false && (compatMode == ActivityManager.COMPAT_MODE_DISABLED
592                || compatMode == ActivityManager.COMPAT_MODE_ENABLED)) {
593            mScreenCompatSection.setVisibility(View.VISIBLE);
594            mAskCompatibilityCB.setChecked(am.getPackageAskScreenCompat(packageName));
595            mAskCompatibilityCB.setOnCheckedChangeListener(this);
596            mEnableCompatibilityCB.setChecked(compatMode == ActivityManager.COMPAT_MODE_ENABLED);
597            mEnableCompatibilityCB.setOnCheckedChangeListener(this);
598        } else {
599            mScreenCompatSection.setVisibility(View.GONE);
600        }
601
602        // Security permissions section
603        LinearLayout permsView = (LinearLayout) mRootView.findViewById(R.id.permissions_section);
604        AppSecurityPermissions asp = new AppSecurityPermissions(getActivity(), packageName);
605        int premiumSmsPermission = getPremiumSmsPermission(packageName);
606        // Premium SMS permission implies the app also has SEND_SMS permission, so the original
607        // application permissions list doesn't have to be shown/hidden separately. The premium
608        // SMS subsection should only be visible if the app has tried to send to a premium SMS.
609        if (asp.getPermissionCount() > 0
610                || premiumSmsPermission != SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN) {
611            permsView.setVisibility(View.VISIBLE);
612        } else {
613            permsView.setVisibility(View.GONE);
614        }
615        // Premium SMS permission subsection
616        TextView securityBillingDesc = (TextView) permsView.findViewById(
617                R.id.security_settings_billing_desc);
618        LinearLayout securityBillingList = (LinearLayout) permsView.findViewById(
619                R.id.security_settings_billing_list);
620        if (premiumSmsPermission != SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN) {
621            // Show the premium SMS permission selector
622            securityBillingDesc.setVisibility(View.VISIBLE);
623            securityBillingList.setVisibility(View.VISIBLE);
624            Spinner spinner = (Spinner) permsView.findViewById(
625                    R.id.security_settings_premium_sms_list);
626            ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(getActivity(),
627                    R.array.security_settings_premium_sms_values,
628                    android.R.layout.simple_spinner_item);
629            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
630            spinner.setAdapter(adapter);
631            // List items are in the same order as SmsUsageMonitor constants, offset by 1.
632            spinner.setSelection(premiumSmsPermission - 1);
633            spinner.setOnItemSelectedListener(new PremiumSmsSelectionListener(
634                    packageName, mSmsManager));
635        } else {
636            // Hide the premium SMS permission selector
637            securityBillingDesc.setVisibility(View.GONE);
638            securityBillingList.setVisibility(View.GONE);
639        }
640        // App permissions subsection
641        if (asp.getPermissionCount() > 0) {
642            // Make the security sections header visible
643            LinearLayout securityList = (LinearLayout) permsView.findViewById(
644                    R.id.security_settings_list);
645            securityList.removeAllViews();
646            securityList.addView(asp.getPermissionsView());
647            // If this app is running under a shared user ID with other apps,
648            // update the description to explain this.
649            String[] packages = mPm.getPackagesForUid(mPackageInfo.applicationInfo.uid);
650            if (packages != null && packages.length > 1) {
651                ArrayList<CharSequence> pnames = new ArrayList<CharSequence>();
652                for (int i=0; i<packages.length; i++) {
653                    String pkg = packages[i];
654                    if (mPackageInfo.packageName.equals(pkg)) {
655                        continue;
656                    }
657                    try {
658                        ApplicationInfo ainfo = mPm.getApplicationInfo(pkg, 0);
659                        pnames.add(ainfo.loadLabel(mPm));
660                    } catch (PackageManager.NameNotFoundException e) {
661                    }
662                }
663                final int N = pnames.size();
664                if (N > 0) {
665                    final Resources res = getActivity().getResources();
666                    String appListStr;
667                    if (N == 1) {
668                        appListStr = pnames.get(0).toString();
669                    } else if (N == 2) {
670                        appListStr = res.getString(R.string.join_two_items, pnames.get(0),
671                                pnames.get(1));
672                    } else {
673                        appListStr = pnames.get(N-2).toString();
674                        for (int i=N-3; i>=0; i--) {
675                            appListStr = res.getString(i == 0 ? R.string.join_many_items_first
676                                    : R.string.join_many_items_middle, pnames.get(i), appListStr);
677                        }
678                        appListStr = res.getString(R.string.join_many_items_last,
679                                appListStr, pnames.get(N-1));
680                    }
681                    TextView descr = (TextView) mRootView.findViewById(
682                            R.id.security_settings_desc);
683                    descr.setText(res.getString(R.string.security_settings_desc_multi,
684                            mPackageInfo.applicationInfo.loadLabel(mPm), appListStr));
685                }
686            }
687        }
688
689        checkForceStop();
690        setAppLabelAndIcon(mPackageInfo);
691        refreshButtons();
692        refreshSizeInfo();
693        return true;
694    }
695
696    private static class PremiumSmsSelectionListener implements AdapterView.OnItemSelectedListener {
697        private final String mPackageName;
698        private final ISms mSmsManager;
699
700        PremiumSmsSelectionListener(String packageName, ISms smsManager) {
701            mPackageName = packageName;
702            mSmsManager = smsManager;
703        }
704
705        @Override
706        public void onItemSelected(AdapterView<?> parent, View view, int position,
707                long id) {
708            if (position >= 0 && position < 3) {
709                Log.d(TAG, "Selected premium SMS policy " + position);
710                setPremiumSmsPermission(mPackageName, (position + 1));
711            } else {
712                Log.e(TAG, "Error: unknown premium SMS policy " + position);
713            }
714        }
715
716        @Override
717        public void onNothingSelected(AdapterView<?> parent) {
718            // Ignored
719        }
720
721        private void setPremiumSmsPermission(String packageName, int permission) {
722            try {
723                if (mSmsManager != null) {
724                    mSmsManager.setPremiumSmsPermission(packageName, permission);
725                }
726            } catch (RemoteException ex) {
727                // ignored
728            }
729        }
730    }
731
732    private void resetLaunchDefaultsUi(TextView title, TextView autoLaunchView) {
733        title.setText(R.string.auto_launch_label);
734        autoLaunchView.setText(R.string.auto_launch_disable_text);
735        // Disable clear activities button
736        mActivitiesButton.setEnabled(false);
737    }
738
739    private void setIntentAndFinish(boolean finish, boolean appChanged) {
740        if(localLOGV) Log.i(TAG, "appChanged="+appChanged);
741        Intent intent = new Intent();
742        intent.putExtra(ManageApplications.APP_CHG, appChanged);
743        PreferenceActivity pa = (PreferenceActivity)getActivity();
744        pa.finishPreferencePanel(this, Activity.RESULT_OK, intent);
745    }
746
747    private void refreshSizeInfo() {
748        if (mAppEntry.size == ApplicationsState.SIZE_INVALID
749                || mAppEntry.size == ApplicationsState.SIZE_UNKNOWN) {
750            mLastCodeSize = mLastDataSize = mLastCacheSize = mLastTotalSize = -1;
751            if (!mHaveSizes) {
752                mAppSize.setText(mComputingStr);
753                mDataSize.setText(mComputingStr);
754                mCacheSize.setText(mComputingStr);
755                mTotalSize.setText(mComputingStr);
756            }
757            mClearDataButton.setEnabled(false);
758            mClearCacheButton.setEnabled(false);
759
760        } else {
761            mHaveSizes = true;
762            long codeSize = mAppEntry.codeSize;
763            long dataSize = mAppEntry.dataSize;
764            if (Environment.isExternalStorageEmulated()) {
765                codeSize += mAppEntry.externalCodeSize;
766                dataSize +=  mAppEntry.externalDataSize;
767            } else {
768                if (mLastExternalCodeSize != mAppEntry.externalCodeSize) {
769                    mLastExternalCodeSize = mAppEntry.externalCodeSize;
770                    mExternalCodeSize.setText(getSizeStr(mAppEntry.externalCodeSize));
771                }
772                if (mLastExternalDataSize !=  mAppEntry.externalDataSize) {
773                    mLastExternalDataSize =  mAppEntry.externalDataSize;
774                    mExternalDataSize.setText(getSizeStr( mAppEntry.externalDataSize));
775                }
776            }
777            if (mLastCodeSize != codeSize) {
778                mLastCodeSize = codeSize;
779                mAppSize.setText(getSizeStr(codeSize));
780            }
781            if (mLastDataSize != dataSize) {
782                mLastDataSize = dataSize;
783                mDataSize.setText(getSizeStr(dataSize));
784            }
785            long cacheSize = mAppEntry.cacheSize + mAppEntry.externalCacheSize;
786            if (mLastCacheSize != cacheSize) {
787                mLastCacheSize = cacheSize;
788                mCacheSize.setText(getSizeStr(cacheSize));
789            }
790            if (mLastTotalSize != mAppEntry.size) {
791                mLastTotalSize = mAppEntry.size;
792                mTotalSize.setText(getSizeStr(mAppEntry.size));
793            }
794
795            if ((mAppEntry.dataSize+ mAppEntry.externalDataSize) <= 0 || !mCanClearData) {
796                mClearDataButton.setEnabled(false);
797            } else {
798                mClearDataButton.setEnabled(true);
799                mClearDataButton.setOnClickListener(this);
800            }
801            if (cacheSize <= 0) {
802                mClearCacheButton.setEnabled(false);
803            } else {
804                mClearCacheButton.setEnabled(true);
805                mClearCacheButton.setOnClickListener(this);
806            }
807        }
808    }
809
810    /*
811     * Private method to handle clear message notification from observer when
812     * the async operation from PackageManager is complete
813     */
814    private void processClearMsg(Message msg) {
815        int result = msg.arg1;
816        String packageName = mAppEntry.info.packageName;
817        mClearDataButton.setText(R.string.clear_user_data_text);
818        if(result == OP_SUCCESSFUL) {
819            Log.i(TAG, "Cleared user data for package : "+packageName);
820            mState.requestSize(mAppEntry.info.packageName);
821        } else {
822            mClearDataButton.setEnabled(true);
823        }
824        checkForceStop();
825    }
826
827    private void refreshButtons() {
828        if (!mMoveInProgress) {
829            initUninstallButtons();
830            initDataButtons();
831            initMoveButton();
832            initNotificationButton();
833        } else {
834            mMoveAppButton.setText(R.string.moving);
835            mMoveAppButton.setEnabled(false);
836            mUninstallButton.setEnabled(false);
837        }
838    }
839
840    private void processMoveMsg(Message msg) {
841        int result = msg.arg1;
842        String packageName = mAppEntry.info.packageName;
843        // Refresh the button attributes.
844        mMoveInProgress = false;
845        if (result == PackageManager.MOVE_SUCCEEDED) {
846            Log.i(TAG, "Moved resources for " + packageName);
847            // Refresh size information again.
848            mState.requestSize(mAppEntry.info.packageName);
849        } else {
850            showDialogInner(DLG_MOVE_FAILED, result);
851        }
852        refreshUi();
853    }
854
855    /*
856     * Private method to initiate clearing user data when the user clicks the clear data
857     * button for a system package
858     */
859    private  void initiateClearUserData() {
860        mClearDataButton.setEnabled(false);
861        // Invoke uninstall or clear user data based on sysPackage
862        String packageName = mAppEntry.info.packageName;
863        Log.i(TAG, "Clearing user data for package : " + packageName);
864        if (mClearDataObserver == null) {
865            mClearDataObserver = new ClearUserDataObserver();
866        }
867        ActivityManager am = (ActivityManager)
868                getActivity().getSystemService(Context.ACTIVITY_SERVICE);
869        boolean res = am.clearApplicationUserData(packageName, mClearDataObserver);
870        if (!res) {
871            // Clearing data failed for some obscure reason. Just log error for now
872            Log.i(TAG, "Couldnt clear application user data for package:"+packageName);
873            showDialogInner(DLG_CANNOT_CLEAR_DATA, 0);
874        } else {
875            mClearDataButton.setText(R.string.recompute_size);
876        }
877    }
878
879    private void showDialogInner(int id, int moveErrorCode) {
880        DialogFragment newFragment = MyAlertDialogFragment.newInstance(id, moveErrorCode);
881        newFragment.setTargetFragment(this, 0);
882        newFragment.show(getFragmentManager(), "dialog " + id);
883    }
884
885    public static class MyAlertDialogFragment extends DialogFragment {
886
887        public static MyAlertDialogFragment newInstance(int id, int moveErrorCode) {
888            MyAlertDialogFragment frag = new MyAlertDialogFragment();
889            Bundle args = new Bundle();
890            args.putInt("id", id);
891            args.putInt("moveError", moveErrorCode);
892            frag.setArguments(args);
893            return frag;
894        }
895
896        InstalledAppDetails getOwner() {
897            return (InstalledAppDetails)getTargetFragment();
898        }
899
900        @Override
901        public Dialog onCreateDialog(Bundle savedInstanceState) {
902            int id = getArguments().getInt("id");
903            int moveErrorCode = getArguments().getInt("moveError");
904            switch (id) {
905                case DLG_CLEAR_DATA:
906                    return new AlertDialog.Builder(getActivity())
907                    .setTitle(getActivity().getText(R.string.clear_data_dlg_title))
908                    .setIconAttribute(android.R.attr.alertDialogIcon)
909                    .setMessage(getActivity().getText(R.string.clear_data_dlg_text))
910                    .setPositiveButton(R.string.dlg_ok,
911                            new DialogInterface.OnClickListener() {
912                        public void onClick(DialogInterface dialog, int which) {
913                            // Clear user data here
914                            getOwner().initiateClearUserData();
915                        }
916                    })
917                    .setNegativeButton(R.string.dlg_cancel, null)
918                    .create();
919                case DLG_FACTORY_RESET:
920                    return new AlertDialog.Builder(getActivity())
921                    .setTitle(getActivity().getText(R.string.app_factory_reset_dlg_title))
922                    .setIconAttribute(android.R.attr.alertDialogIcon)
923                    .setMessage(getActivity().getText(R.string.app_factory_reset_dlg_text))
924                    .setPositiveButton(R.string.dlg_ok,
925                            new DialogInterface.OnClickListener() {
926                        public void onClick(DialogInterface dialog, int which) {
927                            // Clear user data here
928                            getOwner().uninstallPkg(getOwner().mAppEntry.info.packageName);
929                        }
930                    })
931                    .setNegativeButton(R.string.dlg_cancel, null)
932                    .create();
933                case DLG_APP_NOT_FOUND:
934                    return new AlertDialog.Builder(getActivity())
935                    .setTitle(getActivity().getText(R.string.app_not_found_dlg_title))
936                    .setIconAttribute(android.R.attr.alertDialogIcon)
937                    .setMessage(getActivity().getText(R.string.app_not_found_dlg_title))
938                    .setNeutralButton(getActivity().getText(R.string.dlg_ok),
939                            new DialogInterface.OnClickListener() {
940                        public void onClick(DialogInterface dialog, int which) {
941                            //force to recompute changed value
942                            getOwner().setIntentAndFinish(true, true);
943                        }
944                    })
945                    .create();
946                case DLG_CANNOT_CLEAR_DATA:
947                    return new AlertDialog.Builder(getActivity())
948                    .setTitle(getActivity().getText(R.string.clear_failed_dlg_title))
949                    .setIconAttribute(android.R.attr.alertDialogIcon)
950                    .setMessage(getActivity().getText(R.string.clear_failed_dlg_text))
951                    .setNeutralButton(R.string.dlg_ok,
952                            new DialogInterface.OnClickListener() {
953                        public void onClick(DialogInterface dialog, int which) {
954                            getOwner().mClearDataButton.setEnabled(false);
955                            //force to recompute changed value
956                            getOwner().setIntentAndFinish(false, false);
957                        }
958                    })
959                    .create();
960                case DLG_FORCE_STOP:
961                    return new AlertDialog.Builder(getActivity())
962                    .setTitle(getActivity().getText(R.string.force_stop_dlg_title))
963                    .setIconAttribute(android.R.attr.alertDialogIcon)
964                    .setMessage(getActivity().getText(R.string.force_stop_dlg_text))
965                    .setPositiveButton(R.string.dlg_ok,
966                        new DialogInterface.OnClickListener() {
967                        public void onClick(DialogInterface dialog, int which) {
968                            // Force stop
969                            getOwner().forceStopPackage(getOwner().mAppEntry.info.packageName);
970                        }
971                    })
972                    .setNegativeButton(R.string.dlg_cancel, null)
973                    .create();
974                case DLG_MOVE_FAILED:
975                    CharSequence msg = getActivity().getString(R.string.move_app_failed_dlg_text,
976                            getOwner().getMoveErrMsg(moveErrorCode));
977                    return new AlertDialog.Builder(getActivity())
978                    .setTitle(getActivity().getText(R.string.move_app_failed_dlg_title))
979                    .setIconAttribute(android.R.attr.alertDialogIcon)
980                    .setMessage(msg)
981                    .setNeutralButton(R.string.dlg_ok, null)
982                    .create();
983                case DLG_DISABLE:
984                    return new AlertDialog.Builder(getActivity())
985                    .setTitle(getActivity().getText(R.string.app_disable_dlg_title))
986                    .setIconAttribute(android.R.attr.alertDialogIcon)
987                    .setMessage(getActivity().getText(R.string.app_disable_dlg_text))
988                    .setPositiveButton(R.string.dlg_ok,
989                        new DialogInterface.OnClickListener() {
990                        public void onClick(DialogInterface dialog, int which) {
991                            // Disable the app
992                            new DisableChanger(getOwner(), getOwner().mAppEntry.info,
993                                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER)
994                            .execute((Object)null);
995                        }
996                    })
997                    .setNegativeButton(R.string.dlg_cancel, null)
998                    .create();
999                case DLG_DISABLE_NOTIFICATIONS:
1000                    return new AlertDialog.Builder(getActivity())
1001                    .setTitle(getActivity().getText(R.string.app_disable_notifications_dlg_title))
1002                    .setIconAttribute(android.R.attr.alertDialogIcon)
1003                    .setMessage(getActivity().getText(R.string.app_disable_notifications_dlg_text))
1004                    .setPositiveButton(R.string.dlg_ok,
1005                        new DialogInterface.OnClickListener() {
1006                        public void onClick(DialogInterface dialog, int which) {
1007                            // Disable the package's notifications
1008                            getOwner().setNotificationsEnabled(false);
1009                        }
1010                    })
1011                    .setNegativeButton(R.string.dlg_cancel,
1012                        new DialogInterface.OnClickListener() {
1013                        public void onClick(DialogInterface dialog, int which) {
1014                            // Re-enable the checkbox
1015                            getOwner().mNotificationSwitch.setChecked(true);
1016                        }
1017                    })
1018                    .create();
1019            }
1020            throw new IllegalArgumentException("unknown id " + id);
1021        }
1022    }
1023
1024    private void uninstallPkg(String packageName) {
1025         // Create new intent to launch Uninstaller activity
1026        Uri packageURI = Uri.parse("package:"+packageName);
1027        Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI);
1028        startActivity(uninstallIntent);
1029        setIntentAndFinish(true, true);
1030    }
1031
1032    private void forceStopPackage(String pkgName) {
1033        ActivityManager am = (ActivityManager)getActivity().getSystemService(
1034                Context.ACTIVITY_SERVICE);
1035        am.forceStopPackage(pkgName);
1036        mState.invalidatePackage(pkgName);
1037        ApplicationsState.AppEntry newEnt = mState.getEntry(pkgName);
1038        if (newEnt != null) {
1039            mAppEntry = newEnt;
1040        }
1041        checkForceStop();
1042    }
1043
1044    private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() {
1045        @Override
1046        public void onReceive(Context context, Intent intent) {
1047            updateForceStopButton(getResultCode() != Activity.RESULT_CANCELED);
1048        }
1049    };
1050
1051    private void updateForceStopButton(boolean enabled) {
1052        mForceStopButton.setEnabled(enabled);
1053        mForceStopButton.setOnClickListener(InstalledAppDetails.this);
1054    }
1055
1056    private void checkForceStop() {
1057        if (mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
1058            // User can't force stop device admin.
1059            updateForceStopButton(false);
1060        } else if ((mAppEntry.info.flags&ApplicationInfo.FLAG_STOPPED) == 0) {
1061            // If the app isn't explicitly stopped, then always show the
1062            // force stop button.
1063            updateForceStopButton(true);
1064        } else {
1065            Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART,
1066                    Uri.fromParts("package", mAppEntry.info.packageName, null));
1067            intent.putExtra(Intent.EXTRA_PACKAGES, new String[] { mAppEntry.info.packageName });
1068            intent.putExtra(Intent.EXTRA_UID, mAppEntry.info.uid);
1069            getActivity().sendOrderedBroadcast(intent, null, mCheckKillProcessesReceiver, null,
1070                    Activity.RESULT_CANCELED, null, null);
1071        }
1072    }
1073
1074    static class DisableChanger extends AsyncTask<Object, Object, Object> {
1075        final PackageManager mPm;
1076        final WeakReference<InstalledAppDetails> mActivity;
1077        final ApplicationInfo mInfo;
1078        final int mState;
1079
1080        DisableChanger(InstalledAppDetails activity, ApplicationInfo info, int state) {
1081            mPm = activity.mPm;
1082            mActivity = new WeakReference<InstalledAppDetails>(activity);
1083            mInfo = info;
1084            mState = state;
1085        }
1086
1087        @Override
1088        protected Object doInBackground(Object... params) {
1089            mPm.setApplicationEnabledSetting(mInfo.packageName, mState, 0);
1090            return null;
1091        }
1092    }
1093
1094    private void setNotificationsEnabled(boolean enabled) {
1095        String packageName = mAppEntry.info.packageName;
1096        INotificationManager nm = INotificationManager.Stub.asInterface(
1097                ServiceManager.getService(Context.NOTIFICATION_SERVICE));
1098        try {
1099            final boolean enable = mNotificationSwitch.isChecked();
1100            nm.setNotificationsEnabledForPackage(packageName, enabled);
1101        } catch (android.os.RemoteException ex) {
1102            mNotificationSwitch.setChecked(!enabled); // revert
1103        }
1104    }
1105
1106    private int getPremiumSmsPermission(String packageName) {
1107        try {
1108            if (mSmsManager != null) {
1109                return mSmsManager.getPremiumSmsPermission(packageName);
1110            }
1111        } catch (RemoteException ex) {
1112            // ignored
1113        }
1114        return SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN;
1115    }
1116
1117    /*
1118     * Method implementing functionality of buttons clicked
1119     * @see android.view.View.OnClickListener#onClick(android.view.View)
1120     */
1121    public void onClick(View v) {
1122        String packageName = mAppEntry.info.packageName;
1123        if(v == mUninstallButton) {
1124            if (mUpdatedSysApp) {
1125                showDialogInner(DLG_FACTORY_RESET, 0);
1126            } else {
1127                if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
1128                    if (mAppEntry.info.enabled) {
1129                        showDialogInner(DLG_DISABLE, 0);
1130                    } else {
1131                        new DisableChanger(this, mAppEntry.info,
1132                                PackageManager.COMPONENT_ENABLED_STATE_DEFAULT)
1133                        .execute((Object)null);
1134                    }
1135                } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_INSTALLED) == 0) {
1136                    try {
1137                        mPm.installExistingPackage(packageName);
1138                        refreshUi();
1139                    } catch (NameNotFoundException e) {
1140                    }
1141                } else {
1142                    uninstallPkg(packageName);
1143                }
1144            }
1145        } else if(v == mActivitiesButton) {
1146            mPm.clearPackagePreferredActivities(packageName);
1147            try {
1148                mUsbManager.clearDefaults(packageName);
1149            } catch (RemoteException e) {
1150                Log.e(TAG, "mUsbManager.clearDefaults", e);
1151            }
1152            mAppWidgetManager.setBindAppWidgetPermission(packageName, false);
1153            TextView autoLaunchTitleView =
1154                    (TextView) mRootView.findViewById(R.id.auto_launch_title);
1155            TextView autoLaunchView = (TextView) mRootView.findViewById(R.id.auto_launch);
1156            resetLaunchDefaultsUi(autoLaunchTitleView, autoLaunchView);
1157        } else if(v == mClearDataButton) {
1158            if (mAppEntry.info.manageSpaceActivityName != null) {
1159                if (!Utils.isMonkeyRunning()) {
1160                    Intent intent = new Intent(Intent.ACTION_DEFAULT);
1161                    intent.setClassName(mAppEntry.info.packageName,
1162                            mAppEntry.info.manageSpaceActivityName);
1163                    startActivityForResult(intent, -1);
1164                }
1165            } else {
1166                showDialogInner(DLG_CLEAR_DATA, 0);
1167            }
1168        } else if (v == mClearCacheButton) {
1169            // Lazy initialization of observer
1170            if (mClearCacheObserver == null) {
1171                mClearCacheObserver = new ClearCacheObserver();
1172            }
1173            mPm.deleteApplicationCacheFiles(packageName, mClearCacheObserver);
1174        } else if (v == mForceStopButton) {
1175            showDialogInner(DLG_FORCE_STOP, 0);
1176            //forceStopPackage(mAppInfo.packageName);
1177        } else if (v == mMoveAppButton) {
1178            if (mPackageMoveObserver == null) {
1179                mPackageMoveObserver = new PackageMoveObserver();
1180            }
1181            int moveFlags = (mAppEntry.info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0 ?
1182                    PackageManager.MOVE_INTERNAL : PackageManager.MOVE_EXTERNAL_MEDIA;
1183            mMoveInProgress = true;
1184            refreshButtons();
1185            mPm.movePackage(mAppEntry.info.packageName, mPackageMoveObserver, moveFlags);
1186        }
1187    }
1188
1189    @Override
1190    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
1191        String packageName = mAppEntry.info.packageName;
1192        ActivityManager am = (ActivityManager)
1193                getActivity().getSystemService(Context.ACTIVITY_SERVICE);
1194        if (buttonView == mAskCompatibilityCB) {
1195            am.setPackageAskScreenCompat(packageName, isChecked);
1196        } else if (buttonView == mEnableCompatibilityCB) {
1197            am.setPackageScreenCompatMode(packageName, isChecked ?
1198                    ActivityManager.COMPAT_MODE_ENABLED : ActivityManager.COMPAT_MODE_DISABLED);
1199        } else if (buttonView == mNotificationSwitch) {
1200            if (!isChecked) {
1201                showDialogInner(DLG_DISABLE_NOTIFICATIONS, 0);
1202            } else {
1203                setNotificationsEnabled(true);
1204            }
1205        }
1206    }
1207}
1208
1209