/* * Copyright (C) 2007 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.systemui; import com.android.internal.os.ProcessStats; import android.app.Service; import android.content.Context; import android.content.Intent; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PixelFormat; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.view.Gravity; import android.view.View; import android.view.WindowManager; public class LoadAverageService extends Service { private View mView; private static final class Stats extends ProcessStats { String mLoadText; int mLoadWidth; private final Paint mPaint; Stats(Paint paint) { super(false); mPaint = paint; } @Override public void onLoadChanged(float load1, float load5, float load15) { mLoadText = load1 + " / " + load5 + " / " + load15; mLoadWidth = (int)mPaint.measureText(mLoadText); } @Override public int onMeasureProcessName(String name) { return (int)mPaint.measureText(name); } } private class LoadView extends View { private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { if (msg.what == 1) { mStats.update(); updateDisplay(); Message m = obtainMessage(1); sendMessageDelayed(m, 2000); } } }; private final Stats mStats; private Paint mLoadPaint; private Paint mAddedPaint; private Paint mRemovedPaint; private Paint mShadowPaint; private Paint mShadow2Paint; private Paint mIrqPaint; private Paint mSystemPaint; private Paint mUserPaint; private float mAscent; private int mFH; private int mNeededWidth; private int mNeededHeight; LoadView(Context c) { super(c); setPadding(4, 4, 4, 4); //setBackgroundResource(com.android.internal.R.drawable.load_average_background); // Need to scale text size by density... but we won't do it // linearly, because with higher dps it is nice to squeeze the // text a bit to fit more of it. And with lower dps, trying to // go much smaller will result in unreadable text. int textSize = 10; float density = c.getResources().getDisplayMetrics().density; if (density < 1) { textSize = 9; } else { textSize = (int)(10*density); if (textSize < 10) { textSize = 10; } } mLoadPaint = new Paint(); mLoadPaint.setAntiAlias(true); mLoadPaint.setTextSize(textSize); mLoadPaint.setARGB(255, 255, 255, 255); mAddedPaint = new Paint(); mAddedPaint.setAntiAlias(true); mAddedPaint.setTextSize(textSize); mAddedPaint.setARGB(255, 128, 255, 128); mRemovedPaint = new Paint(); mRemovedPaint.setAntiAlias(true); mRemovedPaint.setStrikeThruText(true); mRemovedPaint.setTextSize(textSize); mRemovedPaint.setARGB(255, 255, 128, 128); mShadowPaint = new Paint(); mShadowPaint.setAntiAlias(true); mShadowPaint.setTextSize(textSize); //mShadowPaint.setFakeBoldText(true); mShadowPaint.setARGB(192, 0, 0, 0); mLoadPaint.setShadowLayer(4, 0, 0, 0xff000000); mShadow2Paint = new Paint(); mShadow2Paint.setAntiAlias(true); mShadow2Paint.setTextSize(textSize); //mShadow2Paint.setFakeBoldText(true); mShadow2Paint.setARGB(192, 0, 0, 0); mLoadPaint.setShadowLayer(2, 0, 0, 0xff000000); mIrqPaint = new Paint(); mIrqPaint.setARGB(0x80, 0, 0, 0xff); mIrqPaint.setShadowLayer(2, 0, 0, 0xff000000); mSystemPaint = new Paint(); mSystemPaint.setARGB(0x80, 0xff, 0, 0); mSystemPaint.setShadowLayer(2, 0, 0, 0xff000000); mUserPaint = new Paint(); mUserPaint.setARGB(0x80, 0, 0xff, 0); mSystemPaint.setShadowLayer(2, 0, 0, 0xff000000); mAscent = mLoadPaint.ascent(); float descent = mLoadPaint.descent(); mFH = (int)(descent - mAscent + .5f); mStats = new Stats(mLoadPaint); mStats.init(); updateDisplay(); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); mHandler.sendEmptyMessage(1); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); mHandler.removeMessages(1); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(resolveSize(mNeededWidth, widthMeasureSpec), resolveSize(mNeededHeight, heightMeasureSpec)); } @Override public void onDraw(Canvas canvas) { super.onDraw(canvas); final int W = mNeededWidth; final int RIGHT = getWidth()-1; final Stats stats = mStats; final int userTime = stats.getLastUserTime(); final int systemTime = stats.getLastSystemTime(); final int iowaitTime = stats.getLastIoWaitTime(); final int irqTime = stats.getLastIrqTime(); final int softIrqTime = stats.getLastSoftIrqTime(); final int idleTime = stats.getLastIdleTime(); final int totalTime = userTime+systemTime+iowaitTime+irqTime+softIrqTime+idleTime; if (totalTime == 0) { return; } int userW = (userTime*W)/totalTime; int systemW = (systemTime*W)/totalTime; int irqW = ((iowaitTime+irqTime+softIrqTime)*W)/totalTime; int x = RIGHT - mPaddingRight; int top = mPaddingTop + 2; int bottom = mPaddingTop + mFH - 2; if (irqW > 0) { canvas.drawRect(x-irqW, top, x, bottom, mIrqPaint); x -= irqW; } if (systemW > 0) { canvas.drawRect(x-systemW, top, x, bottom, mSystemPaint); x -= systemW; } if (userW > 0) { canvas.drawRect(x-userW, top, x, bottom, mUserPaint); x -= userW; } int y = mPaddingTop - (int)mAscent; canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth-1, y-1, mShadowPaint); canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth-1, y+1, mShadowPaint); canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth+1, y-1, mShadow2Paint); canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth+1, y+1, mShadow2Paint); canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth, y, mLoadPaint); int N = stats.countWorkingStats(); for (int i=0; i 0) { canvas.drawRect(x-systemW, top, x, bottom, mSystemPaint); x -= systemW; } if (userW > 0) { canvas.drawRect(x-userW, top, x, bottom, mUserPaint); x -= userW; } canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth-1, y-1, mShadowPaint); canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth-1, y+1, mShadowPaint); canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth+1, y-1, mShadow2Paint); canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth+1, y+1, mShadow2Paint); Paint p = mLoadPaint; if (st.added) p = mAddedPaint; if (st.removed) p = mRemovedPaint; canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth, y, p); } } void updateDisplay() { final Stats stats = mStats; final int NW = stats.countWorkingStats(); int maxWidth = stats.mLoadWidth; for (int i=0; i maxWidth) { maxWidth = st.nameWidth; } } int neededWidth = mPaddingLeft + mPaddingRight + maxWidth; int neededHeight = mPaddingTop + mPaddingBottom + (mFH*(1+NW)); if (neededWidth != mNeededWidth || neededHeight != mNeededHeight) { mNeededWidth = neededWidth; mNeededHeight = neededHeight; requestLayout(); } else { invalidate(); } } } @Override public void onCreate() { super.onCreate(); mView = new LoadView(this); WindowManager.LayoutParams params = new WindowManager.LayoutParams( WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, PixelFormat.TRANSLUCENT); params.gravity = Gravity.RIGHT | Gravity.TOP; params.setTitle("Load Average"); WindowManager wm = (WindowManager)getSystemService(WINDOW_SERVICE); wm.addView(mView, params); } @Override public void onDestroy() { super.onDestroy(); ((WindowManager)getSystemService(WINDOW_SERVICE)).removeView(mView); mView = null; } @Override public IBinder onBind(Intent intent) { return null; } }