Add version number to Installed_App_Details
Change uninstall string value to Factory reset for updated system apps
present a new confirmation dialog when factory resetting a system app.
refresh size, app properties and button's text(to clear, uninstall or factory reset) in onStart
Add new version attribute in layout. Add new layout attributes for app snippets instead of using the one
from ManageApps
Use managed dialogs to avoid leaks
diff --git a/res/layout/installed_app_details.xml b/res/layout/installed_app_details.xml
index 7c8a672..13d3b10 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">
- <include
- layout="@layout/manage_applications_item"
- android:id="@+id/app_snippet"/>
+
+ <!-- App snippet -->
+ <RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical">
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_alignParentLeft="true"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="6dip"
+ android:paddingBottom="6dip"
+ android:paddingRight="6dip"
+ android:paddingLeft="6dip" >
+ <!-- application name -->
+ <TextView android:id="@+id/app_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="bold"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:layout_marginBottom="2dip" />
+ <!-- application version -->
+ <TextView android:id="@+id/app_version"
+ android:layout_marginTop="-4dip"
+ android:layout_gravity="center_vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </LinearLayout>
+
+ <!-- application icon -->
+ <ImageView android:id="@+id/app_icon"
+ android:layout_width="@android:dimen/app_icon_size"
+ android:layout_height="@android:dimen/app_icon_size"
+ android:layout_alignParentRight="true"
+ android:paddingTop="6dip"
+ android:paddingBottom="6dip"
+ android:paddingRight="6dip"
+ android:scaleType="fitCenter" />
+ </RelativeLayout>
+
<TextView
style="?android:attr/listSeparatorTextViewStyle"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 19d145a..f4a6846 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1274,6 +1274,8 @@
<string name="uninstall_text">Uninstall</string>
<!-- Manage applications, individual application info screen, button label under Storage heading. Button to clear all data associated with tis app (for exampel, remove all cached emails for an Email app) -->
<string name="clear_user_data_text">Clear data</string>
+ <!-- Manage applications, restore updated system application to factory version -->
+ <string name="app_factory_reset">Factory reset</string>
<!-- Manage applications, individual application info screen, screen, message text under Launch by default heading. This is present if the app is set as a default for some actions. -->
<string name="auto_launch_enable_text">You have selected to launch this application by default for some actions.</string>
<!-- Manage applications, individual application screen, text under Launch by default heading if the app is NOT a default for actions -->
@@ -1319,12 +1321,22 @@
found in the list of installed applications.</string>
<!-- Manage applications, individual application dialog box message. Shown when there was an error trying to clear the data. -->
<string name="clear_data_failed">Unable to clear application data.</string>
+ <!-- Manage applications, factory reset dialog title for system applications. -->
+ <string name="app_factory_reset_dlg_title">Factory reset system app</string>
+ <!-- Manage applications, factory reset option dialog text for system applications. -->
+ <string name="app_factory_reset_dlg_text">Do you want to fallback to factory version of system application?</string>
+ <!-- Manage applications, title for dialog if clear data fails-->
+ <string name="clear_failed_dlg_title">Clear data</string>
+ <!-- Manage applications, text for dialog if clear data fails-->
+ <string name="clear_failed_dlg_text">Failed clearing data for application</string>
<!-- Manage applications, individual application info screen, text that appears under the "Permissions" heading. This describes the permissions that the application has. -->
<string name="security_settings_desc">This application can access the following on your phone:</string>
<string name="computing_size">Computing\u2026</string>
<string name="invalid_size_value">Unable to compute package size</string>
<!-- String displayed when list is empty -->
<string name="empty_list_msg">You do not have any third-party apps installed.</string>
+ <!-- Manage applications, version string displayed in app snippet -->
+ <string name="version_text">version <xliff:g id="version_num">%1$s</xliff:g></string>
<!-- Language Settings --> <skip />
<!-- Title of setting on main settings screen. This item will take the user to the screen to tweak settings realted to locale and text -->
diff --git a/src/com/android/settings/InstalledAppDetails.java b/src/com/android/settings/InstalledAppDetails.java
index 692fc8e..5a4e672 100644
--- a/src/com/android/settings/InstalledAppDetails.java
+++ b/src/com/android/settings/InstalledAppDetails.java
@@ -22,13 +22,16 @@
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.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 @@
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 @@
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 @@
}
};
- 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 @@
}
}
-
+
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 @@
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 @@
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 @@
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<ComponentName> prefActList = new ArrayList<ComponentName>();
- //intent list cannot be null. so pass empty list
+ // Intent list cannot be null. so pass empty list
List<IntentFilter> intentList = new ArrayList<IntentFilter>();
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 @@
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 @@
}
}
- @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 @@
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 @@
if(newTot != oldTot) {
String str = getSizeStr(newTot);
mTotalSize.setText(str);
- mAppSnippetSize.setText(str);
changed = true;
}
if(newPs.codeSize != mSizeInfo.codeSize) {
@@ -421,14 +438,76 @@
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 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 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
}