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"
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"
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>
<!-- 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". -->
<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. -->
<!-- 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>
<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"
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"
private View mInitialView;
private Button mInitiateButton;
+ private View mExternalStorageContainer;
+ private CheckBox mExternalStorage;
private View mFinalView;
private Button mFinalButton;
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.
+ }
}
};
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);
public void onPause() {
super.onPause();
- establishInitialState();
+ if (!isFinishing()) {
+ establishInitialState();
+ }
}
-
}
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
private static final int KEYGUARD_REQUEST = 55;
private LayoutInflater mInflater;
- private LockPatternUtils mLockUtils;
private View mInitialView;
private Button mInitiateButton;
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();
}
};
mInitialView = null;
mFinalView = null;
mInflater = LayoutInflater.from(this);
- mLockUtils = new LockPatternUtils(this);
establishInitialState();
}
public void onPause() {
super.onPause();
- establishInitialState();
+ if (!isFinishing()) {
+ establishInitialState();
+ }
}
-
}
--- /dev/null
+/**
+ *
+ */
+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
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;
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
// 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;
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();
mCurFilterPrefix = constraint;
mEntries = (ArrayList<ApplicationsState.AppEntry>)results.values;
notifyDataSetChanged();
+ updateStorageUsage();
}
};
mEntries = null;
}
notifyDataSetChanged();
+ updateStorageUsage();
if (entries == null) {
mWaitingForData = true;
mBaseEntries = apps;
mEntries = applyPrefixFilter(mCurFilterPrefix, mBaseEntries);
notifyDataSetChanged();
+ updateStorageUsage();
}
@Override
// the list with the new size to reflect it to the user.
rebuild(false);
}
+ updateStorageUsage();
return;
}
}
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);
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);
.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;
}
* 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;
}
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;
}
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) {
mFilterApps = newOption;
selectView(VIEW_LIST);
+ updateStorageUsage();
}
public void onTabChanged(String tabId) {
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;
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;
RunningState.BaseItem mCurSelected;
ListView mListView;
+ ServiceListAdapter mAdapter;
LinearColorBar mColorBar;
TextView mBackgroundProcessText;
TextView mForegroundProcessText;
ActivityManager.RunningServiceInfo mService;
ViewHolder mHolder;
long mFirstRunTime;
+ boolean mSetBackground;
void updateTime(Context context, StringBuilder builder) {
TextView uptimeView = null;
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));
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;
class ServiceListAdapter extends BaseAdapter {
final RunningState mState;
final LayoutInflater mInflater;
+ boolean mShowBackground;
ArrayList<RunningState.MergedItem> mItems;
ServiceListAdapter(RunningState state) {
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;
}
}
}
- 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) {
+ mLastForegroundProcessMemory + mLastServiceProcessMemory;
mColorBar.setRatios(mLastForegroundProcessMemory/totalMem,
mLastServiceProcessMemory/totalMem,
- (availMem+mLastBackgroundProcessMemory)/totalMem);
+ mLastBackgroundProcessMemory/totalMem);
}
}
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);
}
}
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 =
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;
int mUid;
String mProcessName;
+ boolean mShowBackground;
RunningState.MergedItem mMergedItem;
}
}
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();
}
} 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);
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);
}
}
}
+
if (mMergedItem != item) {
mMergedItem = item;
return true;
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);
// 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);
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);
}
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);
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
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;
String mSizeStr;
String mCurSizeStr;
boolean mNeedDivider;
+ boolean mBackground;
public BaseItem(boolean isProcess) {
mIsProcess = isProcess;
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++) {
}
}
+ 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();
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);
}
}
- // 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--;
}
}
}
- 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);
}
long backgroundProcessMemory = 0;
long foregroundProcessMemory = 0;
long serviceProcessMemory = 0;
+ ArrayList<MergedItem> newBackgroundItems = null;
try {
final int numProc = mAllProcessItems.size();
int[] pids = new int[numProc];
}
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) {
} 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;
} 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);
}
mBackgroundProcessMemory = backgroundProcessMemory;
mForegroundProcessMemory = foregroundProcessMemory;
mServiceProcessMemory = serviceProcessMemory;
+ if (newBackgroundItems != null) {
+ mBackgroundItems = newBackgroundItems;
+ if (mWatchingBackgroundItems) {
+ changed = true;
+ }
+ }
if (!mHaveData) {
mHaveData = true;
mLock.notifyAll();
}
}
+ void setWatchingBackgroundItems(boolean watching) {
+ synchronized (mLock) {
+ mWatchingBackgroundItems = watching;
+ }
+ }
+
ArrayList<MergedItem> getCurrentMergedItems() {
synchronized (mLock) {
return mMergedItems;
}
}
+
+ ArrayList<MergedItem> getCurrentBackgroundItems() {
+ synchronized (mLock) {
+ return mBackgroundItems;
+ }
+ }
}
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;
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;
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";
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;
private Preference mSdAvail;
private Preference mSdMountToggle;
private Preference mSdFormat;
+ private PreferenceGroup mSdMountPreferenceGroup;
+
+ boolean mSdMountToggleAdded = true;
// Access using getMountService()
private IMountService mMountService = null;
mSdAvail = findPreference(MEMORY_SD_AVAIL);
mSdMountToggle = findPreference(MEMORY_SD_MOUNT_TOGGLE);
mSdFormat = findPreference(MEMORY_SD_FORMAT);
+
+ mSdMountPreferenceGroup = (PreferenceGroup)findPreference(MEMORY_SD_GROUP);
}
@Override
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;
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());
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));