OSDN Git Service

Fix issue #4021524 HMI63B: "Force stop" button not disabled after app is stopped
[android-x86/packages-apps-Settings.git] / src / com / android / settings / applications / InstalledAppDetails.java
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.settings.R;
20 import com.android.settings.applications.ApplicationsState.AppEntry;
21
22 import android.app.Activity;
23 import android.app.ActivityManager;
24 import android.app.AlertDialog;
25 import android.app.Dialog;
26 import android.app.DialogFragment;
27 import android.app.Fragment;
28 import android.content.BroadcastReceiver;
29 import android.content.Context;
30 import android.content.DialogInterface;
31 import android.content.Intent;
32 import android.content.IntentFilter;
33 import android.content.pm.ApplicationInfo;
34 import android.content.pm.IPackageDataObserver;
35 import android.content.pm.IPackageMoveObserver;
36 import android.content.pm.PackageInfo;
37 import android.content.pm.PackageManager;
38 import android.content.pm.ResolveInfo;
39 import android.content.pm.PackageManager.NameNotFoundException;
40 import android.hardware.usb.IUsbManager;
41 import android.net.Uri;
42 import android.os.AsyncTask;
43 import android.os.Bundle;
44 import android.os.Environment;
45 import android.os.Handler;
46 import android.os.IBinder;
47 import android.os.Message;
48 import android.os.RemoteException;
49 import android.os.ServiceManager;
50 import android.preference.PreferenceActivity;
51 import android.text.format.Formatter;
52 import android.util.Log;
53
54 import java.lang.ref.WeakReference;
55 import java.util.ArrayList;
56 import java.util.List;
57 import android.content.ComponentName;
58 import android.view.LayoutInflater;
59 import android.view.View;
60 import android.view.ViewGroup;
61 import android.widget.AppSecurityPermissions;
62 import android.widget.Button;
63 import android.widget.ImageView;
64 import android.widget.LinearLayout;
65 import android.widget.TextView;
66
67 /**
68  * Activity to display application information from Settings. This activity presents
69  * extended information associated with a package like code, data, total size, permissions
70  * used by the application and also the set of default launchable activities.
71  * For system applications, an option to clear user data is displayed only if data size is > 0.
72  * System applications that do not want clear user data do not have this option.
73  * For non-system applications, there is no option to clear data. Instead there is an option to
74  * uninstall the application.
75  */
76 public class InstalledAppDetails extends Fragment
77         implements View.OnClickListener, ApplicationsState.Callbacks {
78     private static final String TAG="InstalledAppDetails";
79     static final boolean SUPPORT_DISABLE_APPS = false;
80     private static final boolean localLOGV = false;
81     
82     public static final String ARG_PACKAGE_NAME = "package";
83
84     private PackageManager mPm;
85     private IUsbManager mUsbManager;
86     private ApplicationsState mState;
87     private ApplicationsState.AppEntry mAppEntry;
88     private PackageInfo mPackageInfo;
89     private CanBeOnSdCardChecker mCanBeOnSdCardChecker;
90     private View mRootView;
91     private Button mUninstallButton;
92     private boolean mMoveInProgress = false;
93     private boolean mUpdatedSysApp = false;
94     private Button mActivitiesButton;
95     private boolean mCanClearData = true;
96     private TextView mAppVersion;
97     private TextView mTotalSize;
98     private TextView mAppSize;
99     private TextView mDataSize;
100     private TextView mExternalSize;
101     private ClearUserDataObserver mClearDataObserver;
102     // Views related to cache info
103     private TextView mCacheSize;
104     private Button mClearCacheButton;
105     private ClearCacheObserver mClearCacheObserver;
106     private Button mForceStopButton;
107     private Button mClearDataButton;
108     private Button mMoveAppButton;
109     
110     private PackageMoveObserver mPackageMoveObserver;
111     
112     private boolean mHaveSizes = false;
113     private long mLastCodeSize = -1;
114     private long mLastDataSize = -1;
115     private long mLastExternalSize = -1;
116     private long mLastCacheSize = -1;
117     private long mLastTotalSize = -1;
118     
119     //internal constants used in Handler
120     private static final int OP_SUCCESSFUL = 1;
121     private static final int OP_FAILED = 2;
122     private static final int CLEAR_USER_DATA = 1;
123     private static final int CLEAR_CACHE = 3;
124     private static final int PACKAGE_MOVE = 4;
125     
126     // invalid size value used initially and also when size retrieval through PackageManager
127     // fails for whatever reason
128     private static final int SIZE_INVALID = -1;
129     
130     // Resource strings
131     private CharSequence mInvalidSizeStr;
132     private CharSequence mComputingStr;
133     
134     // Dialog identifiers used in showDialog
135     private static final int DLG_BASE = 0;
136     private static final int DLG_CLEAR_DATA = DLG_BASE + 1;
137     private static final int DLG_FACTORY_RESET = DLG_BASE + 2;
138     private static final int DLG_APP_NOT_FOUND = DLG_BASE + 3;
139     private static final int DLG_CANNOT_CLEAR_DATA = DLG_BASE + 4;
140     private static final int DLG_FORCE_STOP = DLG_BASE + 5;
141     private static final int DLG_MOVE_FAILED = DLG_BASE + 6;
142     
143     private Handler mHandler = new Handler() {
144         public void handleMessage(Message msg) {
145             // If the fragment is gone, don't process any more messages.
146             if (getView() == null) {
147                 return;
148             }
149             switch (msg.what) {
150                 case CLEAR_USER_DATA:
151                     processClearMsg(msg);
152                     break;
153                 case CLEAR_CACHE:
154                     // Refresh size info
155                     mState.requestSize(mAppEntry.info.packageName);
156                     break;
157                 case PACKAGE_MOVE:
158                     processMoveMsg(msg);
159                     break;
160                 default:
161                     break;
162             }
163         }
164     };
165     
166     class ClearUserDataObserver extends IPackageDataObserver.Stub {
167        public void onRemoveCompleted(final String packageName, final boolean succeeded) {
168            final Message msg = mHandler.obtainMessage(CLEAR_USER_DATA);
169            msg.arg1 = succeeded?OP_SUCCESSFUL:OP_FAILED;
170            mHandler.sendMessage(msg);
171         }
172     }
173     
174     class ClearCacheObserver extends IPackageDataObserver.Stub {
175         public void onRemoveCompleted(final String packageName, final boolean succeeded) {
176             final Message msg = mHandler.obtainMessage(CLEAR_CACHE);
177             msg.arg1 = succeeded ? OP_SUCCESSFUL:OP_FAILED;
178             mHandler.sendMessage(msg);
179          }
180      }
181
182     class PackageMoveObserver extends IPackageMoveObserver.Stub {
183         public void packageMoved(String packageName, int returnCode) throws RemoteException {
184             final Message msg = mHandler.obtainMessage(PACKAGE_MOVE);
185             msg.arg1 = returnCode;
186             mHandler.sendMessage(msg);
187         }
188     }
189     
190     private String getSizeStr(long size) {
191         if (size == SIZE_INVALID) {
192             return mInvalidSizeStr.toString();
193         }
194         return Formatter.formatFileSize(getActivity(), size);
195     }
196     
197     private void initDataButtons() {
198         if ((mAppEntry.info.flags&(ApplicationInfo.FLAG_SYSTEM
199                 | ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA))
200                 == ApplicationInfo.FLAG_SYSTEM) {
201             mClearDataButton.setText(R.string.clear_user_data_text);
202             mClearDataButton.setEnabled(false);
203             mCanClearData = false;
204         } else {
205             if (mAppEntry.info.manageSpaceActivityName != null) {
206                 mClearDataButton.setText(R.string.manage_space_text);
207             } else {
208                 mClearDataButton.setText(R.string.clear_user_data_text);
209             }
210             mClearDataButton.setOnClickListener(this);
211         }
212     }
213
214     private CharSequence getMoveErrMsg(int errCode) {
215         switch (errCode) {
216             case PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE:
217                 return getActivity().getString(R.string.insufficient_storage);
218             case PackageManager.MOVE_FAILED_DOESNT_EXIST:
219                 return getActivity().getString(R.string.does_not_exist);
220             case PackageManager.MOVE_FAILED_FORWARD_LOCKED:
221                 return getActivity().getString(R.string.app_forward_locked);
222             case PackageManager.MOVE_FAILED_INVALID_LOCATION:
223                 return getActivity().getString(R.string.invalid_location);
224             case PackageManager.MOVE_FAILED_SYSTEM_PACKAGE:
225                 return getActivity().getString(R.string.system_package);
226             case PackageManager.MOVE_FAILED_INTERNAL_ERROR:
227                 return "";
228         }
229         return "";
230     }
231
232     private void initMoveButton() {
233         if (Environment.isExternalStorageEmulated()) {
234             mMoveAppButton.setVisibility(View.INVISIBLE);
235             return;
236         }
237         boolean dataOnly = false;
238         dataOnly = (mPackageInfo == null) && (mAppEntry != null);
239         boolean moveDisable = true;
240         if (dataOnly) {
241             mMoveAppButton.setText(R.string.move_app);
242         } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
243             mMoveAppButton.setText(R.string.move_app_to_internal);
244             // Always let apps move to internal storage from sdcard.
245             moveDisable = false;
246         } else {
247             mMoveAppButton.setText(R.string.move_app_to_sdcard);
248             mCanBeOnSdCardChecker.init();
249             moveDisable = !mCanBeOnSdCardChecker.check(mAppEntry.info);
250         }
251         if (moveDisable) {
252             mMoveAppButton.setEnabled(false);
253         } else {
254             mMoveAppButton.setOnClickListener(this);
255             mMoveAppButton.setEnabled(true);
256         }
257     }
258
259     private void initUninstallButtons() {
260         mUpdatedSysApp = (mAppEntry.info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
261         boolean enabled = true;
262         if (mUpdatedSysApp) {
263             mUninstallButton.setText(R.string.app_factory_reset);
264         } else {
265             if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
266                 enabled = false;
267                 if (SUPPORT_DISABLE_APPS) {
268                     try {
269                         // Try to prevent the user from bricking their phone
270                         // by not allowing disabling of apps signed with the
271                         // system cert and any launcher app in the system.
272                         PackageInfo sys = mPm.getPackageInfo("android",
273                                 PackageManager.GET_SIGNATURES);
274                         Intent intent = new Intent(Intent.ACTION_MAIN);
275                         intent.addCategory(Intent.CATEGORY_HOME);
276                         intent.setPackage(mAppEntry.info.packageName);
277                         List<ResolveInfo> homes = mPm.queryIntentActivities(intent, 0);
278                         if ((homes != null && homes.size() > 0) ||
279                                 (mPackageInfo != null &&
280                                         sys.signatures[0].equals(mPackageInfo.signatures[0]))) {
281                             // Disable button for core system applications.
282                             mUninstallButton.setText(R.string.disable_text);
283                         } else if (mAppEntry.info.enabled) {
284                             mUninstallButton.setText(R.string.disable_text);
285                             enabled = true;
286                         } else {
287                             mUninstallButton.setText(R.string.enable_text);
288                             enabled = true;
289                         }
290                     } catch (PackageManager.NameNotFoundException e) {
291                         Log.w(TAG, "Unable to get package info", e);
292                     }
293                 }
294             } else {
295                 mUninstallButton.setText(R.string.uninstall_text);
296             }
297         }
298         mUninstallButton.setEnabled(enabled);
299         if (enabled) {
300             // Register listener
301             mUninstallButton.setOnClickListener(this);
302         }
303     }
304
305     /** Called when the activity is first created. */
306     @Override
307     public void onCreate(Bundle icicle) {
308         super.onCreate(icicle);
309         
310         mState = ApplicationsState.getInstance(getActivity().getApplication());
311         mPm = getActivity().getPackageManager();
312         IBinder b = ServiceManager.getService(Context.USB_SERVICE);
313         mUsbManager = IUsbManager.Stub.asInterface(b);
314
315         mCanBeOnSdCardChecker = new CanBeOnSdCardChecker();
316     }
317
318     @Override
319     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
320         View view = mRootView = inflater.inflate(R.layout.installed_app_details, null);
321         
322         mComputingStr = getActivity().getText(R.string.computing_size);
323         
324         // Set default values on sizes
325         mTotalSize = (TextView)view.findViewById(R.id.total_size_text);
326         mAppSize = (TextView)view.findViewById(R.id.application_size_text);
327         mDataSize = (TextView)view.findViewById(R.id.data_size_text);
328         mExternalSize = (TextView)view.findViewById(R.id.external_size_text);
329         
330         // Get Control button panel
331         View btnPanel = view.findViewById(R.id.control_buttons_panel);
332         mForceStopButton = (Button) btnPanel.findViewById(R.id.left_button);
333         mForceStopButton.setText(R.string.force_stop);
334         mUninstallButton = (Button)btnPanel.findViewById(R.id.right_button);
335         mForceStopButton.setEnabled(false);
336         
337         // Initialize clear data and move install location buttons
338         View data_buttons_panel = view.findViewById(R.id.data_buttons_panel);
339         mClearDataButton = (Button) data_buttons_panel.findViewById(R.id.left_button);
340         mMoveAppButton = (Button) data_buttons_panel.findViewById(R.id.right_button);
341         
342         // Cache section
343         mCacheSize = (TextView) view.findViewById(R.id.cache_size_text);
344         mClearCacheButton = (Button) view.findViewById(R.id.clear_cache_button);
345
346         mActivitiesButton = (Button)view.findViewById(R.id.clear_activities_button);
347         
348         return view;
349     }
350
351     // Utility method to set applicaiton label and icon.
352     private void setAppLabelAndIcon(PackageInfo pkgInfo) {
353         View appSnippet = mRootView.findViewById(R.id.app_snippet);
354         ImageView icon = (ImageView) appSnippet.findViewById(R.id.app_icon);
355         mState.ensureIcon(mAppEntry);
356         icon.setImageDrawable(mAppEntry.icon);
357         // Set application name.
358         TextView label = (TextView) appSnippet.findViewById(R.id.app_name);
359         label.setText(mAppEntry.label);
360         // Version number of application
361         mAppVersion = (TextView) appSnippet.findViewById(R.id.app_size);
362
363         if (pkgInfo != null && pkgInfo.versionName != null) {
364             mAppVersion.setVisibility(View.VISIBLE);
365             mAppVersion.setText(getActivity().getString(R.string.version_text,
366                     String.valueOf(pkgInfo.versionName)));
367         } else {
368             mAppVersion.setVisibility(View.INVISIBLE);
369         }
370     }
371
372     @Override
373     public void onResume() {
374         super.onResume();
375         
376         mState.resume(this);
377         if (!refreshUi()) {
378             setIntentAndFinish(true, true);
379         }
380     }
381
382     @Override
383     public void onPause() {
384         super.onPause();
385         mState.pause();
386     }
387
388     @Override
389     public void onAllSizesComputed() {
390     }
391
392     @Override
393     public void onPackageIconChanged() {
394     }
395
396     @Override
397     public void onPackageListChanged() {
398         refreshUi();
399     }
400
401     @Override
402     public void onRebuildComplete(ArrayList<AppEntry> apps) {
403     }
404
405     @Override
406     public void onPackageSizeChanged(String packageName) {
407         if (packageName.equals(mAppEntry.info.packageName)) {
408             refreshSizeInfo();
409         }
410     }
411
412     @Override
413     public void onRunningStateChanged(boolean running) {
414     }
415
416     private boolean refreshUi() {
417         if (mMoveInProgress) {
418             return true;
419         }
420         final Bundle args = getArguments();
421         String packageName = (args != null) ? args.getString(ARG_PACKAGE_NAME) : null;
422         if (packageName == null) {
423             Intent intent = (args == null) ?
424                     getActivity().getIntent() : (Intent) args.getParcelable("intent");
425             if (intent != null) {
426                 packageName = intent.getData().getSchemeSpecificPart();
427             }
428         }
429         mAppEntry = mState.getEntry(packageName);
430         
431         if (mAppEntry == null) {
432             return false; // onCreate must have failed, make sure to exit
433         }
434         
435         // Get application info again to refresh changed properties of application
436         try {
437             mPackageInfo = mPm.getPackageInfo(mAppEntry.info.packageName,
438                     PackageManager.GET_DISABLED_COMPONENTS |
439                     PackageManager.GET_UNINSTALLED_PACKAGES |
440                     PackageManager.GET_SIGNATURES);
441         } catch (NameNotFoundException e) {
442             Log.e(TAG, "Exception when retrieving package:" + mAppEntry.info.packageName, e);
443             return false; // onCreate must have failed, make sure to exit
444         }
445         
446         // Get list of preferred activities
447         List<ComponentName> prefActList = new ArrayList<ComponentName>();
448         
449         // Intent list cannot be null. so pass empty list
450         List<IntentFilter> intentList = new ArrayList<IntentFilter>();
451         mPm.getPreferredActivities(intentList, prefActList, packageName);
452         if(localLOGV) Log.i(TAG, "Have "+prefActList.size()+" number of activities in prefered list");
453         boolean hasUsbDefaults = false;
454         try {
455             hasUsbDefaults = mUsbManager.hasDefaults(packageName, mAppEntry.info.uid);
456         } catch (RemoteException e) {
457             Log.e(TAG, "mUsbManager.hasDefaults", e);
458         }
459         TextView autoLaunchView = (TextView)mRootView.findViewById(R.id.auto_launch);
460         if (prefActList.size() <= 0 && !hasUsbDefaults) {
461             // Disable clear activities button
462             autoLaunchView.setText(R.string.auto_launch_disable_text);
463             mActivitiesButton.setEnabled(false);
464         } else {
465             autoLaunchView.setText(R.string.auto_launch_enable_text);
466             mActivitiesButton.setEnabled(true);
467             mActivitiesButton.setOnClickListener(this);
468         }
469          
470         // Security permissions section
471         LinearLayout permsView = (LinearLayout) mRootView.findViewById(R.id.permissions_section);
472         AppSecurityPermissions asp = new AppSecurityPermissions(getActivity(), packageName);
473         if (asp.getPermissionCount() > 0) {
474             permsView.setVisibility(View.VISIBLE);
475             // Make the security sections header visible
476             LinearLayout securityList = (LinearLayout) permsView.findViewById(
477                     R.id.security_settings_list);
478             securityList.removeAllViews();
479             securityList.addView(asp.getPermissionsView());
480         } else {
481             permsView.setVisibility(View.GONE);
482         }
483         
484         checkForceStop();
485         setAppLabelAndIcon(mPackageInfo);
486         refreshButtons();
487         refreshSizeInfo();
488         return true;
489     }
490     
491     private void setIntentAndFinish(boolean finish, boolean appChanged) {
492         if(localLOGV) Log.i(TAG, "appChanged="+appChanged);
493         Intent intent = new Intent();
494         intent.putExtra(ManageApplications.APP_CHG, appChanged);
495         PreferenceActivity pa = (PreferenceActivity)getActivity();
496         pa.finishPreferencePanel(this, Activity.RESULT_OK, intent);
497     }
498     
499     private void refreshSizeInfo() {
500         if (mAppEntry.size == ApplicationsState.SIZE_INVALID
501                 || mAppEntry.size == ApplicationsState.SIZE_UNKNOWN) {
502             mLastCodeSize = mLastDataSize = mLastCacheSize = mLastTotalSize = -1;
503             if (!mHaveSizes) {
504                 mAppSize.setText(mComputingStr);
505                 mDataSize.setText(mComputingStr);
506                 mCacheSize.setText(mComputingStr);
507                 mTotalSize.setText(mComputingStr);
508             }
509             mClearDataButton.setEnabled(false);
510             mClearCacheButton.setEnabled(false);
511             
512         } else {
513             mHaveSizes = true;
514             if (mLastCodeSize != mAppEntry.codeSize) {
515                 mLastCodeSize = mAppEntry.codeSize;
516                 mAppSize.setText(getSizeStr(mAppEntry.codeSize));
517             }
518             if (mLastDataSize != mAppEntry.dataSize) {
519                 mLastDataSize = mAppEntry.dataSize;
520                 mDataSize.setText(getSizeStr(mAppEntry.dataSize));
521             }
522             if (mLastExternalSize != mAppEntry.externalSize) {
523                 mLastExternalSize = mAppEntry.externalSize;
524                 mExternalSize.setText(getSizeStr(mAppEntry.externalSize));
525             }
526             if (mLastCacheSize != mAppEntry.cacheSize) {
527                 mLastCacheSize = mAppEntry.cacheSize;
528                 mCacheSize.setText(getSizeStr(mAppEntry.cacheSize));
529             }
530             if (mLastTotalSize != mAppEntry.size) {
531                 mLastTotalSize = mAppEntry.size;
532                 mTotalSize.setText(getSizeStr(mAppEntry.size));
533             }
534             
535             if (mAppEntry.dataSize <= 0 || !mCanClearData) {
536                 mClearDataButton.setEnabled(false);
537             } else {
538                 mClearDataButton.setEnabled(true);
539                 mClearDataButton.setOnClickListener(this);
540             }
541             if (mAppEntry.cacheSize <= 0) {
542                 mClearCacheButton.setEnabled(false);
543             } else {
544                 mClearCacheButton.setEnabled(true);
545                 mClearCacheButton.setOnClickListener(this);
546             }
547         }
548     }
549     
550     /*
551      * Private method to handle clear message notification from observer when
552      * the async operation from PackageManager is complete
553      */
554     private void processClearMsg(Message msg) {
555         int result = msg.arg1;
556         String packageName = mAppEntry.info.packageName;
557         mClearDataButton.setText(R.string.clear_user_data_text);
558         if(result == OP_SUCCESSFUL) {
559             Log.i(TAG, "Cleared user data for package : "+packageName);
560             mState.requestSize(mAppEntry.info.packageName);
561         } else {
562             mClearDataButton.setEnabled(true);
563         }
564         checkForceStop();
565     }
566
567     private void refreshButtons() {
568         if (!mMoveInProgress) {
569             initUninstallButtons();
570             initDataButtons();
571             initMoveButton();
572         } else {
573             mMoveAppButton.setText(R.string.moving);
574             mMoveAppButton.setEnabled(false);
575             mUninstallButton.setEnabled(false);
576         }
577     }
578
579     private void processMoveMsg(Message msg) {
580         int result = msg.arg1;
581         String packageName = mAppEntry.info.packageName;
582         // Refresh the button attributes.
583         mMoveInProgress = false;
584         if (result == PackageManager.MOVE_SUCCEEDED) {
585             Log.i(TAG, "Moved resources for " + packageName);
586             // Refresh size information again.
587             mState.requestSize(mAppEntry.info.packageName);
588         } else {
589             showDialogInner(DLG_MOVE_FAILED, result);
590         }
591         refreshUi();
592     }
593
594     /*
595      * Private method to initiate clearing user data when the user clicks the clear data 
596      * button for a system package
597      */
598     private  void initiateClearUserData() {
599         mClearDataButton.setEnabled(false);
600         // Invoke uninstall or clear user data based on sysPackage
601         String packageName = mAppEntry.info.packageName;
602         Log.i(TAG, "Clearing user data for package : " + packageName);
603         if (mClearDataObserver == null) {
604             mClearDataObserver = new ClearUserDataObserver();
605         }
606         ActivityManager am = (ActivityManager)
607                 getActivity().getSystemService(Context.ACTIVITY_SERVICE);
608         boolean res = am.clearApplicationUserData(packageName, mClearDataObserver);
609         if (!res) {
610             // Clearing data failed for some obscure reason. Just log error for now
611             Log.i(TAG, "Couldnt clear application user data for package:"+packageName);
612             showDialogInner(DLG_CANNOT_CLEAR_DATA, 0);
613         } else {
614             mClearDataButton.setText(R.string.recompute_size);
615         }
616     }
617     
618     private void showDialogInner(int id, int moveErrorCode) {
619         DialogFragment newFragment = MyAlertDialogFragment.newInstance(id, moveErrorCode);
620         newFragment.setTargetFragment(this, 0);
621         newFragment.show(getFragmentManager(), "dialog " + id);
622     }
623     
624     public static class MyAlertDialogFragment extends DialogFragment {
625
626         public static MyAlertDialogFragment newInstance(int id, int moveErrorCode) {
627             MyAlertDialogFragment frag = new MyAlertDialogFragment();
628             Bundle args = new Bundle();
629             args.putInt("id", id);
630             args.putInt("moveError", moveErrorCode);
631             frag.setArguments(args);
632             return frag;
633         }
634
635         InstalledAppDetails getOwner() {
636             return (InstalledAppDetails)getTargetFragment();
637         }
638
639         @Override
640         public Dialog onCreateDialog(Bundle savedInstanceState) {
641             int id = getArguments().getInt("id");
642             int moveErrorCode = getArguments().getInt("moveError");
643             switch (id) {
644                 case DLG_CLEAR_DATA:
645                     return new AlertDialog.Builder(getActivity())
646                     .setTitle(getActivity().getText(R.string.clear_data_dlg_title))
647                     .setIcon(android.R.drawable.ic_dialog_alert)
648                     .setMessage(getActivity().getText(R.string.clear_data_dlg_text))
649                     .setPositiveButton(R.string.dlg_ok,
650                             new DialogInterface.OnClickListener() {
651                         public void onClick(DialogInterface dialog, int which) {
652                             // Clear user data here
653                             getOwner().initiateClearUserData();
654                         }
655                     })
656                     .setNegativeButton(R.string.dlg_cancel, null)
657                     .create();
658                 case DLG_FACTORY_RESET:
659                     return new AlertDialog.Builder(getActivity())
660                     .setTitle(getActivity().getText(R.string.app_factory_reset_dlg_title))
661                     .setIcon(android.R.drawable.ic_dialog_alert)
662                     .setMessage(getActivity().getText(R.string.app_factory_reset_dlg_text))
663                     .setPositiveButton(R.string.dlg_ok,
664                             new DialogInterface.OnClickListener() {
665                         public void onClick(DialogInterface dialog, int which) {
666                             // Clear user data here
667                             getOwner().uninstallPkg(getOwner().mAppEntry.info.packageName);
668                         }
669                     })
670                     .setNegativeButton(R.string.dlg_cancel, null)
671                     .create();
672                 case DLG_APP_NOT_FOUND:
673                     return new AlertDialog.Builder(getActivity())
674                     .setTitle(getActivity().getText(R.string.app_not_found_dlg_title))
675                     .setIcon(android.R.drawable.ic_dialog_alert)
676                     .setMessage(getActivity().getText(R.string.app_not_found_dlg_title))
677                     .setNeutralButton(getActivity().getText(R.string.dlg_ok),
678                             new DialogInterface.OnClickListener() {
679                         public void onClick(DialogInterface dialog, int which) {
680                             //force to recompute changed value
681                             getOwner().setIntentAndFinish(true, true);
682                         }
683                     })
684                     .create();
685                 case DLG_CANNOT_CLEAR_DATA:
686                     return new AlertDialog.Builder(getActivity())
687                     .setTitle(getActivity().getText(R.string.clear_failed_dlg_title))
688                     .setIcon(android.R.drawable.ic_dialog_alert)
689                     .setMessage(getActivity().getText(R.string.clear_failed_dlg_text))
690                     .setNeutralButton(R.string.dlg_ok,
691                             new DialogInterface.OnClickListener() {
692                         public void onClick(DialogInterface dialog, int which) {
693                             getOwner().mClearDataButton.setEnabled(false);
694                             //force to recompute changed value
695                             getOwner().setIntentAndFinish(false, false);
696                         }
697                     })
698                     .create();
699                 case DLG_FORCE_STOP:
700                     return new AlertDialog.Builder(getActivity())
701                     .setTitle(getActivity().getText(R.string.force_stop_dlg_title))
702                     .setIcon(android.R.drawable.ic_dialog_alert)
703                     .setMessage(getActivity().getText(R.string.force_stop_dlg_text))
704                     .setPositiveButton(R.string.dlg_ok,
705                         new DialogInterface.OnClickListener() {
706                         public void onClick(DialogInterface dialog, int which) {
707                             // Force stop
708                             getOwner().forceStopPackage(getOwner().mAppEntry.info.packageName);
709                         }
710                     })
711                     .setNegativeButton(R.string.dlg_cancel, null)
712                     .create();
713                 case DLG_MOVE_FAILED:
714                     CharSequence msg = getActivity().getString(R.string.move_app_failed_dlg_text,
715                             getOwner().getMoveErrMsg(moveErrorCode));
716                     return new AlertDialog.Builder(getActivity())
717                     .setTitle(getActivity().getText(R.string.move_app_failed_dlg_title))
718                     .setIcon(android.R.drawable.ic_dialog_alert)
719                     .setMessage(msg)
720                     .setNeutralButton(R.string.dlg_ok, null)
721                     .create();
722             }
723             throw new IllegalArgumentException("unknown id " + id);
724         }
725     }
726
727     private void uninstallPkg(String packageName) {
728          // Create new intent to launch Uninstaller activity
729         Uri packageURI = Uri.parse("package:"+packageName);
730         Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI);
731         startActivity(uninstallIntent);
732         setIntentAndFinish(true, true);
733     }
734
735     private void forceStopPackage(String pkgName) {
736         ActivityManager am = (ActivityManager)getActivity().getSystemService(
737                 Context.ACTIVITY_SERVICE);
738         am.forceStopPackage(pkgName);
739         mState.invalidatePackage(pkgName);
740         ApplicationsState.AppEntry newEnt = mState.getEntry(pkgName);
741         if (newEnt != null) {
742             mAppEntry = newEnt;
743         }
744         checkForceStop();
745     }
746
747     private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() {
748         @Override
749         public void onReceive(Context context, Intent intent) {
750             updateForceStopButton(getResultCode() != Activity.RESULT_CANCELED);
751         }
752     };
753
754     private void updateForceStopButton(boolean enabled) {
755         mForceStopButton.setEnabled(enabled);
756         mForceStopButton.setOnClickListener(InstalledAppDetails.this);
757     }
758     
759     private void checkForceStop() {
760         Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART,
761                 Uri.fromParts("package", mAppEntry.info.packageName, null));
762         intent.putExtra(Intent.EXTRA_PACKAGES, new String[] { mAppEntry.info.packageName });
763         intent.putExtra(Intent.EXTRA_UID, mAppEntry.info.uid);
764         if ((mAppEntry.info.flags&ApplicationInfo.FLAG_STOPPED) == 0) {
765             // If the app isn't explicitly stopped, then always show the
766             // force stop button.
767             updateForceStopButton(true);
768         } else {
769             getActivity().sendOrderedBroadcast(intent, null, mCheckKillProcessesReceiver, null,
770                     Activity.RESULT_CANCELED, null, null);
771         }
772     }
773     
774     static class DisableChanger extends AsyncTask<Object, Object, Object> {
775         final PackageManager mPm;
776         final WeakReference<InstalledAppDetails> mActivity;
777         final ApplicationInfo mInfo;
778         final int mState;
779
780         DisableChanger(InstalledAppDetails activity, ApplicationInfo info, int state) {
781             mPm = activity.mPm;
782             mActivity = new WeakReference<InstalledAppDetails>(activity);
783             mInfo = info;
784             mState = state;
785         }
786
787         @Override
788         protected Object doInBackground(Object... params) {
789             mPm.setApplicationEnabledSetting(mInfo.packageName, mState, 0);
790             return null;
791         }
792     }
793
794     /*
795      * Method implementing functionality of buttons clicked
796      * @see android.view.View.OnClickListener#onClick(android.view.View)
797      */
798     public void onClick(View v) {
799         String packageName = mAppEntry.info.packageName;
800         if(v == mUninstallButton) {
801             if (mUpdatedSysApp) {
802                 showDialogInner(DLG_FACTORY_RESET, 0);
803             } else {
804                 if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
805                     new DisableChanger(this, mAppEntry.info, mAppEntry.info.enabled ?
806                             PackageManager.COMPONENT_ENABLED_STATE_DISABLED
807                             : PackageManager.COMPONENT_ENABLED_STATE_DEFAULT).execute((Object)null);
808                 } else {
809                     uninstallPkg(packageName);
810                 }
811             }
812         } else if(v == mActivitiesButton) {
813             mPm.clearPackagePreferredActivities(packageName);
814             try {
815                 mUsbManager.clearDefaults(packageName, mAppEntry.info.uid);
816             } catch (RemoteException e) {
817                 Log.e(TAG, "mUsbManager.clearDefaults", e);
818             }
819             mActivitiesButton.setEnabled(false);
820         } else if(v == mClearDataButton) {
821             if (mAppEntry.info.manageSpaceActivityName != null) {
822                 Intent intent = new Intent(Intent.ACTION_DEFAULT);
823                 intent.setClassName(mAppEntry.info.packageName,
824                         mAppEntry.info.manageSpaceActivityName);
825                 startActivityForResult(intent, -1);
826             } else {
827                 showDialogInner(DLG_CLEAR_DATA, 0);
828             }
829         } else if (v == mClearCacheButton) {
830             // Lazy initialization of observer
831             if (mClearCacheObserver == null) {
832                 mClearCacheObserver = new ClearCacheObserver();
833             }
834             mPm.deleteApplicationCacheFiles(packageName, mClearCacheObserver);
835         } else if (v == mForceStopButton) {
836             showDialogInner(DLG_FORCE_STOP, 0);
837             //forceStopPackage(mAppInfo.packageName);
838         } else if (v == mMoveAppButton) {
839             if (mPackageMoveObserver == null) {
840                 mPackageMoveObserver = new PackageMoveObserver();
841             }
842             int moveFlags = (mAppEntry.info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0 ?
843                     PackageManager.MOVE_INTERNAL : PackageManager.MOVE_EXTERNAL_MEDIA;
844             mMoveInProgress = true;
845             refreshButtons();
846             mPm.movePackage(mAppEntry.info.packageName, mPackageMoveObserver, moveFlags);
847         }
848     }
849 }
850