Merge "Fixing bug 2455152 - Enabled accessibility services are disabled upon restarting accessibility"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index ad4596e..a7066e0 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -39,6 +39,7 @@
     <uses-permission android:name="android.permission.BATTERY_STATS"/>
     <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
     <uses-permission android:name="com.android.launcher.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="android.permission.MOVE_PACKAGE" />
 
     <application android:label="@string/settings_label"
             android:icon="@drawable/ic_launcher_settings"
diff --git a/res/layout/power_usage_action_item.xml b/res/layout/power_usage_action_item.xml
index a53c551..e4d8b5a 100644
--- a/res/layout/power_usage_action_item.xml
+++ b/res/layout/power_usage_action_item.xml
@@ -28,6 +28,7 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_marginTop="2dip"
+            android:paddingBottom="4dip"
             android:ellipsize="marquee"
             android:textAppearance="?android:attr/textAppearanceMedium"/>
 
diff --git a/res/layout/power_usage_details.xml b/res/layout/power_usage_details.xml
index 18781a9..23be53f 100644
--- a/res/layout/power_usage_details.xml
+++ b/res/layout/power_usage_details.xml
@@ -87,6 +87,17 @@
             </RelativeLayout>
         </LinearLayout>
 
+        <!-- Force stop and report buttons -->
+        <LinearLayout
+            android:id="@+id/two_buttons_panel"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingBottom="6dip"
+            android:orientation="vertical">
+            <include
+                layout="@layout/two_buttons_panel"/>
+        </LinearLayout>
+                    
         <TextView
             style="?android:attr/listSeparatorTextViewStyle"
             android:text="@string/details_subtitle" />
diff --git a/res/layout/running_services.xml b/res/layout/running_services.xml
index 2f464a5..5c0da6f 100644
--- a/res/layout/running_services.xml
+++ b/res/layout/running_services.xml
@@ -35,20 +35,20 @@
 	            android:text="@string/no_running_services"
 	            android:textAppearance="?android:attr/textAppearanceLarge" />
     </FrameLayout>
-    <LinearLayout
+    <view class="com.android.settings.RunningServices$LinearColorBar"
+            android:id="@+id/color_bar"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:orientation="horizontal"
-            android:background="?android:attr/colorForeground"
             android:padding="4dp">
-        <TextView android:id="@+id/backgroundText"
+        <TextView android:id="@+id/foregroundText"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_weight="1"
             android:textAppearance="?android:attr/textAppearanceSmallInverse"
             android:color="?android:attr/textColorPrimaryInverse"
             android:singleLine="true" />
-        <TextView android:id="@+id/foregroundText"
+        <TextView android:id="@+id/backgroundText"
             android:layout_gravity="center_vertical|right"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
@@ -56,5 +56,5 @@
             android:textAppearance="?android:attr/textAppearanceSmallInverse"
             android:color="?android:attr/textColorPrimaryInverse"
             android:singleLine="true" />
-    </LinearLayout>
+    </view>
 </LinearLayout>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index ae0fba8..ff68cc7 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -354,4 +354,18 @@
         <item>3</item>
     </string-array>
 
+    <!-- Apps on SD instalaltion location options in ApplicationSettings -->
+    <string-array name="app_install_location_entries">
+        <item>Internal device storage</item>
+        <item>Removable SD card</item>
+        <item>Let the system decide</item>
+    </string-array>
+
+    <!-- Do not translate. -->
+    <string-array name="app_install_location_values" translatable="false">
+        <item>device</item>
+        <item>sdcard</item>
+        <item>auto</item>
+    </string-array>
+
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 3afe481..bc19df5 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1117,7 +1117,7 @@
     <string name="system_update_settings_list_item_summary">""</string>
 
     <!-- About phone screen, status item label -->
-    <string name="firmware_version">Firmware version</string>
+    <string name="firmware_version">Android version</string>
     <!-- About phone screen, status item label-->
     <string name="model_number">Model number</string>
     <!-- About phone screen,  setting option name-->
@@ -1628,9 +1628,15 @@
     <!-- Manage applications, text for Move button  to move app to sdcard -->
     <string name="move_app_to_sdcard">Move to sdcard</string>
     <!-- Manage applications, title for dialog when killing persistent apps-->
+    <!-- Manage applications, text for Move button when move is in progress -->
+    <string name="moving">Moving</string>
     <string name="force_stop_dlg_title">Force Stop</string>
     <!-- Manage applications, text for dialog when killing persistent apps-->
     <string name="force_stop_dlg_text">This application will be restarted right way. Are you sure you want to force stop?</string>
+    <!-- Manage applications, application installation location title -->
+    <string name="app_install_location_title">Preferred install location</string>
+    <!-- Manage applications. application installation location summary -->
+    <string name="app_install_location_summary">Change the preferred installation location for new applications.</string>
 
     <!-- Services settings screen, setting option name for the user to go to the screen to view running services -->
     <string name="runningservices_settings_title">Running services</string>
diff --git a/res/xml/application_settings.xml b/res/xml/application_settings.xml
index b5418e8..4df21da 100644
--- a/res/xml/application_settings.xml
+++ b/res/xml/application_settings.xml
@@ -25,7 +25,15 @@
             android:summaryOff="@string/install_unknown_applications"
             android:summaryOn="@string/install_unknown_applications"
             android:persistent="false" />
-        
+
+    <ListPreference
+        android:key="app_install_location"
+        android:title="@string/app_install_location_title"
+        android:summary="@string/app_install_location_summary"
+        android:persistent="false"
+        android:entries="@array/app_install_location_entries"
+        android:entryValues="@array/app_install_location_values"/>
+
     <PreferenceScreen
             android:key="quick_launch"
             android:title="@string/quick_launch_title"
diff --git a/src/com/android/settings/ApplicationSettings.java b/src/com/android/settings/ApplicationSettings.java
index 6a8aa81..9b7a919 100644
--- a/src/com/android/settings/ApplicationSettings.java
+++ b/src/com/android/settings/ApplicationSettings.java
@@ -21,21 +21,35 @@
 import android.content.res.Configuration;
 import android.os.Bundle;
 import android.preference.CheckBoxPreference;
+import android.preference.ListPreference;
 import android.preference.Preference;
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceScreen;
+import android.preference.Preference.OnPreferenceChangeListener;
 import android.provider.Settings;
 
 public class ApplicationSettings extends PreferenceActivity implements
         DialogInterface.OnClickListener {
     
     private static final String KEY_TOGGLE_INSTALL_APPLICATIONS = "toggle_install_applications";
+    private static final String KEY_APP_INSTALL_LOCATION = "app_install_location";
     private static final String KEY_QUICK_LAUNCH = "quick_launch";
 
+    // App installation location. Default is ask the user.
+    private static final int APP_INSTALL_AUTO = 0;
+    private static final int APP_INSTALL_DEVICE = 1;
+    private static final int APP_INSTALL_SDCARD = 2;
+    
+    private static final String APP_INSTALL_DEVICE_ID = "device";
+    private static final String APP_INSTALL_SDCARD_ID = "sdcard";
+    private static final String APP_INSTALL_AUTO_ID = "auto";
+    
     private CheckBoxPreference mToggleAppInstallation;
-    
+
+    private ListPreference mInstallLocation;
+
     private DialogInterface mWarnInstallApps;
-    
+
     @Override
     protected void onCreate(Bundle icicle) {
         super.onCreate(icicle);
@@ -45,6 +59,23 @@
         mToggleAppInstallation = (CheckBoxPreference) findPreference(KEY_TOGGLE_INSTALL_APPLICATIONS);
         mToggleAppInstallation.setChecked(isNonMarketAppsAllowed());
 
+        mInstallLocation = (ListPreference) findPreference(KEY_APP_INSTALL_LOCATION);
+        // Is app default install location set?
+        boolean userSetInstLocation = (Settings.System.getInt(getContentResolver(),
+                Settings.System.SET_INSTALL_LOCATION, 0) != 0);
+        if (!userSetInstLocation) {
+            getPreferenceScreen().removePreference(mInstallLocation);
+        } else {
+            mInstallLocation.setValue(getAppInstallLocation());
+            mInstallLocation.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
+                public boolean onPreferenceChange(Preference preference, Object newValue) {
+                    String value = (String) newValue;
+                    handleUpdateAppInstallLocation(value);
+                    return false;
+                }
+            });
+        }
+
         if (getResources().getConfiguration().keyboard == Configuration.KEYBOARD_NOKEYS) {
             // No hard keyboard, remove the setting for quick launch
             Preference quickLaunchSetting = findPreference(KEY_QUICK_LAUNCH);
@@ -52,6 +83,24 @@
         }
     }
 
+    protected void handleUpdateAppInstallLocation(final String value) {
+        if(APP_INSTALL_DEVICE_ID.equals(value)) {
+            Settings.System.putInt(getContentResolver(),
+                    Settings.System.DEFAULT_INSTALL_LOCATION, APP_INSTALL_DEVICE);
+        } else if (APP_INSTALL_SDCARD_ID.equals(value)) {
+            Settings.System.putInt(getContentResolver(),
+                    Settings.System.DEFAULT_INSTALL_LOCATION, APP_INSTALL_SDCARD);
+        } else if (APP_INSTALL_AUTO_ID.equals(value)) {
+            Settings.System.putInt(getContentResolver(),
+                    Settings.System.DEFAULT_INSTALL_LOCATION, APP_INSTALL_AUTO);
+        } else {
+            // Should not happen, default to prompt...
+            Settings.System.putInt(getContentResolver(),
+                    Settings.System.DEFAULT_INSTALL_LOCATION, APP_INSTALL_AUTO);
+        }
+        mInstallLocation.setValue(value);
+    }
+
     @Override
     protected void onDestroy() {
         super.onDestroy();
@@ -70,7 +119,7 @@
                 setNonMarketAppsAllowed(false);
             }
         }
-        
+
         return super.onPreferenceTreeClick(preferenceScreen, preference);
     }
 
@@ -92,6 +141,21 @@
                                       Settings.Secure.INSTALL_NON_MARKET_APPS, 0) > 0;
     }
 
+    private String getAppInstallLocation() {
+        int selectedLocation = Settings.System.getInt(getContentResolver(),
+                Settings.System.DEFAULT_INSTALL_LOCATION, APP_INSTALL_AUTO);
+        if (selectedLocation == APP_INSTALL_DEVICE) {
+            return APP_INSTALL_DEVICE_ID;
+        } else if (selectedLocation == APP_INSTALL_SDCARD) {
+            return APP_INSTALL_SDCARD_ID;
+        } else  if (selectedLocation == APP_INSTALL_AUTO) {
+            return APP_INSTALL_AUTO_ID;
+        } else {
+            // Default value, should not happen.
+            return APP_INSTALL_AUTO_ID;
+        }
+    }
+
     private void warnAppInstallation() {
         mWarnInstallApps = new AlertDialog.Builder(this)
                 .setTitle(getString(R.string.error_title))
@@ -101,6 +165,4 @@
                 .setNegativeButton(android.R.string.no, null)
                 .show();
     }
-    
-    
 }
diff --git a/src/com/android/settings/DeviceAdminAdd.java b/src/com/android/settings/DeviceAdminAdd.java
index 126af6b..26ad70c 100644
--- a/src/com/android/settings/DeviceAdminAdd.java
+++ b/src/com/android/settings/DeviceAdminAdd.java
@@ -137,8 +137,18 @@
         mActionButton.setOnClickListener(new View.OnClickListener() {
             public void onClick(View v) {
                 if (mAdding) {
-                    mDPM.setActiveAdmin(mDeviceAdmin.getComponent());
-                    setResult(Activity.RESULT_OK);
+                    try {
+                        mDPM.setActiveAdmin(mDeviceAdmin.getComponent());
+                        setResult(Activity.RESULT_OK);
+                    } catch (RuntimeException e) {
+                        // Something bad happened...  could be that it was
+                        // already set, though.
+                        Log.w(TAG, "Exception trying to activate admin "
+                                + mDeviceAdmin.getComponent(), e);
+                        if (mDPM.isAdminActive(mDeviceAdmin.getComponent())) {
+                            setResult(Activity.RESULT_OK);
+                        }
+                    }
                     finish();
                 } else {
                     mDPM.getRemoveWarning(mDeviceAdmin.getComponent(),
diff --git a/src/com/android/settings/InstalledAppDetails.java b/src/com/android/settings/InstalledAppDetails.java
index 1358133..67f2f8f 100644
--- a/src/com/android/settings/InstalledAppDetails.java
+++ b/src/com/android/settings/InstalledAppDetails.java
@@ -23,14 +23,14 @@
 import android.app.ActivityManager;
 import android.app.AlertDialog;
 import android.app.Dialog;
-import android.app.ActivityManager.RunningAppProcessInfo;
+import android.content.BroadcastReceiver;
 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.IPackageMoveObserver;
 import android.content.pm.IPackageStatsObserver;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
@@ -42,7 +42,6 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.text.format.Formatter;
-import android.util.Config;
 import android.util.Log;
 import java.util.ArrayList;
 import java.util.List;
@@ -87,6 +86,7 @@
     
     PackageStats mSizeInfo;
     private PackageManager mPm;
+    private PackageMoveObserver mPackageMoveObserver;
     
     //internal constants used in Handler
     private static final int OP_SUCCESSFUL = 1;
@@ -94,6 +94,7 @@
     private static final int CLEAR_USER_DATA = 1;
     private static final int GET_PKG_SIZE = 2;
     private static final int CLEAR_CACHE = 3;
+    private static final int PACKAGE_MOVE = 4;
     private static final String ATTR_PACKAGE_STATS="PackageStats";
     
     // invalid size value used initially and also when size retrieval through PackageManager
@@ -125,6 +126,9 @@
                     // Refresh size info
                     mPm.getPackageSizeInfo(mAppInfo.packageName, mSizeObserver);
                     break;
+                case PACKAGE_MOVE:
+                    processMoveMsg(msg);
+                    break;
                 default:
                     break;
             }
@@ -153,10 +157,18 @@
     class ClearCacheObserver extends IPackageDataObserver.Stub {
         public void onRemoveCompleted(final String packageName, final boolean succeeded) {
             final Message msg = mHandler.obtainMessage(CLEAR_CACHE);
-            msg.arg1 = succeeded?OP_SUCCESSFUL:OP_FAILED;
+            msg.arg1 = succeeded ? OP_SUCCESSFUL:OP_FAILED;
             mHandler.sendMessage(msg);
          }
      }
+
+    class PackageMoveObserver extends IPackageMoveObserver.Stub {
+        public void packageMoved(String packageName, int returnCode) throws RemoteException {
+            final Message msg = mHandler.obtainMessage(PACKAGE_MOVE);
+            msg.arg1 = returnCode;
+            mHandler.sendMessage(msg);
+        }
+    }
     
     private String getSizeStr(long size) {
         if (size == SIZE_INVALID) {
@@ -172,23 +184,36 @@
             mClearDataButton.setText(R.string.clear_user_data_text);
         }
         mClearDataButton.setOnClickListener(this);
+        initMoveButton();
+    }
+
+    private void initMoveButton() {
         String pkgName = mAppInfo.packageName;
         boolean dataOnly = false;
         ApplicationInfo info1 = null;
-        ApplicationInfo info2 = null;
 
         try {
             info1 = mPm.getApplicationInfo(pkgName, 0);
         } catch (NameNotFoundException e) {
         }
         dataOnly = (info1 == null) && (mAppInfo != null);
+        boolean moveDisable = true;
         if (dataOnly) {
             mMoveAppButton.setText(R.string.move_app);
         } else if ((mAppInfo.flags & ApplicationInfo.FLAG_ON_SDCARD) != 0) {
             mMoveAppButton.setText(R.string.move_app_to_internal);
+            moveDisable = false;
         } else {
+            moveDisable = (mAppInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0 ||
+            (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
             mMoveAppButton.setText(R.string.move_app_to_sdcard);
         }
+        if (moveDisable) {
+            mMoveAppButton.setEnabled(false);
+        } else {
+            mMoveAppButton.setOnClickListener(this);
+            mMoveAppButton.setEnabled(true);
+        }
     }
 
     private void initControlButtons() {
@@ -207,25 +232,6 @@
             // Register listener
             mUninstallButton.setOnClickListener(this);
         }
-        ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
-        List<RunningAppProcessInfo> rList = am.getRunningAppProcesses();
-        boolean running = false;
-        if (rList != null) {
-            for (RunningAppProcessInfo info : rList) {
-                if (info.pkgList != null) {
-                    for (String rpkg : info.pkgList) {
-                        if (rpkg.equals(mAppInfo.packageName)) {
-                            running = true;
-                            break;
-                        }
-                    }
-                }
-            }
-        }
-        mForceStopButton.setEnabled(running);
-        if (running) {
-            mForceStopButton.setOnClickListener(this);
-        }
     }
 
     /** Called when the activity is first created. */
@@ -265,13 +271,12 @@
         mForceStopButton = (Button) btnPanel.findViewById(R.id.left_button);
         mForceStopButton.setText(R.string.force_stop);
         mUninstallButton = (Button)btnPanel.findViewById(R.id.right_button);
+        mForceStopButton.setEnabled(false);
         initControlButtons();
         // Initialize clear data and move install location buttons
         View data_buttons_panel = findViewById(R.id.data_buttons_panel);
         mClearDataButton = (Button) data_buttons_panel.findViewById(R.id.left_button);
         mMoveAppButton = (Button) data_buttons_panel.findViewById(R.id.right_button);
-        // Disable move for now
-        mMoveAppButton.setEnabled(false);
          // Cache section
          mCacheSize = (TextView) findViewById(R.id.cache_size_text);
          mCacheSize.setText(mComputingStr);
@@ -359,6 +364,7 @@
             showDialogInner(DLG_APP_NOT_FOUND);
             return;
         }
+        checkForceStop();
         refreshAppAttributes(pkgInfo);
     }
 
@@ -444,6 +450,24 @@
             mClearDataButton.setEnabled(true);
         }
     }
+
+    private void processMoveMsg(Message msg) {
+        int result = msg.arg1;
+        String packageName = mAppInfo.packageName;
+        if(result == PackageManager.MOVE_SUCCEEDED) {
+            Log.i(TAG, "Moved resources for " + packageName);
+            try {
+                // Reset flags
+                mAppInfo = mPm.getApplicationInfo(packageName,
+                        PackageManager.GET_UNINSTALLED_PACKAGES);
+                initMoveButton();
+            } catch (NameNotFoundException e) {
+                // TODO error handling
+            }
+        } else {
+            // TODO Present a dialog indicating failure.
+        }
+    }
     
     /*
      * Private method to initiate clearing user data when the user clicks the clear data 
@@ -561,8 +585,25 @@
         ActivityManager am = (ActivityManager)getSystemService(
                 Context.ACTIVITY_SERVICE);
         am.forceStopPackage(pkgName);
+        checkForceStop();
     }
 
+    private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            mForceStopButton.setEnabled(getResultCode() != RESULT_CANCELED);
+        }
+    };
+    
+    private void checkForceStop() {
+        Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART,
+                Uri.fromParts("package", mAppInfo.packageName, null));
+        intent.putExtra(Intent.EXTRA_PACKAGES, new String[] { mAppInfo.packageName });
+        intent.putExtra(Intent.EXTRA_UID, mAppInfo.uid);
+        sendOrderedBroadcast(intent, null, mCheckKillProcessesReceiver, null,
+                Activity.RESULT_CANCELED, null, null);
+    }
+    
     /*
      * Method implementing functionality of buttons clicked
      * @see android.view.View.OnClickListener#onClick(android.view.View)
@@ -601,6 +642,15 @@
             // that the button cannot be enabled or disabled since
             // we do not have this info for now.
             forceStopPackage(mAppInfo.packageName);
+        } else if (v == mMoveAppButton) {
+            if (mPackageMoveObserver == null) {
+                mPackageMoveObserver = new PackageMoveObserver();
+            }
+            int moveFlags = (mAppInfo.flags & ApplicationInfo.FLAG_ON_SDCARD) != 0 ?
+                    PackageManager.MOVE_INTERNAL : PackageManager.MOVE_EXTERNAL_MEDIA;
+            mMoveAppButton.setText(R.string.moving);
+            mMoveAppButton.setEnabled(false);
+            mPm.movePackage(mAppInfo.packageName, mPackageMoveObserver, moveFlags);
         }
     }
 }
diff --git a/src/com/android/settings/RunningServices.java b/src/com/android/settings/RunningServices.java
index 6c11ea0..4808aec 100644
--- a/src/com/android/settings/RunningServices.java
+++ b/src/com/android/settings/RunningServices.java
@@ -35,6 +35,9 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
 import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.Handler;
@@ -53,6 +56,7 @@
 import android.widget.AbsListView;
 import android.widget.BaseAdapter;
 import android.widget.ImageView;
+import android.widget.LinearLayout;
 import android.widget.ListView;
 import android.widget.TextView;
 
@@ -93,13 +97,16 @@
     
     int mProcessBgColor;
     
+    LinearColorBar mColorBar;
     TextView mBackgroundProcessText;
     TextView mForegroundProcessText;
     
     int mLastNumBackgroundProcesses = -1;
     int mLastNumForegroundProcesses = -1;
+    int mLastNumServiceProcesses = -1;
     long mLastBackgroundProcessMemory = -1;
     long mLastForegroundProcessMemory = -1;
+    long mLastServiceProcessMemory = -1;
     long mLastAvailMemory = -1;
     
     Dialog mCurDialog;
@@ -392,6 +399,8 @@
         long mBackgroundProcessMemory;
         int mNumForegroundProcesses;
         long mForegroundProcessMemory;
+        int mNumServiceProcesses;
+        long mServiceProcessMemory;
         
         boolean update(Context context, ActivityManager am) {
             final PackageManager pm = context.getPackageManager();
@@ -576,6 +585,7 @@
             mAllProcessItems.addAll(mProcessItems);
             mNumBackgroundProcesses = 0;
             mNumForegroundProcesses = 0;
+            mNumServiceProcesses = 0;
             NRP = mRunningProcesses.size();
             for (int i=0; i<NRP; i++) {
                 ProcessItem proc = mRunningProcesses.valueAt(i);
@@ -590,13 +600,19 @@
                             ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
                         mNumForegroundProcesses++;
                         mAllProcessItems.add(proc);
+                    } else {
+                        Log.i(TAG, "Unknown non-service process: "
+                                + proc.mProcessName + " #" + proc.mPid);
                     }
+                } else {
+                    mNumServiceProcesses++;
                 }
             }
             
             try {
                 mBackgroundProcessMemory = 0;
                 mForegroundProcessMemory = 0;
+                mServiceProcessMemory = 0;
                 final int numProc = mAllProcessItems.size();
                 int[] pids = new int[numProc];
                 for (int i=0; i<numProc; i++) {
@@ -608,9 +624,8 @@
                     ProcessItem proc = mAllProcessItems.get(i);
                     changed |= proc.updateSize(context, mem[i], mSequence);
                     if (proc.mCurSeq == mSequence) {
-                        continue;
-                    }
-                    if (proc.mRunningProcessInfo.importance >=
+                        mServiceProcessMemory += proc.mSize;
+                    } else if (proc.mRunningProcessInfo.importance >=
                             ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
                         mBackgroundProcessMemory += proc.mSize;
                     } else if (proc.mRunningProcessInfo.importance <=
@@ -725,6 +740,67 @@
         }
     }
     
+    public static class LinearColorBar extends LinearLayout {
+        private float mRedRatio;
+        private float mYellowRatio;
+        private float mGreenRatio;
+        
+        final Rect mRect = new Rect();
+        final Paint mPaint = new Paint();
+        
+        public LinearColorBar(Context context, AttributeSet attrs) {
+            super(context, attrs);
+            setWillNotDraw(false);
+            mPaint.setStyle(Paint.Style.FILL);
+        }
+
+        public void setRatios(float red, float yellow, float green) {
+            mRedRatio = red;
+            mYellowRatio = yellow;
+            mGreenRatio = green;
+            invalidate();
+        }
+        
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+            
+            int width = getWidth();
+            mRect.top = 0;
+            mRect.bottom = getHeight();
+            
+            int left = 0;
+            
+            int right = left + (int)(width*mRedRatio);
+            if (left < right) {
+                mRect.left = left;
+                mRect.right = right;
+                mPaint.setColor(0xffff8080);
+                canvas.drawRect(mRect, mPaint);
+                width -= (right-left);
+                left = right;
+            }
+            
+            right = left + (int)(width*mYellowRatio);
+            if (left < right) {
+                mRect.left = left;
+                mRect.right = right;
+                mPaint.setColor(0xffffff00);
+                canvas.drawRect(mRect, mPaint);
+                width -= (right-left);
+                left = right;
+            }
+            
+            right = left + width;
+            if (left < right) {
+                mRect.left = left;
+                mRect.right = right;
+                mPaint.setColor(0xff80ff80);
+                canvas.drawRect(mRect, mPaint);
+            }
+        }
+    }
+    
     final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
@@ -823,6 +899,7 @@
         setContentView(R.layout.running_services);
         getListView().setDivider(null);
         getListView().setAdapter(new ServiceListAdapter(mState));
+        mColorBar = (LinearColorBar)findViewById(R.id.color_bar);
         mBackgroundProcessText = (TextView)findViewById(R.id.backgroundText);
         mForegroundProcessText = (TextView)findViewById(R.id.foregroundText);
         
@@ -864,6 +941,14 @@
             mForegroundProcessText.setText(getResources().getString(
                     R.string.service_foreground_processes, mLastNumForegroundProcesses, sizeStr));
         }
+        mLastNumServiceProcesses = mState.mNumServiceProcesses;
+        mLastServiceProcessMemory = mState.mServiceProcessMemory;
+        
+        float totalMem = mLastBackgroundProcessMemory
+                + mLastForegroundProcessMemory + mLastServiceProcessMemory;
+        mColorBar.setRatios(mLastForegroundProcessMemory/totalMem,
+                mLastServiceProcessMemory/totalMem,
+                mLastForegroundProcessMemory/totalMem);
     }
     
     @Override
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index fb2f6c9..5b60c45 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -71,7 +71,7 @@
 
     private static final String KEY_LOCK_ENABLED = "lockenabled";
     private static final String KEY_VISIBLE_PATTERN = "visiblepattern";
-    private static final String KEY_TACTILE_FEEDBACK_ENABLED = "tactilefeedback";
+    private static final String KEY_TACTILE_FEEDBACK_ENABLED = "unlock_tactile_feedback";
     private static final String KEY_UNLOCK_METHOD = "unlock_method";
     private static final int UPDATE_PASSWORD_REQUEST = 56;
     private static final int CONFIRM_EXISTING_REQUEST = 57;
@@ -285,13 +285,10 @@
         super.onResume();
 
         final LockPatternUtils lockPatternUtils = mChooseLockSettingsHelper.utils();
-        boolean patternExists = lockPatternUtils.savedPatternExists();
         if (mVisiblePattern != null) {
-            mVisiblePattern.setEnabled(patternExists);
             mVisiblePattern.setChecked(lockPatternUtils.isVisiblePatternEnabled());
         }
         if (mTactileFeedback != null) {
-            mTactileFeedback.setEnabled(patternExists);
             mTactileFeedback.setChecked(lockPatternUtils.isTactileFeedbackEnabled());
         }
 
diff --git a/src/com/android/settings/VoiceInputOutputSettings.java b/src/com/android/settings/VoiceInputOutputSettings.java
index 4011038..87e423c 100644
--- a/src/com/android/settings/VoiceInputOutputSettings.java
+++ b/src/com/android/settings/VoiceInputOutputSettings.java
@@ -100,7 +100,8 @@
             ResolveInfo resolveInfo = availableRecognitionServices.get(0);
             String recognizerComponent =
                     new ComponentName(resolveInfo.serviceInfo.packageName,
-                            resolveInfo.serviceInfo.name).flattenToString();
+                            resolveInfo.serviceInfo.name).flattenToShortString();
+            
             mAvailableRecognizersMap.put(recognizerComponent, resolveInfo);
             
             String currentSetting = Settings.Secure.getString(
@@ -134,7 +135,7 @@
             ResolveInfo resolveInfo = recognizers.get(i);
             String recognizerComponent =
                     new ComponentName(resolveInfo.serviceInfo.packageName,
-                            resolveInfo.serviceInfo.name).flattenToString();
+                            resolveInfo.serviceInfo.name).flattenToShortString();
             
             mAvailableRecognizersMap.put(recognizerComponent, resolveInfo);
 
diff --git a/src/com/android/settings/fuelgauge/PowerUsageDetail.java b/src/com/android/settings/fuelgauge/PowerUsageDetail.java
index a98bfed..da5721a 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageDetail.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageDetail.java
@@ -18,6 +18,9 @@
 
 import android.app.Activity;
 import android.app.ActivityManager;
+import android.app.ApplicationErrorReport;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
@@ -26,9 +29,12 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
+import android.net.Uri;
 import android.os.Bundle;
+import android.os.Process;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -37,6 +43,7 @@
 import android.widget.TextView;
 
 import com.android.settings.InstalledAppDetails;
+import com.android.settings.ManageApplications;
 import com.android.settings.R;
 
 public class PowerUsageDetail extends Activity implements Button.OnClickListener {
@@ -68,6 +75,8 @@
     public static final int ACTION_WIRELESS_SETTINGS = 4;
     public static final int ACTION_APP_DETAILS = 5;
     public static final int ACTION_SECURITY_SETTINGS = 6;
+    public static final int ACTION_FORCE_STOP = 7;
+    public static final int ACTION_REPORT = 8;
 
     public static final int USAGE_SINCE_UNPLUGGED = 1;
     public static final int USAGE_SINCE_RESET = 2;
@@ -78,6 +87,8 @@
     public static final String EXTRA_UID = "uid";
     public static final String EXTRA_USAGE_SINCE = "since";
     public static final String EXTRA_USAGE_DURATION = "duration";
+    public static final String EXTRA_REPORT_DETAILS = "report_details";
+    public static final String EXTRA_REPORT_CHECKIN_DETAILS = "report_checkin_details";
     public static final String EXTRA_DETAIL_TYPES = "types"; // Array of usage types (cpu, gps, etc)
     public static final String EXTRA_DETAIL_VALUES = "values"; // Array of doubles
     public static final String EXTRA_DRAIN_TYPE = "drainType"; // DrainType
@@ -92,6 +103,9 @@
     private int mUid;
     private double[] mValues;
     private TextView mTitleView;
+    private ViewGroup mTwoButtonsPanel;
+    private Button mForceStopButton;
+    private Button mReportButton;
     private ViewGroup mDetailsParent;
     private ViewGroup mControlsParent;
     private long mStartTime;
@@ -105,6 +119,9 @@
     private static final String TAG = "PowerUsageDetail";
     private String[] mPackages;
 
+    ApplicationInfo mApp;
+    ComponentName mInstaller;
+    
     @Override
     protected void onCreate(Bundle icicle) {
         super.onCreate(icicle);
@@ -116,6 +133,7 @@
     protected void onResume() {
         super.onResume();
         mStartTime = android.os.Process.getElapsedCpuTime();
+        checkForceStop();
     }
 
     @Override
@@ -163,6 +181,11 @@
         ((TextView)findViewById(R.id.battery_percentage))
             .setText(String.format("%d%%", percentage));
 
+        mTwoButtonsPanel = (ViewGroup) findViewById(R.id.two_buttons_panel);
+        mForceStopButton = (Button) findViewById(R.id.left_button);
+        mReportButton = (Button) findViewById(R.id.right_button);
+        mForceStopButton.setEnabled(false);
+        
         ImageView gaugeImage = (ImageView) findViewById(R.id.gauge);
         mGauge = new PercentageBar();
         mGauge.percent = gaugeValue;
@@ -178,6 +201,34 @@
         fillDetailsSection();
         fillPackagesSection(mUid);
         fillControlsSection(mUid);
+        
+        if (mUid >= Process.FIRST_APPLICATION_UID) {
+            mForceStopButton.setText(R.string.force_stop);
+            mForceStopButton.setTag(ACTION_FORCE_STOP);
+            mForceStopButton.setOnClickListener(this);
+            mReportButton.setText(com.android.internal.R.string.report);
+            mReportButton.setTag(ACTION_REPORT);
+            mReportButton.setOnClickListener(this);
+            
+            // check if error reporting is enabled in secure settings
+            int enabled = Settings.Secure.getInt(getContentResolver(),
+                    Settings.Secure.SEND_ACTION_APP_ERROR, 0);
+            if (enabled != 0) {
+                if (mPackages != null && mPackages.length > 0) {
+                    try {
+                        mApp = getPackageManager().getApplicationInfo(mPackages[0], 0);
+                        mInstaller = ApplicationErrorReport.getErrorReportReceiver(
+                                this, mPackages[0], mApp.flags);
+                    } catch (NameNotFoundException e) {
+                    }
+                }
+                mReportButton.setEnabled(mInstaller != null);
+            } else {
+                mTwoButtonsPanel.setVisibility(View.GONE);
+            }
+        } else {
+            mTwoButtonsPanel.setVisibility(View.GONE);
+        }
     }
 
     public void onClick(View v) {
@@ -201,12 +252,18 @@
             case ACTION_APP_DETAILS:
                 Intent intent = new Intent(Intent.ACTION_VIEW);
                 intent.setClass(this, InstalledAppDetails.class);
-                intent.putExtra("com.android.settings.ApplicationPkgName", mPackages[0]);
+                intent.putExtra(ManageApplications.APP_PKG_NAME, mPackages[0]);
                 startActivity(intent);
                 break;
             case ACTION_SECURITY_SETTINGS:
                 startActivity(new Intent(Settings.ACTION_SECURITY_SETTINGS));
                 break;
+            case ACTION_FORCE_STOP:
+                killProcesses();
+                break;
+            case ACTION_REPORT:
+                reportBatteryUse();
+                break;
         }
     }
 
@@ -332,8 +389,62 @@
         for (int i = 0; i < mPackages.length; i++) {
             am.forceStopPackage(mPackages[i]);
         }
+        checkForceStop();
     }
 
+    private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            mForceStopButton.setEnabled(getResultCode() != RESULT_CANCELED);
+        }
+    };
+    
+    private void checkForceStop() {
+        if (mPackages == null || mUid < Process.FIRST_APPLICATION_UID) {
+            mForceStopButton.setEnabled(false);
+            return;
+        }
+        Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART,
+                Uri.fromParts("package", mPackages[0], null));
+        intent.putExtra(Intent.EXTRA_PACKAGES, mPackages);
+        intent.putExtra(Intent.EXTRA_UID, mUid);
+        sendOrderedBroadcast(intent, null, mCheckKillProcessesReceiver, null,
+                Activity.RESULT_CANCELED, null, null);
+    }
+    
+    private void reportBatteryUse() {
+        if (mPackages == null) return;
+        
+        final Intent intent = getIntent();
+        final int percentage = intent.getIntExtra(EXTRA_PERCENT, 1);
+        final long duration = intent.getLongExtra(EXTRA_USAGE_DURATION, 0);
+        
+        ApplicationErrorReport report = new ApplicationErrorReport();
+        report.type = ApplicationErrorReport.TYPE_BATTERY;
+        report.packageName = mPackages[0];
+        report.installerPackageName = mInstaller.getPackageName();
+        report.processName = mPackages[0];
+        report.time = System.currentTimeMillis();
+        report.systemApp = (mApp.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+        
+        StringBuilder builder = new StringBuilder();
+        builder.append("Application used " + percentage + "% of battery over "
+                + Utils.formatElapsedTime(this, duration / 1000));
+        builder.append('\n');
+        builder.append(intent.getStringExtra(EXTRA_REPORT_DETAILS));
+        builder.append('\n');
+        builder.append("----------------------------------------------");
+        builder.append('\n');
+        builder.append(intent.getStringExtra(EXTRA_REPORT_CHECKIN_DETAILS));
+        builder.append('\n');
+        report.batteryText = builder.toString();
+        Intent result = new Intent(Intent.ACTION_APP_ERROR);
+        result.setComponent(mInstaller);
+        result.putExtra(Intent.EXTRA_BUG_REPORT, report);
+        result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        startActivity(result);
+    }
+    
     private void fillPackagesSection(int uid) {
         if (uid < 1) {
             removePackagesSection();
@@ -344,7 +455,7 @@
         LayoutInflater inflater = getLayoutInflater();
         
         PackageManager pm = getPackageManager();
-        final Drawable defaultActivityIcon = pm.getDefaultActivityIcon();
+        //final Drawable defaultActivityIcon = pm.getDefaultActivityIcon();
         mPackages = pm.getPackagesForUid(uid);
         if (mPackages == null || mPackages.length < 2) {
             removePackagesSection();
@@ -356,13 +467,13 @@
             try {
                 ApplicationInfo ai = pm.getApplicationInfo(mPackages[i], 0);
                 CharSequence label = ai.loadLabel(pm);
-                Drawable icon = defaultActivityIcon;
+                //Drawable icon = defaultActivityIcon;
                 if (label != null) {
                     mPackages[i] = label.toString();
                 }
-                if (ai.icon != 0) {
-                    icon = ai.loadIcon(pm);
-                }
+                //if (ai.icon != 0) {
+                //    icon = ai.loadIcon(pm);
+                //}
                 ViewGroup item = (ViewGroup) inflater.inflate(R.layout.power_usage_package_item,
                         null);
                 packagesParent.addView(item);
diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
index 10ab2d0..5678160 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
@@ -48,6 +48,9 @@
 import com.android.settings.R;
 import com.android.settings.fuelgauge.PowerUsageDetail.DrainType;
 
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.Writer;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -78,6 +81,7 @@
     private static final int MIN_POWER_THRESHOLD = 5;
     private static final int MAX_ITEMS_TO_LIST = 10;
 
+    private long mStatsPeriod = 0;
     private double mMaxPower = 1;
     private double mTotalPower;
     private PowerProfile mPowerProfile;
@@ -132,6 +136,7 @@
                 Math.ceil(sipper.getSortValue() * 100 / mTotalPower));
         intent.putExtra(PowerUsageDetail.EXTRA_GAUGE, (int)
                 Math.ceil(sipper.getSortValue() * 100 / mMaxPower));
+        intent.putExtra(PowerUsageDetail.EXTRA_USAGE_DURATION, mStatsPeriod);
         intent.putExtra(PowerUsageDetail.EXTRA_ICON_PACKAGE, sipper.defaultPackageName);
         intent.putExtra(PowerUsageDetail.EXTRA_ICON_ID, sipper.iconId);
         intent.putExtra(PowerUsageDetail.EXTRA_NO_COVERAGE, sipper.noCoveragePercent);
@@ -165,6 +170,15 @@
                     0
                 };
 
+                Writer result = new StringWriter();
+                PrintWriter printWriter = new PrintWriter(result);
+                mStats.dumpLocked(printWriter, "", mStatsType, uid.getUid());
+                intent.putExtra(PowerUsageDetail.EXTRA_REPORT_DETAILS, result.toString());
+                
+                result = new StringWriter();
+                printWriter = new PrintWriter(result);
+                mStats.dumpCheckinLocked(printWriter, mStatsType, uid.getUid());
+                intent.putExtra(PowerUsageDetail.EXTRA_REPORT_CHECKIN_DETAILS, result.toString());
             }
             break;
             case CELL:
@@ -303,6 +317,7 @@
         }
         final double averageCostPerByte = getAverageDataCost();
         long uSecTime = mStats.computeBatteryRealtime(SystemClock.elapsedRealtime() * 1000, which);
+        mStatsPeriod = uSecTime;
         updateStatsPeriod(uSecTime);
         SparseArray<? extends Uid> uidStats = mStats.getUidStats();
         final int NU = uidStats.size();