Merge change 1418 into donut

* changes:
  Show locale names in alphabetical order, in their own language.
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
         }