summaryrefslogtreecommitdiffstats
path: root/src/com/android/launcher3/testing
diff options
context:
space:
mode:
authorSunny Goyal <sunnygoyal@google.com>2015-09-21 20:35:29 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2015-09-21 20:35:29 +0000
commite04febbf8ec8326edb095d023e494911381cee66 (patch)
tree5ac674f93f7128f414c4537400c8ef898cbd40a3 /src/com/android/launcher3/testing
parent3c9c7263dcd06cba449597104db039a4019e15ff (diff)
parent322d55622031985c75f7e5db07964b7730a97dac (diff)
downloadandroid_packages_apps_Trebuchet-e04febbf8ec8326edb095d023e494911381cee66.tar.gz
android_packages_apps_Trebuchet-e04febbf8ec8326edb095d023e494911381cee66.tar.bz2
android_packages_apps_Trebuchet-e04febbf8ec8326edb095d023e494911381cee66.zip
Merge "Moving a few testing classes to a separate package" into ub-launcher3-master
Diffstat (limited to 'src/com/android/launcher3/testing')
-rw-r--r--src/com/android/launcher3/testing/DummyWidget.java53
-rw-r--r--src/com/android/launcher3/testing/MemoryDumpActivity.java183
-rw-r--r--src/com/android/launcher3/testing/MemoryTracker.java217
-rw-r--r--src/com/android/launcher3/testing/ToggleWeightWatcher.java32
-rw-r--r--src/com/android/launcher3/testing/WeightWatcher.java267
5 files changed, 752 insertions, 0 deletions
diff --git a/src/com/android/launcher3/testing/DummyWidget.java b/src/com/android/launcher3/testing/DummyWidget.java
new file mode 100644
index 000000000..df887ac1f
--- /dev/null
+++ b/src/com/android/launcher3/testing/DummyWidget.java
@@ -0,0 +1,53 @@
+package com.android.launcher3.testing;
+
+import android.appwidget.AppWidgetProviderInfo;
+
+import com.android.launcher3.CustomAppWidget;
+import com.android.launcher3.R;
+
+public class DummyWidget implements CustomAppWidget {
+ @Override
+ public String getLabel() {
+ return "Dumb Launcher Widget";
+ }
+
+ @Override
+ public int getPreviewImage() {
+ return 0;
+ }
+
+ @Override
+ public int getIcon() {
+ return 0;
+ }
+
+ @Override
+ public int getWidgetLayout() {
+ return R.layout.zzz_dummy_widget;
+ }
+
+ @Override
+ public int getSpanX() {
+ return 2;
+ }
+
+ @Override
+ public int getSpanY() {
+ return 2;
+ }
+
+ @Override
+ public int getMinSpanX() {
+ return 1;
+ }
+
+ @Override
+ public int getMinSpanY() {
+ return 1;
+ }
+
+ @Override
+ public int getResizeMode() {
+ return AppWidgetProviderInfo.RESIZE_BOTH;
+ }
+}
diff --git a/src/com/android/launcher3/testing/MemoryDumpActivity.java b/src/com/android/launcher3/testing/MemoryDumpActivity.java
new file mode 100644
index 000000000..9bcf92b1b
--- /dev/null
+++ b/src/com/android/launcher3/testing/MemoryDumpActivity.java
@@ -0,0 +1,183 @@
+/*
+ * 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.testing;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.IBinder;
+import android.util.Log;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+public class MemoryDumpActivity extends Activity {
+ private static final String TAG = "MemoryDumpActivity";
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ public static String zipUp(ArrayList<String> paths) {
+ final int BUFSIZ = 256 * 1024; // 256K
+ final byte[] buf = new byte[BUFSIZ];
+ final String zipfilePath = String.format("%s/hprof-%d.zip",
+ Environment.getExternalStorageDirectory(),
+ System.currentTimeMillis());
+ ZipOutputStream zos = null;
+ try {
+ OutputStream os = new FileOutputStream(zipfilePath);
+ zos = new ZipOutputStream(new BufferedOutputStream(os));
+ for (String filename : paths) {
+ InputStream is = null;
+ try {
+ is = new BufferedInputStream(new FileInputStream(filename));
+ ZipEntry entry = new ZipEntry(filename);
+ zos.putNextEntry(entry);
+ int len;
+ while ( 0 < (len = is.read(buf, 0, BUFSIZ)) ) {
+ zos.write(buf, 0, len);
+ }
+ zos.closeEntry();
+ } finally {
+ is.close();
+ }
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "error zipping up profile data", e);
+ return null;
+ } finally {
+ if (zos != null) {
+ try {
+ zos.close();
+ } catch (IOException e) {
+ // ugh, whatever
+ }
+ }
+ }
+ return zipfilePath;
+ }
+
+ public static void dumpHprofAndShare(final Context context, MemoryTracker tracker) {
+ final StringBuilder body = new StringBuilder();
+
+ final ArrayList<String> paths = new ArrayList<String>();
+ final int myPid = android.os.Process.myPid();
+
+ final int[] pids_orig = tracker.getTrackedProcesses();
+ final int[] pids_copy = Arrays.copyOf(pids_orig, pids_orig.length);
+ for (int pid : pids_copy) {
+ MemoryTracker.ProcessMemInfo info = tracker.getMemInfo(pid);
+ if (info != null) {
+ body.append("pid ").append(pid).append(":")
+ .append(" up=").append(info.getUptime())
+ .append(" pss=").append(info.currentPss)
+ .append(" uss=").append(info.currentUss)
+ .append("\n");
+ }
+ if (pid == myPid) {
+ final String path = String.format("%s/launcher-memory-%d.ahprof",
+ Environment.getExternalStorageDirectory(),
+ pid);
+ Log.v(TAG, "Dumping memory info for process " + pid + " to " + path);
+ try {
+ android.os.Debug.dumpHprofData(path); // will block
+ } catch (IOException e) {
+ Log.e(TAG, "error dumping memory:", e);
+ }
+ paths.add(path);
+ }
+ }
+
+ String zipfile = zipUp(paths);
+
+ if (zipfile == null) return;
+
+ Intent shareIntent = new Intent(Intent.ACTION_SEND);
+ shareIntent.setType("application/zip");
+
+ final PackageManager pm = context.getPackageManager();
+ shareIntent.putExtra(Intent.EXTRA_SUBJECT, String.format("Launcher memory dump (%d)", myPid));
+ String appVersion;
+ try {
+ appVersion = pm.getPackageInfo(context.getPackageName(), 0).versionName;
+ } catch (PackageManager.NameNotFoundException e) {
+ appVersion = "?";
+ }
+
+ body.append("\nApp version: ").append(appVersion).append("\nBuild: ").append(Build.DISPLAY).append("\n");
+ shareIntent.putExtra(Intent.EXTRA_TEXT, body.toString());
+
+ final File pathFile = new File(zipfile);
+ final Uri pathUri = Uri.fromFile(pathFile);
+
+ shareIntent.putExtra(Intent.EXTRA_STREAM, pathUri);
+ context.startActivity(shareIntent);
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+
+ startDump(this, new Runnable() {
+ @Override
+ public void run() {
+ finish();
+ }
+ });
+ }
+
+ public static void startDump(final Context context) {
+ startDump(context, null);
+ }
+
+ public static void startDump(final Context context, final Runnable andThen) {
+ final ServiceConnection connection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ Log.v(TAG, "service connected, dumping...");
+ dumpHprofAndShare(context,
+ ((MemoryTracker.MemoryTrackerInterface) service).getService());
+ context.unbindService(this);
+ if (andThen != null) andThen.run();
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+ }
+ };
+ Log.v(TAG, "attempting to bind to memory tracker");
+ context.bindService(new Intent(context, MemoryTracker.class),
+ connection, Context.BIND_AUTO_CREATE);
+ }
+}
diff --git a/src/com/android/launcher3/testing/MemoryTracker.java b/src/com/android/launcher3/testing/MemoryTracker.java
new file mode 100644
index 000000000..ed2a3122c
--- /dev/null
+++ b/src/com/android/launcher3/testing/MemoryTracker.java
@@ -0,0 +1,217 @@
+/*
+ * 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.testing;
+
+import android.app.ActivityManager;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.Debug;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.SystemClock;
+import android.util.Log;
+import android.util.LongSparseArray;
+
+import com.android.launcher3.util.TestingUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class MemoryTracker extends Service {
+ public static final String TAG = MemoryTracker.class.getSimpleName();
+
+ private static final long UPDATE_RATE = 5000;
+
+ private static final int MSG_START = 1;
+ private static final int MSG_STOP = 2;
+ private static final int MSG_UPDATE = 3;
+
+ public static class ProcessMemInfo {
+ public int pid;
+ public String name;
+ public long startTime;
+ public long currentPss, currentUss;
+ public long[] pss = new long[256];
+ public long[] uss = new long[256];
+ //= new Meminfo[(int) (30 * 60 / (UPDATE_RATE / 1000))]; // 30 minutes
+ public long max = 1;
+ public int head = 0;
+ public ProcessMemInfo(int pid, String name, long start) {
+ this.pid = pid;
+ this.name = name;
+ this.startTime = start;
+ }
+ public long getUptime() {
+ return System.currentTimeMillis() - startTime;
+ }
+ };
+ public final LongSparseArray<ProcessMemInfo> mData = new LongSparseArray<ProcessMemInfo>();
+ public final ArrayList<Long> mPids = new ArrayList<Long>();
+ private int[] mPidsArray = new int[0];
+ private final Object mLock = new Object();
+
+ Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message m) {
+ switch (m.what) {
+ case MSG_START:
+ mHandler.removeMessages(MSG_UPDATE);
+ mHandler.sendEmptyMessage(MSG_UPDATE);
+ break;
+ case MSG_STOP:
+ mHandler.removeMessages(MSG_UPDATE);
+ break;
+ case MSG_UPDATE:
+ update();
+ mHandler.removeMessages(MSG_UPDATE);
+ mHandler.sendEmptyMessageDelayed(MSG_UPDATE, UPDATE_RATE);
+ break;
+ }
+ }
+ };
+
+ ActivityManager mAm;
+
+ public ProcessMemInfo getMemInfo(int pid) {
+ return mData.get(pid);
+ }
+
+ public int[] getTrackedProcesses() {
+ return mPidsArray;
+ }
+
+ public void startTrackingProcess(int pid, String name, long start) {
+ synchronized (mLock) {
+ final Long lpid = Long.valueOf(pid);
+
+ if (mPids.contains(lpid)) return;
+
+ mPids.add(lpid);
+ updatePidsArrayL();
+
+ mData.put(pid, new ProcessMemInfo(pid, name, start));
+ }
+ }
+
+ void updatePidsArrayL() {
+ final int N = mPids.size();
+ mPidsArray = new int[N];
+ StringBuffer sb = new StringBuffer("Now tracking processes: ");
+ for (int i=0; i<N; i++) {
+ final int p = mPids.get(i).intValue();
+ mPidsArray[i] = p;
+ sb.append(p); sb.append(" ");
+ }
+ Log.v(TAG, sb.toString());
+ }
+
+ void update() {
+ synchronized (mLock) {
+ Debug.MemoryInfo[] dinfos = mAm.getProcessMemoryInfo(mPidsArray);
+ for (int i=0; i<dinfos.length; i++) {
+ Debug.MemoryInfo dinfo = dinfos[i];
+ if (i > mPids.size()) {
+ Log.e(TAG, "update: unknown process info received: " + dinfo);
+ break;
+ }
+ final long pid = mPids.get(i).intValue();
+ final ProcessMemInfo info = mData.get(pid);
+ info.head = (info.head+1) % info.pss.length;
+ info.pss[info.head] = info.currentPss = dinfo.getTotalPss();
+ info.uss[info.head] = info.currentUss = dinfo.getTotalPrivateDirty();
+ if (info.currentPss > info.max) info.max = info.currentPss;
+ if (info.currentUss > info.max) info.max = info.currentUss;
+ // Log.v(TAG, "update: pid " + pid + " pss=" + info.currentPss + " uss=" + info.currentUss);
+ if (info.currentPss == 0) {
+ Log.v(TAG, "update: pid " + pid + " has pss=0, it probably died");
+ mData.remove(pid);
+ }
+ }
+ for (int i=mPids.size()-1; i>=0; i--) {
+ final long pid = mPids.get(i).intValue();
+ if (mData.get(pid) == null) {
+ mPids.remove(i);
+ updatePidsArrayL();
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onCreate() {
+ mAm = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
+
+ // catch up in case we crashed but other processes are still running
+ List<ActivityManager.RunningServiceInfo> svcs = mAm.getRunningServices(256);
+ for (ActivityManager.RunningServiceInfo svc : svcs) {
+ if (svc.service.getPackageName().equals(getPackageName())) {
+ Log.v(TAG, "discovered running service: " + svc.process + " (" + svc.pid + ")");
+ startTrackingProcess(svc.pid, svc.process,
+ System.currentTimeMillis() - (SystemClock.elapsedRealtime() - svc.activeSince));
+ }
+ }
+
+ List<ActivityManager.RunningAppProcessInfo> procs = mAm.getRunningAppProcesses();
+ for (ActivityManager.RunningAppProcessInfo proc : procs) {
+ final String pname = proc.processName;
+ if (pname.startsWith(getPackageName())) {
+ Log.v(TAG, "discovered other running process: " + pname + " (" + proc.pid + ")");
+ startTrackingProcess(proc.pid, pname, System.currentTimeMillis());
+ }
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ mHandler.sendEmptyMessage(MSG_STOP);
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ Log.v(TAG, "Received start id " + startId + ": " + intent);
+
+ if (intent != null) {
+ if (TestingUtils.ACTION_START_TRACKING.equals(intent.getAction())) {
+ final int pid = intent.getIntExtra("pid", -1);
+ final String name = intent.getStringExtra("name");
+ final long start = intent.getLongExtra("start", System.currentTimeMillis());
+ startTrackingProcess(pid, name, start);
+ }
+ }
+
+ mHandler.sendEmptyMessage(MSG_START);
+
+ return START_STICKY;
+ }
+
+ public class MemoryTrackerInterface extends Binder {
+ MemoryTracker getService() {
+ return MemoryTracker.this;
+ }
+ }
+
+ private final IBinder mBinder = new MemoryTrackerInterface();
+
+ public IBinder onBind(Intent intent) {
+ mHandler.sendEmptyMessage(MSG_START);
+
+ return mBinder;
+ }
+}
diff --git a/src/com/android/launcher3/testing/ToggleWeightWatcher.java b/src/com/android/launcher3/testing/ToggleWeightWatcher.java
new file mode 100644
index 000000000..15e55eea6
--- /dev/null
+++ b/src/com/android/launcher3/testing/ToggleWeightWatcher.java
@@ -0,0 +1,32 @@
+package com.android.launcher3.testing;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.view.View;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.util.TestingUtils;
+
+public class ToggleWeightWatcher extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ String spKey = LauncherAppState.getSharedPreferencesKey();
+ SharedPreferences sp = getSharedPreferences(spKey, Context.MODE_PRIVATE);
+ boolean show = sp.getBoolean(TestingUtils.SHOW_WEIGHT_WATCHER, true);
+
+ show = !show;
+ sp.edit().putBoolean(TestingUtils.SHOW_WEIGHT_WATCHER, show).apply();
+
+ Launcher launcher = (Launcher) LauncherAppState.getInstance().getModel().getCallback();
+ if (launcher != null && launcher.mWeightWatcher != null) {
+ launcher.mWeightWatcher.setVisibility(show ? View.VISIBLE : View.GONE);
+ }
+ finish();
+ }
+}
diff --git a/src/com/android/launcher3/testing/WeightWatcher.java b/src/com/android/launcher3/testing/WeightWatcher.java
new file mode 100644
index 000000000..a26a2b642
--- /dev/null
+++ b/src/com/android/launcher3/testing/WeightWatcher.java
@@ -0,0 +1,267 @@
+/*
+ * 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.testing;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.launcher3.util.Thunk;
+
+public class WeightWatcher extends LinearLayout {
+ private static final int RAM_GRAPH_RSS_COLOR = 0xFF990000;
+ private static final int RAM_GRAPH_PSS_COLOR = 0xFF99CC00;
+ private static final int TEXT_COLOR = 0xFFFFFFFF;
+ private static final int BACKGROUND_COLOR = 0xc0000000;
+
+ private static final int UPDATE_RATE = 5000;
+
+ private static final int MSG_START = 1;
+ private static final int MSG_STOP = 2;
+ private static final int MSG_UPDATE = 3;
+
+ static int indexOf(int[] a, int x) {
+ for (int i=0; i<a.length; i++) {
+ if (a[i] == x) return i;
+ }
+ return -1;
+ }
+
+ 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:
+ int[] pids = mMemoryService.getTrackedProcesses();
+
+ final int N = getChildCount();
+ if (pids.length != N) initViews();
+ else for (int i=0; i<N; i++) {
+ ProcessWatcher pw = ((ProcessWatcher) getChildAt(i));
+ if (indexOf(pids, pw.getPid()) < 0) {
+ initViews();
+ break;
+ }
+ pw.update();
+ }
+ mHandler.sendEmptyMessageDelayed(MSG_UPDATE, UPDATE_RATE);
+ break;
+ }
+ }
+ };
+ @Thunk MemoryTracker mMemoryService;
+
+ public WeightWatcher(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ ServiceConnection connection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ mMemoryService = ((MemoryTracker.MemoryTrackerInterface)service).getService();
+ initViews();
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+ mMemoryService = null;
+ }
+ };
+ context.bindService(new Intent(context, MemoryTracker.class),
+ connection, Context.BIND_AUTO_CREATE);
+
+ setOrientation(LinearLayout.VERTICAL);
+
+ setBackgroundColor(BACKGROUND_COLOR);
+ }
+
+ public void initViews() {
+ removeAllViews();
+ int[] processes = mMemoryService.getTrackedProcesses();
+ for (int i=0; i<processes.length; i++) {
+ final ProcessWatcher v = new ProcessWatcher(getContext());
+ v.setPid(processes[i]);
+ addView(v);
+ }
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mHandler.sendEmptyMessage(MSG_START);
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mHandler.sendEmptyMessage(MSG_STOP);
+ }
+
+ public class ProcessWatcher extends LinearLayout {
+ GraphView mRamGraph;
+ TextView mText;
+ int mPid;
+ @Thunk MemoryTracker.ProcessMemInfo mMemInfo;
+
+ public ProcessWatcher(Context context) {
+ this(context, null);
+ }
+
+ public ProcessWatcher(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ final float dp = getResources().getDisplayMetrics().density;
+
+ mText = new TextView(getContext());
+ mText.setTextColor(TEXT_COLOR);
+ mText.setTextSize(TypedValue.COMPLEX_UNIT_PX, 10 * dp);
+ mText.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
+
+ final int p = (int)(2*dp);
+ setPadding(p, 0, p, 0);
+
+ mRamGraph = new GraphView(getContext());
+
+ LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
+ 0,
+ (int)(14 * dp),
+ 1f
+ );
+
+ addView(mText, params);
+ params.leftMargin = (int)(4*dp);
+ params.weight = 0f;
+ params.width = (int)(200 * dp);
+ addView(mRamGraph, params);
+ }
+
+ public void setPid(int pid) {
+ mPid = pid;
+ mMemInfo = mMemoryService.getMemInfo(mPid);
+ if (mMemInfo == null) {
+ Log.v("WeightWatcher", "Missing info for pid " + mPid + ", removing view: " + this);
+ initViews();
+ }
+ }
+
+ public int getPid() {
+ return mPid;
+ }
+
+ public String getUptimeString() {
+ long sec = mMemInfo.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();
+ }
+
+ public void update() {
+ //Log.v("WeightWatcher.ProcessWatcher",
+ // "MSG_UPDATE pss=" + mMemInfo.currentPss);
+ mText.setText("(" + mPid
+ + (mPid == android.os.Process.myPid()
+ ? "/A" // app
+ : "/S") // service
+ + ") up " + getUptimeString()
+ + " P=" + mMemInfo.currentPss
+ + " U=" + mMemInfo.currentUss
+ );
+ mRamGraph.invalidate();
+ }
+
+ public class GraphView extends View {
+ Paint pssPaint, ussPaint, headPaint;
+
+ public GraphView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ pssPaint = new Paint();
+ pssPaint.setColor(RAM_GRAPH_PSS_COLOR);
+ ussPaint = new Paint();
+ ussPaint.setColor(RAM_GRAPH_RSS_COLOR);
+ headPaint = new Paint();
+ headPaint.setColor(Color.WHITE);
+ }
+
+ public GraphView(Context context) {
+ this(context, null);
+ }
+
+ @Override
+ public void onDraw(Canvas c) {
+ int w = c.getWidth();
+ int h = c.getHeight();
+
+ if (mMemInfo == null) return;
+
+ final int N = mMemInfo.pss.length;
+ final float barStep = (float) w / N;
+ final float barWidth = Math.max(1, barStep);
+ final float scale = (float) h / mMemInfo.max;
+
+ int i;
+ float x;
+ for (i=0; i<N; i++) {
+ x = i * barStep;
+ c.drawRect(x, h - scale * mMemInfo.pss[i], x + barWidth, h, pssPaint);
+ c.drawRect(x, h - scale * mMemInfo.uss[i], x + barWidth, h, ussPaint);
+ }
+ x = mMemInfo.head * barStep;
+ c.drawRect(x, 0, x + barWidth, h, headPaint);
+ }
+ }
+ }
+}