OSDN Git Service

Enable moving packages when install location is set to auto.
[android-x86/packages-apps-Settings.git] / src / com / android / settings / InstalledAppDetails.java
1
2
3 /**
4  * Copyright (C) 2007 The Android Open Source Project
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
7  * use this file except in compliance with the License. You may obtain a copy
8  * of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15  * License for the specific language governing permissions and limitations
16  * under the License.
17  */
18
19 package com.android.settings;
20
21 import com.android.internal.content.PackageHelper;
22 import com.android.settings.R;
23 import android.app.Activity;
24 import android.app.ActivityManager;
25 import android.app.AlertDialog;
26 import android.app.Dialog;
27 import android.content.BroadcastReceiver;
28 import android.content.Context;
29 import android.content.DialogInterface;
30 import android.content.Intent;
31 import android.content.IntentFilter;
32 import android.content.pm.ApplicationInfo;
33 import android.content.pm.IPackageDataObserver;
34 import android.content.pm.IPackageManager;
35 import android.content.pm.IPackageMoveObserver;
36 import android.content.pm.IPackageStatsObserver;
37 import android.content.pm.PackageInfo;
38 import android.content.pm.PackageManager;
39 import android.content.pm.PackageParser;
40 import android.content.pm.PackageStats;
41 import android.content.pm.PackageManager.NameNotFoundException;
42 import android.net.Uri;
43 import android.os.Bundle;
44 import android.os.Handler;
45 import android.os.IBinder;
46 import android.os.Message;
47 import android.os.RemoteException;
48 import android.os.ServiceManager;
49 import android.os.storage.IMountService;
50 import android.text.format.Formatter;
51 import android.util.Log;
52 import java.util.ArrayList;
53 import java.util.List;
54 import android.content.ComponentName;
55 import android.view.View;
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 Activity implements View.OnClickListener {
72     private static final String TAG="InstalledAppDetails";
73     private static final int _UNKNOWN_APP=R.string.unknown;
74     private ApplicationInfo mAppInfo;
75     private Button mUninstallButton;
76     private boolean mMoveInProgress = false;
77     private boolean mUpdatedSysApp = false;
78     private Button mActivitiesButton;
79     private boolean localLOGV = false;
80     private TextView mAppVersion;
81     private TextView mTotalSize;
82     private TextView mAppSize;
83     private TextView mDataSize;
84     private PkgSizeObserver mSizeObserver;
85     private ClearUserDataObserver mClearDataObserver;
86     // Views related to cache info
87     private TextView mCacheSize;
88     private Button mClearCacheButton;
89     private ClearCacheObserver mClearCacheObserver;
90     private Button mForceStopButton;
91     private Button mClearDataButton;
92     private Button mMoveAppButton;
93     private int mMoveErrorCode;
94     
95     PackageStats mSizeInfo;
96     private PackageManager mPm;
97     private PackageMoveObserver mPackageMoveObserver;
98     
99     //internal constants used in Handler
100     private static final int OP_SUCCESSFUL = 1;
101     private static final int OP_FAILED = 2;
102     private static final int CLEAR_USER_DATA = 1;
103     private static final int GET_PKG_SIZE = 2;
104     private static final int CLEAR_CACHE = 3;
105     private static final int PACKAGE_MOVE = 4;
106     private static final String ATTR_PACKAGE_STATS="PackageStats";
107     
108     // invalid size value used initially and also when size retrieval through PackageManager
109     // fails for whatever reason
110     private static final int SIZE_INVALID = -1;
111     
112     // Resource strings
113     private CharSequence mInvalidSizeStr;
114     private CharSequence mComputingStr;
115     
116     // Dialog identifiers used in showDialog
117     private static final int DLG_BASE = 0;
118     private static final int DLG_CLEAR_DATA = DLG_BASE + 1;
119     private static final int DLG_FACTORY_RESET = DLG_BASE + 2;
120     private static final int DLG_APP_NOT_FOUND = DLG_BASE + 3;
121     private static final int DLG_CANNOT_CLEAR_DATA = DLG_BASE + 4;
122     private static final int DLG_FORCE_STOP = DLG_BASE + 5;
123     private static final int DLG_MOVE_FAILED = DLG_BASE + 6;
124     
125     private Handler mHandler = new Handler() {
126         public void handleMessage(Message msg) {
127             // If the activity is gone, don't process any more messages.
128             if (isFinishing()) {
129                 return;
130             }
131             switch (msg.what) {
132                 case CLEAR_USER_DATA:
133                     processClearMsg(msg);
134                     break;
135                 case GET_PKG_SIZE:
136                     refreshSizeInfo(msg);
137                     break;
138                 case CLEAR_CACHE:
139                     // Refresh size info
140                     mPm.getPackageSizeInfo(mAppInfo.packageName, mSizeObserver);
141                     break;
142                 case PACKAGE_MOVE:
143                     processMoveMsg(msg);
144                     break;
145                 default:
146                     break;
147             }
148         }
149     };
150     
151     class ClearUserDataObserver extends IPackageDataObserver.Stub {
152        public void onRemoveCompleted(final String packageName, final boolean succeeded) {
153            final Message msg = mHandler.obtainMessage(CLEAR_USER_DATA);
154            msg.arg1 = succeeded?OP_SUCCESSFUL:OP_FAILED;
155            mHandler.sendMessage(msg);
156         }
157     }
158     
159     class PkgSizeObserver extends IPackageStatsObserver.Stub {
160         public void onGetStatsCompleted(PackageStats pStats, boolean succeeded) {
161              Message msg = mHandler.obtainMessage(GET_PKG_SIZE);
162              Bundle data = new Bundle();
163              data.putParcelable(ATTR_PACKAGE_STATS, pStats);
164              msg.setData(data);
165              mHandler.sendMessage(msg);
166             
167          }
168      }
169
170     class ClearCacheObserver extends IPackageDataObserver.Stub {
171         public void onRemoveCompleted(final String packageName, final boolean succeeded) {
172             final Message msg = mHandler.obtainMessage(CLEAR_CACHE);
173             msg.arg1 = succeeded ? OP_SUCCESSFUL:OP_FAILED;
174             mHandler.sendMessage(msg);
175          }
176      }
177
178     class PackageMoveObserver extends IPackageMoveObserver.Stub {
179         public void packageMoved(String packageName, int returnCode) throws RemoteException {
180             final Message msg = mHandler.obtainMessage(PACKAGE_MOVE);
181             msg.arg1 = returnCode;
182             mHandler.sendMessage(msg);
183         }
184     }
185     
186     private String getSizeStr(long size) {
187         if (size == SIZE_INVALID) {
188             return mInvalidSizeStr.toString();
189         }
190         return Formatter.formatFileSize(this, size);
191     }
192     
193     private void initDataButtons() {
194         if (mAppInfo.manageSpaceActivityName != null) {
195             mClearDataButton.setText(R.string.manage_space_text);
196         } else {
197             mClearDataButton.setText(R.string.clear_user_data_text);
198         }
199         mClearDataButton.setOnClickListener(this);
200     }
201
202     private CharSequence getMoveErrMsg(int errCode) {
203         switch (errCode) {
204             case PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE:
205                 return getString(R.string.insufficient_storage);
206             case PackageManager.MOVE_FAILED_DOESNT_EXIST:
207                 return getString(R.string.does_not_exist);
208             case PackageManager.MOVE_FAILED_FORWARD_LOCKED:
209                 return getString(R.string.app_forward_locked);
210             case PackageManager.MOVE_FAILED_INVALID_LOCATION:
211                 return getString(R.string.invalid_location);
212             case PackageManager.MOVE_FAILED_SYSTEM_PACKAGE:
213                 return getString(R.string.system_package);
214             case PackageManager.MOVE_FAILED_INTERNAL_ERROR:
215                 return "";
216         }
217         return "";
218     }
219
220     private void initMoveButton() {
221         String pkgName = mAppInfo.packageName;
222         boolean dataOnly = false;
223         ApplicationInfo info1 = null;
224         PackageInfo pkgInfo = null;
225
226         try {
227             info1 = mPm.getApplicationInfo(pkgName, 0);
228             pkgInfo = mPm.getPackageInfo(mAppInfo.packageName,
229                     PackageManager.GET_UNINSTALLED_PACKAGES);
230         } catch (NameNotFoundException e) {
231         }
232         dataOnly = (info1 == null) && (mAppInfo != null);
233         boolean moveDisable = true;
234         if (dataOnly) {
235             mMoveAppButton.setText(R.string.move_app);
236         } else if ((mAppInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
237             mMoveAppButton.setText(R.string.move_app_to_internal);
238             // Always let apps move to internal storage from sdcard.
239             moveDisable = false;
240         } else {
241             mMoveAppButton.setText(R.string.move_app_to_sdcard);
242             if ((mAppInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK) == 0 &&
243                     (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0 &&
244                     pkgInfo != null) {
245                 if (pkgInfo.installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL ||
246                         pkgInfo.installLocation == PackageInfo.INSTALL_LOCATION_AUTO) {
247                     moveDisable = false;
248                 } else if (pkgInfo.installLocation == PackageInfo.INSTALL_LOCATION_UNSPECIFIED) {
249                     IPackageManager ipm  = IPackageManager.Stub.asInterface(
250                             ServiceManager.getService("package"));
251                     int loc;
252                     try {
253                         loc = ipm.getInstallLocation();
254                     } catch (RemoteException e) {
255                         Log.e(TAG, "Is Pakage Manager running?");
256                         return;
257                     }
258                     if (loc == PackageHelper.APP_INSTALL_EXTERNAL) {
259                         // For apps with no preference and the default value set
260                         // to install on sdcard.
261                         moveDisable = false;
262                     }
263                 }
264             }
265         }
266         if (moveDisable) {
267             mMoveAppButton.setEnabled(false);
268         } else {
269             mMoveAppButton.setOnClickListener(this);
270             mMoveAppButton.setEnabled(true);
271         }
272     }
273
274     private void initUninstallButtons() {
275         mUpdatedSysApp = (mAppInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
276         boolean enabled = true;
277         if (mUpdatedSysApp) {
278             mUninstallButton.setText(R.string.app_factory_reset);
279         } else if ((mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0){
280             mUninstallButton.setText(R.string.uninstall_text);
281         } else {
282             // Disable uninstall for system apps
283             enabled = false;
284         }
285         mUninstallButton.setEnabled(enabled);
286         if (enabled) {
287             // Register listener
288             mUninstallButton.setOnClickListener(this);
289         }
290     }
291
292     private void initAppInfo(String packageName) {
293         try {
294             mAppInfo = mPm.getApplicationInfo(packageName,
295                     PackageManager.GET_UNINSTALLED_PACKAGES);
296         } catch (NameNotFoundException e) {
297             Log.e(TAG, "Exception when retrieving package: " + packageName, e);
298             showDialogInner(DLG_APP_NOT_FOUND);
299             return;
300         }
301     }
302
303     /** Called when the activity is first created. */
304     @Override
305     protected void onCreate(Bundle icicle) {
306         super.onCreate(icicle);
307         // Get package manager
308         mPm = getPackageManager();
309         // Get application's name from intent
310         Intent intent = getIntent();
311         final String packageName = intent.getStringExtra(ManageApplications.APP_PKG_NAME);
312         mComputingStr = getText(R.string.computing_size);
313         // Try retrieving package stats again
314         CharSequence totalSizeStr, appSizeStr, dataSizeStr;
315         totalSizeStr = appSizeStr = dataSizeStr = mComputingStr;
316         if(localLOGV) Log.i(TAG, "Have to compute package sizes");
317         mSizeObserver = new PkgSizeObserver();
318         initAppInfo(packageName);
319         setContentView(R.layout.installed_app_details);
320         //TODO download str and download url
321         // Set default values on sizes
322         mTotalSize = (TextView)findViewById(R.id.total_size_text);
323         mTotalSize.setText(totalSizeStr);
324         mAppSize = (TextView)findViewById(R.id.application_size_text);
325         mAppSize.setText(appSizeStr);
326         mDataSize = (TextView)findViewById(R.id.data_size_text);
327         mDataSize.setText(dataSizeStr);
328         // Get Control button panel
329         View btnPanel = findViewById(R.id.control_buttons_panel);
330         mForceStopButton = (Button) btnPanel.findViewById(R.id.left_button);
331         mForceStopButton.setText(R.string.force_stop);
332         mUninstallButton = (Button)btnPanel.findViewById(R.id.right_button);
333         mForceStopButton.setEnabled(false);
334         // Initialize clear data and move install location buttons
335         View data_buttons_panel = findViewById(R.id.data_buttons_panel);
336         mClearDataButton = (Button) data_buttons_panel.findViewById(R.id.left_button);
337         mMoveAppButton = (Button) data_buttons_panel.findViewById(R.id.right_button);
338          // Cache section
339          mCacheSize = (TextView) findViewById(R.id.cache_size_text);
340          mCacheSize.setText(mComputingStr);
341          mClearCacheButton = (Button) findViewById(R.id.clear_cache_button);
342
343          // Get list of preferred activities
344          mActivitiesButton = (Button)findViewById(R.id.clear_activities_button);
345          List<ComponentName> prefActList = new ArrayList<ComponentName>();
346          // Intent list cannot be null. so pass empty list
347          List<IntentFilter> intentList = new ArrayList<IntentFilter>();
348          mPm.getPreferredActivities(intentList,  prefActList, packageName);
349          if(localLOGV) Log.i(TAG, "Have "+prefActList.size()+" number of activities in prefered list");
350          TextView autoLaunchView = (TextView)findViewById(R.id.auto_launch);
351          if(prefActList.size() <= 0) {
352              // Disable clear activities button
353              autoLaunchView.setText(R.string.auto_launch_disable_text);
354              mActivitiesButton.setEnabled(false);
355          } else {
356              autoLaunchView.setText(R.string.auto_launch_enable_text);
357              mActivitiesButton.setOnClickListener(this);
358          }
359          
360          // Security permissions section
361          LinearLayout permsView = (LinearLayout) findViewById(R.id.permissions_section);
362          AppSecurityPermissions asp = new AppSecurityPermissions(this, packageName);
363          if(asp.getPermissionCount() > 0) {
364              permsView.setVisibility(View.VISIBLE);
365              // Make the security sections header visible
366              LinearLayout securityList = (LinearLayout) permsView.findViewById(
367                      R.id.security_settings_list);
368              securityList.addView(asp.getPermissionsView());
369          } else {
370              permsView.setVisibility(View.GONE);
371          }
372     }
373
374     // Utility method to set applicaiton label and icon.
375     private void setAppLabelAndIcon(PackageInfo pkgInfo) {
376         View appSnippet = findViewById(R.id.app_snippet);
377         ImageView icon = (ImageView) appSnippet.findViewById(R.id.app_icon);
378         icon.setImageDrawable(mAppInfo.loadIcon(mPm));
379         // Set application name.
380         TextView label = (TextView) appSnippet.findViewById(R.id.app_name);
381         label.setText(mAppInfo.loadLabel(mPm));
382         // Version number of application
383         mAppVersion = (TextView) appSnippet.findViewById(R.id.app_size);
384
385         if (pkgInfo != null && pkgInfo.versionName != null) {
386             mAppVersion.setVisibility(View.VISIBLE);
387             mAppVersion.setText(getString(R.string.version_text,
388                     String.valueOf(pkgInfo.versionName)));
389         } else {
390             mAppVersion.setVisibility(View.INVISIBLE);
391         }
392     }
393
394     @Override
395     public void onResume() {
396         super.onResume();
397         initAppInfo(mAppInfo.packageName);
398         PackageInfo pkgInfo = null;
399         // Get application info again to refresh changed properties of application
400         try {
401             pkgInfo = mPm.getPackageInfo(mAppInfo.packageName,
402                     PackageManager.GET_UNINSTALLED_PACKAGES);
403         } catch (NameNotFoundException e) {
404             Log.e(TAG, "Exception when retrieving package:" + mAppInfo.packageName, e);
405             showDialogInner(DLG_APP_NOT_FOUND);
406             return;
407         }
408         checkForceStop();
409         setAppLabelAndIcon(pkgInfo);
410         refreshButtons();
411         // Refresh size info
412         if (mAppInfo != null && mAppInfo.packageName != null) {
413             mPm.getPackageSizeInfo(mAppInfo.packageName, mSizeObserver);
414         }
415     }
416
417     private void setIntentAndFinish(boolean finish, boolean appChanged) {
418         if(localLOGV) Log.i(TAG, "appChanged="+appChanged);
419         Intent intent = new Intent();
420         intent.putExtra(ManageApplications.APP_CHG, appChanged);
421         setResult(ManageApplications.RESULT_OK, intent);
422         if(finish) {
423             finish();
424         }
425     }
426     
427     /*
428      * Private method to handle get size info notification from observer when
429      * the async operation from PackageManager is complete. The current user data
430      * info has to be refreshed in the manage applications screen as well as the current screen.
431      */
432     private void refreshSizeInfo(Message msg) {
433         boolean changed = false;
434         PackageStats newPs = msg.getData().getParcelable(ATTR_PACKAGE_STATS);
435         long newTot = newPs.cacheSize+newPs.codeSize+newPs.dataSize;
436         if(mSizeInfo == null) {
437             mSizeInfo = newPs;
438             String str = getSizeStr(newTot);
439             mTotalSize.setText(str);
440             mAppSize.setText(getSizeStr(newPs.codeSize));
441             mDataSize.setText(getSizeStr(newPs.dataSize));
442             mCacheSize.setText(getSizeStr(newPs.cacheSize));
443         } else {
444             long oldTot = mSizeInfo.cacheSize+mSizeInfo.codeSize+mSizeInfo.dataSize;
445             if(newTot != oldTot) {
446                 String str = getSizeStr(newTot);
447                 mTotalSize.setText(str);
448                 changed = true;
449             }
450             if(newPs.codeSize != mSizeInfo.codeSize) {
451                 mAppSize.setText(getSizeStr(newPs.codeSize));
452                 changed = true;
453             }
454             if(newPs.dataSize != mSizeInfo.dataSize) {
455                 mDataSize.setText(getSizeStr(newPs.dataSize));
456                 changed = true;
457             }
458             if(newPs.cacheSize != mSizeInfo.cacheSize) {
459                 mCacheSize.setText(getSizeStr(newPs.cacheSize));
460                 changed = true;
461             }
462             if(changed) {
463                 mSizeInfo = newPs;
464             }
465         }
466         // If data size is zero disable clear data button
467         if (newPs.dataSize == 0) {
468             mClearDataButton.setEnabled(false);
469         }
470         long data = mSizeInfo.dataSize;
471         refreshCacheInfo(newPs.cacheSize);
472     }
473     
474     private void refreshCacheInfo(long cacheSize) {
475         // Set cache info
476         mCacheSize.setText(getSizeStr(cacheSize));
477         if (cacheSize <= 0) {
478             mClearCacheButton.setEnabled(false);
479         } else {
480             mClearCacheButton.setOnClickListener(this);
481         }
482     }
483     
484     /*
485      * Private method to handle clear message notification from observer when
486      * the async operation from PackageManager is complete
487      */
488     private void processClearMsg(Message msg) {
489         int result = msg.arg1;
490         String packageName = mAppInfo.packageName;
491         mClearDataButton.setText(R.string.clear_user_data_text);
492         if(result == OP_SUCCESSFUL) {
493             Log.i(TAG, "Cleared user data for package : "+packageName);
494             mPm.getPackageSizeInfo(packageName, mSizeObserver);
495         } else {
496             mClearDataButton.setEnabled(true);
497         }
498     }
499
500     private void refreshButtons() {
501         if (!mMoveInProgress) {
502             // Refresh application information again.
503             initAppInfo(mAppInfo.packageName);
504             initUninstallButtons();
505             initDataButtons();
506             initMoveButton();
507         } else {
508             mMoveAppButton.setText(R.string.moving);
509             mMoveAppButton.setEnabled(false);
510             mUninstallButton.setEnabled(false);
511         }
512     }
513
514     private void processMoveMsg(Message msg) {
515         int result = msg.arg1;
516         String packageName = mAppInfo.packageName;
517         // Refresh the button attributes.
518         mMoveInProgress = false;
519         refreshButtons();
520         if(result == PackageManager.MOVE_SUCCEEDED) {
521             Log.i(TAG, "Moved resources for " + packageName);
522             // Refresh size information again.
523             mPm.getPackageSizeInfo(mAppInfo.packageName, mSizeObserver);
524         } else {
525             mMoveErrorCode = result;
526             showDialogInner(DLG_MOVE_FAILED);
527         }
528     }
529
530     /*
531      * Private method to initiate clearing user data when the user clicks the clear data 
532      * button for a system package
533      */
534     private  void initiateClearUserData() {
535         mClearDataButton.setEnabled(false);
536         // Invoke uninstall or clear user data based on sysPackage
537         String packageName = mAppInfo.packageName;
538         Log.i(TAG, "Clearing user data for package : " + packageName);
539         if(mClearDataObserver == null) {
540             mClearDataObserver = new ClearUserDataObserver();
541         }
542         ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
543         boolean res = am.clearApplicationUserData(packageName, mClearDataObserver);
544         if(!res) {
545             // Clearing data failed for some obscure reason. Just log error for now
546             Log.i(TAG, "Couldnt clear application user data for package:"+packageName);
547             showDialogInner(DLG_CANNOT_CLEAR_DATA);
548         } else {
549             mClearDataButton.setText(R.string.recompute_size);
550         }
551     }
552     
553     private void showDialogInner(int id) {
554         //removeDialog(id);
555         showDialog(id);
556     }
557     
558     @Override
559     public Dialog onCreateDialog(int id, Bundle args) {
560         switch (id) {
561         case DLG_CLEAR_DATA:
562             return new AlertDialog.Builder(this)
563             .setTitle(getString(R.string.clear_data_dlg_title))
564             .setIcon(android.R.drawable.ic_dialog_alert)
565             .setMessage(getString(R.string.clear_data_dlg_text))
566             .setPositiveButton(R.string.dlg_ok,
567                     new DialogInterface.OnClickListener() {
568                 public void onClick(DialogInterface dialog, int which) {
569                     // Clear user data here
570                     initiateClearUserData();
571                 }
572             })
573             .setNegativeButton(R.string.dlg_cancel, null)
574             .create();
575         case DLG_FACTORY_RESET:
576             return new AlertDialog.Builder(this)
577             .setTitle(getString(R.string.app_factory_reset_dlg_title))
578             .setIcon(android.R.drawable.ic_dialog_alert)
579             .setMessage(getString(R.string.app_factory_reset_dlg_text))
580             .setPositiveButton(R.string.dlg_ok,
581                     new DialogInterface.OnClickListener() {
582                 public void onClick(DialogInterface dialog, int which) {
583                     // Clear user data here
584                     uninstallPkg(mAppInfo.packageName);
585                 }
586             })
587             .setNegativeButton(R.string.dlg_cancel, null)
588             .create();
589         case DLG_APP_NOT_FOUND:
590             return new AlertDialog.Builder(this)
591             .setTitle(getString(R.string.app_not_found_dlg_title))
592             .setIcon(android.R.drawable.ic_dialog_alert)
593             .setMessage(getString(R.string.app_not_found_dlg_title))
594             .setNeutralButton(getString(R.string.dlg_ok),
595                     new DialogInterface.OnClickListener() {
596                 public void onClick(DialogInterface dialog, int which) {
597                     //force to recompute changed value
598                     setIntentAndFinish(true, true);
599                 }
600             })
601             .create();
602         case DLG_CANNOT_CLEAR_DATA:
603             return new AlertDialog.Builder(this)
604             .setTitle(getString(R.string.clear_failed_dlg_title))
605             .setIcon(android.R.drawable.ic_dialog_alert)
606             .setMessage(getString(R.string.clear_failed_dlg_text))
607             .setNeutralButton(R.string.dlg_ok,
608                     new DialogInterface.OnClickListener() {
609                 public void onClick(DialogInterface dialog, int which) {
610                     mClearDataButton.setEnabled(false);
611                     //force to recompute changed value
612                     setIntentAndFinish(false, false);
613                 }
614             })
615             .create();
616             case DLG_FORCE_STOP:
617                 return new AlertDialog.Builder(this)
618                 .setTitle(getString(R.string.force_stop_dlg_title))
619                 .setIcon(android.R.drawable.ic_dialog_alert)
620                 .setMessage(getString(R.string.force_stop_dlg_text))
621                 .setPositiveButton(R.string.dlg_ok,
622                     new DialogInterface.OnClickListener() {
623                 public void onClick(DialogInterface dialog, int which) {
624                     // Force stop
625                     forceStopPackage(mAppInfo.packageName);
626                 }
627             })
628             .setNegativeButton(R.string.dlg_cancel, null)
629             .create();
630             case DLG_MOVE_FAILED:
631                 CharSequence msg = getString(R.string.move_app_failed_dlg_text,
632                         getMoveErrMsg(mMoveErrorCode));
633                 return new AlertDialog.Builder(this)
634                 .setTitle(getString(R.string.move_app_failed_dlg_title))
635                 .setIcon(android.R.drawable.ic_dialog_alert)
636                 .setMessage(msg)
637                 .setNeutralButton(R.string.dlg_ok, null)
638                 .create();
639         }
640         return null;
641     }
642
643     private void uninstallPkg(String packageName) {
644          // Create new intent to launch Uninstaller activity
645         Uri packageURI = Uri.parse("package:"+packageName);
646         Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI);
647         startActivity(uninstallIntent);
648         setIntentAndFinish(true, true);
649     }
650
651     private void forceStopPackage(String pkgName) {
652         ActivityManager am = (ActivityManager)getSystemService(
653                 Context.ACTIVITY_SERVICE);
654         am.forceStopPackage(pkgName);
655         checkForceStop();
656     }
657
658     private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() {
659         @Override
660         public void onReceive(Context context, Intent intent) {
661             mForceStopButton.setEnabled(getResultCode() != RESULT_CANCELED);
662             mForceStopButton.setOnClickListener(InstalledAppDetails.this);
663         }
664     };
665     
666     private void checkForceStop() {
667         Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART,
668                 Uri.fromParts("package", mAppInfo.packageName, null));
669         intent.putExtra(Intent.EXTRA_PACKAGES, new String[] { mAppInfo.packageName });
670         intent.putExtra(Intent.EXTRA_UID, mAppInfo.uid);
671         sendOrderedBroadcast(intent, null, mCheckKillProcessesReceiver, null,
672                 Activity.RESULT_CANCELED, null, null);
673     }
674     
675     /*
676      * Method implementing functionality of buttons clicked
677      * @see android.view.View.OnClickListener#onClick(android.view.View)
678      */
679     public void onClick(View v) {
680         String packageName = mAppInfo.packageName;
681         if(v == mUninstallButton) {
682             if (mUpdatedSysApp) {
683                 showDialogInner(DLG_FACTORY_RESET);
684             } else {
685                 uninstallPkg(packageName);
686             }
687         } else if(v == mActivitiesButton) {
688             mPm.clearPackagePreferredActivities(packageName);
689             mActivitiesButton.setEnabled(false);
690         } else if(v == mClearDataButton) {
691             if (mAppInfo.manageSpaceActivityName != null) {
692                 Intent intent = new Intent(Intent.ACTION_DEFAULT);
693                 intent.setClassName(mAppInfo.packageName, mAppInfo.manageSpaceActivityName);
694                 startActivityForResult(intent, -1);
695             } else {
696                 showDialogInner(DLG_CLEAR_DATA);
697             }
698         } else if (v == mClearCacheButton) {
699             // Lazy initialization of observer
700             if (mClearCacheObserver == null) {
701                 mClearCacheObserver = new ClearCacheObserver();
702             }
703             mPm.deleteApplicationCacheFiles(packageName, mClearCacheObserver);
704         } else if (v == mForceStopButton) {
705             forceStopPackage(mAppInfo.packageName);
706         } else if (v == mMoveAppButton) {
707             if (mPackageMoveObserver == null) {
708                 mPackageMoveObserver = new PackageMoveObserver();
709             }
710             int moveFlags = (mAppInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0 ?
711                     PackageManager.MOVE_INTERNAL : PackageManager.MOVE_EXTERNAL_MEDIA;
712             mMoveInProgress = true;
713             refreshButtons();
714             mPm.movePackage(mAppInfo.packageName, mPackageMoveObserver, moveFlags);
715         }
716     }
717 }
718