OSDN Git Service

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