2 * Copyright (C) 2013 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.launcher3;
19 import android.content.ComponentName;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.ServiceConnection;
23 import android.graphics.Canvas;
24 import android.graphics.Color;
25 import android.graphics.Paint;
26 import android.os.Handler;
27 import android.os.IBinder;
28 import android.os.Message;
29 import android.util.AttributeSet;
30 import android.util.Log;
31 import android.util.TypedValue;
32 import android.view.Gravity;
33 import android.view.View;
34 import android.widget.LinearLayout;
35 import android.widget.TextView;
37 import com.android.launcher3.util.Thunk;
39 public class WeightWatcher extends LinearLayout {
40 private static final int RAM_GRAPH_RSS_COLOR = 0xFF990000;
41 private static final int RAM_GRAPH_PSS_COLOR = 0xFF99CC00;
42 private static final int TEXT_COLOR = 0xFFFFFFFF;
43 private static final int BACKGROUND_COLOR = 0xc0000000;
45 private static final int UPDATE_RATE = 5000;
47 private static final int MSG_START = 1;
48 private static final int MSG_STOP = 2;
49 private static final int MSG_UPDATE = 3;
51 static int indexOf(int[] a, int x) {
52 for (int i=0; i<a.length; i++) {
53 if (a[i] == x) return i;
58 Handler mHandler = new Handler() {
60 public void handleMessage(Message m) {
63 mHandler.sendEmptyMessage(MSG_UPDATE);
66 mHandler.removeMessages(MSG_UPDATE);
69 int[] pids = mMemoryService.getTrackedProcesses();
71 final int N = getChildCount();
72 if (pids.length != N) initViews();
73 else for (int i=0; i<N; i++) {
74 ProcessWatcher pw = ((ProcessWatcher) getChildAt(i));
75 if (indexOf(pids, pw.getPid()) < 0) {
81 mHandler.sendEmptyMessageDelayed(MSG_UPDATE, UPDATE_RATE);
86 @Thunk MemoryTracker mMemoryService;
88 public WeightWatcher(Context context, AttributeSet attrs) {
89 super(context, attrs);
91 ServiceConnection connection = new ServiceConnection() {
92 public void onServiceConnected(ComponentName className, IBinder service) {
93 mMemoryService = ((MemoryTracker.MemoryTrackerInterface)service).getService();
97 public void onServiceDisconnected(ComponentName className) {
98 mMemoryService = null;
101 context.bindService(new Intent(context, MemoryTracker.class),
102 connection, Context.BIND_AUTO_CREATE);
104 setOrientation(LinearLayout.VERTICAL);
106 setBackgroundColor(BACKGROUND_COLOR);
109 public void initViews() {
111 int[] processes = mMemoryService.getTrackedProcesses();
112 for (int i=0; i<processes.length; i++) {
113 final ProcessWatcher v = new ProcessWatcher(getContext());
114 v.setPid(processes[i]);
119 public WeightWatcher(Context context) {
124 public void onAttachedToWindow() {
125 super.onAttachedToWindow();
126 mHandler.sendEmptyMessage(MSG_START);
130 public void onDetachedFromWindow() {
131 super.onDetachedFromWindow();
132 mHandler.sendEmptyMessage(MSG_STOP);
135 public class ProcessWatcher extends LinearLayout {
139 @Thunk MemoryTracker.ProcessMemInfo mMemInfo;
141 public ProcessWatcher(Context context) {
145 public ProcessWatcher(Context context, AttributeSet attrs) {
146 super(context, attrs);
148 final float dp = getResources().getDisplayMetrics().density;
150 mText = new TextView(getContext());
151 mText.setTextColor(TEXT_COLOR);
152 mText.setTextSize(TypedValue.COMPLEX_UNIT_PX, 10 * dp);
153 mText.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
155 final int p = (int)(2*dp);
156 setPadding(p, 0, p, 0);
158 mRamGraph = new GraphView(getContext());
160 LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
166 addView(mText, params);
167 params.leftMargin = (int)(4*dp);
169 params.width = (int)(200 * dp);
170 addView(mRamGraph, params);
173 public void setPid(int pid) {
175 mMemInfo = mMemoryService.getMemInfo(mPid);
176 if (mMemInfo == null) {
177 Log.v("WeightWatcher", "Missing info for pid " + mPid + ", removing view: " + this);
182 public int getPid() {
186 public String getUptimeString() {
187 long sec = mMemInfo.getUptime() / 1000;
188 StringBuilder sb = new StringBuilder();
189 long days = sec / 86400;
196 long hours = sec / 3600;
203 long mins = sec / 60;
212 return sb.toString();
215 public void update() {
216 //Log.v("WeightWatcher.ProcessWatcher",
217 // "MSG_UPDATE pss=" + mMemInfo.currentPss);
218 mText.setText("(" + mPid
219 + (mPid == android.os.Process.myPid()
222 + ") up " + getUptimeString()
223 + " P=" + mMemInfo.currentPss
224 + " U=" + mMemInfo.currentUss
226 mRamGraph.invalidate();
229 public class GraphView extends View {
230 Paint pssPaint, ussPaint, headPaint;
232 public GraphView(Context context, AttributeSet attrs) {
233 super(context, attrs);
235 pssPaint = new Paint();
236 pssPaint.setColor(RAM_GRAPH_PSS_COLOR);
237 ussPaint = new Paint();
238 ussPaint.setColor(RAM_GRAPH_RSS_COLOR);
239 headPaint = new Paint();
240 headPaint.setColor(Color.WHITE);
243 public GraphView(Context context) {
248 public void onDraw(Canvas c) {
249 int w = c.getWidth();
250 int h = c.getHeight();
252 if (mMemInfo == null) return;
254 final int N = mMemInfo.pss.length;
255 final float barStep = (float) w / N;
256 final float barWidth = Math.max(1, barStep);
257 final float scale = (float) h / mMemInfo.max;
261 for (i=0; i<N; i++) {
263 c.drawRect(x, h - scale * mMemInfo.pss[i], x + barWidth, h, pssPaint);
264 c.drawRect(x, h - scale * mMemInfo.uss[i], x + barWidth, h, ussPaint);
266 x = mMemInfo.head * barStep;
267 c.drawRect(x, 0, x + barWidth, h, headPaint);