diff options
Diffstat (limited to 'src/com/android')
8 files changed, 532 insertions, 161 deletions
diff --git a/src/com/android/settings/MasterClear.java b/src/com/android/settings/MasterClear.java index 4de0e44..e653d90 100644 --- a/src/com/android/settings/MasterClear.java +++ b/src/com/android/settings/MasterClear.java @@ -16,20 +16,16 @@ 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(); + } } - } diff --git a/src/com/android/settings/MediaFormat.java b/src/com/android/settings/MediaFormat.java index b78ff62..d8d57e4 100644 --- a/src/com/android/settings/MediaFormat.java +++ b/src/com/android/settings/MediaFormat.java @@ -16,23 +16,15 @@ 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 index 0000000..74164c4 --- /dev/null +++ b/src/com/android/settings/applications/LinearColorBar.java @@ -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 diff --git a/src/com/android/settings/applications/ManageApplications.java b/src/com/android/settings/applications/ManageApplications.java index 1053d3b..b4cd26e 100644 --- a/src/com/android/settings/applications/ManageApplications.java +++ b/src/com/android/settings/applications/ManageApplications.java @@ -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) { diff --git a/src/com/android/settings/applications/RunningProcessesView.java b/src/com/android/settings/applications/RunningProcessesView.java index 1de67f7..86457bf 100644 --- a/src/com/android/settings/applications/RunningProcessesView.java +++ b/src/com/android/settings/applications/RunningProcessesView.java @@ -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 = diff --git a/src/com/android/settings/applications/RunningServiceDetails.java b/src/com/android/settings/applications/RunningServiceDetails.java index 399c89f..aa89baf 100644 --- a/src/com/android/settings/applications/RunningServiceDetails.java +++ b/src/com/android/settings/applications/RunningServiceDetails.java @@ -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); diff --git a/src/com/android/settings/applications/RunningState.java b/src/com/android/settings/applications/RunningState.java index 6d08c57..dbe4a64 100644 --- a/src/com/android/settings/applications/RunningState.java +++ b/src/com/android/settings/applications/RunningState.java @@ -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; + } + } } diff --git a/src/com/android/settings/deviceinfo/Memory.java b/src/com/android/settings/deviceinfo/Memory.java index b574849..0d00528 100644 --- a/src/com/android/settings/deviceinfo/Memory.java +++ b/src/com/android/settings/deviceinfo/Memory.java @@ -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)); |