Home | History | Annotate | Download | only in systemui
      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 android.app.Service;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.graphics.Canvas;
     23 import android.graphics.Paint;
     24 import android.graphics.PixelFormat;
     25 import android.os.Handler;
     26 import android.os.IBinder;
     27 import android.os.Message;
     28 import android.view.Gravity;
     29 import android.view.View;
     30 import android.view.WindowManager;
     31 
     32 import com.android.internal.os.ProcessCpuTracker;
     33 
     34 public class LoadAverageService extends Service {
     35     private View mView;
     36 
     37     private static final class CpuTracker extends ProcessCpuTracker {
     38         String mLoadText;
     39         int mLoadWidth;
     40 
     41         private final Paint mPaint;
     42 
     43         CpuTracker(Paint paint) {
     44             super(false);
     45             mPaint = paint;
     46         }
     47 
     48         @Override
     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
     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 CpuTracker 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 
     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 CpuTracker(mLoadPaint);
    154             mStats.init();
    155             updateDisplay();
    156         }
    157 
    158         @Override
    159         protected void onAttachedToWindow() {
    160             super.onAttachedToWindow();
    161             mHandler.sendEmptyMessage(1);
    162         }
    163 
    164         @Override
    165         protected void onDetachedFromWindow() {
    166             super.onDetachedFromWindow();
    167             mHandler.removeMessages(1);
    168         }
    169 
    170         @Override
    171         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    172             setMeasuredDimension(resolveSize(mNeededWidth, widthMeasureSpec),
    173                     resolveSize(mNeededHeight, heightMeasureSpec));
    174         }
    175 
    176         @Override
    177         public void onDraw(Canvas canvas) {
    178             super.onDraw(canvas);
    179             final int W = mNeededWidth;
    180             final int RIGHT = getWidth()-1;
    181 
    182             final CpuTracker 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                 CpuTracker.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 
    261         void updateDisplay() {
    262             final CpuTracker stats = mStats;
    263             final int NW = stats.countWorkingStats();
    264 
    265             int maxWidth = stats.mLoadWidth;
    266             for (int i=0; i<NW; i++) {
    267                 CpuTracker.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
    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.END | Gravity.TOP;
    297         params.setTitle("Load Average");
    298         WindowManager wm = (WindowManager)getSystemService(WINDOW_SERVICE);
    299         wm.addView(mView, params);
    300     }
    301 
    302     @Override
    303     public void onDestroy() {
    304         super.onDestroy();
    305         ((WindowManager)getSystemService(WINDOW_SERVICE)).removeView(mView);
    306         mView = null;
    307     }
    308 
    309     @Override
    310     public IBinder onBind(Intent intent) {
    311         return null;
    312     }
    313 
    314 }
    315