diff --git a/res/layout/installed_app_details.xml b/res/layout/installed_app_details.xml index 7c8a672608f..13d3b1006d5 100644 --- a/res/layout/installed_app_details.xml +++ b/res/layout/installed_app_details.xml @@ -28,9 +28,51 @@ android:paddingTop="5dip" android:paddingBottom="5dip" android:orientation="vertical"> - + + + + + + + + + + + + + + + Uninstall Clear data + + Factory reset You have selected to launch this application by default for some actions. @@ -1319,12 +1321,22 @@ found in the list of installed applications. Unable to clear application data. + + Factory reset system app + + Do you want to fallback to factory version of system application? + + Clear data + + Failed clearing data for application This application can access the following on your phone: Computing\u2026 Unable to compute package size You do not have any third-party apps installed. + + version %1$s diff --git a/src/com/android/settings/InstalledAppDetails.java b/src/com/android/settings/InstalledAppDetails.java index 692fc8eba45..5a4e672b9d5 100644 --- a/src/com/android/settings/InstalledAppDetails.java +++ b/src/com/android/settings/InstalledAppDetails.java @@ -22,13 +22,16 @@ import com.android.settings.R; import android.app.Activity; import android.app.ActivityManager; import android.app.AlertDialog; +import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageDataObserver; +import android.content.pm.IPackageDeleteObserver; import android.content.pm.IPackageStatsObserver; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageStats; import android.content.pm.PackageManager.NameNotFoundException; @@ -36,6 +39,7 @@ import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Message; +import android.os.RemoteException; import android.text.format.Formatter; import android.util.Config; import android.util.Log; @@ -64,9 +68,8 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene private ApplicationInfo mAppInfo; private Button mAppButton; private Button mActivitiesButton; - private boolean mCanUninstall; - private boolean localLOGV=Config.LOGV || false; - private TextView mAppSnippetSize; + private boolean localLOGV = false; + private TextView mAppVersion; private TextView mTotalSize; private TextView mAppSize; private TextView mDataSize; @@ -100,10 +103,18 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene private CharSequence mComputingStr; private CharSequence mAppButtonText; + // Dialog identifiers used in showDialog + private static final int DLG_BASE = 0; + private static final int DLG_CLEAR_DATA = DLG_BASE + 1; + private static final int DLG_FACTORY_RESET = DLG_BASE + 2; + private static final int DLG_APP_NOT_FOUND = DLG_BASE + 3; + private static final int DLG_CANNOT_CLEAR_DATA = DLG_BASE + 4; + // Possible btn states private enum AppButtonStates { CLEAR_DATA, UNINSTALL, + FACTORY_RESET, NONE } private AppButtonStates mAppButtonState; @@ -127,14 +138,6 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene } }; - private boolean isUninstallable() { - if (((mAppInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) && - ((mAppInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0)) { - return false; - } - return true; - } - class ClearUserDataObserver extends IPackageDataObserver.Stub { public void onRemoveCompleted(final String packageName, final boolean succeeded) { final Message msg = mHandler.obtainMessage(CLEAR_USER_DATA); @@ -154,7 +157,7 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene } } - + class ClearCacheObserver extends IPackageDataObserver.Stub { public void onRemoveCompleted(final String packageName, final boolean succeeded) { final Message msg = mHandler.obtainMessage(CLEAR_CACHE); @@ -170,40 +173,13 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene return Formatter.formatFileSize(this, size); } - private void setAppBtnState() { - boolean visible = false; - if(mCanUninstall) { - //app can clear user data - if((mAppInfo.flags & ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) - == ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) { - mAppButtonText = getText(R.string.clear_user_data_text); - mAppButtonState = AppButtonStates.CLEAR_DATA; - visible = true; - } else { - //hide button if diableClearUserData is set - visible = false; - mAppButtonState = AppButtonStates.NONE; - } - } else { - visible = true; - mAppButtonState = AppButtonStates.UNINSTALL; - mAppButtonText = getText(R.string.uninstall_text); - } - if(visible) { - mAppButton.setText(mAppButtonText); - mAppButton.setVisibility(View.VISIBLE); - } else { - mAppButton.setVisibility(View.GONE); - } - } - /** Called when the activity is first created. */ @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); - //get package manager + // Get package manager mPm = getPackageManager(); - //get application's name from intent + // Get application's name from intent Intent intent = getIntent(); final String packageName = intent.getStringExtra(ManageApplications.APP_PKG_NAME); mComputingStr = getText(R.string.computing_size); @@ -217,38 +193,26 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene PackageManager.GET_UNINSTALLED_PACKAGES); } catch (NameNotFoundException e) { Log.e(TAG, "Exception when retrieving package:"+packageName, e); - displayErrorDialog(R.string.app_not_found_dlg_text, true, true); + showDialogInner(DLG_APP_NOT_FOUND); + return; } - setContentView(R.layout.installed_app_details); - ((ImageView)findViewById(R.id.app_icon)).setImageDrawable(mAppInfo.loadIcon(mPm)); - //set application name TODO version - CharSequence appName = mAppInfo.loadLabel(mPm); - if(appName == null) { - appName = getString(_UNKNOWN_APP); - } - ((TextView)findViewById(R.id.app_name)).setText(appName); - mAppSnippetSize = ((TextView)findViewById(R.id.app_size)); - mAppSnippetSize.setText(totalSizeStr); + setContentView(R.layout.installed_app_details); //TODO download str and download url - //set values on views + // Set default values on sizes mTotalSize = (TextView)findViewById(R.id.total_size_text); mTotalSize.setText(totalSizeStr); mAppSize = (TextView)findViewById(R.id.application_size_text); mAppSize.setText(appSizeStr); mDataSize = (TextView)findViewById(R.id.data_size_text); mDataSize.setText(dataSizeStr); - + // Get AppButton mAppButton = ((Button)findViewById(R.id.uninstall_button)); - //determine if app is a system app - mCanUninstall = !isUninstallable(); - if(localLOGV) Log.i(TAG, "Is systemPackage "+mCanUninstall); - setAppBtnState(); + // Get ManageSpaceButton mManageSpaceButton = (Button)findViewById(R.id.manage_space_button); if(mAppInfo.manageSpaceActivityName != null) { mManageSpaceButton.setVisibility(View.VISIBLE); mManageSpaceButton.setOnClickListener(this); } - // Cache section mCachePanel = findViewById(R.id.cache_panel); mCacheSize = (TextView) findViewById(R.id.cache_size_text); @@ -256,17 +220,16 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene mClearCacheButton = (Button) findViewById(R.id.clear_cache_button); mForceStopButton = (Button) findViewById(R.id.force_stop_button); mForceStopButton.setOnClickListener(this); - - //clear activities + // Get list of preferred activities mActivitiesButton = (Button)findViewById(R.id.clear_activities_button); List prefActList = new ArrayList(); - //intent list cannot be null. so pass empty list + // Intent list cannot be null. so pass empty list List intentList = new ArrayList(); mPm.getPreferredActivities(intentList, prefActList, packageName); if(localLOGV) Log.i(TAG, "Have "+prefActList.size()+" number of activities in prefered list"); TextView autoLaunchView = (TextView)findViewById(R.id.auto_launch); if(prefActList.size() <= 0) { - //disable clear activities button + // Disable clear activities button autoLaunchView.setText(R.string.auto_launch_disable_text); mActivitiesButton.setEnabled(false); } else { @@ -274,7 +237,7 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene mActivitiesButton.setOnClickListener(this); } - // security permissions section + // Security permissions section LinearLayout permsView = (LinearLayout) findViewById(R.id.permissions_section); AppSecurityPermissions asp = new AppSecurityPermissions(this, packageName); if(asp.getPermissionCount() > 0) { @@ -288,29 +251,85 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene } } - @Override - public void onStart() { - super.onStart(); + private void refreshAppAttributes(PackageInfo pkgInfo) { + setAppLabelAndIcon(); + // Version number of application + setAppVersion(pkgInfo); + setAppBtnState(); + // Refresh size info if (mAppInfo != null && mAppInfo.packageName != null) { mPm.getPackageSizeInfo(mAppInfo.packageName, mSizeObserver); } } - private void displayErrorDialog(int msgId, final boolean finish, final boolean changed) { - //display confirmation dialog - new AlertDialog.Builder(this) - .setTitle(getString(R.string.app_not_found_dlg_title)) - .setIcon(android.R.drawable.ic_dialog_alert) - .setMessage(getString(msgId)) - .setNeutralButton(getString(R.string.dlg_ok), - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - //force to recompute changed value - setIntentAndFinish(finish, changed); - } + // Utility method to set applicaiton label and icon. + private void setAppLabelAndIcon() { + ((ImageView)findViewById(R.id.app_icon)).setImageDrawable(mAppInfo.loadIcon(mPm)); + //set application name TODO version + CharSequence appName = mAppInfo.loadLabel(mPm); + if(appName == null) { + appName = getString(_UNKNOWN_APP); + } + ((TextView)findViewById(R.id.app_name)).setText(appName); + } + + // Utility method to set application version + private void setAppVersion(PackageInfo pkgInfo) { + // Version number of application + mAppVersion = ((TextView)findViewById(R.id.app_version)); + if (pkgInfo != null) { + mAppVersion.setVisibility(View.VISIBLE); + mAppVersion.setText(getString(R.string.version_text, + String.valueOf(pkgInfo.versionCode))); + } else { + mAppVersion.setVisibility(View.GONE); + } + } + + // Utility method to set button state + private void setAppBtnState() { + boolean visible = true; + if ((mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { + if ((mAppInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { + mAppButtonState = AppButtonStates.FACTORY_RESET; + mAppButtonText = getText(R.string.app_factory_reset); + } else { + if ((mAppInfo.flags & ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) == 0) { + // Hide button if diableClearUserData is set + mAppButtonState = AppButtonStates.NONE; + visible = false; + } else { + mAppButtonState = AppButtonStates.CLEAR_DATA; + mAppButtonText = getText(R.string.clear_user_data_text); } - ) - .show(); + } + } else { + mAppButtonState = AppButtonStates.UNINSTALL; + mAppButtonText = getText(R.string.uninstall_text); + } + if(visible) { + mAppButton.setText(mAppButtonText); + mAppButton.setVisibility(View.VISIBLE); + } else { + mAppButton.setVisibility(View.GONE); + } + } + + @Override + public void onStart() { + super.onStart(); + PackageInfo pkgInfo; + // Get application info again to refresh changed properties of application + try { + mAppInfo = mPm.getApplicationInfo(mAppInfo.packageName, + PackageManager.GET_UNINSTALLED_PACKAGES); + pkgInfo = mPm.getPackageInfo(mAppInfo.packageName, 0); + } catch (NameNotFoundException e) { + Log.e(TAG, "Exception when retrieving package:" + mAppInfo.packageName, e); + showDialogInner(DLG_APP_NOT_FOUND); + return; + } + refreshAppAttributes(pkgInfo); } private void setIntentAndFinish(boolean finish, boolean appChanged) { @@ -337,7 +356,6 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene mSizeInfo = newPs; String str = getSizeStr(newTot); mTotalSize.setText(str); - mAppSnippetSize.setText(str); mAppSize.setText(getSizeStr(newPs.codeSize)); mDataSize.setText(getSizeStr(newPs.dataSize)); mCacheSize.setText(getSizeStr(newPs.cacheSize)); @@ -346,7 +364,6 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene if(newTot != oldTot) { String str = getSizeStr(newTot); mTotalSize.setText(str); - mAppSnippetSize.setText(str); changed = true; } if(newPs.codeSize != mSizeInfo.codeSize) { @@ -421,14 +438,76 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); boolean res = am.clearApplicationUserData(packageName, mClearDataObserver); if(!res) { - //doesnt initiate clear. some error. should not happen but just log error for now + // Clearing data failed for some obscure reason. Just log error for now Log.i(TAG, "Couldnt clear application user data for package:"+packageName); - displayErrorDialog(R.string.clear_data_failed, false, false); + showDialogInner(DLG_CANNOT_CLEAR_DATA); } else { mAppButton.setText(R.string.recompute_size); } } + private void showDialogInner(int id) { + //removeDialog(id); + showDialog(id); + } + + @Override + public Dialog onCreateDialog(int id) { + switch (id) { + case DLG_CLEAR_DATA: + return new AlertDialog.Builder(this) + .setTitle(getString(R.string.clear_data_dlg_title)) + .setIcon(android.R.drawable.ic_dialog_alert) + .setMessage(getString(R.string.clear_data_dlg_text)) + .setPositiveButton(R.string.dlg_ok, this) + .setNegativeButton(R.string.dlg_cancel, this) + .create(); + case DLG_FACTORY_RESET: + return new AlertDialog.Builder(this) + .setTitle(getString(R.string.app_factory_reset_dlg_title)) + .setIcon(android.R.drawable.ic_dialog_alert) + .setMessage(getString(R.string.app_factory_reset_dlg_text)) + .setPositiveButton(R.string.dlg_ok, this) + .setNegativeButton(R.string.dlg_cancel, this) + .create(); + case DLG_APP_NOT_FOUND: + return new AlertDialog.Builder(this) + .setTitle(getString(R.string.app_not_found_dlg_title)) + .setIcon(android.R.drawable.ic_dialog_alert) + .setMessage(getString(R.string.app_not_found_dlg_title)) + .setNeutralButton(getString(R.string.dlg_ok), + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + //force to recompute changed value + setIntentAndFinish(true, true); + } + }) + .create(); + case DLG_CANNOT_CLEAR_DATA: + return new AlertDialog.Builder(this) + .setTitle(getString(R.string.clear_failed_dlg_title)) + .setIcon(android.R.drawable.ic_dialog_alert) + .setMessage(getString(R.string.clear_failed_dlg_text)) + .setNeutralButton(R.string.dlg_ok, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + //force to recompute changed value + setIntentAndFinish(false, false); + } + }) + .create(); + } + return null; + } + + private void uninstallPkg(String packageName) { + // Create new intent to launch Uninstaller activity + Uri packageURI = Uri.parse("package:"+packageName); + Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI); + startActivity(uninstallIntent); + setIntentAndFinish(true, true); + } + /* * Method implementing functionality of buttons clicked * @see android.view.View.OnClickListener#onClick(android.view.View) @@ -436,21 +515,12 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene public void onClick(View v) { String packageName = mAppInfo.packageName; if(v == mAppButton) { - if(mCanUninstall) { - //display confirmation dialog - new AlertDialog.Builder(this) - .setTitle(getString(R.string.clear_data_dlg_title)) - .setIcon(android.R.drawable.ic_dialog_alert) - .setMessage(getString(R.string.clear_data_dlg_text)) - .setPositiveButton(R.string.dlg_ok, this) - .setNegativeButton(R.string.dlg_cancel, this) - .show(); - } else { - //create new intent to launch Uninstaller activity - Uri packageURI = Uri.parse("package:"+packageName); - Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI); - startActivity(uninstallIntent); - setIntentAndFinish(true, true); + if (mAppButtonState == AppButtonStates.CLEAR_DATA) { + showDialogInner(DLG_CLEAR_DATA); + } else if (mAppButtonState == AppButtonStates.FACTORY_RESET) { + showDialogInner(DLG_FACTORY_RESET); + } else if (mAppButtonState == AppButtonStates.UNINSTALL) { + uninstallPkg(packageName); } } else if(v == mActivitiesButton) { mPm.clearPackagePreferredActivities(packageName); @@ -474,8 +544,13 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene public void onClick(DialogInterface dialog, int which) { if(which == AlertDialog.BUTTON_POSITIVE) { - //invoke uninstall or clear user data based on sysPackage - initiateClearUserDataForSysPkg(); + if (mAppButtonState == AppButtonStates.CLEAR_DATA) { + // Invoke uninstall or clear user data based on sysPackage + initiateClearUserDataForSysPkg(); + } else if (mAppButtonState == AppButtonStates.FACTORY_RESET) { + // Initiate package installer to delete package + uninstallPkg(mAppInfo.packageName); + } } else { //cancel do nothing just retain existing screen }