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