blob: b9ffdbb929e15beb28b925842c2ac1d8633edac4 [file] [log] [blame]
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -04001/*
2 * Copyright (C) 2013 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.systemui;
18
19import android.content.BroadcastReceiver;
20import android.content.Context;
21import android.content.Intent;
22import android.content.IntentFilter;
23import android.content.res.Resources;
24import android.content.res.TypedArray;
25import android.graphics.Canvas;
26import android.graphics.Paint;
John Spurlockfceb7ed2013-09-07 12:39:49 -040027import android.graphics.Path;
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040028import android.graphics.RectF;
29import android.graphics.Typeface;
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040030import android.os.BatteryManager;
John Spurlock3c875662013-08-31 15:07:25 -040031import android.os.Bundle;
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040032import android.provider.Settings;
33import android.util.AttributeSet;
34import android.view.View;
35
John Spurlock3c875662013-08-31 15:07:25 -040036public class BatteryMeterView extends View implements DemoMode {
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040037 public static final String TAG = BatteryMeterView.class.getSimpleName();
38 public static final String ACTION_LEVEL_TEST = "com.android.systemui.BATTERY_LEVEL_TEST";
39
John Spurlock4b786ff2013-12-17 15:19:16 -050040 private static final boolean ENABLE_PERCENT = true;
41 private static final boolean SINGLE_DIGIT_PERCENT = false;
42 private static final boolean SHOW_100_PERCENT = false;
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040043
John Spurlock4b786ff2013-12-17 15:19:16 -050044 private static final int FULL = 96;
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040045
John Spurlock4b786ff2013-12-17 15:19:16 -050046 private static final float SUBPIXEL = 0.4f; // inset rects for softer edges
47 private static final float BOLT_LEVEL_THRESHOLD = 0.3f; // opaque bolt below this fraction
John Spurlockcfab9902013-09-25 18:07:52 -040048
John Spurlock4b786ff2013-12-17 15:19:16 -050049 private final int[] mColors;
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040050
51 boolean mShowPercent = true;
John Spurlock4b786ff2013-12-17 15:19:16 -050052 private final Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint, mBoltPaint;
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040053 private float mTextHeight, mWarningTextHeight;
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040054
55 private int mHeight;
56 private int mWidth;
57 private String mWarningString;
John Spurlock3332ba52014-03-10 17:44:07 -040058 private final int mCriticalLevel;
John Spurlocke189f662013-08-25 10:38:32 -040059 private final int mChargeColor;
John Spurlockfceb7ed2013-09-07 12:39:49 -040060 private final float[] mBoltPoints;
61 private final Path mBoltPath = new Path();
62
63 private final RectF mFrame = new RectF();
64 private final RectF mButtonFrame = new RectF();
John Spurlockd8595fd2013-11-05 11:55:04 -050065 private final RectF mBoltFrame = new RectF();
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040066
John Spurlock4b786ff2013-12-17 15:19:16 -050067 private final Path mShapePath = new Path();
68 private final Path mClipPath = new Path();
John Spurlock1fd0b932014-02-05 11:56:17 -050069 private final Path mTextPath = new Path();
John Spurlock4b786ff2013-12-17 15:19:16 -050070
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040071 private class BatteryTracker extends BroadcastReceiver {
Daniel Sandler05021e52013-10-14 10:27:45 -040072 public static final int UNKNOWN_LEVEL = -1;
73
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040074 // current battery status
Daniel Sandler05021e52013-10-14 10:27:45 -040075 int level = UNKNOWN_LEVEL;
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040076 String percentStr;
77 int plugType;
78 boolean plugged;
79 int health;
80 int status;
81 String technology;
82 int voltage;
83 int temperature;
84 boolean testmode = false;
85
86 @Override
87 public void onReceive(Context context, Intent intent) {
88 final String action = intent.getAction();
89 if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
90 if (testmode && ! intent.getBooleanExtra("testmode", false)) return;
91
92 level = (int)(100f
93 * intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0)
94 / intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100));
95
96 plugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
97 plugged = plugType != 0;
98 health = intent.getIntExtra(BatteryManager.EXTRA_HEALTH,
99 BatteryManager.BATTERY_HEALTH_UNKNOWN);
100 status = intent.getIntExtra(BatteryManager.EXTRA_STATUS,
101 BatteryManager.BATTERY_STATUS_UNKNOWN);
102 technology = intent.getStringExtra(BatteryManager.EXTRA_TECHNOLOGY);
103 voltage = intent.getIntExtra(BatteryManager.EXTRA_VOLTAGE, 0);
104 temperature = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0);
105
106 setContentDescription(
107 context.getString(R.string.accessibility_battery_level, level));
108 postInvalidate();
109 } else if (action.equals(ACTION_LEVEL_TEST)) {
110 testmode = true;
111 post(new Runnable() {
112 int curLevel = 0;
113 int incr = 1;
114 int saveLevel = level;
115 int savePlugged = plugType;
116 Intent dummy = new Intent(Intent.ACTION_BATTERY_CHANGED);
117 @Override
118 public void run() {
119 if (curLevel < 0) {
120 testmode = false;
121 dummy.putExtra("level", saveLevel);
122 dummy.putExtra("plugged", savePlugged);
123 dummy.putExtra("testmode", false);
124 } else {
125 dummy.putExtra("level", curLevel);
126 dummy.putExtra("plugged", incr > 0 ? BatteryManager.BATTERY_PLUGGED_AC : 0);
127 dummy.putExtra("testmode", true);
128 }
129 getContext().sendBroadcast(dummy);
130
131 if (!testmode) return;
132
133 curLevel += incr;
134 if (curLevel == 100) {
135 incr *= -1;
136 }
137 postDelayed(this, 200);
138 }
139 });
140 }
141 }
142 }
143
144 BatteryTracker mTracker = new BatteryTracker();
145
146 @Override
147 public void onAttachedToWindow() {
148 super.onAttachedToWindow();
149
150 IntentFilter filter = new IntentFilter();
151 filter.addAction(Intent.ACTION_BATTERY_CHANGED);
152 filter.addAction(ACTION_LEVEL_TEST);
Daniel Sandler05021e52013-10-14 10:27:45 -0400153 final Intent sticky = getContext().registerReceiver(mTracker, filter);
154 if (sticky != null) {
155 // preload the battery level
156 mTracker.onReceive(getContext(), sticky);
157 }
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400158 }
159
160 @Override
161 public void onDetachedFromWindow() {
162 super.onDetachedFromWindow();
163
164 getContext().unregisterReceiver(mTracker);
165 }
166
167 public BatteryMeterView(Context context) {
168 this(context, null, 0);
169 }
170
171 public BatteryMeterView(Context context, AttributeSet attrs) {
172 this(context, attrs, 0);
173 }
174
175 public BatteryMeterView(Context context, AttributeSet attrs, int defStyle) {
176 super(context, attrs, defStyle);
177
178 final Resources res = context.getResources();
John Spurlock29786fc2014-02-04 17:55:47 -0500179 TypedArray atts = context.obtainStyledAttributes(attrs, R.styleable.BatteryMeterView,
180 defStyle, 0);
181 final int frameColor = atts.getColor(R.styleable.BatteryMeterView_frameColor,
182 res.getColor(R.color.batterymeter_frame_color));
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400183 TypedArray levels = res.obtainTypedArray(R.array.batterymeter_color_levels);
184 TypedArray colors = res.obtainTypedArray(R.array.batterymeter_color_values);
185
186 final int N = levels.length();
187 mColors = new int[2*N];
188 for (int i=0; i<N; i++) {
189 mColors[2*i] = levels.getInt(i, 0);
190 mColors[2*i+1] = colors.getColor(i, 0);
191 }
John Spurlockfceb7ed2013-09-07 12:39:49 -0400192 levels.recycle();
193 colors.recycle();
John Spurlock29786fc2014-02-04 17:55:47 -0500194 atts.recycle();
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400195 mShowPercent = ENABLE_PERCENT && 0 != Settings.System.getInt(
196 context.getContentResolver(), "status_bar_show_battery_percent", 0);
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400197 mWarningString = context.getString(R.string.battery_meter_very_low_overlay_symbol);
John Spurlock3332ba52014-03-10 17:44:07 -0400198 mCriticalLevel = mContext.getResources().getInteger(
199 com.android.internal.R.integer.config_criticalBatteryWarningLevel);
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400200
201 mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
John Spurlock29786fc2014-02-04 17:55:47 -0500202 mFramePaint.setColor(frameColor);
John Spurlockcfab9902013-09-25 18:07:52 -0400203 mFramePaint.setDither(true);
204 mFramePaint.setStrokeWidth(0);
205 mFramePaint.setStyle(Paint.Style.FILL_AND_STROKE);
John Spurlockcfab9902013-09-25 18:07:52 -0400206
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400207 mBatteryPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
John Spurlockcfab9902013-09-25 18:07:52 -0400208 mBatteryPaint.setDither(true);
209 mBatteryPaint.setStrokeWidth(0);
210 mBatteryPaint.setStyle(Paint.Style.FILL_AND_STROKE);
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400211
212 mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
John Spurlock4b786ff2013-12-17 15:19:16 -0500213 Typeface font = Typeface.create("sans-serif-condensed", Typeface.BOLD);
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400214 mTextPaint.setTypeface(font);
215 mTextPaint.setTextAlign(Paint.Align.CENTER);
216
217 mWarningTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
218 mWarningTextPaint.setColor(mColors[1]);
219 font = Typeface.create("sans-serif", Typeface.BOLD);
220 mWarningTextPaint.setTypeface(font);
221 mWarningTextPaint.setTextAlign(Paint.Align.CENTER);
222
John Spurlocke189f662013-08-25 10:38:32 -0400223 mChargeColor = getResources().getColor(R.color.batterymeter_charge_color);
John Spurlockfceb7ed2013-09-07 12:39:49 -0400224
John Spurlock4b786ff2013-12-17 15:19:16 -0500225 mBoltPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
John Spurlockcfab9902013-09-25 18:07:52 -0400226 mBoltPaint.setColor(res.getColor(R.color.batterymeter_bolt_color));
John Spurlockfceb7ed2013-09-07 12:39:49 -0400227 mBoltPoints = loadBoltPoints(res);
228 }
229
230 private static float[] loadBoltPoints(Resources res) {
231 final int[] pts = res.getIntArray(R.array.batterymeter_bolt_points);
232 int maxX = 0, maxY = 0;
233 for (int i = 0; i < pts.length; i += 2) {
234 maxX = Math.max(maxX, pts[i]);
235 maxY = Math.max(maxY, pts[i + 1]);
236 }
237 final float[] ptsF = new float[pts.length];
238 for (int i = 0; i < pts.length; i += 2) {
239 ptsF[i] = (float)pts[i] / maxX;
240 ptsF[i + 1] = (float)pts[i + 1] / maxY;
241 }
242 return ptsF;
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400243 }
244
245 @Override
246 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
247 mHeight = h;
248 mWidth = w;
249 mWarningTextPaint.setTextSize(h * 0.75f);
250 mWarningTextHeight = -mWarningTextPaint.getFontMetrics().ascent;
251 }
252
253 private int getColorForLevel(int percent) {
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400254 int thresh, color = 0;
255 for (int i=0; i<mColors.length; i+=2) {
256 thresh = mColors[i];
257 color = mColors[i+1];
258 if (percent <= thresh) return color;
259 }
260 return color;
261 }
262
263 @Override
264 public void draw(Canvas c) {
John Spurlock3c875662013-08-31 15:07:25 -0400265 BatteryTracker tracker = mDemoMode ? mDemoTracker : mTracker;
266 final int level = tracker.level;
Daniel Sandler05021e52013-10-14 10:27:45 -0400267
268 if (level == BatteryTracker.UNKNOWN_LEVEL) return;
269
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400270 float drawFrac = (float) level / 100f;
271 final int pt = getPaddingTop();
272 final int pl = getPaddingLeft();
273 final int pr = getPaddingRight();
274 final int pb = getPaddingBottom();
John Spurlock4b786ff2013-12-17 15:19:16 -0500275 final int height = mHeight - pt - pb;
276 final int width = mWidth - pl - pr;
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400277
John Spurlock4b786ff2013-12-17 15:19:16 -0500278 final int buttonHeight = (int) (height * 0.12f);
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400279
John Spurlockfceb7ed2013-09-07 12:39:49 -0400280 mFrame.set(0, 0, width, height);
281 mFrame.offset(pl, pt);
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400282
John Spurlock4b786ff2013-12-17 15:19:16 -0500283 // button-frame: area above the battery body
John Spurlockfceb7ed2013-09-07 12:39:49 -0400284 mButtonFrame.set(
285 mFrame.left + width * 0.25f,
286 mFrame.top,
287 mFrame.right - width * 0.25f,
John Spurlock4b786ff2013-12-17 15:19:16 -0500288 mFrame.top + buttonHeight);
John Spurlockcfab9902013-09-25 18:07:52 -0400289
290 mButtonFrame.top += SUBPIXEL;
291 mButtonFrame.left += SUBPIXEL;
292 mButtonFrame.right -= SUBPIXEL;
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400293
John Spurlock4b786ff2013-12-17 15:19:16 -0500294 // frame: battery body area
295 mFrame.top += buttonHeight;
John Spurlockcfab9902013-09-25 18:07:52 -0400296 mFrame.left += SUBPIXEL;
297 mFrame.top += SUBPIXEL;
298 mFrame.right -= SUBPIXEL;
299 mFrame.bottom -= SUBPIXEL;
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400300
John Spurlock4b786ff2013-12-17 15:19:16 -0500301 // set the battery charging color
302 mBatteryPaint.setColor(tracker.plugged ? mChargeColor : getColorForLevel(level));
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400303
304 if (level >= FULL) {
305 drawFrac = 1f;
John Spurlock3332ba52014-03-10 17:44:07 -0400306 } else if (level <= mCriticalLevel) {
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400307 drawFrac = 0f;
308 }
309
John Spurlock4b786ff2013-12-17 15:19:16 -0500310 final float levelTop = drawFrac == 1f ? mButtonFrame.top
311 : (mFrame.top + (mFrame.height() * (1f - drawFrac)));
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400312
John Spurlock4b786ff2013-12-17 15:19:16 -0500313 // define the battery shape
314 mShapePath.reset();
315 mShapePath.moveTo(mButtonFrame.left, mButtonFrame.top);
316 mShapePath.lineTo(mButtonFrame.right, mButtonFrame.top);
317 mShapePath.lineTo(mButtonFrame.right, mFrame.top);
318 mShapePath.lineTo(mFrame.right, mFrame.top);
319 mShapePath.lineTo(mFrame.right, mFrame.bottom);
320 mShapePath.lineTo(mFrame.left, mFrame.bottom);
321 mShapePath.lineTo(mFrame.left, mFrame.top);
322 mShapePath.lineTo(mButtonFrame.left, mFrame.top);
323 mShapePath.lineTo(mButtonFrame.left, mButtonFrame.top);
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400324
John Spurlockd19877f2013-09-17 11:03:03 -0400325 if (tracker.plugged) {
John Spurlock4b786ff2013-12-17 15:19:16 -0500326 // define the bolt shape
John Spurlockd8595fd2013-11-05 11:55:04 -0500327 final float bl = mFrame.left + mFrame.width() / 4.5f;
328 final float bt = mFrame.top + mFrame.height() / 6f;
329 final float br = mFrame.right - mFrame.width() / 7f;
330 final float bb = mFrame.bottom - mFrame.height() / 10f;
John Spurlockfceb7ed2013-09-07 12:39:49 -0400331 if (mBoltFrame.left != bl || mBoltFrame.top != bt
332 || mBoltFrame.right != br || mBoltFrame.bottom != bb) {
333 mBoltFrame.set(bl, bt, br, bb);
334 mBoltPath.reset();
335 mBoltPath.moveTo(
336 mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
337 mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
338 for (int i = 2; i < mBoltPoints.length; i += 2) {
339 mBoltPath.lineTo(
340 mBoltFrame.left + mBoltPoints[i] * mBoltFrame.width(),
341 mBoltFrame.top + mBoltPoints[i + 1] * mBoltFrame.height());
342 }
343 mBoltPath.lineTo(
344 mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
345 mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
346 }
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400347
John Spurlock4b786ff2013-12-17 15:19:16 -0500348 float boltPct = (mBoltFrame.bottom - levelTop) / (mBoltFrame.bottom - mBoltFrame.top);
349 boltPct = Math.min(Math.max(boltPct, 0), 1);
350 if (boltPct <= BOLT_LEVEL_THRESHOLD) {
351 // draw the bolt if opaque
352 c.drawPath(mBoltPath, mBoltPaint);
353 } else {
354 // otherwise cut the bolt out of the overall shape
355 mShapePath.op(mBoltPath, Path.Op.DIFFERENCE);
356 }
357 }
358
John Spurlock1fd0b932014-02-05 11:56:17 -0500359 // compute percentage text
360 boolean pctOpaque = false;
361 float pctX = 0, pctY = 0;
362 String pctText = null;
John Spurlock3332ba52014-03-10 17:44:07 -0400363 if (!tracker.plugged && level > mCriticalLevel && mShowPercent
John Spurlock1fd0b932014-02-05 11:56:17 -0500364 && !(tracker.level == 100 && !SHOW_100_PERCENT)) {
365 mTextPaint.setColor(getColorForLevel(level));
366 mTextPaint.setTextSize(height *
367 (SINGLE_DIGIT_PERCENT ? 0.75f
368 : (tracker.level == 100 ? 0.38f : 0.5f)));
369 mTextHeight = -mTextPaint.getFontMetrics().ascent;
370 pctText = String.valueOf(SINGLE_DIGIT_PERCENT ? (level/10) : level);
371 pctX = mWidth * 0.5f;
372 pctY = (mHeight + mTextHeight) * 0.47f;
373 pctOpaque = levelTop > pctY;
374 if (!pctOpaque) {
375 mTextPath.reset();
376 mTextPaint.getTextPath(pctText, 0, pctText.length(), pctX, pctY, mTextPath);
377 // cut the percentage text out of the overall shape
378 mShapePath.op(mTextPath, Path.Op.DIFFERENCE);
379 }
380 }
381
John Spurlock4b786ff2013-12-17 15:19:16 -0500382 // draw the battery shape background
383 c.drawPath(mShapePath, mFramePaint);
384
385 // draw the battery shape, clipped to charging level
386 mFrame.top = levelTop;
387 mClipPath.reset();
388 mClipPath.addRect(mFrame, Path.Direction.CCW);
389 mShapePath.op(mClipPath, Path.Op.INTERSECT);
390 c.drawPath(mShapePath, mBatteryPaint);
391
392 if (!tracker.plugged) {
John Spurlock3332ba52014-03-10 17:44:07 -0400393 if (level <= mCriticalLevel) {
John Spurlock4b786ff2013-12-17 15:19:16 -0500394 // draw the warning text
395 final float x = mWidth * 0.5f;
396 final float y = (mHeight + mWarningTextHeight) * 0.48f;
397 c.drawText(mWarningString, x, y, mWarningTextPaint);
John Spurlock1fd0b932014-02-05 11:56:17 -0500398 } else if (pctOpaque) {
John Spurlock4b786ff2013-12-17 15:19:16 -0500399 // draw the percentage text
John Spurlock1fd0b932014-02-05 11:56:17 -0500400 c.drawText(pctText, pctX, pctY, mTextPaint);
John Spurlock4b786ff2013-12-17 15:19:16 -0500401 }
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400402 }
403 }
John Spurlock3c875662013-08-31 15:07:25 -0400404
Jorim Jaggi0d266892014-07-28 14:49:13 +0200405 @Override
406 public boolean hasOverlappingRendering() {
407 return false;
408 }
409
John Spurlock3c875662013-08-31 15:07:25 -0400410 private boolean mDemoMode;
411 private BatteryTracker mDemoTracker = new BatteryTracker();
412
413 @Override
414 public void dispatchDemoCommand(String command, Bundle args) {
415 if (!mDemoMode && command.equals(COMMAND_ENTER)) {
416 mDemoMode = true;
417 mDemoTracker.level = mTracker.level;
418 mDemoTracker.plugged = mTracker.plugged;
419 } else if (mDemoMode && command.equals(COMMAND_EXIT)) {
420 mDemoMode = false;
421 postInvalidate();
422 } else if (mDemoMode && command.equals(COMMAND_BATTERY)) {
423 String level = args.getString("level");
424 String plugged = args.getString("plugged");
425 if (level != null) {
426 mDemoTracker.level = Math.min(Math.max(Integer.parseInt(level), 0), 100);
427 }
428 if (plugged != null) {
429 mDemoTracker.plugged = Boolean.parseBoolean(plugged);
430 }
431 postInvalidate();
432 }
433 }
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400434}