diff options
author | Jason Monk <jmonk@android.com> | 2015-05-21 15:24:37 -0400 |
---|---|---|
committer | Jason Monk <jmonk@google.com> | 2015-05-26 11:41:37 -0400 |
commit | beb171d2e50f93b5fb78d73b372a4981e13e04ff (patch) | |
tree | 23e2f38cf7954e0236504e3077880ece287bca6f | |
parent | 85a72a9088d6be0cd0fda03d0e80a24a8fcaa4cb (diff) | |
download | packages_apps_Settings-beb171d2e50f93b5fb78d73b372a4981e13e04ff.zip packages_apps_Settings-beb171d2e50f93b5fb78d73b372a4981e13e04ff.tar.gz packages_apps_Settings-beb171d2e50f93b5fb78d73b372a4981e13e04ff.tar.bz2 |
Unbanish memory screen and new UX
Give memory screen a makeover so that it looks nice enough to be
restored to its rightful home.
Bug: 20694769
Change-Id: I2f6933037b3fbbfb0d9fe5e3ca821ef59e171faa
23 files changed, 633 insertions, 453 deletions
diff --git a/res/layout/app_item_linear_color.xml b/res/layout/app_item_linear_color.xml index 62eebb9..7a4aad5 100755 --- a/res/layout/app_item_linear_color.xml +++ b/res/layout/app_item_linear_color.xml @@ -15,7 +15,7 @@ limitations under the License. --> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:minHeight="?android:attr/listPreferredItemHeight" @@ -34,16 +34,19 @@ android:duplicateParentState="true" /> <LinearLayout - android:layout_width="0dp" - android:layout_height="match_parent" - android:layout_weight="1" - android:orientation="vertical" + android:id="@+id/text_area" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_alignParentTop="true" + android:layout_toEndOf="@android:id/icon" + android:orientation="horizontal" android:duplicateParentState="true"> <TextView android:id="@android:id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_weight="1" android:layout_marginTop="2dip" android:singleLine="true" android:ellipsize="marquee" @@ -55,20 +58,22 @@ android:id="@android:id/summary" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_weight="1" android:textAppearance="@android:style/TextAppearance.Material.Body1" android:textColor="?android:attr/textColorSecondary" - android:textAlignment="viewStart" + android:gravity="end|bottom" android:duplicateParentState="true" /> </LinearLayout> <com.android.settings.applications.LinearColorBar android:id="@+id/linear_color_bar" - android:layout_width="0dp" - android:layout_height="match_parent" - android:layout_weight="1" - android:layout_marginTop="5dp" + android:layout_width="match_parent" + android:layout_height="10dp" + android:layout_marginTop="7dp" android:layout_marginBottom="5dp" + android:layout_toEndOf="@android:id/icon" + android:layout_below="@id/text_area" android:duplicateParentState="true" /> -</LinearLayout> +</RelativeLayout> diff --git a/res/layout/horizontal_preference.xml b/res/layout/horizontal_preference.xml index 4e16e9a..722e053 100644 --- a/res/layout/horizontal_preference.xml +++ b/res/layout/horizontal_preference.xml @@ -38,6 +38,6 @@ android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_weight="1" - android:gravity="end" /> + android:gravity="end|bottom" /> </LinearLayout> diff --git a/res/layout/proc_stats_ui.xml b/res/layout/proc_stats_ui.xml index 5f78178..9d0a22d 100644 --- a/res/layout/proc_stats_ui.xml +++ b/res/layout/proc_stats_ui.xml @@ -28,28 +28,18 @@ android:id="@+id/memory_state" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="20dp" - android:layout_marginBottom="10dp" - android:textAppearance="@android:style/TextAppearance.Material.Subhead" + android:layout_marginTop="5dp" + android:layout_marginBottom="5dp" + android:textColor="?android:attr/colorAccent" + android:textAppearance="@android:style/TextAppearance.Material.Display1" /> <com.android.settings.applications.LinearColorBar android:id="@+id/color_bar" android:layout_width="match_parent" - android:layout_height="30dp" + android:layout_height="28dp" + android:layout_marginBottom="15dp" /> - <TextView - android:id="@+id/memory_used" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="2dp" - android:layout_marginBottom="10dp" - android:textAppearance="@android:style/TextAppearance.Material.Small" - android:textColor="?android:attr/textColorSecondary" - /> - - <include layout="@layout/memory_key" /> - </LinearLayout> diff --git a/res/layout/single_button_panel.xml b/res/layout/single_button_panel.xml index 2af1765..348f7ce 100755 --- a/res/layout/single_button_panel.xml +++ b/res/layout/single_button_panel.xml @@ -25,8 +25,8 @@ android:paddingStart="?android:attr/listPreferredItemPaddingStart" android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" android:gravity="bottom" - android:paddingTop="6dip" - android:paddingBottom="6dip" + android:paddingTop="8dip" + android:paddingBottom="8dip" android:orientation="horizontal"> <Button android:id="@+id/button" diff --git a/res/values/arrays.xml b/res/values/arrays.xml index 1af15f9..36924ee 100644 --- a/res/values/arrays.xml +++ b/res/values/arrays.xml @@ -1225,13 +1225,15 @@ <!-- [CHAR LIMIT=40] Labels for memory states --> <string-array name="ram_states"> <!-- Normal desired memory state. --> - <item>Good performance</item> + <item>Normal</item> <!-- Moderate memory state, not as good as normal. --> - <item>Ok performance</item> + <item>Moderate</item> <!-- Memory is running low. --> - <item>Poor performance</item> + <item>Low</item> <!-- Memory is critical. --> - <item>Very poor performance</item> + <item>Critical</item> + <!-- Unknown memory state --> + <item>\?</item> </string-array> <array name="ram_colors"> diff --git a/res/values/strings.xml b/res/values/strings.xml index b1628d9..0071926 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -6556,13 +6556,13 @@ <string name="memory_details_title">Memory details</string> <!-- Description of app always running [CHAR LIMIT=45] --> - <string name="always_running">Always running</string> + <string name="always_running">Always running (<xliff:g id="percentage" example="5%">%s</xliff:g>)</string> <!-- Description of app sometimes running [CHAR LIMIT=45] --> - <string name="sometimes_running">Sometimes running</string> + <string name="sometimes_running">Sometimes running (<xliff:g id="percentage" example="5%">%s</xliff:g>)</string> <!-- Description of app rarely running [CHAR LIMIT=45] --> - <string name="rarely_running">Rarely running</string> + <string name="rarely_running">Rarely running (<xliff:g id="percentage" example="5%">%s</xliff:g>)</string> <!-- Maximum memory usage key [CHAR LIMIT=25] --> <string name="memory_max_use">Maximum</string> @@ -6657,4 +6657,43 @@ <!-- Footer text in the manage assist screen. [CHAR LIMIT=NONE] --> <string name="assist_footer">Assist apps help you identify and act on useful information without having to ask. Some apps support both launcher and voice input services to give you integrated assistance.</string> + + <!-- Label for average memory use section [CHAR LIMIT=30] --> + <string name="average_memory_use">Average memory use</string> + + <!-- Label for maximum memory use section [CHAR LIMIT=30] --> + <string name="maximum_memory_use">Maximum memory use</string> + + <!-- Menu item for Sorting list by average memory use [CHAR LIMIT=NONE]--> + <string name="sort_avg_use">Sort by avg use</string> + + <!-- Menu item for Sorting list by maximum memory use [CHAR LIMIT=NONE] --> + <string name="sort_max_use">Sort by max use</string> + + <!-- Label for the current performance of the device [CHAR LIMIT=25] --> + <string name="memory_performance">Performance</string> + + <!-- Label for total memory of device [CHAR LIMIT=25] --> + <string name="total_memory">Total memory</string> + + <!-- Label for average memory usage of device [CHAR LIMIT=25] --> + <string name="average_used">Average used (%)</string> + + <!-- Label for free memory of device [CHAR LIMIT=25] --> + <string name="free_memory">Free</string> + + <!-- Label for button that leads to list of apps and their memory usage [CHAR LIMIT=40]--> + <string name="memory_usage_apps">Memory used by apps</string> + + <!-- Description of number of apps using memory [CHAR LIMIT=NONE] --> + <plurals name="memory_usage_apps_summary"> + <item quantity="one">1 app used memory in the last <xliff:g id="duration" example="3 hours">%2$s</xliff:g></item> + <item quantity="other"><xliff:g id="count" example="10">%1$d</xliff:g> apps used memory in the last <xliff:g id="duration" example="3 hours">%2$s</xliff:g></item> + </plurals> + + <!-- Label for frequency that the app is runnig (e.g. always, sometimes, etc.) [CHAR LIMIT=25] --> + <string name="running_frequency">Frequency</string> + + <!-- Label for maximum amount of memory app has used [CHAR LIMIT=25] --> + <string name="memory_maximum_usage">Maximum usage</string> </resources> diff --git a/res/xml/advanced_apps.xml b/res/xml/advanced_apps.xml index 1e2d516..b38900b 100644 --- a/res/xml/advanced_apps.xml +++ b/res/xml/advanced_apps.xml @@ -49,8 +49,4 @@ android:value="com.android.settings.Settings$HighPowerApplicationsActivity" /> </PreferenceScreen> - <PreferenceScreen - android:title="@string/memory_settings_title" - android:fragment="com.android.settings.applications.ProcessStatsUi" /> - </PreferenceScreen> diff --git a/res/xml/app_memory_settings.xml b/res/xml/app_memory_settings.xml index 2c3db21..41de52f 100644 --- a/res/xml/app_memory_settings.xml +++ b/res/xml/app_memory_settings.xml @@ -17,8 +17,26 @@ <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" android:title="@string/memory_details_title"> + <PreferenceCategory + android:title="@string/average_memory_use" /> + <com.android.settings.applications.LayoutPreference - android:key="details_header" - android:layout="@layout/process_stats_details" /> + android:key="status_header" + android:layout="@layout/proc_stats_ui" /> + + <Preference + android:key="frequency" + android:selectable="false" + android:layout="@layout/horizontal_preference" + android:title="@string/running_frequency" /> + + <Preference + android:key="max_usage" + android:selectable="false" + android:layout="@layout/horizontal_preference" + android:title="@string/memory_maximum_usage" /> + + <com.android.settings.applications.SpacePreference + android:layout_height="15dp" /> </PreferenceScreen> diff --git a/res/xml/app_storage_settings.xml b/res/xml/app_storage_settings.xml index 5bb9204..7c5c25c 100644 --- a/res/xml/app_storage_settings.xml +++ b/res/xml/app_storage_settings.xml @@ -63,9 +63,13 @@ android:layout="@layout/single_button_panel" /> </PreferenceCategory> + <com.android.settings.applications.SpacePreference + android:layout_height="8dp" /> + <Preference android:key="cache_size" android:title="@string/cache_size_label" + android:selectable="false" android:layout="@layout/horizontal_preference" /> <com.android.settings.applications.LayoutPreference diff --git a/res/xml/dashboard_categories.xml b/res/xml/dashboard_categories.xml index 14a4db6..5b8c243 100644 --- a/res/xml/dashboard_categories.xml +++ b/res/xml/dashboard_categories.xml @@ -134,13 +134,13 @@ android:icon="@drawable/ic_settings_multiuser" /> - <!-- Memory (hidden for now) + <!-- Memory --> <dashboard-tile android:id="@+id/manage_memory" android:title="@string/memory_settings_title" - android:fragment="com.android.settings.applications.ProcessStatsUi" + android:fragment="com.android.settings.applications.ProcessStatsSummary" android:icon="@drawable/ic_settings_memory" - /> --> + /> <!-- Manage NFC payment apps --> <dashboard-tile diff --git a/res/xml/process_stats_summary.xml b/res/xml/process_stats_summary.xml index 46bb160..d267272 100644 --- a/res/xml/process_stats_summary.xml +++ b/res/xml/process_stats_summary.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2013 The Android Open Source Project +<!-- Copyright (C) 2015 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,7 +18,43 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:title="@string/app_memory_use" android:key="app_list"> + <PreferenceCategory + android:title="@string/average_memory_use" /> + <com.android.settings.applications.LayoutPreference android:key="status_header" + android:selectable="false" android:layout="@layout/proc_stats_ui" /> + + <Preference + android:key="performance" + android:selectable="false" + android:layout="@layout/horizontal_preference" + android:title="@string/memory_performance" /> + + <Preference + android:key="total_memory" + android:selectable="false" + android:layout="@layout/horizontal_preference" + android:title="@string/total_memory" /> + + <Preference + android:key="average_used" + android:selectable="false" + android:layout="@layout/horizontal_preference" + android:title="@string/average_used" /> + + <Preference + android:key="free" + android:selectable="false" + android:layout="@layout/horizontal_preference" + android:title="@string/free_memory" /> + + <com.android.settings.applications.SpacePreference + android:layout_height="15dp" /> + + <Preference + android:key="apps_list" + android:title="@string/memory_usage_apps" /> + </PreferenceScreen> diff --git a/res/xml/process_stats_ui.xml b/res/xml/process_stats_ui.xml new file mode 100644 index 0000000..ba9066e --- /dev/null +++ b/res/xml/process_stats_ui.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<PreferenceScreen + xmlns:android="http://schemas.android.com/apk/res/android" + android:title="@string/app_memory_use"> + + <PreferenceCategory + android:key="app_list" + android:title="@string/average_memory_use" /> + +</PreferenceScreen> diff --git a/src/com/android/settings/InstrumentedFragment.java b/src/com/android/settings/InstrumentedFragment.java index 2da39da..2fe631d 100644 --- a/src/com/android/settings/InstrumentedFragment.java +++ b/src/com/android/settings/InstrumentedFragment.java @@ -26,7 +26,8 @@ public abstract class InstrumentedFragment extends PreferenceFragment { // Declare new temporary categories here, starting after this value. public static final int UNDECLARED = 100000; - public static final int APPLICATIONS_MANAGE_ASSIST = UNDECLARED+1; + public static final int APPLICATIONS_MANAGE_ASSIST = UNDECLARED + 1; + public static final int PROCESS_STATS_SUMMARY = UNDECLARED + 2; /** * Declare the view of this category. diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index d3d515e..b7f62a3 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -147,6 +147,8 @@ public final class Utils { private static final int SECONDS_PER_HOUR = 60 * 60; private static final int SECONDS_PER_DAY = 24 * 60 * 60; + public static final String OS_PKG = "os"; + private static SparseArray<Bitmap> sDarkDefaultUserBitmapCache = new SparseArray<Bitmap>(); /** diff --git a/src/com/android/settings/applications/LayoutPreference.java b/src/com/android/settings/applications/LayoutPreference.java index 8a4e533..75387d3 100644 --- a/src/com/android/settings/applications/LayoutPreference.java +++ b/src/com/android/settings/applications/LayoutPreference.java @@ -33,6 +33,7 @@ public class LayoutPreference extends Preference { public LayoutPreference(Context context, AttributeSet attrs) { super(context, attrs); + setSelectable(false); final TypedArray a = context.obtainStyledAttributes( attrs, com.android.internal.R.styleable.Preference, 0, 0); int layoutResource = a.getResourceId(com.android.internal.R.styleable.Preference_layout, diff --git a/src/com/android/settings/applications/ProcStatsData.java b/src/com/android/settings/applications/ProcStatsData.java index af7d94d..5dba409 100644 --- a/src/com/android/settings/applications/ProcStatsData.java +++ b/src/com/android/settings/applications/ProcStatsData.java @@ -35,6 +35,7 @@ import com.android.internal.app.ProcessStats.ProcessDataCollection; import com.android.internal.app.ProcessStats.TotalMemoryUseCollection; import com.android.internal.util.MemInfoReader; import com.android.settings.R; +import com.android.settings.Utils; import java.io.IOException; import java.io.InputStream; @@ -57,8 +58,6 @@ public class ProcStatsData { private IProcessStats mProcessStats; private ProcessStats mStats; - private int mMemState; - private boolean mUseUss; private long mDuration; @@ -187,28 +186,28 @@ public class ProcStatsData { ProcStatsPackageEntry osPkg = new ProcStatsPackageEntry("os", memTotalTime); ProcStatsEntry osEntry; if (totalMem.sysMemNativeWeight > 0) { - osEntry = new ProcStatsEntry("os", 0, + osEntry = new ProcStatsEntry(Utils.OS_PKG, 0, mContext.getString(R.string.process_stats_os_native), memTotalTime, (long) (totalMem.sysMemNativeWeight / memTotalTime)); osEntry.evaluateTargetPackage(mPm, mStats, bgTotals, runTotals, sEntryCompare, mUseUss); osPkg.addEntry(osEntry); } if (totalMem.sysMemKernelWeight > 0) { - osEntry = new ProcStatsEntry("os", 0, + osEntry = new ProcStatsEntry(Utils.OS_PKG, 0, mContext.getString(R.string.process_stats_os_kernel), memTotalTime, (long) (totalMem.sysMemKernelWeight / memTotalTime)); osEntry.evaluateTargetPackage(mPm, mStats, bgTotals, runTotals, sEntryCompare, mUseUss); osPkg.addEntry(osEntry); } if (totalMem.sysMemZRamWeight > 0) { - osEntry = new ProcStatsEntry("os", 0, + osEntry = new ProcStatsEntry(Utils.OS_PKG, 0, mContext.getString(R.string.process_stats_os_zram), memTotalTime, (long) (totalMem.sysMemZRamWeight / memTotalTime)); osEntry.evaluateTargetPackage(mPm, mStats, bgTotals, runTotals, sEntryCompare, mUseUss); osPkg.addEntry(osEntry); } if (baseCacheRam > 0) { - osEntry = new ProcStatsEntry("os", 0, + osEntry = new ProcStatsEntry(Utils.OS_PKG, 0, mContext.getString(R.string.process_stats_os_cache), memTotalTime, baseCacheRam / 1024); osEntry.evaluateTargetPackage(mPm, mStats, bgTotals, runTotals, sEntryCompare, mUseUss); @@ -296,7 +295,6 @@ public class ProcStatsData { private void load() { try { - mMemState = mProcessStats.getCurrentMemoryState(); ParcelFileDescriptor pfd = mProcessStats.getStatsOverTime(mDuration); mStats = new ProcessStats(false); InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pfd); diff --git a/src/com/android/settings/applications/ProcStatsPackageEntry.java b/src/com/android/settings/applications/ProcStatsPackageEntry.java index e056b06..ef74bc6 100644 --- a/src/com/android/settings/applications/ProcStatsPackageEntry.java +++ b/src/com/android/settings/applications/ProcStatsPackageEntry.java @@ -23,6 +23,7 @@ import android.os.Parcel; import android.os.Parcelable; import com.android.settings.R; +import com.android.settings.Utils; import java.util.ArrayList; @@ -89,10 +90,10 @@ public class ProcStatsPackageEntry implements Parcelable { final int N = mEntries.size(); for (int i=0; i < N; i++) { ProcStatsEntry entry = mEntries.get(i); - mBgDuration += entry.mBgDuration; + mBgDuration = Math.max(entry.mBgDuration, mBgDuration); mAvgBgMem += entry.mAvgBgMem; mBgWeight += entry.mBgWeight; - mRunDuration += entry.mRunDuration; + mRunDuration = Math.max(entry.mRunDuration, mRunDuration); mAvgRunMem += entry.mAvgRunMem; mRunWeight += entry.mRunWeight; @@ -161,12 +162,15 @@ public class ProcStatsPackageEntry implements Parcelable { // TODO: Find better place for this. public static CharSequence getFrequency(float amount, Context context) { - if (amount> ALWAYS_THRESHOLD) { - return context.getString(R.string.always_running); - } else if (amount> SOMETIMES_THRESHOLD) { - return context.getString(R.string.sometimes_running); + if (amount > ALWAYS_THRESHOLD) { + return context.getString(R.string.always_running, + Utils.formatPercentage((int) (amount * 100))); + } else if (amount > SOMETIMES_THRESHOLD) { + return context.getString(R.string.sometimes_running, + Utils.formatPercentage((int) (amount * 100))); } else { - return context.getString(R.string.rarely_running); + return context.getString(R.string.rarely_running, + Utils.formatPercentage((int) (amount * 100))); } } } diff --git a/src/com/android/settings/applications/ProcessStatsBase.java b/src/com/android/settings/applications/ProcessStatsBase.java new file mode 100644 index 0000000..c2f96d2 --- /dev/null +++ b/src/com/android/settings/applications/ProcessStatsBase.java @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.applications; + +import android.os.Bundle; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView.OnItemSelectedListener; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.Spinner; + +import com.android.internal.app.ProcessStats; +import com.android.settings.R; +import com.android.settings.SettingsPreferenceFragment; + +public abstract class ProcessStatsBase extends SettingsPreferenceFragment + implements OnItemSelectedListener { + private static final String DURATION = "duration"; + + protected static final String ARG_TRANSFER_STATS = "transfer_stats"; + protected static final String ARG_DURATION_INDEX = "duration_index"; + + protected static final int NUM_DURATIONS = 4; + + // The actual duration value to use for each duration option. Note these + // are lower than the actual duration, since our durations are computed in + // batches of 3 hours so we want to allow the time we use to be slightly + // smaller than the actual time selected instead of bumping up to 3 hours + // beyond it. + private static final long DURATION_QUANTUM = ProcessStats.COMMIT_PERIOD; + protected static long[] sDurations = new long[] { + 3 * 60 * 60 * 1000 - DURATION_QUANTUM / 2, 6 * 60 *60 * 1000 - DURATION_QUANTUM / 2, + 12 * 60 * 60 * 1000 - DURATION_QUANTUM / 2, 24 * 60 * 60 * 1000 - DURATION_QUANTUM / 2 + }; + protected static int[] sDurationLabels = new int[] { + R.string.menu_duration_3h, R.string.menu_duration_6h, + R.string.menu_duration_12h, R.string.menu_duration_1d + }; + + private ViewGroup mSpinnerHeader; + private Spinner mFilterSpinner; + private ArrayAdapter<String> mFilterAdapter; + + protected ProcStatsData mStatsManager; + protected int mDurationIndex; + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + Bundle args = getArguments(); + mStatsManager = new ProcStatsData(getActivity(), icicle != null + || (args != null && args.getBoolean(ARG_TRANSFER_STATS, false))); + + mDurationIndex = icicle != null + ? icicle.getInt(ARG_DURATION_INDEX) + : args != null ? args.getInt(ARG_DURATION_INDEX) : 0; + mStatsManager.setDuration(icicle != null + ? icicle.getLong(DURATION, sDurations[0]) : sDurations[0]); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putLong(DURATION, mStatsManager.getDuration()); + outState.putInt(ARG_DURATION_INDEX, mDurationIndex); + } + + @Override + public void onResume() { + super.onResume(); + mStatsManager.refreshStats(false); + refreshUi(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (getActivity().isChangingConfigurations()) { + mStatsManager.xferStats(); + } + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + mSpinnerHeader = (ViewGroup) setPinnedHeaderView(R.layout.apps_filter_spinner); + mFilterSpinner = (Spinner) mSpinnerHeader.findViewById(R.id.filter_spinner); + mFilterAdapter = new ArrayAdapter<String>(getActivity(), R.layout.filter_spinner_item); + mFilterAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + for (int i = 0; i < NUM_DURATIONS; i++) { + mFilterAdapter.add(getString(sDurationLabels[i])); + } + mFilterSpinner.setAdapter(mFilterAdapter); + mFilterSpinner.setSelection(mDurationIndex); + mFilterSpinner.setOnItemSelectedListener(this); + } + + @Override + public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { + mDurationIndex = position; + mStatsManager.setDuration(sDurations[position]); + refreshUi(); + } + + @Override + public void onNothingSelected(AdapterView<?> parent) { + // Select something. + mFilterSpinner.setSelection(0); + } + + public abstract void refreshUi(); +} diff --git a/src/com/android/settings/applications/ProcessStatsDetail.java b/src/com/android/settings/applications/ProcessStatsDetail.java index b29b2fe..1cf5ab4 100644 --- a/src/com/android/settings/applications/ProcessStatsDetail.java +++ b/src/com/android/settings/applications/ProcessStatsDetail.java @@ -31,13 +31,15 @@ import android.content.pm.ServiceInfo; import android.graphics.drawable.ColorDrawable; import android.os.Bundle; import android.os.Process; +import android.preference.Preference; import android.preference.PreferenceCategory; -import android.text.TextUtils; import android.text.format.Formatter; import android.util.ArrayMap; import android.util.Log; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.View; -import android.widget.Button; import android.widget.TextView; import com.android.internal.logging.MetricsLogger; @@ -46,6 +48,7 @@ import com.android.settings.CancellablePreference; import com.android.settings.CancellablePreference.OnCancelListener; import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; +import com.android.settings.Utils; import com.android.settings.applications.ProcStatsEntry.Service; import java.util.ArrayList; @@ -54,36 +57,35 @@ import java.util.Comparator; import java.util.HashMap; import java.util.List; -public class ProcessStatsDetail extends SettingsPreferenceFragment - implements Button.OnClickListener { +public class ProcessStatsDetail extends SettingsPreferenceFragment { private static final String TAG = "ProcessStatsDetail"; - public static final int ACTION_FORCE_STOP = 1; + public static final int MENU_FORCE_STOP = 1; public static final String EXTRA_PACKAGE_ENTRY = "package_entry"; - public static final String EXTRA_USE_USS = "use_uss"; public static final String EXTRA_WEIGHT_TO_RAM = "weight_to_ram"; public static final String EXTRA_TOTAL_TIME = "total_time"; public static final String EXTRA_MAX_MEMORY_USAGE = "max_memory_usage"; public static final String EXTRA_TOTAL_SCALE = "total_scale"; - private static final String KEY_DETAILS_HEADER = "details_header"; + private static final String KEY_DETAILS_HEADER = "status_header"; + + private static final String KEY_FREQUENCY = "frequency"; + private static final String KEY_MAX_USAGE = "max_usage"; private final ArrayMap<ComponentName, CancellablePreference> mServiceMap = new ArrayMap<>(); private PackageManager mPm; private DevicePolicyManager mDpm; + private MenuItem mForceStop; + private ProcStatsPackageEntry mApp; - private boolean mUseUss; private double mWeightToRam; private long mTotalTime; private long mOnePercentTime; - private Button mForceStopButton; - private Button mReportButton; - private LinearColorBar mColorBar; private double mMaxMemoryUsage; @@ -98,7 +100,6 @@ public class ProcessStatsDetail extends SettingsPreferenceFragment final Bundle args = getArguments(); mApp = args.getParcelable(EXTRA_PACKAGE_ENTRY); mApp.retrieveUiData(getActivity(), mPm); - mUseUss = args.getBoolean(EXTRA_USE_USS); mWeightToRam = args.getDouble(EXTRA_WEIGHT_TO_RAM); mTotalTime = args.getLong(EXTRA_TOTAL_TIME); mMaxMemoryUsage = args.getDouble(EXTRA_MAX_MEMORY_USAGE); @@ -107,6 +108,7 @@ public class ProcessStatsDetail extends SettingsPreferenceFragment mServiceMap.clear(); createDetails(); + setHasOptionsMenu(true); } @Override @@ -115,7 +117,8 @@ public class ProcessStatsDetail extends SettingsPreferenceFragment AppHeader.createAppHeader(this, mApp.mUiTargetApp != null ? mApp.mUiTargetApp.loadIcon(mPm) : new ColorDrawable(0), - mApp.mUiLabel, AppInfoWithHeader.getInfoIntent(this, mApp.mPackage)); + mApp.mUiLabel, mApp.mPackage.equals(Utils.OS_PKG) ? null + : AppInfoWithHeader.getInfoIntent(this, mApp.mPackage)); } @Override @@ -126,8 +129,8 @@ public class ProcessStatsDetail extends SettingsPreferenceFragment @Override public void onResume() { super.onResume(); - checkForceStop(); + checkForceStop(); updateRunningServices(); } @@ -173,55 +176,42 @@ public class ProcessStatsDetail extends SettingsPreferenceFragment LayoutPreference headerLayout = (LayoutPreference) findPreference(KEY_DETAILS_HEADER); - TextView avgUsed = (TextView) headerLayout.findViewById(R.id.memory_avg); - TextView maxUsed = (TextView) headerLayout.findViewById(R.id.memory_max); - avgUsed.setText(getString(R.string.memory_avg_desc, - Formatter.formatShortFileSize(getActivity(), - (long) (Math.max(mApp.mBgWeight, mApp.mRunWeight) * mWeightToRam)))); - maxUsed.setText(getString(R.string.memory_max_desc, - Formatter.formatShortFileSize(getActivity(), - (long) (Math.max(mApp.mMaxBgMem, mApp.mMaxRunMem) * 1024 * mTotalScale)))); - - mForceStopButton = (Button) headerLayout.findViewById(R.id.right_button); - mReportButton = (Button) headerLayout.findViewById(R.id.left_button); - - if (mApp.mEntries.get(0).mUid >= android.os.Process.FIRST_APPLICATION_UID) { - mForceStopButton.setEnabled(false); - mReportButton.setVisibility(View.INVISIBLE); - - mForceStopButton.setText(R.string.force_stop); - mForceStopButton.setTag(ACTION_FORCE_STOP); - mForceStopButton.setOnClickListener(this); - } else { - mReportButton.setVisibility(View.GONE); - mForceStopButton.setVisibility(View.GONE); - } - // TODO: Find way to share this code with ProcessStatsPreference. boolean statsForeground = mApp.mRunWeight > mApp.mBgWeight; - float avgRatio = (float) ((statsForeground ? mApp.mRunWeight : mApp.mBgWeight) - * mWeightToRam / mMaxMemoryUsage); - float maxRatio = (float) ((statsForeground ? mApp.mMaxRunMem : mApp.mMaxBgMem) - * mTotalScale * 1024 / mMaxMemoryUsage - avgRatio); - float remainingRatio = 1 - avgRatio - maxRatio; + double avgRam = (statsForeground ? mApp.mRunWeight : mApp.mBgWeight) * mWeightToRam; + float avgRatio = (float) (avgRam / mMaxMemoryUsage); + float remainingRatio = 1 - avgRatio; mColorBar = (LinearColorBar) headerLayout.findViewById(R.id.color_bar); Context context = getActivity(); - mColorBar.setColors(context.getColor(R.color.memory_avg_use), - context.getColor(R.color.memory_max_use), + mColorBar.setColors( context.getColor(R.color.memory_max_use), 0, context.getColor(R.color.memory_remaining)); - mColorBar.setRatios(avgRatio, maxRatio, remainingRatio); + mColorBar.setRatios(avgRatio, 0, remainingRatio); + ((TextView) headerLayout.findViewById(R.id.memory_state)).setText( + Formatter.formatShortFileSize(getContext(), (long) avgRam)); + + long duration = Math.max(mApp.mRunDuration, mApp.mBgDuration); + CharSequence frequency = ProcStatsPackageEntry.getFrequency(duration + / (float) mTotalTime, getActivity()); + findPreference(KEY_FREQUENCY).setSummary(frequency); + double max = Math.max(mApp.mMaxBgMem, mApp.mMaxRunMem) * mTotalScale * 1024; + findPreference(KEY_MAX_USAGE).setSummary( + Formatter.formatShortFileSize(getContext(), (long) max)); } - public void onClick(View v) { - doAction((Integer) v.getTag()); + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + mForceStop = menu.add(0, MENU_FORCE_STOP, 0, R.string.force_stop); + checkForceStop(); } - private void doAction(int action) { - switch (action) { - case ACTION_FORCE_STOP: + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case MENU_FORCE_STOP: killProcesses(); - break; + return true; } + return false; } final static Comparator<ProcStatsEntry> sEntryCompare = new Comparator<ProcStatsEntry>() { @@ -250,8 +240,7 @@ public class ProcessStatsDetail extends SettingsPreferenceFragment Collections.sort(entries, sEntryCompare); for (int ie = 0; ie < entries.size(); ie++) { ProcStatsEntry entry = entries.get(ie); - PreferenceCategory processPref = new PreferenceCategory(getActivity()); - processPref.setLayoutResource(R.layout.process_preference_category); + Preference processPref = new Preference(getActivity()); processPref.setTitle(entry.mLabel); long duration = Math.max(entry.mRunDuration, entry.mBgDuration); @@ -259,11 +248,10 @@ public class ProcessStatsDetail extends SettingsPreferenceFragment (long) (entry.mBgWeight * mWeightToRam)); String memoryString = Formatter.formatShortFileSize(getActivity(), memoryUse); CharSequence frequency = ProcStatsPackageEntry.getFrequency(duration - / (float)mTotalTime, getActivity()); + / (float) mTotalTime, getActivity()); processPref.setSummary( getString(R.string.memory_use_running_format, memoryString, frequency)); getPreferenceScreen().addPreference(processPref); - fillServicesSection(entry, processPref); } } @@ -423,12 +411,14 @@ public class ProcessStatsDetail extends SettingsPreferenceFragment am.forceStopPackage(ent.mPackages.get(j)); } } - checkForceStop(); } private void checkForceStop() { + if (mForceStop == null) { + return; + } if (mApp.mEntries.get(0).mUid < Process.FIRST_APPLICATION_UID) { - mForceStopButton.setEnabled(false); + mForceStop.setVisible(false); return; } boolean isStarted = false; @@ -437,7 +427,7 @@ public class ProcessStatsDetail extends SettingsPreferenceFragment for (int j=0; j<ent.mPackages.size(); j++) { String pkg = ent.mPackages.get(j); if (mDpm.packageHasActiveAdmins(pkg)) { - mForceStopButton.setEnabled(false); + mForceStop.setEnabled(false); return; } try { @@ -450,7 +440,7 @@ public class ProcessStatsDetail extends SettingsPreferenceFragment } } if (isStarted) { - mForceStopButton.setEnabled(true); + mForceStop.setVisible(true); } } } diff --git a/src/com/android/settings/applications/ProcessStatsPreference.java b/src/com/android/settings/applications/ProcessStatsPreference.java index ffbc560..48c6a9f 100644 --- a/src/com/android/settings/applications/ProcessStatsPreference.java +++ b/src/com/android/settings/applications/ProcessStatsPreference.java @@ -21,8 +21,8 @@ import android.content.pm.PackageManager; import android.graphics.drawable.ColorDrawable; import android.preference.Preference; import android.text.TextUtils; +import android.text.format.Formatter; import android.util.AttributeSet; -import android.util.Log; import android.view.View; import com.android.settings.R; @@ -30,11 +30,9 @@ import com.android.settings.R; public class ProcessStatsPreference extends Preference { private ProcStatsPackageEntry mEntry; - private final int mAvgColor; - private final int mMaxColor; + private final int mColor; private final int mRemainingColor; - private float mAvgRatio; - private float mMaxRatio; + private float mRatio; private float mRemainingRatio; public ProcessStatsPreference(Context context) { @@ -53,13 +51,12 @@ public class ProcessStatsPreference extends Preference { int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); setLayoutResource(R.layout.app_item_linear_color); - mAvgColor = context.getColor(R.color.memory_avg_use); - mMaxColor = context.getColor(R.color.memory_max_use); + mColor = context.getColor(R.color.memory_max_use); mRemainingColor = context.getColor(R.color.memory_remaining); } public void init(ProcStatsPackageEntry entry, PackageManager pm, double maxMemory, - double weightToRam, double totalScale) { + double weightToRam, double totalScale, boolean avg) { mEntry = entry; setTitle(TextUtils.isEmpty(entry.mUiLabel) ? entry.mPackage : entry.mUiLabel); if (entry.mUiTargetApp != null) { @@ -68,13 +65,11 @@ public class ProcessStatsPreference extends Preference { setIcon(new ColorDrawable(0)); } boolean statsForeground = entry.mRunWeight > entry.mBgWeight; - setSummary(entry.mRunDuration > entry.mBgDuration ? entry.getRunningFrequency(getContext()) - : entry.getBackgroundFrequency(getContext())); - mAvgRatio = (float) ((statsForeground ? entry.mRunWeight : entry.mBgWeight) - * weightToRam / maxMemory); - mMaxRatio = (float) ((statsForeground ? entry.mMaxRunMem : entry.mMaxBgMem) - * totalScale * 1024 / maxMemory - mAvgRatio); - mRemainingRatio = 1 - mAvgRatio - mMaxRatio; + double amount = avg ? (statsForeground ? entry.mRunWeight : entry.mBgWeight) * weightToRam + : (statsForeground ? entry.mMaxRunMem : entry.mMaxBgMem) * totalScale * 1024; + setSummary(Formatter.formatShortFileSize(getContext(), (long) amount)); + mRatio = (float) (amount / maxMemory); + mRemainingRatio = 1 - mRatio; } public ProcStatsPackageEntry getEntry() { @@ -86,7 +81,7 @@ public class ProcessStatsPreference extends Preference { super.onBindView(view); LinearColorBar linearColorBar = (LinearColorBar) view.findViewById(R.id.linear_color_bar); - linearColorBar.setColors(mAvgColor, mMaxColor, mRemainingColor); - linearColorBar.setRatios(mAvgRatio, mMaxRatio, mRemainingRatio); + linearColorBar.setColors(mColor, mColor, mRemainingColor); + linearColorBar.setRatios(mRatio, 0, mRemainingRatio); } } diff --git a/src/com/android/settings/applications/ProcessStatsSummary.java b/src/com/android/settings/applications/ProcessStatsSummary.java new file mode 100644 index 0000000..068cb43 --- /dev/null +++ b/src/com/android/settings/applications/ProcessStatsSummary.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.applications; + +import android.content.Context; +import android.os.Bundle; +import android.preference.Preference; +import android.preference.Preference.OnPreferenceClickListener; +import android.text.format.Formatter; +import android.widget.TextView; + +import com.android.settings.InstrumentedFragment; +import com.android.settings.R; +import com.android.settings.Utils; +import com.android.settings.applications.ProcStatsData.MemInfo; + +public class ProcessStatsSummary extends ProcessStatsBase implements OnPreferenceClickListener { + + private static final String KEY_STATUS_HEADER = "status_header"; + + private static final String KEY_PERFORMANCE = "performance"; + private static final String KEY_TOTAL_MEMORY = "total_memory"; + private static final String KEY_AVERAGY_USED = "average_used"; + private static final String KEY_FREE = "free"; + private static final String KEY_APP_LIST = "apps_list"; + + private LinearColorBar mColors; + private LayoutPreference mHeader; + private TextView mMemStatus; + + private Preference mPerformance; + private Preference mTotalMemory; + private Preference mAverageUsed; + private Preference mFree; + private Preference mAppListPreference; + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + addPreferencesFromResource(R.xml.process_stats_summary); + mHeader = (LayoutPreference) findPreference(KEY_STATUS_HEADER); + mMemStatus = (TextView) mHeader.findViewById(R.id.memory_state); + mColors = (LinearColorBar) mHeader.findViewById(R.id.color_bar); + + mPerformance = findPreference(KEY_PERFORMANCE); + mTotalMemory = findPreference(KEY_TOTAL_MEMORY); + mAverageUsed = findPreference(KEY_AVERAGY_USED); + mFree = findPreference(KEY_FREE); + mAppListPreference = findPreference(KEY_APP_LIST); + mAppListPreference.setOnPreferenceClickListener(this); + } + + @Override + public void refreshUi() { + Context context = getContext(); + int memColor = context.getColor(R.color.running_processes_apps_ram); + mColors.setColors(memColor, memColor, context.getColor(R.color.running_processes_free_ram)); + + MemInfo memInfo = mStatsManager.getMemInfo(); + + double usedRam = memInfo.realUsedRam; + double totalRam = memInfo.realTotalRam; + double freeRam = memInfo.realFreeRam; + String usedString = Formatter.formatShortFileSize(context, (long) usedRam); + String totalString = Formatter.formatShortFileSize(context, (long) totalRam); + String freeString = Formatter.formatShortFileSize(context, (long) freeRam); + CharSequence memString; + CharSequence[] memStatesStr = getResources().getTextArray(R.array.ram_states); + int memState = mStatsManager.getMemState(); + if (memState >= 0 && memState < memStatesStr.length - 1) { + memString = memStatesStr[memState]; + } else { + memString = memStatesStr[memStatesStr.length - 1]; + } + mMemStatus.setText(usedString); + float usedRatio = (float)(usedRam / (freeRam + usedRam)); + mColors.setRatios(usedRatio, 0, 1 - usedRatio); + + mPerformance.setSummary(memString); + mTotalMemory.setSummary(totalString); + mAverageUsed.setSummary(Utils.formatPercentage((long) usedRam, (long) totalRam)); + mFree.setSummary(freeString); + String durationString = getString(sDurationLabels[mDurationIndex]); + int numApps = mStatsManager.getEntries().size(); + mAppListPreference.setSummary(getResources().getQuantityString( + R.plurals.memory_usage_apps_summary, numApps, numApps, durationString)); + } + + @Override + protected int getMetricsCategory() { + return InstrumentedFragment.PROCESS_STATS_SUMMARY; + } + + @Override + public boolean onPreferenceClick(Preference preference) { + if (preference == mAppListPreference) { + Bundle args = new Bundle(); + args.putBoolean(ARG_TRANSFER_STATS, true); + args.putInt(ARG_DURATION_INDEX, mDurationIndex); + mStatsManager.xferStats(); + startFragment(this, ProcessStatsUi.class.getName(), R.string.app_memory_use, 0, args); + return true; + } + return false; + } + +} diff --git a/src/com/android/settings/applications/ProcessStatsUi.java b/src/com/android/settings/applications/ProcessStatsUi.java index 3dc0661..a4ecbdd 100644 --- a/src/com/android/settings/applications/ProcessStatsUi.java +++ b/src/com/android/settings/applications/ProcessStatsUi.java @@ -16,171 +16,89 @@ package com.android.settings.applications; -import android.app.AlertDialog; import android.content.Context; -import android.content.DialogInterface; import android.content.pm.PackageManager; import android.os.Bundle; import android.preference.Preference; import android.preference.PreferenceGroup; import android.preference.PreferenceScreen; -import android.text.format.Formatter; import android.util.Log; import android.util.TimeUtils; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; -import android.widget.TextView; import com.android.internal.app.ProcessStats; import com.android.internal.logging.MetricsLogger; -import com.android.settings.InstrumentedPreferenceFragment; import com.android.settings.R; import com.android.settings.SettingsActivity; -import com.android.settings.Utils; import com.android.settings.applications.ProcStatsData.MemInfo; import java.util.Collections; import java.util.Comparator; import java.util.List; -public class ProcessStatsUi extends InstrumentedPreferenceFragment { - private static final String MEM_REGION = "mem_region"; - private static final String STATS_TYPE = "stats_type"; - private static final String USE_USS = "use_uss"; - private static final String SHOW_SYSTEM = "show_system"; - private static final String SHOW_PERCENTAGE = "show_percentage"; - private static final String DURATION = "duration"; +public class ProcessStatsUi extends ProcessStatsBase { static final String TAG = "ProcessStatsUi"; static final boolean DEBUG = false; private static final String KEY_APP_LIST = "app_list"; - private static final String KEY_STATUS_HEADER = "status_header"; - private static final int NUM_DURATIONS = 4; - - private static final int MENU_STATS_REFRESH = Menu.FIRST; - private static final int MENU_DURATION = Menu.FIRST + 1; - private static final int MENU_SHOW_PERCENTAGE = MENU_DURATION + NUM_DURATIONS; - private static final int MENU_SHOW_SYSTEM = MENU_SHOW_PERCENTAGE + 1; - private static final int MENU_USE_USS = MENU_SHOW_SYSTEM + 1; - private static final int MENU_TYPE_BACKGROUND = MENU_USE_USS + 1; - private static final int MENU_TYPE_FOREGROUND = MENU_TYPE_BACKGROUND + 1; - private static final int MENU_TYPE_CACHED = MENU_TYPE_FOREGROUND + 1; - - static final int MAX_ITEMS_TO_LIST = 60; - - final static Comparator<ProcStatsPackageEntry> sPackageEntryCompare - = new Comparator<ProcStatsPackageEntry>() { - @Override - public int compare(ProcStatsPackageEntry lhs, ProcStatsPackageEntry rhs) { - double rhsWeight = Math.max(rhs.mRunWeight, rhs.mBgWeight); - double lhsWeight = Math.max(lhs.mRunWeight, lhs.mBgWeight); - if (lhsWeight == rhsWeight) { - return 0; - } - return lhsWeight < rhsWeight ? 1 : -1; - } - }; - - private boolean mShowPercentage; - private boolean mShowSystem; - private boolean mUseUss; - private int mMemRegion; - - private MenuItem[] mDurationMenus = new MenuItem[NUM_DURATIONS]; - private MenuItem mShowPercentageMenu; - private MenuItem mShowSystemMenu; - private MenuItem mUseUssMenu; - private MenuItem mTypeBackgroundMenu; - private MenuItem mTypeForegroundMenu; - private MenuItem mTypeCachedMenu; + private static final int MENU_SHOW_AVG = Menu.FIRST; + private static final int MENU_SHOW_MAX = Menu.FIRST + 1; private PreferenceGroup mAppListGroup; - private TextView mMemStatus; - - private long[] mMemTimes = new long[ProcessStats.ADJ_MEM_FACTOR_COUNT]; - private LinearColorBar mColors; - private TextView mMemUsed; - private LayoutPreference mHeader; private PackageManager mPm; - private long memTotalTime; - - private int mStatsType; - - // The actual duration value to use for each duration option. Note these - // are lower than the actual duration, since our durations are computed in - // batches of 3 hours so we want to allow the time we use to be slightly - // smaller than the actual time selected instead of bumping up to 3 hours - // beyond it. - private static final long DURATION_QUANTUM = ProcessStats.COMMIT_PERIOD; - private static long[] sDurations = new long[] { - 3*60*60*1000 - DURATION_QUANTUM/2, 6*60*60*1000 - DURATION_QUANTUM/2, - 12*60*60*1000 - DURATION_QUANTUM/2, 24*60*60*1000 - DURATION_QUANTUM/2 - }; - private static int[] sDurationLabels = new int[] { - R.string.menu_duration_3h, R.string.menu_duration_6h, - R.string.menu_duration_12h, R.string.menu_duration_1d - }; - private ProcStatsData mStatsManager; - private double mMaxMemoryUsage; + private boolean mShowMax; + private MenuItem mMenuAvg; + private MenuItem mMenuMax; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); - mStatsManager = new ProcStatsData(getActivity(), icicle != null); - mPm = getActivity().getPackageManager(); - addPreferencesFromResource(R.xml.process_stats_summary); + addPreferencesFromResource(R.xml.process_stats_ui); mAppListGroup = (PreferenceGroup) findPreference(KEY_APP_LIST); - mHeader = (LayoutPreference)mAppListGroup.findPreference(KEY_STATUS_HEADER); - mMemStatus = (TextView) mHeader.findViewById(R.id.memory_state); - mColors = (LinearColorBar) mHeader.findViewById(R.id.color_bar); - mMemUsed = (TextView) mHeader.findViewById(R.id.memory_used); - mStatsManager.setDuration(icicle != null - ? icicle.getLong(DURATION, sDurations[0]) : sDurations[0]); - mShowPercentage = icicle != null ? icicle.getBoolean(SHOW_PERCENTAGE) : true; - mShowSystem = icicle != null ? icicle.getBoolean(SHOW_SYSTEM) : false; - mUseUss = icicle != null ? icicle.getBoolean(USE_USS) : false; - mStatsType = icicle != null ? icicle.getInt(STATS_TYPE, MENU_TYPE_BACKGROUND) - : MENU_TYPE_BACKGROUND; - mMemRegion = icicle != null ? icicle.getInt(MEM_REGION, LinearColorBar.REGION_GREEN) - : LinearColorBar.REGION_GREEN; setHasOptionsMenu(true); } @Override - protected int getMetricsCategory() { - return MetricsLogger.APPLICATIONS_PROCESS_STATS_UI; + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + mMenuAvg = menu.add(0, MENU_SHOW_AVG, 0, R.string.sort_avg_use); + mMenuMax = menu.add(0, MENU_SHOW_MAX, 0, R.string.sort_max_use); + updateMenu(); } @Override - public void onResume() { - super.onResume(); - mStatsManager.refreshStats(false); - refreshUi(); + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case MENU_SHOW_AVG: + case MENU_SHOW_MAX: + mShowMax = !mShowMax; + refreshUi(); + updateMenu(); + return true; + } + return super.onOptionsItemSelected(item); + } + + private void updateMenu() { + mMenuMax.setVisible(!mShowMax); + mMenuAvg.setVisible(mShowMax); } @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putLong(DURATION, mStatsManager.getDuration()); - outState.putBoolean(SHOW_PERCENTAGE, mShowPercentage); - outState.putBoolean(SHOW_SYSTEM, mShowSystem); - outState.putBoolean(USE_USS, mUseUss); - outState.putInt(STATS_TYPE, mStatsType); - outState.putInt(MEM_REGION, mMemRegion); + protected int getMetricsCategory() { + return MetricsLogger.APPLICATIONS_PROCESS_STATS_UI; } @Override - public void onDestroy() { - super.onDestroy(); - if (getActivity().isChangingConfigurations()) { - mStatsManager.xferStats(); - } + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); } @Override @@ -192,142 +110,19 @@ public class ProcessStatsUi extends InstrumentedPreferenceFragment { ProcessStatsPreference pgp = (ProcessStatsPreference) preference; Bundle args = new Bundle(); args.putParcelable(ProcessStatsDetail.EXTRA_PACKAGE_ENTRY, pgp.getEntry()); - args.putBoolean(ProcessStatsDetail.EXTRA_USE_USS, mUseUss); + MemInfo memInfo = mStatsManager.getMemInfo(); args.putDouble(ProcessStatsDetail.EXTRA_WEIGHT_TO_RAM, - mStatsManager.getMemInfo().weightToRam); - args.putLong(ProcessStatsDetail.EXTRA_TOTAL_TIME, memTotalTime); - args.putDouble(ProcessStatsDetail.EXTRA_MAX_MEMORY_USAGE, mMaxMemoryUsage); - args.putDouble(ProcessStatsDetail.EXTRA_TOTAL_SCALE, mStatsManager.getMemInfo().totalScale); + memInfo.weightToRam); + args.putLong(ProcessStatsDetail.EXTRA_TOTAL_TIME, memInfo.memTotalTime); + args.putDouble(ProcessStatsDetail.EXTRA_MAX_MEMORY_USAGE, + memInfo.usedWeight * memInfo.weightToRam); + args.putDouble(ProcessStatsDetail.EXTRA_TOTAL_SCALE, memInfo.totalScale); ((SettingsActivity) getActivity()).startPreferencePanel( ProcessStatsDetail.class.getName(), args, R.string.details_title, null, null, 0); return super.onPreferenceTreeClick(preferenceScreen, preference); } - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - MenuItem refresh = menu.add(0, MENU_STATS_REFRESH, 0, R.string.menu_stats_refresh) - .setIcon(R.drawable.ic_menu_refresh_holo_dark) - .setAlphabeticShortcut('r'); - refresh.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM | - MenuItem.SHOW_AS_ACTION_WITH_TEXT); - menu.add(0, MENU_DURATION, 0, R.string.menu_proc_stats_duration); - - // Hide these for now, until their need is determined. -// mShowPercentageMenu = menu.add(0, MENU_SHOW_PERCENTAGE, 0, R.string.menu_show_percentage) -// .setAlphabeticShortcut('p') -// .setCheckable(true); -// mShowSystemMenu = menu.add(0, MENU_SHOW_SYSTEM, 0, R.string.menu_show_system) -// .setAlphabeticShortcut('s') -// .setCheckable(true); -// mUseUssMenu = menu.add(0, MENU_USE_USS, 0, R.string.menu_use_uss) -// .setAlphabeticShortcut('u') -// .setCheckable(true); -// subMenu = menu.addSubMenu(R.string.menu_proc_stats_type); -// mTypeBackgroundMenu = subMenu.add(0, MENU_TYPE_BACKGROUND, 0, -// R.string.menu_proc_stats_type_background) -// .setAlphabeticShortcut('b') -// .setCheckable(true); -// mTypeForegroundMenu = subMenu.add(0, MENU_TYPE_FOREGROUND, 0, -// R.string.menu_proc_stats_type_foreground) -// .setAlphabeticShortcut('f') -// .setCheckable(true); -// mTypeCachedMenu = subMenu.add(0, MENU_TYPE_CACHED, 0, -// R.string.menu_proc_stats_type_cached) -// .setCheckable(true); - - updateMenus(); - } - - void updateMenus() { - int closestIndex = 0; - long closestDelta = Math.abs(sDurations[0] - mStatsManager.getDuration()); - for (int i = 1; i < NUM_DURATIONS; i++) { - long delta = Math.abs(sDurations[i] - mStatsManager.getDuration()); - if (delta < closestDelta) { - closestDelta = delta; - closestIndex = i; - } - } - for (int i=0; i<NUM_DURATIONS; i++) { - if (mDurationMenus[i] != null) { - mDurationMenus[i].setChecked(i == closestIndex); - } - } - mStatsManager.setDuration(sDurations[closestIndex]); - if (mShowPercentageMenu != null) { - mShowPercentageMenu.setChecked(mShowPercentage); - } - if (mShowSystemMenu != null) { - mShowSystemMenu.setChecked(mShowSystem); - mShowSystemMenu.setEnabled(mStatsType == MENU_TYPE_BACKGROUND); - } - if (mUseUssMenu != null) { - mUseUssMenu.setChecked(mUseUss); - } - if (mTypeBackgroundMenu != null) { - mTypeBackgroundMenu.setChecked(mStatsType == MENU_TYPE_BACKGROUND); - } - if (mTypeForegroundMenu != null) { - mTypeForegroundMenu.setChecked(mStatsType == MENU_TYPE_FOREGROUND); - } - if (mTypeCachedMenu != null) { - mTypeCachedMenu.setChecked(mStatsType == MENU_TYPE_CACHED); - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case MENU_STATS_REFRESH: - mStatsManager.refreshStats(false); - refreshUi(); - return true; - case MENU_SHOW_PERCENTAGE: - mShowPercentage = !mShowPercentage; - refreshUi(); - return true; - case MENU_SHOW_SYSTEM: - mShowSystem = !mShowSystem; - refreshUi(); - return true; - case MENU_USE_USS: - mUseUss = !mUseUss; - refreshUi(); - return true; - case MENU_TYPE_BACKGROUND: - case MENU_TYPE_FOREGROUND: - case MENU_TYPE_CACHED: - mStatsType = item.getItemId(); - if (mStatsType == MENU_TYPE_FOREGROUND) { - mStatsManager.setStats(FOREGROUND_PROC_STATES); - } else if (mStatsType == MENU_TYPE_CACHED) { - mStatsManager.setStats(CACHED_PROC_STATES); - } else { - mStatsManager.setStats(mShowSystem ? BACKGROUND_AND_SYSTEM_PROC_STATES - : ProcessStats.BACKGROUND_PROC_STATES); - } - refreshUi(); - return true; - case MENU_DURATION: - CharSequence[] durations = new CharSequence[sDurationLabels.length]; - for (int i = 0; i < sDurationLabels.length; i++) { - durations[i] = getString(sDurationLabels[i]); - } - new AlertDialog.Builder(getContext()) - .setTitle(item.getTitle()) - .setItems(durations, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - mStatsManager.setDuration(sDurations[which]); - refreshUi(); - } - }).show(); - return true; - } - return false; - } - /** * All states in which we consider a process to be actively running (rather than * something that can be freely killed to reclaim RAM). Note this also includes @@ -358,103 +153,66 @@ public class ProcessStatsUi extends InstrumentedPreferenceFragment { return sb.toString(); } - private void refreshUi() { - updateMenus(); - + public void refreshUi() { mAppListGroup.removeAll(); mAppListGroup.setOrderingAsAdded(false); - mHeader.setOrder(-1); - mAppListGroup.addPreference(mHeader); - - final long elapsedTime = mStatsManager.getElapsedTime(); + mAppListGroup.setTitle(mShowMax ? R.string.maximum_memory_use + : R.string.average_memory_use); final Context context = getActivity(); - // TODO: More Colors. - - // For computing the ratio to show, we want to count the baseline cached RAM we - // need (at which point we start killing processes) as used RAM, so that if we - // reach the point of thrashing due to no RAM for any background processes we - // report that as RAM being full. To do this, we need to first convert the weights - // back to actual RAM... and since the RAM values we compute here won't exactly - // match the real physical RAM, scale those to the actual physical RAM. No problem! MemInfo memInfo = mStatsManager.getMemInfo(); - memTotalTime = memInfo.memTotalTime; - double usedRam = memInfo.realUsedRam; - double totalRam = memInfo.realTotalRam; - double freeRam = memInfo.realFreeRam; - String durationString = Utils.formatElapsedTime(context, elapsedTime, false); - String usedString = Formatter.formatShortFileSize(context, (long) usedRam); - String totalString = Formatter.formatShortFileSize(context, (long) totalRam); - CharSequence memString; - CharSequence[] memStatesStr = getResources().getTextArray(R.array.ram_states); - int memState = mStatsManager.getMemState(); - int memColor; - if (memState >= 0 && memState < memStatesStr.length) { - memString = memStatesStr[memState]; - memColor = getResources().getIntArray(R.array.ram_colors)[memState]; - } else { - memString = "?"; - memColor = context.getColor(R.color.running_processes_apps_ram); - } - mColors.setColors(memColor, memColor, context.getColor(R.color.running_processes_free_ram)); - if (mShowPercentage) { - mMemUsed.setText(context.getString( - R.string.process_stats_total_duration_percentage, - Utils.formatPercentage((long) usedRam, (long) totalRam), - durationString)); - } else { - mMemUsed.setText(context.getString(R.string.process_stats_total_duration, - usedString, totalString, durationString)); - } - mMemStatus.setText(memString); - float usedRatio = (float)(usedRam / (freeRam + usedRam)); - mColors.setRatios(usedRatio, 0, 1-usedRatio); - List<ProcStatsPackageEntry> pkgEntries = mStatsManager.getEntries(); // Update everything and get the absolute maximum of memory usage for scaling. - mMaxMemoryUsage = 0; for (int i=0, N=pkgEntries.size(); i<N; i++) { ProcStatsPackageEntry pkg = pkgEntries.get(i); pkg.updateMetrics(); - double maxMem = Math.max(pkg.mMaxBgMem, pkg.mMaxRunMem) * 1024 * memInfo.totalScale; - if (maxMem > mMaxMemoryUsage) { - mMaxMemoryUsage = maxMem; - } } - Collections.sort(pkgEntries, sPackageEntryCompare); + Collections.sort(pkgEntries, mShowMax ? sMaxPackageEntryCompare : sPackageEntryCompare); // Now collect the per-process information into applications, so that applications // running as multiple processes will have only one entry representing all of them. if (DEBUG) Log.d(TAG, "-------------------- BUILDING UI"); - // Find where we should stop. Because we have two properties we are looking at, - // we need to go from the back looking for the first place either holds. - int end = pkgEntries.size()-1; - while (end >= 0) { - ProcStatsPackageEntry pkg = pkgEntries.get(end); - final double percentOfWeight = (pkg.mRunWeight - / (memInfo.totalRam / memInfo.weightToRam)) * 100; - final double percentOfTime = (((double) pkg.mRunDuration) / memTotalTime) * 100; - if (percentOfWeight >= .01 || percentOfTime >= 25) { - break; - } - end--; - } - for (int i=0; i <= end; i++) { + double maxMemory = mShowMax ? memInfo.realTotalRam + : memInfo.usedWeight * memInfo.weightToRam; + for (int i = 0; i < pkgEntries.size(); i++) { ProcStatsPackageEntry pkg = pkgEntries.get(i); ProcessStatsPreference pref = new ProcessStatsPreference(context); pkg.retrieveUiData(context, mPm); - pref.init(pkg, mPm, mMaxMemoryUsage, memInfo.weightToRam, memInfo.totalScale); + pref.init(pkg, mPm, maxMemory, memInfo.weightToRam, + memInfo.totalScale, !mShowMax); pref.setOrder(i); mAppListGroup.addPreference(pref); - if (mAppListGroup.getPreferenceCount() > (MAX_ITEMS_TO_LIST+1)) { - if (DEBUG) Log.d(TAG, "Done with UI, hit item limit!"); - break; - } } } + + final static Comparator<ProcStatsPackageEntry> sPackageEntryCompare + = new Comparator<ProcStatsPackageEntry>() { + @Override + public int compare(ProcStatsPackageEntry lhs, ProcStatsPackageEntry rhs) { + double rhsWeight = Math.max(rhs.mRunWeight, rhs.mBgWeight); + double lhsWeight = Math.max(lhs.mRunWeight, lhs.mBgWeight); + if (lhsWeight == rhsWeight) { + return 0; + } + return lhsWeight < rhsWeight ? 1 : -1; + } + }; + + final static Comparator<ProcStatsPackageEntry> sMaxPackageEntryCompare + = new Comparator<ProcStatsPackageEntry>() { + @Override + public int compare(ProcStatsPackageEntry lhs, ProcStatsPackageEntry rhs) { + double rhsMax = Math.max(rhs.mMaxBgMem, rhs.mMaxRunMem); + double lhsMax = Math.max(lhs.mMaxBgMem, lhs.mMaxRunMem); + if (lhsMax == rhsMax) { + return 0; + } + return lhsMax < rhsMax ? 1 : -1; + } + }; } diff --git a/src/com/android/settings/applications/SpacePreference.java b/src/com/android/settings/applications/SpacePreference.java new file mode 100644 index 0000000..deaa987 --- /dev/null +++ b/src/com/android/settings/applications/SpacePreference.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.applications; + +import android.content.Context; +import android.content.res.TypedArray; +import android.preference.Preference; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewGroup.LayoutParams; +import android.widget.Space; + +/** + * A blank preference that has a specified height by android:layout_height. It can be used + * to fine tune screens that combine custom layouts and standard preferences. + */ +public class SpacePreference extends Preference { + + private int mHeight; + + public SpacePreference(Context context, AttributeSet attrs) { + this(context, attrs, com.android.internal.R.attr.preferenceStyle); + } + + public SpacePreference(Context context, AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); + } + + public SpacePreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + + final TypedArray a = context.obtainStyledAttributes(attrs, + new int[] { com.android.internal.R.attr.layout_height }, defStyleAttr, defStyleRes); + mHeight = a.getDimensionPixelSize(0, 0); + } + + public void setHeight(int height) { + mHeight = height; + } + + @Override + protected View onCreateView(ViewGroup parent) { + return new Space(getContext()); + } + + @Override + protected void onBindView(View view) { + super.onBindView(view); + + LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, mHeight); + view.setLayoutParams(params); + } + +} |