1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 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 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 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. 15 */ 16 17 package com.android.systemui; 18 19 import com.android.internal.os.ProcessStats; 20 21 import android.app.Service; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.graphics.Canvas; 25 import android.graphics.Paint; 26 import android.graphics.PixelFormat; 27 import android.os.Handler; 28 import android.os.IBinder; 29 import android.os.Message; 30 import android.view.Gravity; 31 import android.view.View; 32 import android.view.WindowManager; 33 34 public class LoadAverageService extends Service { 35 private View mView; 36 37 private static final class Stats extends ProcessStats { 38 String mLoadText; 39 int mLoadWidth; 40 41 private final Paint mPaint; 42 Stats(Paint paint)43 Stats(Paint paint) { 44 super(false); 45 mPaint = paint; 46 } 47 48 @Override onLoadChanged(float load1, float load5, float load15)49 public void onLoadChanged(float load1, float load5, float load15) { 50 mLoadText = load1 + " / " + load5 + " / " + load15; 51 mLoadWidth = (int)mPaint.measureText(mLoadText); 52 } 53 54 @Override onMeasureProcessName(String name)55 public int onMeasureProcessName(String name) { 56 return (int)mPaint.measureText(name); 57 } 58 } 59 60 private class LoadView extends View { 61 private Handler mHandler = new Handler() { 62 @Override 63 public void handleMessage(Message msg) { 64 if (msg.what == 1) { 65 mStats.update(); 66 updateDisplay(); 67 Message m = obtainMessage(1); 68 sendMessageDelayed(m, 2000); 69 } 70 } 71 }; 72 73 private final Stats mStats; 74 75 private Paint mLoadPaint; 76 private Paint mAddedPaint; 77 private Paint mRemovedPaint; 78 private Paint mShadowPaint; 79 private Paint mShadow2Paint; 80 private Paint mIrqPaint; 81 private Paint mSystemPaint; 82 private Paint mUserPaint; 83 private float mAscent; 84 private int mFH; 85 86 private int mNeededWidth; 87 private int mNeededHeight; 88 LoadView(Context c)89 LoadView(Context c) { 90 super(c); 91 92 setPadding(4, 4, 4, 4); 93 //setBackgroundResource(com.android.internal.R.drawable.load_average_background); 94 95 // Need to scale text size by density... but we won't do it 96 // linearly, because with higher dps it is nice to squeeze the 97 // text a bit to fit more of it. And with lower dps, trying to 98 // go much smaller will result in unreadable text. 99 int textSize = 10; 100 float density = c.getResources().getDisplayMetrics().density; 101 if (density < 1) { 102 textSize = 9; 103 } else { 104 textSize = (int)(10*density); 105 if (textSize < 10) { 106 textSize = 10; 107 } 108 } 109 mLoadPaint = new Paint(); 110 mLoadPaint.setAntiAlias(true); 111 mLoadPaint.setTextSize(textSize); 112 mLoadPaint.setARGB(255, 255, 255, 255); 113 114 mAddedPaint = new Paint(); 115 mAddedPaint.setAntiAlias(true); 116 mAddedPaint.setTextSize(textSize); 117 mAddedPaint.setARGB(255, 128, 255, 128); 118 119 mRemovedPaint = new Paint(); 120 mRemovedPaint.setAntiAlias(true); 121 mRemovedPaint.setStrikeThruText(true); 122 mRemovedPaint.setTextSize(textSize); 123 mRemovedPaint.setARGB(255, 255, 128, 128); 124 125 mShadowPaint = new Paint(); 126 mShadowPaint.setAntiAlias(true); 127 mShadowPaint.setTextSize(textSize); 128 //mShadowPaint.setFakeBoldText(true); 129 mShadowPaint.setARGB(192, 0, 0, 0); 130 mLoadPaint.setShadowLayer(4, 0, 0, 0xff000000); 131 132 mShadow2Paint = new Paint(); 133 mShadow2Paint.setAntiAlias(true); 134 mShadow2Paint.setTextSize(textSize); 135 //mShadow2Paint.setFakeBoldText(true); 136 mShadow2Paint.setARGB(192, 0, 0, 0); 137 mLoadPaint.setShadowLayer(2, 0, 0, 0xff000000); 138 139 mIrqPaint = new Paint(); 140 mIrqPaint.setARGB(0x80, 0, 0, 0xff); 141 mIrqPaint.setShadowLayer(2, 0, 0, 0xff000000); 142 mSystemPaint = new Paint(); 143 mSystemPaint.setARGB(0x80, 0xff, 0, 0); 144 mSystemPaint.setShadowLayer(2, 0, 0, 0xff000000); 145 mUserPaint = new Paint(); 146 mUserPaint.setARGB(0x80, 0, 0xff, 0); 147 mSystemPaint.setShadowLayer(2, 0, 0, 0xff000000); 148 149 mAscent = mLoadPaint.ascent(); 150 float descent = mLoadPaint.descent(); 151 mFH = (int)(descent - mAscent + .5f); 152 153 mStats = new Stats(mLoadPaint); 154 mStats.init(); 155 updateDisplay(); 156 } 157 158 @Override onAttachedToWindow()159 protected void onAttachedToWindow() { 160 super.onAttachedToWindow(); 161 mHandler.sendEmptyMessage(1); 162 } 163 164 @Override onDetachedFromWindow()165 protected void onDetachedFromWindow() { 166 super.onDetachedFromWindow(); 167 mHandler.removeMessages(1); 168 } 169 170 @Override onMeasure(int widthMeasureSpec, int heightMeasureSpec)171 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 172 setMeasuredDimension(resolveSize(mNeededWidth, widthMeasureSpec), 173 resolveSize(mNeededHeight, heightMeasureSpec)); 174 } 175 176 @Override onDraw(Canvas canvas)177 public void onDraw(Canvas canvas) { 178 super.onDraw(canvas); 179 final int W = mNeededWidth; 180 final int RIGHT = getWidth()-1; 181 182 final Stats stats = mStats; 183 final int userTime = stats.getLastUserTime(); 184 final int systemTime = stats.getLastSystemTime(); 185 final int iowaitTime = stats.getLastIoWaitTime(); 186 final int irqTime = stats.getLastIrqTime(); 187 final int softIrqTime = stats.getLastSoftIrqTime(); 188 final int idleTime = stats.getLastIdleTime(); 189 190 final int totalTime = userTime+systemTime+iowaitTime+irqTime+softIrqTime+idleTime; 191 if (totalTime == 0) { 192 return; 193 } 194 int userW = (userTime*W)/totalTime; 195 int systemW = (systemTime*W)/totalTime; 196 int irqW = ((iowaitTime+irqTime+softIrqTime)*W)/totalTime; 197 198 int x = RIGHT - mPaddingRight; 199 int top = mPaddingTop + 2; 200 int bottom = mPaddingTop + mFH - 2; 201 202 if (irqW > 0) { 203 canvas.drawRect(x-irqW, top, x, bottom, mIrqPaint); 204 x -= irqW; 205 } 206 if (systemW > 0) { 207 canvas.drawRect(x-systemW, top, x, bottom, mSystemPaint); 208 x -= systemW; 209 } 210 if (userW > 0) { 211 canvas.drawRect(x-userW, top, x, bottom, mUserPaint); 212 x -= userW; 213 } 214 215 int y = mPaddingTop - (int)mAscent; 216 canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth-1, 217 y-1, mShadowPaint); 218 canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth-1, 219 y+1, mShadowPaint); 220 canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth+1, 221 y-1, mShadow2Paint); 222 canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth+1, 223 y+1, mShadow2Paint); 224 canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth, 225 y, mLoadPaint); 226 227 int N = stats.countWorkingStats(); 228 for (int i=0; i<N; i++) { 229 Stats.Stats st = stats.getWorkingStats(i); 230 y += mFH; 231 top += mFH; 232 bottom += mFH; 233 234 userW = (st.rel_utime*W)/totalTime; 235 systemW = (st.rel_stime*W)/totalTime; 236 x = RIGHT - mPaddingRight; 237 if (systemW > 0) { 238 canvas.drawRect(x-systemW, top, x, bottom, mSystemPaint); 239 x -= systemW; 240 } 241 if (userW > 0) { 242 canvas.drawRect(x-userW, top, x, bottom, mUserPaint); 243 x -= userW; 244 } 245 246 canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth-1, 247 y-1, mShadowPaint); 248 canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth-1, 249 y+1, mShadowPaint); 250 canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth+1, 251 y-1, mShadow2Paint); 252 canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth+1, 253 y+1, mShadow2Paint); 254 Paint p = mLoadPaint; 255 if (st.added) p = mAddedPaint; 256 if (st.removed) p = mRemovedPaint; 257 canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth, y, p); 258 } 259 } 260 updateDisplay()261 void updateDisplay() { 262 final Stats stats = mStats; 263 final int NW = stats.countWorkingStats(); 264 265 int maxWidth = stats.mLoadWidth; 266 for (int i=0; i<NW; i++) { 267 Stats.Stats st = stats.getWorkingStats(i); 268 if (st.nameWidth > maxWidth) { 269 maxWidth = st.nameWidth; 270 } 271 } 272 273 int neededWidth = mPaddingLeft + mPaddingRight + maxWidth; 274 int neededHeight = mPaddingTop + mPaddingBottom + (mFH*(1+NW)); 275 if (neededWidth != mNeededWidth || neededHeight != mNeededHeight) { 276 mNeededWidth = neededWidth; 277 mNeededHeight = neededHeight; 278 requestLayout(); 279 } else { 280 invalidate(); 281 } 282 } 283 } 284 285 @Override onCreate()286 public void onCreate() { 287 super.onCreate(); 288 mView = new LoadView(this); 289 WindowManager.LayoutParams params = new WindowManager.LayoutParams( 290 WindowManager.LayoutParams.MATCH_PARENT, 291 WindowManager.LayoutParams.WRAP_CONTENT, 292 WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY, 293 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| 294 WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, 295 PixelFormat.TRANSLUCENT); 296 params.gravity = Gravity.RIGHT | Gravity.TOP; 297 params.setTitle("Load Average"); 298 WindowManager wm = (WindowManager)getSystemService(WINDOW_SERVICE); 299 wm.addView(mView, params); 300 } 301 302 @Override onDestroy()303 public void onDestroy() { 304 super.onDestroy(); 305 ((WindowManager)getSystemService(WINDOW_SERVICE)).removeView(mView); 306 mView = null; 307 } 308 309 @Override onBind(Intent intent)310 public IBinder onBind(Intent intent) { 311 return null; 312 } 313 314 } 315