summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason Monk <jmonk@android.com>2015-05-21 15:24:37 -0400
committerJason Monk <jmonk@google.com>2015-05-26 11:41:37 -0400
commitbeb171d2e50f93b5fb78d73b372a4981e13e04ff (patch)
tree23e2f38cf7954e0236504e3077880ece287bca6f
parent85a72a9088d6be0cd0fda03d0e80a24a8fcaa4cb (diff)
downloadpackages_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
-rwxr-xr-xres/layout/app_item_linear_color.xml27
-rw-r--r--res/layout/horizontal_preference.xml2
-rw-r--r--res/layout/proc_stats_ui.xml22
-rwxr-xr-xres/layout/single_button_panel.xml4
-rw-r--r--res/values/arrays.xml10
-rw-r--r--res/values/strings.xml45
-rw-r--r--res/xml/advanced_apps.xml4
-rw-r--r--res/xml/app_memory_settings.xml22
-rw-r--r--res/xml/app_storage_settings.xml4
-rw-r--r--res/xml/dashboard_categories.xml6
-rw-r--r--res/xml/process_stats_summary.xml38
-rw-r--r--res/xml/process_stats_ui.xml25
-rw-r--r--src/com/android/settings/InstrumentedFragment.java3
-rw-r--r--src/com/android/settings/Utils.java2
-rw-r--r--src/com/android/settings/applications/LayoutPreference.java1
-rw-r--r--src/com/android/settings/applications/ProcStatsData.java12
-rw-r--r--src/com/android/settings/applications/ProcStatsPackageEntry.java18
-rw-r--r--src/com/android/settings/applications/ProcessStatsBase.java127
-rw-r--r--src/com/android/settings/applications/ProcessStatsDetail.java110
-rw-r--r--src/com/android/settings/applications/ProcessStatsPreference.java29
-rw-r--r--src/com/android/settings/applications/ProcessStatsSummary.java121
-rw-r--r--src/com/android/settings/applications/ProcessStatsUi.java386
-rw-r--r--src/com/android/settings/applications/SpacePreference.java68
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 (&#x0025;)</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);
+ }
+
+}