OSDN Git Service

Implement issue #3094621 and #3094609 - wipe sd card
authorDianne Hackborn <hackbod@google.com>
Thu, 14 Oct 2010 18:58:30 +0000 (11:58 -0700)
committerDianne Hackborn <hackbod@google.com>
Sat, 16 Oct 2010 23:27:25 +0000 (16:27 -0700)
3094621: add "wipe sd card" option to factory data reset
3094609: collapse unmount/format into one command

Implements requested UI changes.  Also some final tweaks to
Manage Applications.

Change-Id: I0219195dd0c74d8c003ef1c3f6e09714859d7f89

13 files changed:
res/layout/manage_applications.xml
res/layout/master_clear_primary.xml
res/layout/running_processes_view.xml
res/values/strings.xml
res/xml/device_info_memory.xml
src/com/android/settings/MasterClear.java
src/com/android/settings/MediaFormat.java
src/com/android/settings/applications/LinearColorBar.java [new file with mode: 0644]
src/com/android/settings/applications/ManageApplications.java
src/com/android/settings/applications/RunningProcessesView.java
src/com/android/settings/applications/RunningServiceDetails.java
src/com/android/settings/applications/RunningState.java
src/com/android/settings/deviceinfo/Memory.java

index 2716460..078322a 100755 (executable)
     android:layout_width="match_parent"
     android:layout_height="match_parent" >
 
-    <FrameLayout android:id="@+id/list_container"
+    <LinearLayout android:id="@+id/list_container"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
+            android:orientation="vertical"
             android:visibility="gone">
-        <ListView android:id="@android:id/list"
-            android:drawSelectorOnTop="false"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent" />
-        <TextView android:id="@android:id/empty"
+        <FrameLayout android:layout_width="match_parent"
+                android:layout_height="0px"
+                android:layout_weight="1">
+            <ListView android:id="@android:id/list"
+                android:drawSelectorOnTop="false"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent" />
+            <TextView android:id="@android:id/empty"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:gravity="center"
+                    android:text="@string/no_applications"
+                    android:textAppearance="?android:attr/textAppearanceLarge" />
+        </FrameLayout>
+        <view class="com.android.settings.applications.LinearColorBar"
+                android:id="@+id/storage_color_bar"
                 android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:gravity="center"
-                android:text="@string/no_applications"
-                android:textAppearance="?android:attr/textAppearanceLarge" />
-    </FrameLayout>
+                android:layout_height="wrap_content"
+                android:layout_marginTop="-5dp"
+                android:orientation="horizontal"
+                android:paddingTop="30dp"
+                android:paddingLeft="2dp"
+                android:paddingRight="2dp"
+                android:paddingBottom="1dp">
+            <TextView android:id="@+id/usedStorageText"
+                android:layout_width="0px"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:textAppearance="?android:attr/textAppearanceSmallInverse"
+                android:textColor="#000"
+                android:singleLine="true" />
+            <TextView android:id="@+id/storageChartLabel"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_weight="0"
+                android:textAppearance="?android:attr/textAppearanceSmallInverse"
+                android:textColor="#000"
+                android:textStyle="bold"
+                android:singleLine="true"
+                android:text="@string/internal_storage" />
+            <TextView android:id="@+id/freeStorageText"
+                android:layout_gravity="center_vertical|right"
+                android:layout_width="0px"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:gravity="right"
+                android:textAppearance="?android:attr/textAppearanceSmallInverse"
+                android:textColor="#000"
+                android:singleLine="true" />
+        </view>
+    </LinearLayout>
 
     <view class="com.android.settings.applications.RunningProcessesView"
             android:id="@+id/running_processes"
index 2c4156b..dd25900 100644 (file)
             android:layout_width="fill_parent"
             android:layout_height="0dip"
             android:layout_weight="1">
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:textSize="18sp"
-            android:text="@string/master_clear_desc" />
+        <LinearLayout android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical">
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:textSize="18sp"
+                android:text="@string/master_clear_desc" />
+            <LinearLayout android:id="@+id/erase_external_container"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    android:focusable="true"
+                    android:clickable="true">
+                <CheckBox android:id="@+id/erase_external"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:layout_gravity="top"
+                        android:paddingRight="8dp"
+                        android:focusable="false"
+                        android:clickable="false"
+                        android:duplicateParentState="true" />
+                <LinearLayout android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:orientation="vertical">
+                    <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:paddingTop="12dp"
+                        android:textSize="18sp"
+                        android:text="@string/erase_external_storage" />
+                    <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:paddingTop="4sp"
+                        android:textSize="14sp"
+                        android:text="@string/erase_external_storage_description" />
+                </LinearLayout>
+            </LinearLayout>
+        </LinearLayout>
     </ScrollView>
     <Button
             android:id="@+id/initiate_master_clear"
index 6810ba0..9f01eda 100644 (file)
                 android:text="@string/no_running_services"
                 android:textAppearance="?android:attr/textAppearanceLarge" />
     </FrameLayout>
-    <view class="com.android.settings.applications.RunningProcessesView$LinearColorBar"
+    <view class="com.android.settings.applications.LinearColorBar"
             android:id="@+id/color_bar"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
+            android:layout_marginTop="-5dp"
             android:orientation="horizontal"
-            android:padding="4dp">
+            android:paddingTop="30dp"
+            android:paddingLeft="2dp"
+            android:paddingRight="2dp"
+            android:paddingBottom="1dp">
         <TextView android:id="@+id/foregroundText"
-            android:layout_width="wrap_content"
+            android:layout_width="0px"
             android:layout_height="wrap_content"
             android:layout_weight="1"
+            android:focusable="true"
+            android:gravity="left|bottom"
             android:textAppearance="?android:attr/textAppearanceSmallInverse"
-            android:color="?android:attr/textColorPrimaryInverse"
+            android:textColor="#000"
             android:singleLine="true" />
-        <TextView android:id="@+id/backgroundText"
-            android:layout_gravity="center_vertical|right"
+        <TextView
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_weight="0"
             android:textAppearance="?android:attr/textAppearanceSmallInverse"
-            android:color="?android:attr/textColorPrimaryInverse"
+            android:textColor="#000"
+            android:textStyle="bold"
+            android:singleLine="true"
+            android:text="@string/memory" />
+        <TextView android:id="@+id/backgroundText"
+            android:layout_gravity="center_vertical|right"
+            android:layout_width="0px"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:focusable="true"
+            android:gravity="right|bottom"
+            android:textAppearance="?android:attr/textAppearanceSmallInverse"
+            android:textColor="#000"
             android:singleLine="true" />
     </view>
 </LinearLayout>
index e099bbb..b28fe46 100755 (executable)
     <!-- SD card & phone storage settings screen heading.  The total amount of storage space for some storage partition.  For example, this is listed under both the "Internal phone storage" section and the "SD card" section -->
     <string name="memory_size">Total space</string>
     <!-- SD card & phone storage settings item title that will result in the phone unmounting the SD card.  This will be done before the user phyiscally removes the SD card from the phone.  Kind of like the "Safely remove" on some operating systems.   [CHAR LIMIT=25] -->
-    <string name="sd_eject" product="default">Unmount</string>
+    <string name="sd_eject" product="default">Unmount SD card</string>
     <!-- SD card & phone storage settings item title that will result in the phone unmounting the SD card.  This will be done before the user phyiscally removes the SD card from the phone.  Kind of like the "Safely remove" on some operating systems.   [CHAR LIMIT=30] -->
     <string name="sd_eject_summary" product="nosdcard">Unmount the internal USB storage so you can format it</string>
     <!-- SD card & phone storage settings item title that will result in the phone unmounting the SD card.  This will be done before the user phyiscally removes the SD card from the phone.  Kind of like the "Safely remove" on some operating systems.   -->
     <!-- SD card & phone storage settings item summary that is displayed when no SD card is inserted -->
     <string name="sd_insert_summary" product="default">Insert an SD card for mounting</string>
     <!-- SD card & phone storage settings item title that will result in the phone mounting the SD card. [CHAR LIMIT=25] -->
-    <string name="sd_mount">Mount</string>
-    <!-- SD card & phone storage settings item title that will result in the phone mounting the SD card. [CHAR LIMIT=30] -->
-    <string name="sd_mount_summary" product="nosdcard">Mount the internal USB storage</string>
+    <string name="sd_mount">Mount SD card</string>
     <!-- SD card & phone storage settings item title that will result in the phone mounting the SD card. -->
-    <string name="sd_mount_summary" product="default">Mount the SD card</string>
+    <string name="sd_mount_summary">Mount the SD card</string>
+    <!-- SD card & phone storage settings item title that will result in the phone formatting the USB storage.   [CHAR LIMIT=25] -->
+    <string name="sd_format" product="nosdcard">Erase USB storage</string>
     <!-- SD card & phone storage settings item title that will result in the phone formatting the SD card.   [CHAR LIMIT=25] -->
-    <string name="sd_format">Format</string>
+    <string name="sd_format" product="default">Erase SD card</string>
     <!-- SD card & phone storage settings item title that will result in the phone unmounting the SD card.   [CHAR LIMIT=30] -->
-    <string name="sd_format_summary" product="nosdcard">Format (erase) the internal USB storage</string>
+    <string name="sd_format_summary" product="nosdcard">Erases all data on the phone\'s internal USB storage, such such as music and photos.</string>
     <!-- SD card & phone storage settings item title that will result in the phone unmounting the SD card.   -->
-    <string name="sd_format_summary" product="default">Format (erase) the SD card</string>
+    <string name="sd_format_summary" product="default">Erases all data on the phone\'s SD card, such as music and photos.</string>
     <!-- SD card status when it is not available status -->
     <string name="sd_unavailable">Unavailable</string>
     <!-- SD card status when it is mounted as read only  -->
     <!-- SD card & phone storage settings screen, setting option summary text under Internal phone storage heading -->
     <string name="master_clear_summary">Erases all data on phone</string>
     <!-- SD card & phone storage settings screen, message on screen after user selects Factory data reset [CHAR LIMIT=NONE] -->
-    <string name="master_clear_desc" product="nosdcard">"This will erase all data from your phone, including:\n<li>Your Google account</li>\n<li>System and application data and settings</li>\n<li>Downloaded applications</li>\nIt will not erase:\n<li>Current system software and bundled applications</li>\n<li>Files in USB storage, such as music or photos: use the Storage settings to format (erase) USB storage</li>"</string>
+    <string name="master_clear_desc" product="nosdcard">"This will erase all data from your phone\'s <b>internal storage</b>, including:\n\n<li>Your Google account</li>\n<li>System and application data and settings</li>\n<li>Downloaded applications</li>\n\nTo clear all data on this phone the <b>USB storage</b> needs to be erased.\n\n"</string>
     <!-- SD card & phone storage settings screen, message on screen after user selects Factory data reset -->
-    <string name="master_clear_desc" product="default">"This will erase all data from your phone, including:\n<li>Your Google account</li>\n<li>System and application data and settings</li>\n<li>Downloaded applications</li>\nIt will not erase:\n<li>Current system software and bundled applications</li>\n<li>SD card files, such as music or photos: use the Storage settings to format (erase) the SD card</li>"</string>
+    <string name="master_clear_desc" product="default" >"This will erase all data from your phone\'s <b>internal storage</b>, including:\n\n<li>Your Google account</li>\n<li>System and application data and settings</li>\n<li>Downloaded applications</li>\n\nTo also clear music, pictures, and other user data, the <b>SD card</b> needs to be erased.\n\n"</string>
+    <!-- SD card & phone storage settings screen, label for check box to erase USB storage [CHAR LIMIT=30] -->
+    <string name="erase_external_storage" product="nosdcard">Erase USB storage</string>
+    <!-- SD card & phone storage settings screen, label for check box to erase SD card [CHAR LIMIT=30] -->
+    <string name="erase_external_storage" product="default">Erase SD card</string>
+    <!-- SD card & phone storage settings screen, description for check box to erase USB storage [CHAR LIMIT=30] -->
+    <string name="erase_external_storage_description" product="nosdcard">Erase all the data on the phone\'s internal USB storage, such as music or photos.</string>
+    <!-- SD card & phone storage settings screen, description for check box to erase USB storage [CHAR LIMIT=30] -->
+    <string name="erase_external_storage_description" product="default">Erase all the data on the phone\'s SD card, such as music or photos.</string>
     <!-- SD card & phone storage settings screen, button on screen after user selects Factory data reset -->
     <string name="master_clear_button_text">Reset phone</string>
     <!-- SD card & phone storage settings screen, message on screen after user selects Reset phone button -->
 
     <!-- Media Format -->
     <!-- SD card & phone storage settings screen, setting option name under Internal phone storage heading [CHAR LIMIT=25] -->
-    <string name="media_format_title" product="nosdcard">Format USB storage</string>
+    <string name="media_format_title" product="nosdcard">Erase USB storage</string>
     <!-- SD card & phone storage settings screen, setting option name under Internal phone storage heading -->
-    <string name="media_format_title" product="default">Format SD card</string>
+    <string name="media_format_title" product="default">Erase SD card</string>
     <!-- SD card & phone storage settings screen, setting option summary text under Internal phone storage heading [CHAR LIMIT=30] -->
     <string name="media_format_summary" product="nosdcard">Erases all data in USB storage</string>
     <!-- SD card & phone storage settings screen, setting option summary text under Internal phone storage heading -->
     <string name="media_format_summary" product="default">Erases all data on the SD card</string>
     <!-- SD card & phone storage settings screen, message on screen after user selects Factory data reset [CHAR LIMIT=NONE] -->
-    <string name="media_format_desc" product="nosdcard">This action will erase the USB storage. You will lose ALL data in USB storage!</string>
+    <string name="media_format_desc" product="nosdcard">This action will erase the USB storage. You will lose <b>all</b> data stored there!</string>
     <!-- SD card & phone storage settings screen, message on screen after user selects Factory data reset [CHAR LIMIT=NONE] -->
-    <string name="media_format_desc" product="default">This action will erase the SD card. You will lose ALL data on the card!</string>
+    <string name="media_format_desc" product="default">This action will erase the SD card. You will lose <b>all</b> data on the card!</string>
     <!-- SD card & phone storage settings screen, button on screen after user selects Factory data reset [CHAR LIMIT=25] -->
-    <string name="media_format_button_text" product="nosdcard">Format USB storage</string>
+    <string name="media_format_button_text" product="nosdcard">Erase USB storage</string>
     <!-- SD card & phone storage settings screen, button on screen after user selects Factory data reset -->
-    <string name="media_format_button_text" product="default">Format SD card</string>
+    <string name="media_format_button_text" product="default">Erase SD card</string>
     <!-- SD card & phone storage settings screen, message on screen after user selects Format media button [CHAR LIMIT=NONE] -->
     <string name="media_format_final_desc" product="nosdcard">Format USB storage, erasing all files stored there? Action cannot be reversed!</string>
     <!-- SD card & phone storage settings screen, message on screen after user selects Format media button [CHAR LIMIT=NONE] -->
     <string name="sort_order_alpha">Sort by name</string>
     <!-- Manage applications screen, menu item. Sorts all of the apps in the list based on their file size.  This is used to uninstall when space is getting low. -->
     <string name="sort_order_size">Sort by size</string>
+    <!-- [CHAR LIMIT=25] Manage applications screen, menu item.  Show running services. -->
+    <string name="show_running_services">Show running services</string>
+    <!-- [CHAR LIMIT=25] Manage applications screen, menu item.  Show background cached processes. -->
+    <string name="show_background_processes">Show cached processes</string>
     <!-- Manage applications screen, individual app screen, button label when the user wants to manage the space taken up by an app. -->
     <string name="manage_space_text">Manage space</string>
     <!-- Text for menu option in ManageApps screen to present various menu options -->
     <string name="disabled">Disabled</string>
     <!-- [CHAR LIMIT=25] Text shown when there are no applications to display. -->
     <string name="no_applications">No applications.</string>
+    <!-- [CHAR LIMIT=15] Manage applications, label for chart showing internal storage use. -->
+    <string name="internal_storage">Internal storage</string>
+    <!-- [CHAR LIMIT=15] Manage applications, label for chart showing SD card storage use. -->
+    <string name="sd_card_storage" product="nosdcard">USB storage</string>
+    <!-- [CHAR LIMIT=15] Manage applications, label for chart showing SD card storage use. -->
+    <string name="sd_card_storage" product="default">SD card storage</string>
     <!-- Manage app screen, shown when the activity is busy recomputing the size of each app -->
     <string name="recompute_size">Recomputing size\u2026</string>
     <!-- Manage applications, individual application screen, confirmation dialog title. Displays when user selects to "Clear data". -->
@@ -1831,16 +1849,20 @@ found in the list of installed applications.</string>
     <string name="runningservices_settings_summary">View and control currently running services</string>
     <!-- Label for a service item when it is restarting -->
     <string name="service_restarting">Restarting</string>
+    <!-- Label for a process item representing a background process -->
+    <string name="cached">Cached background process</string>
     <!-- [CHAR LIMIT=25] Text shown when there are no services running -->
     <string name="no_running_services">Nothing running.</string>
     <!-- Running services, description for a service in the started state -->
     <string name="service_started_by_app">Started by application.</string>
     <!-- Running services, description for a service in the started state -->
     <string name="service_client_name"><xliff:g id="client_name">%1$s</xliff:g></string>
-    <!-- Running services, summary of background processes -->
-    <string name="service_background_processes"><xliff:g id="memory">%1$s</xliff:g> available</string>
-    <!-- Running services, summary of foreground processes -->
-    <string name="service_foreground_processes"><xliff:g id="memory">%1$s</xliff:g> in use</string>
+    <!-- [CHAR LIMIT=10] Running services, summary of background processes -->
+    <string name="service_background_processes"><xliff:g id="memory">%1$s</xliff:g> free</string>
+    <!-- [CHAR LIMIT=10] Running services, summary of foreground processes -->
+    <string name="service_foreground_processes"><xliff:g id="memory">%1$s</xliff:g> used</string>
+    <!-- [CHAR LIMIT=10] Running services, label for chart showing memory use. -->
+    <string name="memory">RAM</string>
     <!-- Text to label a process entry with the process name. -->
     <string name="service_process_name"><xliff:g id="process">%1$s</xliff:g></string>
     <!-- Descriptive text of a running process: singular process, singular service. -->
@@ -1874,6 +1896,10 @@ found in the list of installed applications.</string>
     <!-- Running service details, description for running heavy-weight process. -->
     <string name="heavy_weight_stop_description">This application can not safely
         be stopped.  Doing so may lose some of your current work.</string>
+    <!-- Running service details, description for background process. -->
+    <string name="background_process_stop_description">This is an old application
+        process that is being kept for better speed in case it is needed again.
+        There is usually no reason to stop it.</string>
     <!-- Running service details, default description for services that are managed. -->
     <string name="service_manage_description"><xliff:g id="client_name">%1$s</xliff:g>:
         currently in use.  Touch Settings to control it.</string>
index 785fded..fd0bf4e 100644 (file)
@@ -16,7 +16,8 @@
 
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <PreferenceCategory android:title="@string/sd_memory">
+    <PreferenceCategory android:key="memory_sd"
+            android:title="@string/sd_memory">
         <Preference android:key="memory_sd_size" 
             style="?android:attr/preferenceInformationStyle" 
             android:title="@string/memory_size"
index 4de0e44..e653d90 100644 (file)
 
 package com.android.settings;
 
+import com.android.internal.os.storage.ExternalStorageFormatter;
 import com.android.internal.widget.LockPatternUtils;
 
 import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
-import android.os.ServiceManager;
-import android.os.SystemProperties;
-import android.text.TextUtils;
-import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.Button;
+import android.widget.CheckBox;
 
 /**
  * Confirm and execute a reset of the device to a clean "just out of the box"
@@ -48,6 +44,8 @@ public class MasterClear extends Activity {
 
     private View mInitialView;
     private Button mInitiateButton;
+    private View mExternalStorageContainer;
+    private CheckBox mExternalStorage;
 
     private View mFinalView;
     private Button mFinalButton;
@@ -63,8 +61,14 @@ public class MasterClear extends Activity {
                     return;
                 }
 
-                sendBroadcast(new Intent("android.intent.action.MASTER_CLEAR"));
-                // Intent handling is asynchronous -- assume it will happen soon.
+                if (mExternalStorage.isChecked()) {
+                    Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
+                    intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
+                    startService(intent);
+                } else {
+                    sendBroadcast(new Intent("android.intent.action.MASTER_CLEAR"));
+                    // Intent handling is asynchronous -- assume it will happen soon.
+                }
             }
         };
 
@@ -145,6 +149,16 @@ public class MasterClear extends Activity {
             mInitiateButton =
                     (Button) mInitialView.findViewById(R.id.initiate_master_clear);
             mInitiateButton.setOnClickListener(mInitiateListener);
+            mExternalStorageContainer =
+                mInitialView.findViewById(R.id.erase_external_container);
+            mExternalStorage =
+                    (CheckBox) mInitialView.findViewById(R.id.erase_external);
+            mExternalStorageContainer.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    mExternalStorage.toggle();
+                }
+            });
         }
 
         setContentView(mInitialView);
@@ -170,7 +184,8 @@ public class MasterClear extends Activity {
     public void onPause() {
         super.onPause();
 
-        establishInitialState();
+        if (!isFinishing()) {
+            establishInitialState();
+        }
     }
-
 }
index b78ff62..d8d57e4 100644 (file)
 
 package com.android.settings;
 
-import com.android.internal.widget.LockPatternUtils;
-
 import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
-import android.os.storage.IMountService;
-import android.os.ServiceManager;
-import android.os.SystemProperties;
-import android.os.Environment;
-import android.text.TextUtils;
-import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.Button;
 
+import com.android.internal.os.storage.ExternalStorageFormatter;
+
 /**
  * Confirm and execute a format of the sdcard.
  * Multiple confirmations are required: first, a general "are you sure
@@ -46,7 +38,6 @@ public class MediaFormat extends Activity {
     private static final int KEYGUARD_REQUEST = 55;
 
     private LayoutInflater mInflater;
-    private LockPatternUtils mLockUtils;
 
     private View mInitialView;
     private Button mInitiateButton;
@@ -64,23 +55,10 @@ public class MediaFormat extends Activity {
                 if (Utils.isMonkeyRunning()) {
                     return;
                 }
-                final IMountService service =
-                        IMountService.Stub.asInterface(ServiceManager.getService("mount"));
-                if (service != null) {
-                    new Thread() {
-                        public void run() {
-                            try {
-                                service.formatVolume(Environment.getExternalStorageDirectory().toString());
-                            } catch (Exception e) {
-                                // Intentionally blank - there's nothing we can do here
-                                Log.w("MediaFormat", "Unable to invoke IMountService.formatMedia()");
-                            }
-                        }
-                    }.start();
-                } else {
-                    Log.w("MediaFormat", "Unable to locate IMountService");
-                }
-            finish();
+                Intent intent = new Intent(ExternalStorageFormatter.FORMAT_ONLY);
+                intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
+                startService(intent);
+                finish();
             }
         };
 
@@ -171,7 +149,6 @@ public class MediaFormat extends Activity {
         mInitialView = null;
         mFinalView = null;
         mInflater = LayoutInflater.from(this);
-        mLockUtils = new LockPatternUtils(this);
 
         establishInitialState();
     }
@@ -184,7 +161,8 @@ public class MediaFormat extends Activity {
     public void onPause() {
         super.onPause();
 
-        establishInitialState();
+        if (!isFinishing()) {
+            establishInitialState();
+        }
     }
-
 }
diff --git a/src/com/android/settings/applications/LinearColorBar.java b/src/com/android/settings/applications/LinearColorBar.java
new file mode 100644 (file)
index 0000000..74164c4
--- /dev/null
@@ -0,0 +1,163 @@
+/**
+ *
+ */
+package com.android.settings.applications;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.LinearGradient;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.Rect;
+import android.graphics.Shader;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.widget.LinearLayout;
+
+public class LinearColorBar extends LinearLayout {
+    static final int LEFT_COLOR = 0xffa0a0a0;
+    static final int MIDDLE_COLOR = 0xff7070ff;
+    static final int RIGHT_COLOR = 0xffa0c0a0;
+
+    private float mRedRatio;
+    private float mYellowRatio;
+    private float mGreenRatio;
+
+    private boolean mShowingGreen;
+
+    final Rect mRect = new Rect();
+    final Paint mPaint = new Paint();
+
+    int mLastInterestingLeft, mLastInterestingRight;
+    int mLineWidth;
+
+    final Path mColorPath = new Path();
+    final Path mEdgePath = new Path();
+    final Paint mColorGradientPaint = new Paint();
+    final Paint mEdgeGradientPaint = new Paint();
+
+    public LinearColorBar(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setWillNotDraw(false);
+        mPaint.setStyle(Paint.Style.FILL);
+        mColorGradientPaint.setStyle(Paint.Style.FILL);
+        mColorGradientPaint.setAntiAlias(true);
+        mEdgeGradientPaint.setStyle(Paint.Style.STROKE);
+        mLineWidth = getResources().getDisplayMetrics().densityDpi >= DisplayMetrics.DENSITY_HIGH
+                ? 2 : 1;
+        mEdgeGradientPaint.setStrokeWidth(mLineWidth);
+        mEdgeGradientPaint.setAntiAlias(true);
+    }
+
+    public void setRatios(float red, float yellow, float green) {
+        mRedRatio = red;
+        mYellowRatio = yellow;
+        mGreenRatio = green;
+        invalidate();
+    }
+
+    public void setShowingGreen(boolean showingGreen) {
+        if (mShowingGreen != showingGreen) {
+            mShowingGreen = showingGreen;
+            updateIndicator();
+            invalidate();
+        }
+    }
+
+    private void updateIndicator() {
+        int off = getPaddingTop() - getPaddingBottom();
+        if (off < 0) off = 0;
+        mRect.top = off;
+        mRect.bottom = getHeight();
+        if (mShowingGreen) {
+            mColorGradientPaint.setShader(new LinearGradient(
+                    0, 0, 0, off-2, RIGHT_COLOR&0xffffff, RIGHT_COLOR, Shader.TileMode.CLAMP));
+        } else {
+            mColorGradientPaint.setShader(new LinearGradient(
+                    0, 0, 0, off-2, MIDDLE_COLOR&0xffffff, MIDDLE_COLOR, Shader.TileMode.CLAMP));
+        }
+        mEdgeGradientPaint.setShader(new LinearGradient(
+                0, 0, 0, off/2, 0x00a0a0a0, 0xffa0a0a0, Shader.TileMode.CLAMP));
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+        updateIndicator();
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+
+        int width = getWidth();
+
+        int left = 0;
+
+        int right = left + (int)(width*mRedRatio);
+        int right2 = right + (int)(width*mYellowRatio);
+        int right3 = right2 + (int)(width*mGreenRatio);
+
+        int indicatorLeft, indicatorRight;
+        if (mShowingGreen) {
+            indicatorLeft = right2;
+            indicatorRight = right3;
+        } else {
+            indicatorLeft = right;
+            indicatorRight = right2;
+        }
+
+        if (mLastInterestingLeft != indicatorLeft || mLastInterestingRight != indicatorRight) {
+            mColorPath.reset();
+            mEdgePath.reset();
+            if (indicatorLeft < indicatorRight) {
+                mColorPath.moveTo(indicatorLeft, mRect.top);
+                mColorPath.lineTo(-1, 0);
+                mColorPath.lineTo(width, 0);
+                mColorPath.lineTo(indicatorRight, mRect.top);
+                mColorPath.close();
+                float lineOffset = mLineWidth+.5f;
+                mEdgePath.moveTo(indicatorLeft+lineOffset, mRect.top);
+                mEdgePath.lineTo(-1+lineOffset, 0);
+                mEdgePath.moveTo(indicatorRight-lineOffset, mRect.top);
+                mEdgePath.lineTo(width-lineOffset, 0);
+            }
+            mLastInterestingLeft = indicatorLeft;
+            mLastInterestingRight = indicatorRight;
+        }
+
+        if (!mColorPath.isEmpty()) {
+            canvas.drawPath(mEdgePath, mEdgeGradientPaint);
+            canvas.drawPath(mColorPath, mColorGradientPaint);
+        }
+
+        if (left < right) {
+            mRect.left = left;
+            mRect.right = right;
+            mPaint.setColor(LEFT_COLOR);
+            canvas.drawRect(mRect, mPaint);
+            width -= (right-left);
+            left = right;
+        }
+
+        right = right2;
+
+        if (left < right) {
+            mRect.left = left;
+            mRect.right = right;
+            mPaint.setColor(MIDDLE_COLOR);
+            canvas.drawRect(mRect, mPaint);
+            width -= (right-left);
+            left = right;
+        }
+
+
+        right = left + width;
+        if (left < right) {
+            mRect.left = left;
+            mRect.right = right;
+            mPaint.setColor(RIGHT_COLOR);
+            canvas.drawRect(mRect, mPaint);
+        }
+    }
+}
\ No newline at end of file
index 1053d3b..b4cd26e 100644 (file)
@@ -29,9 +29,12 @@ import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Environment;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.StatFs;
 import android.provider.Settings;
+import android.text.format.Formatter;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.Menu;
@@ -126,6 +129,8 @@ public class ManageApplications extends TabActivity implements
 
     public static final int SORT_ORDER_ALPHA = MENU_OPTIONS_BASE + 4;
     public static final int SORT_ORDER_SIZE = MENU_OPTIONS_BASE + 5;
+    public static final int SHOW_RUNNING_SERVICES = MENU_OPTIONS_BASE + 6;
+    public static final int SHOW_BACKGROUND_PROCESSES = MENU_OPTIONS_BASE + 7;
     // sort order
     private int mSortOrder = SORT_ORDER_ALPHA;
     // Filter value
@@ -152,6 +157,11 @@ public class ManageApplications extends TabActivity implements
     // Custom view used to display running processes
     private RunningProcessesView mRunningProcessesView;
     
+    LinearColorBar mColorBar;
+    TextView mStorageChartLabel;
+    TextView mUsedStorageText;
+    TextView mFreeStorageText;
+
     // These are for keeping track of activity and tab switch state.
     private int mCurView;
     private boolean mCreatedRunning;
@@ -160,6 +170,11 @@ public class ManageApplications extends TabActivity implements
     private boolean mActivityResumed;
     private Object mNonConfigInstance;
     
+    private StatFs mDataFileStats;
+    private StatFs mSDCardFileStats;
+    private boolean mLastShowedInternalStorage = true;
+    private long mLastUsedStorage, mLastAppStorage, mLastFreeStorage;
+
     final Runnable mRunningProcessesAvail = new Runnable() {
         public void run() {
             handleRunningProcessesAvail();
@@ -222,6 +237,7 @@ public class ManageApplications extends TabActivity implements
                 mCurFilterPrefix = constraint;
                 mEntries = (ArrayList<ApplicationsState.AppEntry>)results.values;
                 notifyDataSetChanged();
+                updateStorageUsage();
             }
         };
 
@@ -294,6 +310,7 @@ public class ManageApplications extends TabActivity implements
                 mEntries = null;
             }
             notifyDataSetChanged();
+            updateStorageUsage();
 
             if (entries == null) {
                 mWaitingForData = true;
@@ -338,6 +355,7 @@ public class ManageApplications extends TabActivity implements
             mBaseEntries = apps;
             mEntries = applyPrefixFilter(mCurFilterPrefix, mBaseEntries);
             notifyDataSetChanged();
+            updateStorageUsage();
         }
 
         @Override
@@ -367,6 +385,7 @@ public class ManageApplications extends TabActivity implements
                         // the list with the new size to reflect it to the user.
                         rebuild(false);
                     }
+                    updateStorageUsage();
                     return;
                 }
             }
@@ -502,6 +521,9 @@ public class ManageApplications extends TabActivity implements
         
         mNonConfigInstance = getLastNonConfigurationInstance();
         
+        mDataFileStats = new StatFs("/data");
+        mSDCardFileStats = new StatFs(Environment.getExternalStorageDirectory().toString());
+
         // initialize some window features
         requestWindowFeature(Window.FEATURE_RIGHT_ICON);
         requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
@@ -526,6 +548,10 @@ public class ManageApplications extends TabActivity implements
         mListView = lv;
         lv.setRecyclerListener(mApplicationsAdapter);
         mListView.setAdapter(mApplicationsAdapter);
+        mColorBar = (LinearColorBar)mListContainer.findViewById(R.id.storage_color_bar);
+        mStorageChartLabel = (TextView)mListContainer.findViewById(R.id.storageChartLabel);
+        mUsedStorageText = (TextView)mListContainer.findViewById(R.id.usedStorageText);
+        mFreeStorageText = (TextView)mListContainer.findViewById(R.id.freeStorageText);
         mRunningProcessesView = (RunningProcessesView)mRootView.findViewById(
                 R.id.running_processes);
 
@@ -609,6 +635,8 @@ public class ManageApplications extends TabActivity implements
                 .setIcon(android.R.drawable.ic_menu_sort_alphabetically);
         menu.add(0, SORT_ORDER_SIZE, 2, R.string.sort_order_size)
                 .setIcon(android.R.drawable.ic_menu_sort_by_size); 
+        menu.add(0, SHOW_RUNNING_SERVICES, 3, R.string.show_running_services);
+        menu.add(0, SHOW_BACKGROUND_PROCESSES, 3, R.string.show_background_processes);
         return true;
     }
     
@@ -619,11 +647,17 @@ public class ManageApplications extends TabActivity implements
          * so bringing up this menu in that case doesn't make any sense.
          */
         if (mCurView == VIEW_RUNNING) {
-            return false;
+            boolean showingBackground = mRunningProcessesView.mAdapter.getShowBackground();
+            menu.findItem(SORT_ORDER_ALPHA).setVisible(false);
+            menu.findItem(SORT_ORDER_SIZE).setVisible(false);
+            menu.findItem(SHOW_RUNNING_SERVICES).setVisible(showingBackground);
+            menu.findItem(SHOW_BACKGROUND_PROCESSES).setVisible(!showingBackground);
+        } else {
+            menu.findItem(SORT_ORDER_ALPHA).setVisible(mSortOrder != SORT_ORDER_ALPHA);
+            menu.findItem(SORT_ORDER_SIZE).setVisible(mSortOrder != SORT_ORDER_SIZE);
+            menu.findItem(SHOW_RUNNING_SERVICES).setVisible(false);
+            menu.findItem(SHOW_BACKGROUND_PROCESSES).setVisible(false);
         }
-
-        menu.findItem(SORT_ORDER_ALPHA).setVisible(mSortOrder != SORT_ORDER_ALPHA);
-        menu.findItem(SORT_ORDER_SIZE).setVisible(mSortOrder != SORT_ORDER_SIZE);
         return true;
     }
 
@@ -632,7 +666,13 @@ public class ManageApplications extends TabActivity implements
         int menuId = item.getItemId();
         if ((menuId == SORT_ORDER_ALPHA) || (menuId == SORT_ORDER_SIZE)) {
             mSortOrder = menuId;
-            mApplicationsAdapter.rebuild(mFilterApps, mSortOrder);
+            if (mCurView != VIEW_RUNNING) {
+                mApplicationsAdapter.rebuild(mFilterApps, mSortOrder);
+            }
+        } else if (menuId == SHOW_RUNNING_SERVICES) {
+            mRunningProcessesView.mAdapter.setShowBackground(false);
+        } else if (menuId == SHOW_BACKGROUND_PROCESSES) {
+            mRunningProcessesView.mAdapter.setShowBackground(true);
         }
         return true;
     }
@@ -657,6 +697,82 @@ public class ManageApplications extends TabActivity implements
     static final int VIEW_LIST = 1;
     static final int VIEW_RUNNING = 2;
 
+    void updateStorageUsage() {
+        if (mCurView == VIEW_RUNNING) {
+            return;
+        }
+
+        long freeStorage = 0;
+        long appStorage = 0;
+        long totalStorage = 0;
+        CharSequence newLabel = null;
+
+        if (mFilterApps == FILTER_APPS_SDCARD) {
+            if (mLastShowedInternalStorage) {
+                mLastShowedInternalStorage = false;
+            }
+            newLabel = this.getText(R.string.sd_card_storage);
+            mSDCardFileStats.restat(Environment.getExternalStorageDirectory().toString());
+            try {
+                totalStorage = (long)mSDCardFileStats.getBlockCount() *
+                        mSDCardFileStats.getBlockSize();
+                freeStorage = (long) mSDCardFileStats.getAvailableBlocks() *
+                mSDCardFileStats.getBlockSize();
+            } catch (IllegalArgumentException e) {
+                // use the old value of mFreeMem
+            }
+        } else {
+            if (!mLastShowedInternalStorage) {
+                mLastShowedInternalStorage = true;
+            }
+            newLabel = this.getText(R.string.internal_storage);
+            mDataFileStats.restat("/data");
+            try {
+                totalStorage = (long)mDataFileStats.getBlockCount() *
+                        mDataFileStats.getBlockSize();
+                freeStorage = (long) mDataFileStats.getAvailableBlocks() *
+                    mDataFileStats.getBlockSize();
+            } catch (IllegalArgumentException e) {
+            }
+            final int N = mApplicationsAdapter.getCount();
+            for (int i=0; i<N; i++) {
+                ApplicationsState.AppEntry ae = mApplicationsAdapter.getAppEntry(i);
+                appStorage += ae.codeSize + ae.dataSize;
+                freeStorage += ae.cacheSize;
+            }
+        }
+        if (newLabel != null) {
+            mStorageChartLabel.setText(newLabel);
+        }
+        if (totalStorage > 0) {
+            mColorBar.setRatios((totalStorage-freeStorage-appStorage)/(float)totalStorage,
+                    appStorage/(float)totalStorage, freeStorage/(float)totalStorage);
+            long usedStorage = totalStorage - freeStorage;
+            if (mLastUsedStorage != usedStorage) {
+                mLastUsedStorage = usedStorage;
+                String sizeStr = Formatter.formatShortFileSize(this, usedStorage);
+                mUsedStorageText.setText(getResources().getString(
+                        R.string.service_foreground_processes, sizeStr));
+            }
+            if (mLastFreeStorage != freeStorage) {
+                mLastFreeStorage = freeStorage;
+                String sizeStr = Formatter.formatShortFileSize(this, freeStorage);
+                mFreeStorageText.setText(getResources().getString(
+                        R.string.service_background_processes, sizeStr));
+            }
+        } else {
+            mColorBar.setRatios(0, 0, 0);
+            if (mLastUsedStorage != -1) {
+                mLastUsedStorage = -1;
+                mUsedStorageText.setText("");
+            }
+            if (mLastFreeStorage != -1) {
+                mLastFreeStorage = -1;
+                mFreeStorageText.setText("");
+            }
+        }
+    }
+
     private void selectView(int which) {
         if (which == VIEW_LIST) {
             if (mResumedRunning) {
@@ -724,6 +840,7 @@ public class ManageApplications extends TabActivity implements
         
         mFilterApps = newOption;
         selectView(VIEW_LIST);
+        updateStorageUsage();
     }
 
     public void onTabChanged(String tabId) {
index 1de67f7..86457bf 100644 (file)
@@ -22,9 +22,7 @@ import android.app.ActivityManager;
 import android.app.Dialog;
 import android.content.Context;
 import android.content.Intent;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
+import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.os.SystemProperties;
@@ -39,7 +37,6 @@ import android.widget.AdapterView;
 import android.widget.BaseAdapter;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
-import android.widget.LinearLayout;
 import android.widget.ListView;
 import android.widget.TextView;
 import android.widget.AbsListView.RecyclerListener;
@@ -71,6 +68,7 @@ public class RunningProcessesView extends FrameLayout
     RunningState.BaseItem mCurSelected;
     
     ListView mListView;
+    ServiceListAdapter mAdapter;
     LinearColorBar mColorBar;
     TextView mBackgroundProcessText;
     TextView mForegroundProcessText;
@@ -93,6 +91,7 @@ public class RunningProcessesView extends FrameLayout
         ActivityManager.RunningServiceInfo mService;
         ViewHolder mHolder;
         long mFirstRunTime;
+        boolean mSetBackground;
         
         void updateTime(Context context, StringBuilder builder) {
             TextView uptimeView = null;
@@ -109,14 +108,21 @@ public class RunningProcessesView extends FrameLayout
                     mHolder.size.setText(size);
                 }
                 
-                if (mItem instanceof RunningState.MergedItem) {
-                    // This item represents both services and proceses,
+                if (mItem.mBackground) {
+                    // This is a background process; no uptime.
+                    if (!mSetBackground) {
+                        mSetBackground = true;
+                        mHolder.uptime.setText("");
+                    }
+                } else if (mItem instanceof RunningState.MergedItem) {
+                    // This item represents both services and processes,
                     // so show the service uptime below.
                     uptimeView = mHolder.uptime;
                 }
             }
             
             if (uptimeView != null) {
+                mSetBackground = false;
                 if (mFirstRunTime >= 0) {
                     //Log.i("foo", "Time for " + mItem.mDisplayLabel
                     //        + ": " + (SystemClock.uptimeMillis()-mFirstRunTime));
@@ -159,16 +165,29 @@ public class RunningProcessesView extends FrameLayout
         public ActiveItem bind(RunningState state, RunningState.BaseItem item,
                 StringBuilder builder) {
             synchronized (state.mLock) {
+                PackageManager pm = rootView.getContext().getPackageManager();
+                if (item.mPackageInfo == null && item instanceof RunningState.MergedItem) {
+                    // Items for background processes don't normally load
+                    // their labels for performance reasons.  Do it now.
+                    ((RunningState.MergedItem)item).mProcess.ensureLabel(pm);
+                    item.mPackageInfo = ((RunningState.MergedItem)item).mProcess.mPackageInfo;
+                    item.mDisplayLabel = ((RunningState.MergedItem)item).mProcess.mDisplayLabel;
+                }
                 name.setText(item.mDisplayLabel);
                 ActiveItem ai = new ActiveItem();
                 ai.mRootView = rootView;
                 ai.mItem = item;
                 ai.mHolder = this;
                 ai.mFirstRunTime = item.mActiveSince;
-                description.setText(item.mDescription);
+                if (item.mBackground) {
+                    description.setText(rootView.getContext().getText(R.string.cached));
+                } else {
+                    description.setText(item.mDescription);
+                }
                 item.mCurSizeStr = null;
-                icon.setImageDrawable(item.mPackageInfo.loadIcon(
-                        rootView.getContext().getPackageManager()));
+                if (item.mPackageInfo != null) {
+                    icon.setImageDrawable(item.mPackageInfo.loadIcon(pm));
+                }
                 icon.setVisibility(View.VISIBLE);
                 ai.updateTime(rootView.getContext(), builder);
                 return ai;
@@ -185,6 +204,7 @@ public class RunningProcessesView extends FrameLayout
     class ServiceListAdapter extends BaseAdapter {
         final RunningState mState;
         final LayoutInflater mInflater;
+        boolean mShowBackground;
         ArrayList<RunningState.MergedItem> mItems;
         
         ServiceListAdapter(RunningState state) {
@@ -194,8 +214,24 @@ public class RunningProcessesView extends FrameLayout
             refreshItems();
         }
 
+        void setShowBackground(boolean showBackground) {
+            if (mShowBackground != showBackground) {
+                mShowBackground = showBackground;
+                mState.setWatchingBackgroundItems(showBackground);
+                refreshItems();
+                notifyDataSetChanged();
+                mColorBar.setShowingGreen(mShowBackground);
+            }
+        }
+
+        boolean getShowBackground() {
+            return mShowBackground;
+        }
+
         void refreshItems() {
-            ArrayList<RunningState.MergedItem> newItems = mState.getCurrentMergedItems();
+            ArrayList<RunningState.MergedItem> newItems =
+                mShowBackground ? mState.getCurrentBackgroundItems()
+                        : mState.getCurrentMergedItems();
             if (mItems != newItems) {
                 mItems = newItems;
             }
@@ -266,67 +302,6 @@ public class RunningProcessesView extends FrameLayout
         }
     }
     
-    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);
-            }
-        }
-    }
-    
     private boolean matchText(byte[] buffer, int index, String text) {
         int N = text.length();
         if ((index+N) >= buffer.length) {
@@ -434,7 +409,7 @@ public class RunningProcessesView extends FrameLayout
                     + mLastForegroundProcessMemory + mLastServiceProcessMemory;
             mColorBar.setRatios(mLastForegroundProcessMemory/totalMem,
                     mLastServiceProcessMemory/totalMem,
-                    (availMem+mLastBackgroundProcessMemory)/totalMem);
+                    mLastBackgroundProcessMemory/totalMem);
         }
     }
     
@@ -445,6 +420,7 @@ public class RunningProcessesView extends FrameLayout
         Intent intent = new Intent();
         intent.putExtra(RunningServiceDetails.KEY_UID, mi.mProcess.mUid);
         intent.putExtra(RunningServiceDetails.KEY_PROCESS, mi.mProcess.mProcessName);
+        intent.putExtra(RunningServiceDetails.KEY_BACKGROUND, mAdapter.mShowBackground);
         intent.setClass(getContext(), RunningServiceDetails.class);
         getContext().startActivity(intent);
     }
@@ -470,10 +446,23 @@ public class RunningProcessesView extends FrameLayout
         }
         mListView.setOnItemClickListener(this);
         mListView.setRecyclerListener(this);
-        mListView.setAdapter(new ServiceListAdapter(mState));
+        mAdapter = new ServiceListAdapter(mState);
+        mListView.setAdapter(mAdapter);
         mColorBar = (LinearColorBar)findViewById(R.id.color_bar);
         mBackgroundProcessText = (TextView)findViewById(R.id.backgroundText);
+        mBackgroundProcessText.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mAdapter.setShowBackground(true);
+            }
+        });
         mForegroundProcessText = (TextView)findViewById(R.id.foregroundText);
+        mForegroundProcessText.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mAdapter.setShowBackground(false);
+            }
+        });
         
         // Magic!  Implementation detail!  Don't count on this!
         SECONDARY_SERVER_MEM =
index 399c89f..aa89baf 100644 (file)
@@ -43,6 +43,7 @@ public class RunningServiceDetails extends Activity
     
     static final String KEY_UID = "uid";
     static final String KEY_PROCESS = "process";
+    static final String KEY_BACKGROUND = "background";
     
     static final int DIALOG_CONFIRM_STOP = 1;
     
@@ -54,6 +55,7 @@ public class RunningServiceDetails extends Activity
     
     int mUid;
     String mProcessName;
+    boolean mShowBackground;
     
     RunningState.MergedItem mMergedItem;
     
@@ -90,9 +92,14 @@ public class RunningServiceDetails extends Activity
                 }
             }
             stopService(new Intent().setComponent(si.mRunningService.service));
-            if (mMergedItem == null || mMergedItem.mServices.size() <= 1) {
+            if (mMergedItem == null) {
+                // If this is gone, we are gone.
+                mState.updateNow();
+                finish();
+            } else if (!mShowBackground && mMergedItem.mServices.size() <= 1) {
                 // If there was only one service, we are finishing it,
                 // so no reason for the UI to stick around.
+                mState.updateNow();
                 finish();
             } else {
                 mState.updateNow();
@@ -166,6 +173,10 @@ public class RunningServiceDetails extends Activity
                 }
             } else if (mServiceItem != null) {
                 stopActiveService(false);
+            } else if (mActiveItem.mItem.mBackground) {
+                // Background process.  Just kill it.
+                mAm.killBackgroundProcesses(mActiveItem.mItem.mPackageInfo.packageName);
+                finish();
             } else {
                 // Heavy-weight process.  We'll do a force-stop on it.
                 mAm.forceStopPackage(mActiveItem.mItem.mPackageInfo.packageName);
@@ -178,7 +189,8 @@ public class RunningServiceDetails extends Activity
     
     boolean findMergedItem() {
         RunningState.MergedItem item = null;
-        ArrayList<RunningState.MergedItem> newItems = mState.getCurrentMergedItems();
+        ArrayList<RunningState.MergedItem> newItems = mShowBackground
+                ? mState.getCurrentBackgroundItems() : mState.getCurrentMergedItems();
         if (newItems != null) {
             for (int i=0; i<newItems.size(); i++) {
                 RunningState.MergedItem mi = newItems.get(i);
@@ -189,6 +201,7 @@ public class RunningServiceDetails extends Activity
                 }
             }
         }
+
         if (mMergedItem != item) {
             mMergedItem = item;
             return true;
@@ -227,7 +240,9 @@ public class RunningServiceDetails extends Activity
                     si.mServiceInfo.packageName, si.mServiceInfo.descriptionRes,
                     si.mServiceInfo.applicationInfo));
         } else {
-            if (detail.mManageIntent != null) {
+            if (mi.mBackground) {
+                description.setText(R.string.background_process_stop_description);
+            } else if (detail.mManageIntent != null) {
                 try {
                     Resources clientr = getPackageManager().getResourcesForApplication(
                             si.mRunningService.clientPackage);
@@ -254,7 +269,7 @@ public class RunningServiceDetails extends Activity
         // 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 (enabled != 0 && si != null) {
             detail.mInstaller = ApplicationErrorReport.getErrorReportReceiver(
                     this, si.mServiceInfo.packageName, si.mServiceInfo.applicationInfo.flags);
             detail.mReportButton.setEnabled(detail.mInstaller != null);
@@ -351,7 +366,7 @@ public class RunningServiceDetails extends Activity
             
             if (mMergedItem.mServices.size() <= 0) {
                 // This item does not have any services, so it must be
-                // a heavy-weight process...  we will put a fake service
+                // another interesting process...  we will put a fake service
                 // entry for it, to allow the user to "stop" it.
                 addServiceDetailsView(null, mMergedItem);
             }
@@ -396,6 +411,7 @@ public class RunningServiceDetails extends Activity
         
         mUid = getIntent().getIntExtra(KEY_UID, 0);
         mProcessName = getIntent().getStringExtra(KEY_PROCESS);
+        mShowBackground = getIntent().getBooleanExtra(KEY_BACKGROUND, false);
         
         mAm = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
         mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
index 6d08c57..dbe4a64 100644 (file)
@@ -85,9 +85,9 @@ public class RunningState {
     final ServiceProcessComparator mServiceProcessComparator
             = new ServiceProcessComparator();
     
-    // Additional heavy-weight processes to be shown to the user, even if
+    // Additional interesting processes to be shown to the user, even if
     // there is no service running in them.
-    final ArrayList<ProcessItem> mHeavyProcesses = new ArrayList<ProcessItem>();
+    final ArrayList<ProcessItem> mInterestingProcesses = new ArrayList<ProcessItem>();
     
     // All currently running processes, for finding dependencies etc.
     final SparseArray<ProcessItem> mRunningProcesses
@@ -109,9 +109,11 @@ public class RunningState {
     
     boolean mResumed;
     boolean mHaveData;
+    boolean mWatchingBackgroundItems;
 
     ArrayList<BaseItem> mItems = new ArrayList<BaseItem>();
     ArrayList<MergedItem> mMergedItems = new ArrayList<MergedItem>();
+    ArrayList<MergedItem> mBackgroundItems = new ArrayList<MergedItem>();
     
     int mNumBackgroundProcesses;
     long mBackgroundProcessMemory;
@@ -207,6 +209,7 @@ public class RunningState {
         String mSizeStr;
         String mCurSizeStr;
         boolean mNeedDivider;
+        boolean mBackground;
         
         public BaseItem(boolean isProcess) {
             mIsProcess = isProcess;
@@ -437,26 +440,36 @@ public class RunningState {
         final ArrayList<ProcessItem> mOtherProcesses = new ArrayList<ProcessItem>();
         final ArrayList<ServiceItem> mServices = new ArrayList<ServiceItem>();
         
+        private int mLastNumProcesses = -1, mLastNumServices = -1;
+
         MergedItem() {
             super(false);
         }
         
-        boolean update(Context context) {
+        boolean update(Context context, boolean background) {
             mPackageInfo = mProcess.mPackageInfo;
             mDisplayLabel = mProcess.mDisplayLabel;
             mLabel = mProcess.mLabel;
+            mBackground = background;
             
-            int numProcesses = (mProcess.mPid > 0 ? 1 : 0) + mOtherProcesses.size();
-            int numServices = mServices.size();
-            int resid = R.string.running_processes_item_description_s_s;
-            if (numProcesses != 1) {
-                resid = numServices != 1
-                        ? R.string.running_processes_item_description_p_p
-                        : R.string.running_processes_item_description_p_s;
-            } else if (numServices != 1) {
-                resid = R.string.running_processes_item_description_s_p;
-            }
-            mDescription = context.getResources().getString(resid, numProcesses, numServices);
+            if (!mBackground) {
+                int numProcesses = (mProcess.mPid > 0 ? 1 : 0) + mOtherProcesses.size();
+                int numServices = mServices.size();
+                if (mLastNumProcesses != numProcesses || mLastNumServices != numServices) {
+                    mLastNumProcesses = numProcesses;
+                    mLastNumServices = numServices;
+                    int resid = R.string.running_processes_item_description_s_s;
+                    if (numProcesses != 1) {
+                        resid = numServices != 1
+                                ? R.string.running_processes_item_description_p_p
+                                : R.string.running_processes_item_description_p_s;
+                    } else if (numServices != 1) {
+                        resid = R.string.running_processes_item_description_s_p;
+                    }
+                    mDescription = context.getResources().getString(resid, numProcesses,
+                            numServices);
+                }
+            }
             
             mActiveSince = -1;
             for (int i=0; i<mServices.size(); i++) {
@@ -587,6 +600,19 @@ public class RunningState {
         }
     }
 
+    private boolean isInterestingProcess(ActivityManager.RunningAppProcessInfo pi) {
+        if ((pi.flags&ActivityManager.RunningAppProcessInfo.FLAG_CANT_SAVE_STATE) != 0) {
+            return true;
+        }
+        if ((pi.flags&ActivityManager.RunningAppProcessInfo.FLAG_PERSISTENT) == 0
+                && pi.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
+                && pi.importanceReasonCode
+                        == ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN) {
+            return true;
+        }
+        return false;
+    }
+
     private boolean update(Context context, ActivityManager am) {
         final PackageManager pm = context.getPackageManager();
         
@@ -666,10 +692,10 @@ public class RunningState {
                 proc.mDependentProcesses.clear();
             }
             
-            if ((pi.flags&ActivityManager.RunningAppProcessInfo.FLAG_CANT_SAVE_STATE) != 0) {
-                if (!mHeavyProcesses.contains(proc)) {
+            if (isInterestingProcess(pi)) {
+                if (!mInterestingProcesses.contains(proc)) {
                     changed = true;
-                    mHeavyProcesses.add(proc);
+                    mInterestingProcesses.add(proc);
                 }
                 proc.mCurSeq = mSequence;
                 proc.ensureLabel(pm);
@@ -706,13 +732,13 @@ public class RunningState {
             }
         }
         
-        // Remove any old heavy processes.
-        int NHP = mHeavyProcesses.size();
+        // Remove any old interesting processes.
+        int NHP = mInterestingProcesses.size();
         for (int i=0; i<NHP; i++) {
-            ProcessItem proc = mHeavyProcesses.get(i);
+            ProcessItem proc = mInterestingProcesses.get(i);
             if (mRunningProcesses.get(proc.mPid) == null) {
                 changed = true;
-                mHeavyProcesses.remove(i);
+                mInterestingProcesses.remove(i);
                 i--;
                 NHP--;
             }
@@ -841,21 +867,21 @@ public class RunningState {
                     }
                 }
                 
-                mergedItem.update(context);
+                mergedItem.update(context, false);
                 newMergedItems.add(mergedItem);
             }
             
-            // Finally, heavy-weight processes need to be shown and will
+            // Finally, interesting processes need to be shown and will
             // go at the top.
-            NHP = mHeavyProcesses.size();
+            NHP = mInterestingProcesses.size();
             for (int i=0; i<NHP; i++) {
-                ProcessItem proc = mHeavyProcesses.get(i);
+                ProcessItem proc = mInterestingProcesses.get(i);
                 if (proc.mClient == null && proc.mServices.size() <= 0) {
                     if (proc.mMergedItem == null) {
                         proc.mMergedItem = new MergedItem();
                         proc.mMergedItem.mProcess = proc;
                     }
-                    proc.mMergedItem.update(context);
+                    proc.mMergedItem.update(context, false);
                     newMergedItems.add(0, proc.mMergedItem);
                     mProcessItems.add(proc);
                 }
@@ -900,6 +926,7 @@ public class RunningState {
         long backgroundProcessMemory = 0;
         long foregroundProcessMemory = 0;
         long serviceProcessMemory = 0;
+        ArrayList<MergedItem> newBackgroundItems = null;
         try {
             final int numProc = mAllProcessItems.size();
             int[] pids = new int[numProc];
@@ -908,7 +935,8 @@ public class RunningState {
             }
             Debug.MemoryInfo[] mem = ActivityManagerNative.getDefault()
                     .getProcessMemoryInfo(pids);
-            for (int i=pids.length-1; i>=0; i--) {
+            int bgIndex = 0;
+            for (int i=0; i<pids.length; i++) {
                 ProcessItem proc = mAllProcessItems.get(i);
                 changed |= proc.updateSize(context, mem[i], mSequence);
                 if (proc.mCurSeq == mSequence) {
@@ -916,6 +944,28 @@ public class RunningState {
                 } else if (proc.mRunningProcessInfo.importance >=
                         ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
                     backgroundProcessMemory += proc.mSize;
+                    MergedItem mergedItem;
+                    if (newBackgroundItems != null) {
+                        mergedItem = proc.mMergedItem = new MergedItem();
+                        proc.mMergedItem.mProcess = proc;
+                        newBackgroundItems.add(mergedItem);
+                    } else {
+                        if (bgIndex >= mBackgroundItems.size()
+                                || mBackgroundItems.get(bgIndex).mProcess != proc) {
+                            newBackgroundItems = new ArrayList<MergedItem>(numBackgroundProcesses);
+                            for (int bgi=0; bgi<bgIndex; bgi++) {
+                                newBackgroundItems.add(mBackgroundItems.get(bgi));
+                            }
+                            mergedItem = proc.mMergedItem = new MergedItem();
+                            proc.mMergedItem.mProcess = proc;
+                            newBackgroundItems.add(mergedItem);
+                        } else {
+                            mergedItem = mBackgroundItems.get(bgIndex);
+                        }
+                    }
+                    mergedItem.update(context, true);
+                    mergedItem.updateSize(context);
+                    bgIndex++;
                 } else if (proc.mRunningProcessInfo.importance <=
                         ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
                     foregroundProcessMemory += proc.mSize;
@@ -924,6 +974,16 @@ public class RunningState {
         } catch (RemoteException e) {
         }
         
+        if (newBackgroundItems == null) {
+            // One or more at the bottom may no longer exit.
+            if (mBackgroundItems.size() > numBackgroundProcesses) {
+                newBackgroundItems = new ArrayList<MergedItem>(numBackgroundProcesses);
+                for (int bgi=0; bgi<numBackgroundProcesses; bgi++) {
+                    newBackgroundItems.add(mBackgroundItems.get(bgi));
+                }
+            }
+        }
+
         for (int i=0; i<mMergedItems.size(); i++) {
             mMergedItems.get(i).updateSize(context);
         }
@@ -935,6 +995,12 @@ public class RunningState {
             mBackgroundProcessMemory = backgroundProcessMemory;
             mForegroundProcessMemory = foregroundProcessMemory;
             mServiceProcessMemory = serviceProcessMemory;
+            if (newBackgroundItems != null) {
+                mBackgroundItems = newBackgroundItems;
+                if (mWatchingBackgroundItems) {
+                    changed = true;
+                }
+            }
             if (!mHaveData) {
                 mHaveData = true;
                 mLock.notifyAll();
@@ -950,9 +1016,21 @@ public class RunningState {
         }
     }
     
+    void setWatchingBackgroundItems(boolean watching) {
+        synchronized (mLock) {
+            mWatchingBackgroundItems = watching;
+        }
+    }
+
     ArrayList<MergedItem> getCurrentMergedItems() {
         synchronized (mLock) {
             return mMergedItems;
         }
     }
+
+    ArrayList<MergedItem> getCurrentBackgroundItems() {
+        synchronized (mLock) {
+            return mBackgroundItems;
+        }
+    }
 }
index b574849..0d00528 100644 (file)
@@ -26,13 +26,9 @@ import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.DialogInterface.OnCancelListener;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.os.Bundle;
-import android.os.Handler;
 import android.os.IBinder;
-import android.os.Message;
 import android.os.RemoteException;
 import android.os.Environment;
 import android.os.storage.IMountService;
@@ -42,6 +38,7 @@ import android.os.storage.StorageManager;
 import android.os.storage.StorageEventListener;
 import android.preference.Preference;
 import android.preference.PreferenceActivity;
+import android.preference.PreferenceGroup;
 import android.preference.PreferenceScreen;
 import android.text.format.Formatter;
 import android.util.Log;
@@ -50,9 +47,7 @@ import android.widget.Toast;
 import com.android.settings.R;
 
 import java.io.File;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
 
 public class Memory extends PreferenceActivity implements OnCancelListener {
     private static final String TAG = "Memory";
@@ -66,6 +61,8 @@ public class Memory extends PreferenceActivity implements OnCancelListener {
 
     private static final String MEMORY_SD_FORMAT = "memory_sd_format";
 
+    private static final String MEMORY_SD_GROUP = "memory_sd";
+
     private static final int DLG_CONFIRM_UNMOUNT = 1;
     private static final int DLG_ERROR_UNMOUNT = 2;
 
@@ -75,6 +72,9 @@ public class Memory extends PreferenceActivity implements OnCancelListener {
     private Preference mSdAvail;
     private Preference mSdMountToggle;
     private Preference mSdFormat;
+    private PreferenceGroup mSdMountPreferenceGroup;
+
+    boolean mSdMountToggleAdded = true;
     
     // Access using getMountService()
     private IMountService mMountService = null;
@@ -97,6 +97,8 @@ public class Memory extends PreferenceActivity implements OnCancelListener {
         mSdAvail = findPreference(MEMORY_SD_AVAIL);
         mSdMountToggle = findPreference(MEMORY_SD_MOUNT_TOGGLE);
         mSdFormat = findPreference(MEMORY_SD_FORMAT);
+
+        mSdMountPreferenceGroup = (PreferenceGroup)findPreference(MEMORY_SD_GROUP);
     }
     
     @Override
@@ -225,7 +227,6 @@ public class Memory extends PreferenceActivity implements OnCancelListener {
     private boolean hasAppsAccessingStorage() throws RemoteException {
         String extStoragePath = Environment.getExternalStorageDirectory().toString();
         IMountService mountService = getMountService();
-        boolean showPidDialog = false;
         int stUsers[] = mountService.getStorageUsers(extStoragePath);
         if (stUsers != null && stUsers.length > 0) {
             return true;
@@ -275,9 +276,15 @@ public class Memory extends PreferenceActivity implements OnCancelListener {
             readOnly = mRes.getString(R.string.read_only);
         }
  
-        mSdFormat.setEnabled(false);
-
         if (status.equals(Environment.MEDIA_MOUNTED)) {
+            if (!Environment.isExternalStorageRemovable()) {
+                // This device has built-in storage that is not removable.
+                // There is no reason for the user to unmount it.
+                if (mSdMountToggleAdded) {
+                    mSdMountPreferenceGroup.removePreference(mSdMountToggle);
+                    mSdMountToggleAdded = false;
+                }
+            }
             try {
                 File path = Environment.getExternalStorageDirectory();
                 StatFs stat = new StatFs(path.getPath());
@@ -303,10 +310,18 @@ public class Memory extends PreferenceActivity implements OnCancelListener {
             mSdAvail.setSummary(mRes.getString(R.string.sd_unavailable));
 
 
+            if (!Environment.isExternalStorageRemovable()) {
+                if (status.equals(Environment.MEDIA_UNMOUNTED)) {
+                    if (!mSdMountToggleAdded) {
+                        mSdMountPreferenceGroup.addPreference(mSdMountToggle);
+                        mSdMountToggleAdded = true;
+                    }
+                }
+            }
+
             if (status.equals(Environment.MEDIA_UNMOUNTED) ||
                 status.equals(Environment.MEDIA_NOFS) ||
                 status.equals(Environment.MEDIA_UNMOUNTABLE) ) {
-                mSdFormat.setEnabled(true);
                 mSdMountToggle.setEnabled(true);
                 mSdMountToggle.setTitle(mRes.getString(R.string.sd_mount));
                 mSdMountToggle.setSummary(mRes.getString(R.string.sd_mount_summary));