Allow tapping on memory status regions to filter proc stats.

Change-Id: Iade56907df648a95600919578154635c49ac9dce
diff --git a/res/layout/power_usage_detail_item_text.xml b/res/layout/power_usage_detail_item_text.xml
index e4aee1b..9c9c72c 100644
--- a/res/layout/power_usage_detail_item_text.xml
+++ b/res/layout/power_usage_detail_item_text.xml
@@ -31,7 +31,8 @@
         android:layout_toStartOf="@+id/value"
         android:layout_marginBottom="4dip"
         android:layout_marginTop="4dip"
-        android:layout_marginStart="4dip" />
+        android:layout_marginStart="4dip"
+        android:layout_marginEnd="4dip"/>
     <TextView
         android:id="@+id/value"
         android:layout_width="wrap_content"
diff --git a/res/layout/preference_linearcolor.xml b/res/layout/preference_linearcolor.xml
index bbaf7a1..d3a2603 100644
--- a/res/layout/preference_linearcolor.xml
+++ b/res/layout/preference_linearcolor.xml
@@ -14,17 +14,21 @@
      limitations under the License.
 -->
 
-<com.android.settings.applications.LinearColorBar
-        xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:minHeight="?android:attr/listPreferredItemHeight"
-    android:gravity="center_vertical"
-    android:id="@+android:id/linear_color_bar"
-    android:paddingEnd="?android:attr/scrollbarSize"
-    android:textAppearance="?android:attr/textAppearanceMedium"
-    android:shadowRadius="4"
-    android:shadowColor="?android:attr/colorBackground"
-    android:shadowDx="2"
-    android:shadowDy="2">
-</com.android.settings.applications.LinearColorBar>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="?android:attr/listPreferredItemHeight"
+        android:paddingEnd="?android:attr/scrollbarSize">
+    <com.android.settings.applications.LinearColorBar
+        android:id="@+android:id/linear_color_bar"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_marginTop="16dp"
+        android:layout_marginBottom="16dp"
+        android:gravity="center_vertical"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:shadowRadius="4"
+        android:shadowColor="?android:attr/colorBackground"
+        android:shadowDx="2"
+        android:shadowDy="2">
+    </com.android.settings.applications.LinearColorBar>
+</FrameLayout>
\ No newline at end of file
diff --git a/src/com/android/settings/applications/LinearColorBar.java b/src/com/android/settings/applications/LinearColorBar.java
index 8343595..f374c29 100644
--- a/src/com/android/settings/applications/LinearColorBar.java
+++ b/src/com/android/settings/applications/LinearColorBar.java
@@ -12,12 +12,15 @@
 import android.graphics.Shader;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
+import android.view.MotionEvent;
 import android.widget.LinearLayout;
 
 public class LinearColorBar extends LinearLayout {
     static final int LEFT_COLOR = 0xff0099cc;
     static final int MIDDLE_COLOR = 0xff0099cc;
     static final int RIGHT_COLOR = 0xff888888;
+    static final int GRAY_COLOR = 0xff555555;
+    static final int WHITE_COLOR = 0xffffffff;
 
     private float mRedRatio;
     private float mYellowRatio;
@@ -30,17 +33,32 @@
     private boolean mShowIndicator = true;
     private boolean mShowingGreen;
 
+    private OnRegionTappedListener mOnRegionTappedListener;
+    private int mColoredRegions = REGION_RED | REGION_YELLOW | REGION_GREEN;
+
     final Rect mRect = new Rect();
     final Paint mPaint = new Paint();
 
     int mLastInterestingLeft, mLastInterestingRight;
     int mLineWidth;
 
+    int mLastLeftDiv, mLastRightDiv;
+    int mLastRegion;
+
     final Path mColorPath = new Path();
     final Path mEdgePath = new Path();
     final Paint mColorGradientPaint = new Paint();
     final Paint mEdgeGradientPaint = new Paint();
 
+    public static final int REGION_RED = 1<<0;
+    public static final int REGION_YELLOW = 1<<1;
+    public static final int REGION_GREEN = 1<<2;
+    public static final int REGION_ALL = REGION_RED | REGION_YELLOW | REGION_GREEN;
+
+    public interface OnRegionTappedListener {
+        public void onRegionTapped(int region);
+    }
+
     public LinearColorBar(Context context, AttributeSet attrs) {
         super(context, attrs);
         setWillNotDraw(false);
@@ -55,6 +73,18 @@
         
     }
 
+    public void setOnRegionTappedListener(OnRegionTappedListener listener) {
+        if (listener != mOnRegionTappedListener) {
+            mOnRegionTappedListener = listener;
+            setClickable(listener != null);
+        }
+    }
+
+    public void setColoredRegions(int regions) {
+        mColoredRegions = regions;
+        invalidate();
+    }
+
     public void setRatios(float red, float yellow, float green) {
         mRedRatio = red;
         mYellowRatio = yellow;
@@ -110,6 +140,50 @@
     }
 
     @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        if (mOnRegionTappedListener != null) {
+            switch (event.getAction()) {
+                case MotionEvent.ACTION_DOWN: {
+                    final int x = (int) event.getX();
+                    if (x < mLastLeftDiv) {
+                        mLastRegion = REGION_RED;
+                    } else if (x < mLastRightDiv) {
+                        mLastRegion = REGION_YELLOW;
+                    } else {
+                        mLastRegion = REGION_GREEN;
+                    }
+                    invalidate();
+                } break;
+            }
+        }
+        return super.onTouchEvent(event);
+    }
+
+    @Override
+    protected void dispatchSetPressed(boolean pressed) {
+        invalidate();
+    }
+
+    @Override
+    public boolean performClick() {
+        if (mOnRegionTappedListener != null && mLastRegion != 0) {
+            mOnRegionTappedListener.onRegionTapped(mLastRegion);
+            mLastRegion = 0;
+        }
+        return super.performClick();
+    }
+
+    private int pickColor(int color, int region) {
+        if (isPressed() && (mLastRegion&region) != 0) {
+            return WHITE_COLOR;
+        }
+        if ((mColoredRegions&region) == 0) {
+            return GRAY_COLOR;
+        }
+        return color;
+    }
+
+    @Override
     protected void onDraw(Canvas canvas) {
         super.onDraw(canvas);
 
@@ -168,18 +242,21 @@
         if (left < right) {
             mRect.left = left;
             mRect.right = right;
-            mPaint.setColor(mLeftColor);
+            mPaint.setColor(pickColor(mLeftColor, REGION_RED));
             canvas.drawRect(mRect, mPaint);
             width -= (right-left);
             left = right;
         }
 
+        mLastLeftDiv = right;
+        mLastRightDiv = right2;
+
         right = right2;
 
         if (left < right) {
             mRect.left = left;
             mRect.right = right;
-            mPaint.setColor(mMiddleColor);
+            mPaint.setColor(pickColor(mMiddleColor, REGION_YELLOW));
             canvas.drawRect(mRect, mPaint);
             width -= (right-left);
             left = right;
@@ -190,7 +267,7 @@
         if (left < right) {
             mRect.left = left;
             mRect.right = right;
-            mPaint.setColor(mRightColor);
+            mPaint.setColor(pickColor(mRightColor, REGION_GREEN));
             canvas.drawRect(mRect, mPaint);
         }
     }
diff --git a/src/com/android/settings/applications/LinearColorPreference.java b/src/com/android/settings/applications/LinearColorPreference.java
index 6d9a399..8d9fb72 100644
--- a/src/com/android/settings/applications/LinearColorPreference.java
+++ b/src/com/android/settings/applications/LinearColorPreference.java
@@ -25,6 +25,8 @@
     float mRedRatio;
     float mYellowRatio;
     float mGreenRatio;
+    int mColoredRegions = LinearColorBar.REGION_ALL;
+    LinearColorBar.OnRegionTappedListener mOnRegionTappedListener;
 
     public LinearColorPreference(Context context) {
         super(context);
@@ -38,6 +40,16 @@
         notifyChanged();
     }
 
+    public void setOnRegionTappedListener(LinearColorBar.OnRegionTappedListener listener) {
+        mOnRegionTappedListener = listener;
+        notifyChanged();
+    }
+
+    public void setColoredRegions(int regions) {
+        mColoredRegions = regions;
+        notifyChanged();
+    }
+
     @Override
     protected void onBindView(View view) {
         super.onBindView(view);
@@ -45,7 +57,9 @@
         LinearColorBar colors = (LinearColorBar)view.findViewById(
                 R.id.linear_color_bar);
         colors.setShowIndicator(false);
-        colors.setColors(0xffcc3000, 0xffcccc00, 0xff00cc30);
+        colors.setColors(0xffaa5030, 0xffaaaa30, 0xff30aa50);
         colors.setRatios(mRedRatio, mYellowRatio, mGreenRatio);
+        colors.setColoredRegions(mColoredRegions);
+        colors.setOnRegionTappedListener(mOnRegionTappedListener);
     }
 }
diff --git a/src/com/android/settings/applications/ProcessStatsUi.java b/src/com/android/settings/applications/ProcessStatsUi.java
index 0e27577..8322ea3 100644
--- a/src/com/android/settings/applications/ProcessStatsUi.java
+++ b/src/com/android/settings/applications/ProcessStatsUi.java
@@ -48,7 +48,8 @@
 import java.util.Collections;
 import java.util.Comparator;
 
-public class ProcessStatsUi extends PreferenceFragment {
+public class ProcessStatsUi extends PreferenceFragment
+        implements LinearColorBar.OnRegionTappedListener {
     static final String TAG = "ProcessStatsUi";
     static final boolean DEBUG = false;
 
@@ -96,6 +97,7 @@
     private boolean mShowSystem;
     private boolean mUseUss;
     private int mStatsType;
+    private int mMemRegion;
 
     private MenuItem[] mDurationMenus = new MenuItem[NUM_DURATIONS];
     private MenuItem mShowSystemMenu;
@@ -144,6 +146,8 @@
         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);
     }
 
@@ -165,6 +169,7 @@
         outState.putBoolean("show_system", mShowSystem);
         outState.putBoolean("use_uss", mUseUss);
         outState.putInt("stats_type", mStatsType);
+        outState.putInt("mem_region", mMemRegion);
     }
 
     @Override
@@ -300,6 +305,14 @@
         }
     }
 
+    @Override
+    public void onRegionTapped(int region) {
+        if (mMemRegion != region) {
+            mMemRegion = region;
+            refreshStats();
+        }
+    }
+
     private void addNotAvailableMessage() {
         Preference notAvailable = new Preference(getActivity());
         notAvailable.setTitle(R.string.power_usage_not_available);
@@ -322,6 +335,15 @@
             ProcessStats.STATE_CACHED_EMPTY
     };
 
+    public static final int[] RED_MEM_STATES = new int[] {
+            ProcessStats.ADJ_MEM_FACTOR_CRITICAL
+    };
+
+    public static final int[] YELLOW_MEM_STATES = new int[] {
+            ProcessStats.ADJ_MEM_FACTOR_CRITICAL, ProcessStats.ADJ_MEM_FACTOR_LOW,
+            ProcessStats.ADJ_MEM_FACTOR_MODERATE
+    };
+
     private String makeDuration(long time) {
         StringBuilder sb = new StringBuilder(32);
         TimeUtils.formatDuration(time, sb);
@@ -357,9 +379,9 @@
         String durationString = Utils.formatElapsedTime(getActivity(),
                 mStats.mTimePeriodEndRealtime-mStats.mTimePeriodStartRealtime, false);
         CharSequence memString;
-        CharSequence[] memStates = getResources().getTextArray(R.array.ram_states);
-        if (mMemState >= 0 && mMemState < memStates.length) {
-            memString = memStates[mMemState];
+        CharSequence[] memStatesStr = getResources().getTextArray(R.array.ram_states);
+        if (mMemState >= 0 && mMemState < memStatesStr.length) {
+            memString = memStatesStr[mMemState];
         } else {
             memString = "?";
         }
@@ -378,9 +400,6 @@
         mAppListGroup.addPreference(hist);
         */
 
-        ProcessStats.ProcessDataCollection totals = new ProcessStats.ProcessDataCollection(
-                ProcessStats.ALL_SCREEN_ADJ, ProcessStats.ALL_MEM_ADJ, stats);
-
         long now = SystemClock.uptimeMillis();
 
         final PackageManager pm = getActivity().getPackageManager();
@@ -389,10 +408,6 @@
                 mStats.mMemFactor, mStats.mStartTime, now);
         if (DEBUG) Log.d(TAG, "Total time of stats: " + makeDuration(mTotalTime));
 
-        LinearColorPreference colors = new LinearColorPreference(getActivity());
-        colors.setOrder(-1);
-        mAppListGroup.addPreference(colors);
-
         long[] memTimes = new long[ProcessStats.ADJ_MEM_FACTOR_COUNT];
         for (int iscreen=0; iscreen<ProcessStats.ADJ_COUNT; iscreen+=ProcessStats.ADJ_SCREEN_MOD) {
             for (int imem=0; imem<ProcessStats.ADJ_MEM_FACTOR_COUNT; imem++) {
@@ -401,10 +416,40 @@
             }
         }
 
+        long memTotalTime;
+        int[] memStates;
+
+        LinearColorPreference colors = new LinearColorPreference(getActivity());
+        colors.setOrder(-1);
+        colors.setOnRegionTappedListener(this);
+        switch (mMemRegion) {
+            case LinearColorBar.REGION_RED:
+                colors.setColoredRegions(LinearColorBar.REGION_RED);
+                memTotalTime = memTimes[ProcessStats.ADJ_MEM_FACTOR_CRITICAL];
+                memStates = RED_MEM_STATES;
+                break;
+            case LinearColorBar.REGION_YELLOW:
+                colors.setColoredRegions(LinearColorBar.REGION_RED
+                        | LinearColorBar.REGION_YELLOW);
+                memTotalTime = memTimes[ProcessStats.ADJ_MEM_FACTOR_CRITICAL]
+                        + memTimes[ProcessStats.ADJ_MEM_FACTOR_LOW]
+                        + memTimes[ProcessStats.ADJ_MEM_FACTOR_MODERATE];
+                memStates = YELLOW_MEM_STATES;
+                break;
+            default:
+                colors.setColoredRegions(LinearColorBar.REGION_ALL);
+                memTotalTime = mTotalTime;
+                memStates = ProcessStats.ALL_MEM_ADJ;
+                break;
+        }
         colors.setRatios(memTimes[ProcessStats.ADJ_MEM_FACTOR_CRITICAL] / (float)mTotalTime,
                 (memTimes[ProcessStats.ADJ_MEM_FACTOR_LOW]
                         + memTimes[ProcessStats.ADJ_MEM_FACTOR_MODERATE]) / (float)mTotalTime,
                 memTimes[ProcessStats.ADJ_MEM_FACTOR_NORMAL] / (float)mTotalTime);
+        mAppListGroup.addPreference(colors);
+
+        ProcessStats.ProcessDataCollection totals = new ProcessStats.ProcessDataCollection(
+                ProcessStats.ALL_SCREEN_ADJ, memStates, stats);
 
         ArrayList<ProcStatsEntry> entries = new ArrayList<ProcStatsEntry>();
 
@@ -441,7 +486,7 @@
                         if (ent.mDuration > 0) {
                             if (DEBUG) Log.d(TAG, "Adding proc " + proc.mName + "/"
                                     + proc.mUid + ": time=" + makeDuration(ent.mDuration) + " ("
-                                    + ((((double)ent.mDuration) / mTotalTime) * 100) + "%)"
+                                    + ((((double)ent.mDuration) / memTotalTime) * 100) + "%)"
                                     + " pss=" + ent.mAvgPss);
                             entriesMap.put(proc.mName, proc.mUid, ent);
                             entries.add(ent);
@@ -492,7 +537,7 @@
                 if (ent.mDuration > 0) {
                     if (DEBUG) Log.d(TAG, "Adding proc " + st.mName + "/" + st.mUid + ": time="
                             + makeDuration(ent.mDuration) + " ("
-                            + ((((double)ent.mDuration) / mTotalTime) * 100) + "%)");
+                            + ((((double)ent.mDuration) / memTotalTime) * 100) + "%)");
                     procs.add(ent);
                     ArrayMap<String, ProcStatsEntry> uidProcs = processes.get(ent.mUid);
                     if (uidProcs == null) {
@@ -521,7 +566,7 @@
         for (int i=0, N=(entries != null ? entries.size() : 0); i<N; i++) {
             ProcStatsEntry proc = entries.get(i);
             final double percentOfWeight = (((double)proc.mWeight) / maxWeight) * 100;
-            final double percentOfTime = (((double)proc.mDuration) / mTotalTime) * 100;
+            final double percentOfTime = (((double)proc.mDuration) / memTotalTime) * 100;
             if (percentOfWeight < 1 && percentOfTime < 33) {
                 if (DEBUG) Log.d(TAG, "Skipping " + proc.mName + " weight=" + percentOfWeight
                         + " time=" + percentOfTime);