BatteryHistoryChart.java revision cb818619c669d4257a4df969dd03eff479ba84d0
1/* 2 * Copyright (C) 2010 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 17package com.android.settings.fuelgauge; 18 19import com.android.settings.R; 20 21import android.content.Context; 22import android.content.res.ColorStateList; 23import android.content.res.TypedArray; 24import android.graphics.Canvas; 25import android.graphics.Paint; 26import android.graphics.Path; 27import android.graphics.Typeface; 28import android.os.BatteryStats; 29import android.os.SystemClock; 30import android.os.BatteryStats.HistoryItem; 31import android.telephony.ServiceState; 32import android.text.TextPaint; 33import android.util.AttributeSet; 34import android.util.TypedValue; 35import android.view.View; 36 37public class BatteryHistoryChart extends View { 38 static final int SANS = 1; 39 static final int SERIF = 2; 40 static final int MONOSPACE = 3; 41 42 static final int BATTERY_WARN = 29; 43 static final int BATTERY_CRITICAL = 14; 44 45 // First value if for phone off; sirst value is "scanning"; following values 46 // are battery stats signal strength buckets. 47 static final int NUM_PHONE_SIGNALS = 7; 48 49 final Paint mBatteryBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 50 final Paint mBatteryGoodPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 51 final Paint mBatteryWarnPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 52 final Paint mBatteryCriticalPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 53 final Paint mChargingPaint = new Paint(); 54 final Paint mScreenOnPaint = new Paint(); 55 final Paint mGpsOnPaint = new Paint(); 56 final Paint mWifiRunningPaint = new Paint(); 57 final Paint mWakeLockPaint = new Paint(); 58 final Paint[] mPhoneSignalPaints = new Paint[NUM_PHONE_SIGNALS]; 59 final int[] mPhoneSignalColors = new int[] { 60 0x00000000, 0xffa00000, 0xffa0a000, 0xff808020, 61 0xff808040, 0xff808060, 0xff008000 62 }; 63 final TextPaint mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); 64 65 final Path mBatLevelPath = new Path(); 66 final Path mBatGoodPath = new Path(); 67 final Path mBatWarnPath = new Path(); 68 final Path mBatCriticalPath = new Path(); 69 final Path mChargingPath = new Path(); 70 final Path mScreenOnPath = new Path(); 71 final Path mGpsOnPath = new Path(); 72 final Path mWifiRunningPath = new Path(); 73 final Path mWakeLockPath = new Path(); 74 75 int mFontSize; 76 77 BatteryStats mStats; 78 long mStatsPeriod; 79 String mDurationString; 80 String mTotalDurationString; 81 String mChargingLabel; 82 String mScreenOnLabel; 83 String mGpsOnLabel; 84 String mWifiRunningLabel; 85 String mWakeLockLabel; 86 String mPhoneSignalLabel; 87 88 int mTextAscent; 89 int mTextDescent; 90 int mDurationStringWidth; 91 int mTotalDurationStringWidth; 92 93 boolean mLargeMode; 94 95 int mLineWidth; 96 int mThinLineWidth; 97 int mChargingOffset; 98 int mScreenOnOffset; 99 int mGpsOnOffset; 100 int mWifiRunningOffset; 101 int mWakeLockOffset; 102 int mPhoneSignalOffset; 103 int mLevelOffset; 104 int mLevelTop; 105 int mLevelBottom; 106 static final int PHONE_SIGNAL_X_MASK = 0x0000ffff; 107 static final int PHONE_SIGNAL_BIN_MASK = 0xffff0000; 108 static final int PHONE_SIGNAL_BIN_SHIFT = 16; 109 int mNumPhoneSignalTicks; 110 int[] mPhoneSignalTicks; 111 112 int mNumHist; 113 BatteryStats.HistoryItem mHistFirst; 114 long mHistStart; 115 long mHistEnd; 116 int mBatLow; 117 int mBatHigh; 118 boolean mHaveWifi; 119 boolean mHaveGps; 120 121 public BatteryHistoryChart(Context context, AttributeSet attrs) { 122 super(context, attrs); 123 124 mBatteryBackgroundPaint.setARGB(255, 128, 128, 128); 125 mBatteryBackgroundPaint.setStyle(Paint.Style.FILL); 126 mBatteryGoodPaint.setARGB(128, 0, 255, 0); 127 mBatteryGoodPaint.setStyle(Paint.Style.STROKE); 128 mBatteryWarnPaint.setARGB(128, 255, 255, 0); 129 mBatteryWarnPaint.setStyle(Paint.Style.STROKE); 130 mBatteryCriticalPaint.setARGB(192, 255, 0, 0); 131 mBatteryCriticalPaint.setStyle(Paint.Style.STROKE); 132 mChargingPaint.setARGB(255, 0, 128, 0); 133 mChargingPaint.setStyle(Paint.Style.STROKE); 134 mScreenOnPaint.setARGB(255, 0, 0, 255); 135 mScreenOnPaint.setStyle(Paint.Style.STROKE); 136 mGpsOnPaint.setARGB(255, 0, 0, 255); 137 mGpsOnPaint.setStyle(Paint.Style.STROKE); 138 mWifiRunningPaint.setARGB(255, 0, 0, 255); 139 mWifiRunningPaint.setStyle(Paint.Style.STROKE); 140 mWakeLockPaint.setARGB(255, 0, 0, 255); 141 mWakeLockPaint.setStyle(Paint.Style.STROKE); 142 for (int i=0; i<NUM_PHONE_SIGNALS; i++) { 143 mPhoneSignalPaints[i] = new Paint(); 144 mPhoneSignalPaints[i].setColor(mPhoneSignalColors[i]); 145 mPhoneSignalPaints[i].setStyle(Paint.Style.FILL); 146 } 147 148 mTextPaint.density = getResources().getDisplayMetrics().density; 149 mTextPaint.setCompatibilityScaling( 150 getResources().getCompatibilityInfo().applicationScale); 151 152 TypedArray a = 153 context.obtainStyledAttributes( 154 attrs, R.styleable.BatteryHistoryChart, 0, 0); 155 156 ColorStateList textColor = null; 157 int textSize = 15; 158 int typefaceIndex = -1; 159 int styleIndex = -1; 160 161 TypedArray appearance = null; 162 int ap = a.getResourceId(R.styleable.BatteryHistoryChart_android_textAppearance, -1); 163 if (ap != -1) { 164 appearance = context.obtainStyledAttributes(ap, 165 com.android.internal.R.styleable. 166 TextAppearance); 167 } 168 if (appearance != null) { 169 int n = appearance.getIndexCount(); 170 for (int i = 0; i < n; i++) { 171 int attr = appearance.getIndex(i); 172 173 switch (attr) { 174 case com.android.internal.R.styleable.TextAppearance_textColor: 175 textColor = appearance.getColorStateList(attr); 176 break; 177 178 case com.android.internal.R.styleable.TextAppearance_textSize: 179 textSize = appearance.getDimensionPixelSize(attr, textSize); 180 break; 181 182 case com.android.internal.R.styleable.TextAppearance_typeface: 183 typefaceIndex = appearance.getInt(attr, -1); 184 break; 185 186 case com.android.internal.R.styleable.TextAppearance_textStyle: 187 styleIndex = appearance.getInt(attr, -1); 188 break; 189 } 190 } 191 192 appearance.recycle(); 193 } 194 195 int shadowcolor = 0; 196 float dx=0, dy=0, r=0; 197 198 int n = a.getIndexCount(); 199 for (int i = 0; i < n; i++) { 200 int attr = a.getIndex(i); 201 202 switch (attr) { 203 case R.styleable.BatteryHistoryChart_android_shadowColor: 204 shadowcolor = a.getInt(attr, 0); 205 break; 206 207 case R.styleable.BatteryHistoryChart_android_shadowDx: 208 dx = a.getFloat(attr, 0); 209 break; 210 211 case R.styleable.BatteryHistoryChart_android_shadowDy: 212 dy = a.getFloat(attr, 0); 213 break; 214 215 case R.styleable.BatteryHistoryChart_android_shadowRadius: 216 r = a.getFloat(attr, 0); 217 break; 218 219 case R.styleable.BatteryHistoryChart_android_textColor: 220 textColor = a.getColorStateList(attr); 221 break; 222 223 case R.styleable.BatteryHistoryChart_android_textSize: 224 textSize = a.getDimensionPixelSize(attr, textSize); 225 break; 226 227 case R.styleable.BatteryHistoryChart_android_typeface: 228 typefaceIndex = a.getInt(attr, typefaceIndex); 229 break; 230 231 case R.styleable.BatteryHistoryChart_android_textStyle: 232 styleIndex = a.getInt(attr, styleIndex); 233 break; 234 } 235 } 236 237 mTextPaint.setColor(textColor.getDefaultColor()); 238 mTextPaint.setTextSize(textSize); 239 240 Typeface tf = null; 241 switch (typefaceIndex) { 242 case SANS: 243 tf = Typeface.SANS_SERIF; 244 break; 245 246 case SERIF: 247 tf = Typeface.SERIF; 248 break; 249 250 case MONOSPACE: 251 tf = Typeface.MONOSPACE; 252 break; 253 } 254 255 setTypeface(tf, styleIndex); 256 257 if (shadowcolor != 0) { 258 mTextPaint.setShadowLayer(r, dx, dy, shadowcolor); 259 } 260 } 261 262 public void setTypeface(Typeface tf, int style) { 263 if (style > 0) { 264 if (tf == null) { 265 tf = Typeface.defaultFromStyle(style); 266 } else { 267 tf = Typeface.create(tf, style); 268 } 269 270 mTextPaint.setTypeface(tf); 271 // now compute what (if any) algorithmic styling is needed 272 int typefaceStyle = tf != null ? tf.getStyle() : 0; 273 int need = style & ~typefaceStyle; 274 mTextPaint.setFakeBoldText((need & Typeface.BOLD) != 0); 275 mTextPaint.setTextSkewX((need & Typeface.ITALIC) != 0 ? -0.25f : 0); 276 } else { 277 mTextPaint.setFakeBoldText(false); 278 mTextPaint.setTextSkewX(0); 279 mTextPaint.setTypeface(tf); 280 } 281 } 282 283 void setStats(BatteryStats stats) { 284 mStats = stats; 285 286 long uSecTime = mStats.computeBatteryRealtime(SystemClock.elapsedRealtime() * 1000, 287 BatteryStats.STATS_SINCE_CHARGED); 288 mStatsPeriod = uSecTime; 289 String durationString = Utils.formatElapsedTime(getContext(), mStatsPeriod / 1000); 290 mDurationString = getContext().getString(R.string.battery_stats_on_battery, 291 durationString); 292 mChargingLabel = getContext().getString(R.string.battery_stats_charging_label); 293 mScreenOnLabel = getContext().getString(R.string.battery_stats_screen_on_label); 294 mGpsOnLabel = getContext().getString(R.string.battery_stats_gps_on_label); 295 mWifiRunningLabel = getContext().getString(R.string.battery_stats_wifi_running_label); 296 mWakeLockLabel = getContext().getString(R.string.battery_stats_wake_lock_label); 297 mPhoneSignalLabel = getContext().getString(R.string.battery_stats_phone_signal_label); 298 299 BatteryStats.HistoryItem rec = stats.getHistory(); 300 mHistFirst = null; 301 int pos = 0; 302 int lastInteresting = 0; 303 byte lastLevel = -1; 304 mBatLow = 0; 305 mBatHigh = 100; 306 int aggrStates = 0; 307 while (rec != null) { 308 pos++; 309 if (rec.cmd == HistoryItem.CMD_UPDATE) { 310 if (mHistFirst == null) { 311 mHistFirst = rec; 312 mHistStart = rec.time; 313 } 314 if (rec.batteryLevel != lastLevel || pos == 1) { 315 lastLevel = rec.batteryLevel; 316 lastInteresting = pos; 317 mHistEnd = rec.time; 318 } 319 aggrStates |= rec.states; 320 } 321 rec = rec.next; 322 } 323 mNumHist = lastInteresting; 324 mHaveGps = (aggrStates&HistoryItem.STATE_GPS_ON_FLAG) != 0; 325 mHaveWifi = (aggrStates&HistoryItem.STATE_WIFI_RUNNING_FLAG) != 0; 326 327 if (mHistEnd <= mHistStart) mHistEnd = mHistStart+1; 328 mTotalDurationString = Utils.formatElapsedTime(getContext(), mHistEnd - mHistStart); 329 } 330 331 @Override 332 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 333 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 334 mDurationStringWidth = (int)mTextPaint.measureText(mDurationString); 335 mTotalDurationStringWidth = (int)mTextPaint.measureText(mTotalDurationString); 336 mTextAscent = (int)mTextPaint.ascent(); 337 mTextDescent = (int)mTextPaint.descent(); 338 } 339 340 void addPhoneSignalTick(int x, int bin) { 341 mPhoneSignalTicks[mNumPhoneSignalTicks] 342 = x | bin << PHONE_SIGNAL_BIN_SHIFT; 343 mNumPhoneSignalTicks++; 344 } 345 346 void finishPaths(int w, int h, int levelh, int startX, int y, Path curLevelPath, 347 int lastX, boolean lastCharging, boolean lastScreenOn, boolean lastGpsOn, 348 boolean lastWifiRunning, boolean lastWakeLock, int lastPhoneSignal, Path lastPath) { 349 if (curLevelPath != null) { 350 if (lastX >= 0 && lastX < w) { 351 if (lastPath != null) { 352 lastPath.lineTo(w, y); 353 } 354 curLevelPath.lineTo(w, y); 355 } 356 curLevelPath.lineTo(w, mLevelTop+levelh); 357 curLevelPath.lineTo(startX, mLevelTop+levelh); 358 curLevelPath.close(); 359 } 360 361 if (lastCharging) { 362 mChargingPath.lineTo(w, h-mChargingOffset); 363 } 364 if (lastScreenOn) { 365 mScreenOnPath.lineTo(w, h-mScreenOnOffset); 366 } 367 if (lastGpsOn) { 368 mGpsOnPath.lineTo(w, h-mGpsOnOffset); 369 } 370 if (lastWifiRunning) { 371 mWifiRunningPath.lineTo(w, h-mWifiRunningOffset); 372 } 373 if (lastWakeLock) { 374 mWakeLockPath.lineTo(w, h-mWakeLockOffset); 375 } 376 if (lastPhoneSignal != 0) { 377 addPhoneSignalTick(w, 0); 378 } 379 } 380 381 @Override 382 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 383 super.onSizeChanged(w, h, oldw, oldh); 384 385 int textHeight = mTextDescent - mTextAscent; 386 mThinLineWidth = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 387 2, getResources().getDisplayMetrics()); 388 if (h > (textHeight*6)) { 389 mLargeMode = true; 390 mLineWidth = textHeight/2; 391 mLevelTop = textHeight + mLineWidth; 392 } else { 393 mLargeMode = false; 394 mLineWidth = mThinLineWidth; 395 mLevelTop = 0; 396 } 397 if (mLineWidth <= 0) mLineWidth = 1; 398 mTextPaint.setStrokeWidth(mThinLineWidth); 399 mBatteryGoodPaint.setStrokeWidth(mThinLineWidth); 400 mBatteryWarnPaint.setStrokeWidth(mThinLineWidth); 401 mBatteryCriticalPaint.setStrokeWidth(mThinLineWidth); 402 mChargingPaint.setStrokeWidth(mLineWidth); 403 mScreenOnPaint.setStrokeWidth(mLineWidth); 404 mGpsOnPaint.setStrokeWidth(mLineWidth); 405 mWifiRunningPaint.setStrokeWidth(mLineWidth); 406 mWakeLockPaint.setStrokeWidth(mLineWidth); 407 408 if (mLargeMode) { 409 int barOffset = textHeight + mLineWidth; 410 mChargingOffset = mLineWidth; 411 mScreenOnOffset = mChargingOffset + barOffset; 412 mWakeLockOffset = mScreenOnOffset + barOffset; 413 mWifiRunningOffset = mWakeLockOffset + barOffset; 414 mGpsOnOffset = mWifiRunningOffset + (mHaveWifi ? barOffset : 0); 415 mPhoneSignalOffset = mGpsOnOffset + (mHaveGps ? barOffset : 0); 416 mLevelOffset = mPhoneSignalOffset + barOffset + mLineWidth; 417 mPhoneSignalTicks = new int[w+2]; 418 } else { 419 mScreenOnOffset = mGpsOnOffset = mWifiRunningOffset 420 = mWakeLockOffset = mLineWidth; 421 mChargingOffset = mLineWidth*2; 422 mPhoneSignalOffset = 0; 423 mLevelOffset = mLineWidth*3; 424 mPhoneSignalTicks = null; 425 } 426 427 mBatLevelPath.reset(); 428 mBatGoodPath.reset(); 429 mBatWarnPath.reset(); 430 mBatCriticalPath.reset(); 431 mScreenOnPath.reset(); 432 mGpsOnPath.reset(); 433 mWifiRunningPath.reset(); 434 mWakeLockPath.reset(); 435 mChargingPath.reset(); 436 437 final long timeStart = mHistStart; 438 final long timeChange = mHistEnd-mHistStart; 439 440 final int batLow = mBatLow; 441 final int batChange = mBatHigh-mBatLow; 442 443 final int levelh = h - mLevelOffset - mLevelTop; 444 mLevelBottom = mLevelTop + levelh; 445 446 BatteryStats.HistoryItem rec = mHistFirst; 447 int x = 0, y = 0, startX = 0, lastX = -1, lastY = -1; 448 int i = 0; 449 Path curLevelPath = null; 450 Path lastLinePath = null; 451 boolean lastCharging = false, lastScreenOn = false, lastGpsOn = false; 452 boolean lastWifiRunning = false, lastWakeLock = false; 453 int lastPhoneSignalBin = 0; 454 final int N = mNumHist; 455 while (rec != null && i < N) { 456 if (rec.cmd == BatteryStats.HistoryItem.CMD_UPDATE) { 457 x = (int)(((rec.time-timeStart)*w)/timeChange); 458 y = mLevelTop + levelh - ((rec.batteryLevel-batLow)*(levelh-1))/batChange; 459 460 if (lastX != x) { 461 // We have moved by at least a pixel. 462 if (lastY != y) { 463 // Don't plot changes within a pixel. 464 Path path; 465 byte value = rec.batteryLevel; 466 if (value <= BATTERY_CRITICAL) path = mBatCriticalPath; 467 else if (value <= BATTERY_WARN) path = mBatWarnPath; 468 else path = mBatGoodPath; 469 470 if (path != lastLinePath) { 471 if (lastLinePath != null) { 472 lastLinePath.lineTo(x, y); 473 } 474 path.moveTo(x, y); 475 lastLinePath = path; 476 } else { 477 path.lineTo(x, y); 478 } 479 480 if (curLevelPath == null) { 481 curLevelPath = mBatLevelPath; 482 curLevelPath.moveTo(x, y); 483 startX = x; 484 } else { 485 curLevelPath.lineTo(x, y); 486 } 487 lastX = x; 488 lastY = y; 489 } 490 491 final boolean charging = 492 (rec.states&HistoryItem.STATE_BATTERY_PLUGGED_FLAG) != 0; 493 if (charging != lastCharging) { 494 if (charging) { 495 mChargingPath.moveTo(x, h-mChargingOffset); 496 } else { 497 mChargingPath.lineTo(x, h-mChargingOffset); 498 } 499 lastCharging = charging; 500 } 501 502 final boolean screenOn = 503 (rec.states&HistoryItem.STATE_SCREEN_ON_FLAG) != 0; 504 if (screenOn != lastScreenOn) { 505 if (screenOn) { 506 mScreenOnPath.moveTo(x, h-mScreenOnOffset); 507 } else { 508 mScreenOnPath.lineTo(x, h-mScreenOnOffset); 509 } 510 lastScreenOn = screenOn; 511 } 512 513 final boolean gpsOn = 514 (rec.states&HistoryItem.STATE_GPS_ON_FLAG) != 0; 515 if (gpsOn != lastGpsOn) { 516 if (gpsOn) { 517 mGpsOnPath.moveTo(x, h-mGpsOnOffset); 518 } else { 519 mGpsOnPath.lineTo(x, h-mGpsOnOffset); 520 } 521 lastGpsOn = gpsOn; 522 } 523 524 final boolean wifiRunning = 525 (rec.states&HistoryItem.STATE_WIFI_RUNNING_FLAG) != 0; 526 if (wifiRunning != lastWifiRunning) { 527 if (wifiRunning) { 528 mWifiRunningPath.moveTo(x, h-mWifiRunningOffset); 529 } else { 530 mWifiRunningPath.lineTo(x, h-mWifiRunningOffset); 531 } 532 lastWifiRunning = wifiRunning; 533 } 534 535 final boolean wakeLock = 536 (rec.states&HistoryItem.STATE_WAKE_LOCK_FLAG) != 0; 537 if (wakeLock != lastWakeLock) { 538 if (wakeLock) { 539 mWakeLockPath.moveTo(x, h-mWakeLockOffset); 540 } else { 541 mWakeLockPath.lineTo(x, h-mWakeLockOffset); 542 } 543 lastWakeLock = wakeLock; 544 } 545 546 if (mLargeMode) { 547 int bin; 548 if (((rec.states&HistoryItem.STATE_PHONE_STATE_MASK) 549 >> HistoryItem.STATE_PHONE_STATE_SHIFT) 550 == ServiceState.STATE_POWER_OFF) { 551 bin = 0; 552 } else if ((rec.states&HistoryItem.STATE_PHONE_SCANNING_FLAG) != 0) { 553 bin = 1; 554 } else { 555 bin = (rec.states&HistoryItem.STATE_SIGNAL_STRENGTH_MASK) 556 >> HistoryItem.STATE_SIGNAL_STRENGTH_SHIFT; 557 bin += 2; 558 } 559 if (bin != lastPhoneSignalBin) { 560 addPhoneSignalTick(x, bin); 561 lastPhoneSignalBin = bin; 562 } 563 } 564 } 565 566 } else if (rec.cmd != BatteryStats.HistoryItem.CMD_OVERFLOW) { 567 if (curLevelPath != null) { 568 finishPaths(x+1, h, levelh, startX, lastY, curLevelPath, lastX, 569 lastCharging, lastScreenOn, lastGpsOn, lastWifiRunning, 570 lastWakeLock, lastPhoneSignalBin, lastLinePath); 571 lastX = lastY = -1; 572 curLevelPath = null; 573 lastLinePath = null; 574 lastCharging = lastScreenOn = lastGpsOn = lastWakeLock = false; 575 lastPhoneSignalBin = 0; 576 } 577 } 578 579 rec = rec.next; 580 i++; 581 } 582 583 finishPaths(w, h, levelh, startX, lastY, curLevelPath, lastX, 584 lastCharging, lastScreenOn, lastGpsOn, lastWifiRunning, 585 lastWakeLock, lastPhoneSignalBin, lastLinePath); 586 } 587 588 @Override 589 protected void onDraw(Canvas canvas) { 590 super.onDraw(canvas); 591 592 final int width = getWidth(); 593 final int height = getHeight(); 594 595 canvas.drawPath(mBatLevelPath, mBatteryBackgroundPaint); 596 if (mLargeMode) { 597 canvas.drawText(mDurationString, 0, -mTextAscent + (mLineWidth/2), 598 mTextPaint); 599 canvas.drawText(mTotalDurationString, (width/2) - (mTotalDurationStringWidth/2), 600 mLevelBottom - mTextAscent + mThinLineWidth, mTextPaint); 601 } else { 602 canvas.drawText(mDurationString, (width/2) - (mDurationStringWidth/2), 603 (height/2) - ((mTextDescent-mTextAscent)/2) - mTextAscent, mTextPaint); 604 } 605 if (!mBatGoodPath.isEmpty()) { 606 canvas.drawPath(mBatGoodPath, mBatteryGoodPaint); 607 } 608 if (!mBatWarnPath.isEmpty()) { 609 canvas.drawPath(mBatWarnPath, mBatteryWarnPaint); 610 } 611 if (!mBatCriticalPath.isEmpty()) { 612 canvas.drawPath(mBatCriticalPath, mBatteryCriticalPaint); 613 } 614 int lastBin=0, lastX=0; 615 int top = height-mPhoneSignalOffset - (mLineWidth/2); 616 int bottom = top + mLineWidth; 617 for (int i=0; i<mNumPhoneSignalTicks; i++) { 618 int tick = mPhoneSignalTicks[i]; 619 int x = tick&PHONE_SIGNAL_X_MASK; 620 int bin = (tick&PHONE_SIGNAL_BIN_MASK) >> PHONE_SIGNAL_BIN_SHIFT; 621 if (lastBin != 0) { 622 canvas.drawRect(lastX, top, x, bottom, mPhoneSignalPaints[lastBin]); 623 } 624 lastBin = bin; 625 lastX = x; 626 } 627 if (!mScreenOnPath.isEmpty()) { 628 canvas.drawPath(mScreenOnPath, mScreenOnPaint); 629 } 630 if (!mChargingPath.isEmpty()) { 631 canvas.drawPath(mChargingPath, mChargingPaint); 632 } 633 if (mHaveGps) { 634 if (!mGpsOnPath.isEmpty()) { 635 canvas.drawPath(mGpsOnPath, mGpsOnPaint); 636 } 637 } 638 if (mHaveWifi) { 639 if (!mWifiRunningPath.isEmpty()) { 640 canvas.drawPath(mWifiRunningPath, mWifiRunningPaint); 641 } 642 } 643 if (!mWakeLockPath.isEmpty()) { 644 canvas.drawPath(mWakeLockPath, mWakeLockPaint); 645 } 646 647 if (mLargeMode) { 648 canvas.drawText(mPhoneSignalLabel, 0, 649 height - mPhoneSignalOffset - mTextDescent, mTextPaint); 650 if (mHaveGps) { 651 canvas.drawText(mGpsOnLabel, 0, 652 height - mGpsOnOffset - mTextDescent, mTextPaint); 653 } 654 if (mHaveWifi) { 655 canvas.drawText(mWifiRunningLabel, 0, 656 height - mWifiRunningOffset - mTextDescent, mTextPaint); 657 } 658 canvas.drawText(mWakeLockLabel, 0, 659 height - mWakeLockOffset - mTextDescent, mTextPaint); 660 canvas.drawText(mChargingLabel, 0, 661 height - mChargingOffset - mTextDescent, mTextPaint); 662 canvas.drawText(mScreenOnLabel, 0, 663 height - mScreenOnOffset - mTextDescent, mTextPaint); 664 canvas.drawLine(0, mLevelBottom+(mThinLineWidth/2), width, 665 mLevelBottom+(mThinLineWidth/2), mTextPaint); 666 canvas.drawLine(0, mLevelTop, 0, 667 mLevelBottom+(mThinLineWidth/2), mTextPaint); 668 for (int i=0; i<10; i++) { 669 int y = mLevelTop + ((mLevelBottom-mLevelTop)*i)/10; 670 canvas.drawLine(0, y, mThinLineWidth*2, y, mTextPaint); 671 } 672 } 673 } 674} 675