Memory debugging overlay for L3.

Change-Id: Id26e9dcf23017abaffed4015166d57e21e751e6c
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 512ed96..70fa7eb 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -70,29 +70,15 @@
 import android.text.TextUtils;
 import android.text.method.TextKeyListener;
 import android.util.Log;
-import android.view.Display;
-import android.view.HapticFeedbackConstants;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.Surface;
-import android.view.View;
+import android.view.*;
 import android.view.View.OnLongClickListener;
-import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
 import android.view.ViewTreeObserver.OnGlobalLayoutListener;
-import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.AccelerateDecelerateInterpolator;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.DecelerateInterpolator;
 import android.view.inputmethod.InputMethodManager;
-import android.widget.Advanceable;
-import android.widget.ImageView;
-import android.widget.TextView;
-import android.widget.Toast;
+import android.widget.*;
 
 import com.android.launcher3.R;
 import com.android.launcher3.DropTarget.DragObject;
@@ -121,10 +107,11 @@
     static final String TAG = "Launcher";
     static final boolean LOGD = false;
 
-    static final boolean PROFILE_STARTUP = false;
+    static final boolean PROFILE_STARTUP = true;
     static final boolean DEBUG_WIDGETS = false;
     static final boolean DEBUG_STRICT_MODE = false;
-    static final boolean DEBUG_RESUME_TIME = false;
+    static final boolean DEBUG_RESUME_TIME = true;
+    static final boolean DEBUG_MEMORY = true;
 
     private static final int MENU_GROUP_WALLPAPER = 1;
     private static final int MENU_WALLPAPER_SETTINGS = Menu.FIRST + 1;
@@ -740,6 +727,7 @@
         long startTime = 0;
         if (DEBUG_RESUME_TIME) {
             startTime = System.currentTimeMillis();
+            Log.v(TAG, "Launcher.onResume()");
         }
         super.onResume();
 
@@ -1022,6 +1010,16 @@
         if (mSearchDropTargetBar != null) {
             mSearchDropTargetBar.setup(this, dragController);
         }
+
+        if (DEBUG_MEMORY) {
+            Log.v(TAG, "adding WeightWatcher");
+            ((FrameLayout) mLauncherView).addView(new WeightWatcher(this),
+                    new FrameLayout.LayoutParams(
+                            FrameLayout.LayoutParams.MATCH_PARENT,
+                            44,
+                            Gravity.BOTTOM)
+            );
+        }
     }
 
     /**
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index fb49d93..3ac64e7 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -36,9 +36,9 @@
     private static float sScreenDensity;
     private static int sLongPressTimeout = 300;
     private static final String sSharedPreferencesKey = "com.android.launcher3.prefs";
-    WeakReference<LauncherProvider> mLauncherProvider;
+    private long mUptime;
 
-    private static LauncherAppState INSTANCE;
+    WeakReference<LauncherProvider> mLauncherProvider;
 
     private static final LauncherAppState INSTANCE = new LauncherAppState();
 
@@ -59,6 +59,8 @@
     private void initialize(Context context) {
         mContext = context;
 
+        mUptime = System.currentTimeMillis();
+
         // set sIsScreenXLarge and sScreenDensity *before* creating icon cache
         sIsScreenLarge = context.getResources().getBoolean(R.bool.is_large_screen);
         sScreenDensity = context.getResources().getDisplayMetrics().density;
@@ -132,7 +134,7 @@
         return mWidgetPreviewCacheDb;
     }
 
-   void setLauncherProvider(LauncherProvider provider) {
+    void setLauncherProvider(LauncherProvider provider) {
         mLauncherProvider = new WeakReference<LauncherProvider>(provider);
     }
 
@@ -140,6 +142,13 @@
         return mLauncherProvider.get();
     }
 
+    /**
+     * @return Milliseconds since the application state was created.
+     */
+    public long getUptime() {
+        return System.currentTimeMillis() - mUptime;
+    }
+
     public static String getSharedPreferencesKey() {
         return sSharedPreferencesKey;
     }
diff --git a/src/com/android/launcher3/WeightWatcher.java b/src/com/android/launcher3/WeightWatcher.java
new file mode 100644
index 0000000..15de93c
--- /dev/null
+++ b/src/com/android/launcher3/WeightWatcher.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2013 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.launcher3;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.os.Debug;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+public class WeightWatcher extends LinearLayout {
+    private static final long UPDATE_RATE = 5000;
+
+    private static final int RAM_GRAPH_COLOR = 0x9099CC00;
+    private static final int TEXT_COLOR = 0x90FFFFFF;
+    private static final int BACKGROUND_COLOR = 0x40000000;
+
+    private static final int MSG_START = 1;
+    private static final int MSG_STOP = 2;
+    private static final int MSG_UPDATE = 3;
+
+    TextView mRamText;
+    GraphView mRamGraph;
+    TextView mUptimeText;
+
+    Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message m) {
+            switch (m.what) {
+                case MSG_START:
+                    mHandler.sendEmptyMessage(MSG_UPDATE);
+                    break;
+                case MSG_STOP:
+                    mHandler.removeMessages(MSG_UPDATE);
+                    break;
+                case MSG_UPDATE:
+                    update();
+                    mHandler.sendEmptyMessageDelayed(MSG_UPDATE, UPDATE_RATE);
+                    break;
+            }
+        }
+    };
+
+    public WeightWatcher(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        final float dp = getResources().getDisplayMetrics().density;
+
+        setBackgroundColor(BACKGROUND_COLOR);
+
+        mRamText = new TextView(getContext());
+        mUptimeText = new TextView(getContext());
+        mRamText.setTextColor(TEXT_COLOR);
+        mUptimeText.setTextColor(TEXT_COLOR);
+
+        final int p = (int)(4*dp);
+        setPadding(p, 0, p, 0);
+
+        mRamGraph = new GraphView(getContext());
+
+        LinearLayout.LayoutParams wrapParams = new LinearLayout.LayoutParams(
+                LinearLayout.LayoutParams.WRAP_CONTENT,
+                LinearLayout.LayoutParams.WRAP_CONTENT
+        );
+        wrapParams.gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL;
+        wrapParams.setMarginEnd((int)(8*dp));
+
+        LinearLayout.LayoutParams fillParams = new LinearLayout.LayoutParams(
+                0,
+                LinearLayout.LayoutParams.MATCH_PARENT,
+                1.0f
+        );
+
+        addView(mUptimeText, wrapParams);
+        addView(mRamText, wrapParams);
+        addView(mRamGraph, fillParams);
+    }
+
+    public WeightWatcher(Context context) {
+        this(context, null);
+    }
+
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mHandler.sendEmptyMessage(MSG_START);
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        mRamText.setTextSize(h * 0.25f);
+        mUptimeText.setTextSize(h * 0.25f);
+    }
+
+    @Override
+    public void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mHandler.sendEmptyMessage(MSG_STOP);
+    }
+
+    public String getUptimeString() {
+        long sec = LauncherAppState.getInstance().getUptime() / 1000;
+        StringBuilder sb = new StringBuilder();
+        long days = sec / 86400;
+        if (days > 0) {
+            sec -= days * 86400;
+            sb.append(days);
+            sb.append("d");
+        }
+
+        long hours = sec / 3600;
+        if (hours > 0) {
+            sec -= hours * 3600;
+            sb.append(hours);
+            sb.append("h");
+        }
+
+        long mins = sec / 60;
+        if (mins > 0) {
+            sec -= mins * 60;
+            sb.append(mins);
+            sb.append("m");
+        }
+
+        sb.append(sec);
+        sb.append("s");
+        return sb.toString();
+    }
+
+    void update() {
+        final long pss = Debug.getPss();
+
+        mRamGraph.add(pss);
+        mRamText.setText("pss=" + pss);
+        mUptimeText.setText("uptime=" + getUptimeString());
+
+        postInvalidate();
+    }
+
+    public static class GraphView extends View {
+        final long[] data = new long[256];
+        long max = 1;
+        int head = 0;
+
+        Paint paint;
+
+        public GraphView(Context context, AttributeSet attrs) {
+            super(context, attrs);
+
+            paint = new Paint();
+            paint.setColor(RAM_GRAPH_COLOR);
+        }
+
+        public GraphView(Context context) {
+            this(context, null);
+        }
+
+        public void add(long dat) {
+            head = (head+1) % data.length;
+            data[head] = dat;
+            if (dat > max) max = dat;
+            invalidate();
+        }
+
+        @Override
+        public void onDraw(Canvas c) {
+            int w = c.getWidth();
+            int h = c.getHeight();
+
+            final float barWidth = (float) w / data.length;
+            final float scale = (float) h / max;
+
+            for (int i=0; i<data.length; i++) {
+                c.drawRect(i * barWidth, h - scale * data[i], (i+1) * barWidth, h, paint);
+            }
+        }
+    }
+}