1fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson/* 293e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas * Copyright (C) 2012 The Android Open Source Project 3fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson * 4fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson * Licensed under the Apache License, Version 2.0 (the "License"); 5fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson * you may not use this file except in compliance with the License. 6fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson * You may obtain a copy of the License at 7fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson * 8fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson * http://www.apache.org/licenses/LICENSE-2.0 9fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson * 10fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson * Unless required by applicable law or agreed to in writing, software 11fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson * distributed under the License is distributed on an "AS IS" BASIS, 12fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson * See the License for the specific language governing permissions and 14fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson * limitations under the License. 15fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson */ 16fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson 17fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelsonpackage com.android.deskclock.timer; 18fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson 19fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelsonimport android.content.Context; 20fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelsonimport android.content.res.Resources; 21fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelsonimport android.graphics.Canvas; 227b5c5b16646932fbe991c86ffd9404cdbdc0f84fJustin Klaassenimport android.graphics.Color; 23fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelsonimport android.graphics.Paint; 24fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelsonimport android.graphics.Typeface; 2593e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultasimport android.text.TextUtils; 26fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelsonimport android.util.AttributeSet; 274261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Tingimport android.view.MotionEvent; 28fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelsonimport android.view.View; 291c4ab87072b0fb21e05ed221acd28560d6110b12Sara Tingimport android.view.accessibility.AccessibilityManager; 30fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson 31cdbb71b08c13c84af850f4036febc0b90dcfcc7dJustin Klaassenimport com.android.deskclock.LogUtils; 32fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelsonimport com.android.deskclock.R; 3372332c2290d17c344ece074726f72b35ea469f31Sam Blitzsteinimport com.android.deskclock.Utils; 34fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson 356a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas/** 366a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas * Class to measure and draw the time in the {@link com.android.deskclock.CircleTimerView}. 376a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas * This class manages and sums the work of the four members mBigHours, mBigMinutes, 386a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas * mBigSeconds and mMedHundredths. Those members are each tasked with measuring, sizing and 396a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas * drawing digits (and optional label) of the time set in {@link #setTime(long, boolean, boolean)} 406a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas */ 41fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelsonpublic class CountingTimerView extends View { 42fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson private static final String TWO_DIGITS = "%02d"; 43fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson private static final String ONE_DIGIT = "%01d"; 44fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson private static final String NEG_TWO_DIGITS = "-%02d"; 45fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson private static final String NEG_ONE_DIGIT = "-%01d"; 46efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas private static final float TEXT_SIZE_TO_WIDTH_RATIO = 0.85f; 476a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas // This is the ratio of the font height needed to vertically offset the font for alignment 486a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas // from the center. 49d049a230efed6c04cf7d2ab8cc176d9f4f56e51aYorke Lee private static final float FONT_VERTICAL_OFFSET = 0.14f; 50d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas // Ratio of the space trailing the Hours and Minutes 51efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas private static final float HOURS_MINUTES_SPACING = 0.4f; 52d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas // Ratio of the space leading the Hundredths 53d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas private static final float HUNDREDTHS_SPACING = 0.5f; 54efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas // Radial offset of the enclosing circle 55efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas private final float mRadiusOffset; 56fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson 5793e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas private String mHours, mMinutes, mSeconds, mHundredths; 58fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson 59fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson private boolean mShowTimeStr = true; 60fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson private final Paint mPaintBigThin = new Paint(); 61fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson private final Paint mPaintMed = new Paint(); 6293e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas private final float mBigFontSize, mSmallFontSize; 636a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas // Hours and minutes are signed for when a timer goes past the set time and thus negative 649cddb91746c17851627e874f5824b6f3cb1bfeffIsaac Katzenelson private final SignedTime mBigHours, mBigMinutes; 656a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas // Seconds are always shown with minutes, so are never signed 666a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas private final UnsignedTime mBigSeconds; 679cddb91746c17851627e874f5824b6f3cb1bfeffIsaac Katzenelson private final Hundredths mMedHundredths; 68d049a230efed6c04cf7d2ab8cc176d9f4f56e51aYorke Lee private float mTextHeight = 0; 69fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson private float mTotalTextWidth; 70fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson private boolean mRemeasureText = true; 711a1b54d6fe0c9e4f478a9e96f3cb6b49f72720edRobyn Coultas 721a1b54d6fe0c9e4f478a9e96f3cb6b49f72720edRobyn Coultas private int mDefaultColor; 734261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting private final int mPressedColor; 741a1b54d6fe0c9e4f478a9e96f3cb6b49f72720edRobyn Coultas private final int mWhiteColor; 7569a4b4f2810100f19e997b4e539f1b0e56b0afb5rachelzhang private final int mAccentColor; 761c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting private final AccessibilityManager mAccessibilityManager; 774261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting 784261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting // Fields for the text serving as a virtual button. 794261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting private boolean mVirtualButtonEnabled = false; 804261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting private boolean mVirtualButtonPressedOn = false; 81fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson 82fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson Runnable mBlinkThread = new Runnable() { 8300cb5981c984bc13aa2f6af510a9dd9a784f2af0Sam Blitzstein private boolean mVisible = true; 84fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson @Override 85fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson public void run() { 8600cb5981c984bc13aa2f6af510a9dd9a784f2af0Sam Blitzstein mVisible = !mVisible; 8700cb5981c984bc13aa2f6af510a9dd9a784f2af0Sam Blitzstein CountingTimerView.this.showTime(mVisible); 88fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson postDelayed(mBlinkThread, 500); 89fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson } 90fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson }; 91fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson 926a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas /** 936a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas * Class to measure and draw the digit pairs of hours, minutes, seconds or hundredths. Digits 946a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas * may have an optional label. for hours, minutes and seconds, this label trails the digits 956a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas * and for seconds, precedes the digits. 966a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas */ 97d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas static class UnsignedTime { 9893e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas protected Paint mPaint; 9993e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas protected float mEm; 10093e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas protected float mWidth = 0; 1019cddb91746c17851627e874f5824b6f3cb1bfeffIsaac Katzenelson private final String mWidest; 102d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas protected final float mSpacingRatio; 10393e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas private float mLabelWidth = 0; 10493e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas 105d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas public UnsignedTime(Paint paint, float spacingRatio, String allDigits) { 10693e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas mPaint = paint; 107d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas mSpacingRatio = spacingRatio; 10893e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas 10993e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas if (TextUtils.isEmpty(allDigits)) { 110cdbb71b08c13c84af850f4036febc0b90dcfcc7dJustin Klaassen LogUtils.wtf("Locale digits missing - using English"); 11193e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas allDigits = "0123456789"; 11293e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } 11393e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas 11493e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas float widths[] = new float[allDigits.length()]; 11593e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas int ll = mPaint.getTextWidths(allDigits, widths); 11693e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas int largest = 0; 11793e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas for (int ii = 1; ii < ll; ii++) { 11893e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas if (widths[ii] > widths[largest]) { 11993e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas largest = ii; 12093e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } 12193e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } 12293e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas 12393e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas mEm = widths[largest]; 12493e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas mWidest = allDigits.substring(largest, largest + 1); 12593e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } 12693e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas 127d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas public UnsignedTime(UnsignedTime unsignedTime, float spacingRatio) { 12893e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas this.mPaint = unsignedTime.mPaint; 12993e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas this.mEm = unsignedTime.mEm; 13093e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas this.mWidth = unsignedTime.mWidth; 13193e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas this.mWidest = unsignedTime.mWidest; 132d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas this.mSpacingRatio = spacingRatio; 13393e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } 13493e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas 13593e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas protected void updateWidth(final String time) { 13693e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas mEm = mPaint.measureText(mWidest); 137d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas mLabelWidth = mSpacingRatio * mEm; 13893e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas mWidth = time.length() * mEm; 13993e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } 14093e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas 14193e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas protected void resetWidth() { 14293e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas mWidth = mLabelWidth = 0; 14393e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } 14493e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas 14593e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas public float calcTotalWidth(final String time) { 14693e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas if (time != null) { 14793e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas updateWidth(time); 14893e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas return mWidth + mLabelWidth; 14993e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } else { 15093e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas resetWidth(); 15193e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas return 0; 15293e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } 15393e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } 15493e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas 15593e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas public float getLabelWidth() { 15693e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas return mLabelWidth; 15793e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } 15893e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas 159d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas /** 160d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas * Draws each character with a fixed spacing from time starting at ii. 161d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas * @param canvas the canvas on which the time segment will be drawn 162d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas * @param time time segment 163d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas * @param ii what character to start the draw 164d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas * @param x offset 165d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas * @param y offset 166d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas * @return X location for the next segment 167d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas */ 16893e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas protected float drawTime(Canvas canvas, final String time, int ii, float x, float y) { 16993e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas float textEm = mEm / 2f; 17093e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas while (ii < time.length()) { 17193e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas x += textEm; 17293e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas canvas.drawText(time.substring(ii, ii + 1), x, y, mPaint); 17393e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas x += textEm; 17493e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas ii++; 17593e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } 17693e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas return x; 17793e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } 17893e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas 179d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas /** 180d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas * Draw this time segment and append the intra-segment spacing to the x 181d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas * @param canvas the canvas on which the time segment will be drawn 182d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas * @param time time segment 183d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas * @param x offset 184d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas * @param y offset 185d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas * @return X location for the next segment 186d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas */ 187d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas public float draw(Canvas canvas, final String time, float x, float y) { 188d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas return drawTime(canvas, time, 0, x, y) + getLabelWidth(); 18993e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } 19093e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } 19193e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas 1926a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas /** 1936a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas * Special derivation to handle the hundredths painting with the label in front. 1946a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas */ 195d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas static class Hundredths extends UnsignedTime { 196d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas public Hundredths(Paint paint, float spacingRatio, final String allDigits) { 197d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas super(paint, spacingRatio, allDigits); 19893e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } 19993e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas 200d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas /** 201d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas * Draw this time segment after prepending the intra-segment spacing to the x location. 202d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas * {@link UnsignedTime#draw(android.graphics.Canvas, String, float, float)} 203d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas */ 20493e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas @Override 205d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas public float draw(Canvas canvas, final String time, float x, float y) { 20693e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas return drawTime(canvas, time, 0, x + getLabelWidth(), y); 20793e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } 20893e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } 20993e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas 2106a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas /** 2116a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas * Special derivation to handle a negative number 2126a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas */ 213d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas static class SignedTime extends UnsignedTime { 21493e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas private float mMinusWidth = 0; 21593e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas 216d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas public SignedTime (UnsignedTime unsignedTime, float spacingRatio) { 217d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas super(unsignedTime, spacingRatio); 21893e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } 21993e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas 22093e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas @Override 22193e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas protected void updateWidth(final String time) { 22293e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas super.updateWidth(time); 22393e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas if (time.contains("-")) { 22493e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas mMinusWidth = mPaint.measureText("-"); 22593e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas mWidth += (mMinusWidth - mEm); 22693e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } else { 22793e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas mMinusWidth = 0; 22893e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } 22993e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } 23093e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas 23193e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas @Override 23293e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas protected void resetWidth() { 23393e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas super.resetWidth(); 23493e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas mMinusWidth = 0; 23593e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } 23693e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas 237d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas /** 238d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas * Draws each character with a fixed spacing from time, handling the special negative 239d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas * number case. 240d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas * {@link UnsignedTime#draw(android.graphics.Canvas, String, float, float)} 241d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas */ 24293e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas @Override 243d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas public float draw(Canvas canvas, final String time, float x, float y) { 24493e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas int ii = 0; 24593e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas if (mMinusWidth != 0f) { 24693e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas float minusWidth = mMinusWidth / 2; 24793e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas x += minusWidth; 248d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas //TODO:hyphen is too thick when painted 2496a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas canvas.drawText(time.substring(0, 1), x, y, mPaint); 25093e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas x += minusWidth; 25193e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas ii++; 25293e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } 253d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas return drawTime(canvas, time, ii, x, y) + getLabelWidth(); 25493e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } 25593e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } 256fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson 2576a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas @SuppressWarnings("unused") 258fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson public CountingTimerView(Context context) { 259fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson this(context, null); 260fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson } 261fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson 262fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson public CountingTimerView(Context context, AttributeSet attrs) { 263fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson super(context, attrs); 2641c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting mAccessibilityManager = 2651c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE); 266fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson Resources r = context.getResources(); 2677b5c5b16646932fbe991c86ffd9404cdbdc0f84fJustin Klaassen mDefaultColor = mWhiteColor = r.getColor(R.color.clock_white); 2687b5c5b16646932fbe991c86ffd9404cdbdc0f84fJustin Klaassen mPressedColor = mAccentColor = Utils.obtainStyledColor( 2697b5c5b16646932fbe991c86ffd9404cdbdc0f84fJustin Klaassen context, R.attr.colorAccent, Color.RED); 27093e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas mBigFontSize = r.getDimension(R.dimen.big_font_size); 27193e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas mSmallFontSize = r.getDimension(R.dimen.small_font_size); 2721a1b54d6fe0c9e4f478a9e96f3cb6b49f72720edRobyn Coultas 2736a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas Typeface androidClockMonoThin = Typeface. 2746a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas createFromAsset(context.getAssets(), "fonts/AndroidClockMono-Thin.ttf"); 275fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson mPaintBigThin.setAntiAlias(true); 276fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson mPaintBigThin.setStyle(Paint.Style.STROKE); 27793e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas mPaintBigThin.setTextAlign(Paint.Align.CENTER); 2786a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas mPaintBigThin.setTypeface(androidClockMonoThin); 279fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson 2806a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas Typeface androidClockMonoLight = Typeface. 2816a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas createFromAsset(context.getAssets(), "fonts/AndroidClockMono-Light.ttf"); 282fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson mPaintMed.setAntiAlias(true); 283fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson mPaintMed.setStyle(Paint.Style.STROKE); 28493e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas mPaintMed.setTextAlign(Paint.Align.CENTER); 2856a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas mPaintMed.setTypeface(androidClockMonoLight); 286fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson 28793e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas resetTextSize(); 2881a1b54d6fe0c9e4f478a9e96f3cb6b49f72720edRobyn Coultas setTextColor(mDefaultColor); 28993e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas 29093e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas // allDigits will contain ten digits: "0123456789" in the default locale 29193e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas final String allDigits = String.format("%010d", 123456789); 292d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas mBigSeconds = new UnsignedTime(mPaintBigThin, 0.f, allDigits); 293d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas mBigHours = new SignedTime(mBigSeconds, HOURS_MINUTES_SPACING); 294d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas mBigMinutes = new SignedTime(mBigSeconds, HOURS_MINUTES_SPACING); 295d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas mMedHundredths = new Hundredths(mPaintMed, HUNDREDTHS_SPACING, allDigits); 296efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas 297efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas mRadiusOffset = Utils.calculateRadiusOffset(r); 29893e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } 29993e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas 30093e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas protected void resetTextSize() { 30193e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas mTextHeight = mBigFontSize; 30293e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas mPaintBigThin.setTextSize(mBigFontSize); 30393e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas mPaintMed.setTextSize(mSmallFontSize); 3041a1b54d6fe0c9e4f478a9e96f3cb6b49f72720edRobyn Coultas } 3051a1b54d6fe0c9e4f478a9e96f3cb6b49f72720edRobyn Coultas 3061a1b54d6fe0c9e4f478a9e96f3cb6b49f72720edRobyn Coultas protected void setTextColor(int textColor) { 3071a1b54d6fe0c9e4f478a9e96f3cb6b49f72720edRobyn Coultas mPaintBigThin.setColor(textColor); 3081a1b54d6fe0c9e4f478a9e96f3cb6b49f72720edRobyn Coultas mPaintMed.setColor(textColor); 309fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson } 310fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson 3116a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas /** 3126a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas * Update the time to display. Separates that time into the hours, minutes, seconds and 3136a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas * hundredths. If update is true, the view is invalidated so that it will draw again. 3146a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas * 3156a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas * @param time new time to display - in milliseconds 3166a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas * @param showHundredths flag to show hundredths resolution 3176a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas * @param update to invalidate the view - otherwise the time is examined to see if it is within 3186a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas * 100 milliseconds of zero seconds and when so, invalidate the view. 3196a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas */ 320d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas // TODO:showHundredths S/B attribute or setter - i.e. unchanging over object life 32126fd3d012330e5abf4f6452e811938374004d0d8Sam Blitzstein public void setTime(long time, boolean showHundredths, boolean update) { 3226a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas int oldLength = getDigitsLength(); 32326fd3d012330e5abf4f6452e811938374004d0d8Sam Blitzstein boolean neg = false, showNeg = false; 3246a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas String format; 325fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson if (time < 0) { 3260cb4a8571f6473c422cb69e469aa12f17458ff0dIsaac Katzenelson time = -time; 32726fd3d012330e5abf4f6452e811938374004d0d8Sam Blitzstein neg = showNeg = true; 328fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson } 329fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson long hundreds, seconds, minutes, hours; 330287f2d82aaf91d881f5de50a133d21684a8d4821Sam Blitzstein seconds = time / 1000; 331287f2d82aaf91d881f5de50a133d21684a8d4821Sam Blitzstein hundreds = (time - seconds * 1000) / 10; 332fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson minutes = seconds / 60; 333fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson seconds = seconds - minutes * 60; 334fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson hours = minutes / 60; 335fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson minutes = minutes - hours * 60; 33687bf27c22cf71bfb89e97eba92d4513148d3d8c8Robyn Coultas if (hours > 999) { 337fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson hours = 0; 338fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson } 3396a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas // The time can be between 0 and -1 seconds, but the "truncated" equivalent time of hours 3406a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas // and minutes and seconds could be zero, so since we do not show fractions of seconds 3410cb4a8571f6473c422cb69e469aa12f17458ff0dIsaac Katzenelson // when counting down, do not show the minus sign. 342d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas // TODO:does it matter that we do not look at showHundredths? 3436a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas if (hours == 0 && minutes == 0 && seconds == 0) { 34426fd3d012330e5abf4f6452e811938374004d0d8Sam Blitzstein showNeg = false; 3450cb4a8571f6473c422cb69e469aa12f17458ff0dIsaac Katzenelson } 34693e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas 3476a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas // Normalize and check if it is 'time' to invalidate 3488daab6be9a079de0bf2c0f26601a753ca9a71617Sam Blitzstein if (!showHundredths) { 3498daab6be9a079de0bf2c0f26601a753ca9a71617Sam Blitzstein if (!neg && hundreds != 0) { 3508daab6be9a079de0bf2c0f26601a753ca9a71617Sam Blitzstein seconds++; 3518daab6be9a079de0bf2c0f26601a753ca9a71617Sam Blitzstein if (seconds == 60) { 3528daab6be9a079de0bf2c0f26601a753ca9a71617Sam Blitzstein seconds = 0; 3538daab6be9a079de0bf2c0f26601a753ca9a71617Sam Blitzstein minutes++; 3548daab6be9a079de0bf2c0f26601a753ca9a71617Sam Blitzstein if (minutes == 60) { 3558daab6be9a079de0bf2c0f26601a753ca9a71617Sam Blitzstein minutes = 0; 3568daab6be9a079de0bf2c0f26601a753ca9a71617Sam Blitzstein hours++; 3578daab6be9a079de0bf2c0f26601a753ca9a71617Sam Blitzstein } 3588daab6be9a079de0bf2c0f26601a753ca9a71617Sam Blitzstein } 3598daab6be9a079de0bf2c0f26601a753ca9a71617Sam Blitzstein } 3608daab6be9a079de0bf2c0f26601a753ca9a71617Sam Blitzstein if (hundreds < 10 || hundreds > 90) { 3618daab6be9a079de0bf2c0f26601a753ca9a71617Sam Blitzstein update = true; 3628daab6be9a079de0bf2c0f26601a753ca9a71617Sam Blitzstein } 3638daab6be9a079de0bf2c0f26601a753ca9a71617Sam Blitzstein } 3648daab6be9a079de0bf2c0f26601a753ca9a71617Sam Blitzstein 3656a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas // Hours may be empty 366fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson if (hours >= 10) { 36726fd3d012330e5abf4f6452e811938374004d0d8Sam Blitzstein format = showNeg ? NEG_TWO_DIGITS : TWO_DIGITS; 368fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson mHours = String.format(format, hours); 369fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson } else if (hours > 0) { 37026fd3d012330e5abf4f6452e811938374004d0d8Sam Blitzstein format = showNeg ? NEG_ONE_DIGIT : ONE_DIGIT; 371fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson mHours = String.format(format, hours); 372fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson } else { 373fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson mHours = null; 374fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson } 375fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson 3766a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas // Minutes are never empty and when hours are non-empty, must be two digits 377fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson if (minutes >= 10 || hours > 0) { 37826fd3d012330e5abf4f6452e811938374004d0d8Sam Blitzstein format = (showNeg && hours == 0) ? NEG_TWO_DIGITS : TWO_DIGITS; 379fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson mMinutes = String.format(format, minutes); 380fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson } else { 38126fd3d012330e5abf4f6452e811938374004d0d8Sam Blitzstein format = (showNeg && hours == 0) ? NEG_ONE_DIGIT : ONE_DIGIT; 382fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson mMinutes = String.format(format, minutes); 383fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson } 384fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson 3856a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas // Seconds are always two digits 386fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson mSeconds = String.format(TWO_DIGITS, seconds); 3876a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas 3886a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas // Hundredths are optional and then two digits 389fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson if (showHundredths) { 39093e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas mHundredths = String.format(TWO_DIGITS, hundreds); 391fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson } else { 39293e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas mHundredths = null; 39393e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } 39493e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas 39593e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas int newLength = getDigitsLength(); 39693e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas if (oldLength != newLength) { 39793e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas if (oldLength > newLength) { 39893e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas resetTextSize(); 39993e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } 40093e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas mRemeasureText = true; 401fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson } 40226fd3d012330e5abf4f6452e811938374004d0d8Sam Blitzstein 40326fd3d012330e5abf4f6452e811938374004d0d8Sam Blitzstein if (update) { 4041c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting setContentDescription(getTimeStringForAccessibility((int) hours, (int) minutes, 4051c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting (int) seconds, showNeg, getResources())); 4065f594531901d5f562c0c6a8e1d4ffd2e57709764Daria Evdokimova postInvalidateOnAnimation(); 40726fd3d012330e5abf4f6452e811938374004d0d8Sam Blitzstein } 408fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson } 409fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson 41093e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas private int getDigitsLength() { 41193e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas return ((mHours == null) ? 0 : mHours.length()) 41293e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas + ((mMinutes == null) ? 0 : mMinutes.length()) 41393e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas + ((mSeconds == null) ? 0 : mSeconds.length()) 41493e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas + ((mHundredths == null) ? 0 : mHundredths.length()); 41593e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } 41693e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas 41793e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas private void calcTotalTextWidth() { 41893e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas mTotalTextWidth = mBigHours.calcTotalWidth(mHours) + mBigMinutes.calcTotalWidth(mMinutes) 4196a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas + mBigSeconds.calcTotalWidth(mSeconds) 42093e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas + mMedHundredths.calcTotalWidth(mHundredths); 42193e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } 42293e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas 423efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas /** 424efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas * Adjust the size of the fonts to fit within the the circle and painted object in 425efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas * {@link com.android.deskclock.CircleTimerView#onDraw(android.graphics.Canvas)} 426efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas */ 42793e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas private void setTotalTextWidth() { 42893e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas calcTotalTextWidth(); 429d049a230efed6c04cf7d2ab8cc176d9f4f56e51aYorke Lee // To determine the maximum width, we find the minimum of the height and width (since the 430d049a230efed6c04cf7d2ab8cc176d9f4f56e51aYorke Lee // circle we are trying to fit the text into has its radius sized to the smaller of the 431d049a230efed6c04cf7d2ab8cc176d9f4f56e51aYorke Lee // two. 432d049a230efed6c04cf7d2ab8cc176d9f4f56e51aYorke Lee int width = Math.min(getWidth(), getHeight()); 433fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson if (width != 0) { 434efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas // Shrink 'width' to account for circle stroke and other painted objects. 435efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas // Note on the "4 *": (1) To reduce divisions, using the diameter instead of the radius. 436efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas // (2) The radius of the enclosing circle is reduced by mRadiusOffset and the 437efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas // text needs to fit within a circle further reduced by mRadiusOffset. 438efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas width -= (int) (4 * mRadiusOffset + 0.5f); 439efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas 440efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas final float wantDiameter2 = TEXT_SIZE_TO_WIDTH_RATIO * width * width; 441efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas float totalDiameter2 = getHypotenuseSquared(); 442efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas 443efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas // If the hypotenuse of the bounding box is too large, reduce all the paint text sizes 444efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas while (totalDiameter2 > wantDiameter2) { 445efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas // Convergence is slightly difficult due to quantization in the mTotalTextWidth 446efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas // calculation. Reducing the ratio by 1% converges more quickly without excessive 447efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas // loss of quality. 448efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas float sizeRatio = 0.99f * (float) Math.sqrt(wantDiameter2/totalDiameter2); 44993e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas mPaintBigThin.setTextSize(mPaintBigThin.getTextSize() * sizeRatio); 45093e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas mPaintMed.setTextSize(mPaintMed.getTextSize() * sizeRatio); 4516a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas // Recalculate the new total text height and half-width 4526a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas mTextHeight = mPaintBigThin.getTextSize(); 45393e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas calcTotalTextWidth(); 454efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas totalDiameter2 = getHypotenuseSquared(); 455fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson } 456fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson } 457fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson } 458fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson 459efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas /** 460efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas * Calculate the square of the diameter to use in {@link CountingTimerView#setTotalTextWidth()} 461efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas */ 462efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas private float getHypotenuseSquared() { 463efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas return mTotalTextWidth * mTotalTextWidth + mTextHeight * mTextHeight; 464efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas } 465efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas 466fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson public void blinkTimeStr(boolean blink) { 467fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson if (blink) { 468fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson removeCallbacks(mBlinkThread); 4699cddb91746c17851627e874f5824b6f3cb1bfeffIsaac Katzenelson post(mBlinkThread); 470fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson } else { 471fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson removeCallbacks(mBlinkThread); 47200cb5981c984bc13aa2f6af510a9dd9a784f2af0Sam Blitzstein showTime(true); 473fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson } 474fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson } 475fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson 47600cb5981c984bc13aa2f6af510a9dd9a784f2af0Sam Blitzstein public void showTime(boolean visible) { 47700cb5981c984bc13aa2f6af510a9dd9a784f2af0Sam Blitzstein mShowTimeStr = visible; 47800cb5981c984bc13aa2f6af510a9dd9a784f2af0Sam Blitzstein invalidate(); 47900cb5981c984bc13aa2f6af510a9dd9a784f2af0Sam Blitzstein } 48000cb5981c984bc13aa2f6af510a9dd9a784f2af0Sam Blitzstein 48180eafdf26fc496ffa112b9eb1b44d7b80333c80arachelzhang public void setTimeStrTextColor(boolean active, boolean forceUpdate) { 48269a4b4f2810100f19e997b4e539f1b0e56b0afb5rachelzhang mDefaultColor = active ? mAccentColor : mWhiteColor; 4831a1b54d6fe0c9e4f478a9e96f3cb6b49f72720edRobyn Coultas setTextColor(mDefaultColor); 4841a1b54d6fe0c9e4f478a9e96f3cb6b49f72720edRobyn Coultas if (forceUpdate) { 4851a1b54d6fe0c9e4f478a9e96f3cb6b49f72720edRobyn Coultas invalidate(); 4861a1b54d6fe0c9e4f478a9e96f3cb6b49f72720edRobyn Coultas } 4871a1b54d6fe0c9e4f478a9e96f3cb6b49f72720edRobyn Coultas } 4881a1b54d6fe0c9e4f478a9e96f3cb6b49f72720edRobyn Coultas 4891c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting private static String getTimeStringForAccessibility(int hours, int minutes, int seconds, 4901c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting boolean showNeg, Resources r) { 4911c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting StringBuilder s = new StringBuilder(); 4921c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting if (showNeg) { 4931c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting // This must be followed by a non-zero number or it will be audible as "hyphen" 4941c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting // instead of "minus". 4951c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting s.append("-"); 4961c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting } 4971c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting if (showNeg && hours == 0 && minutes == 0) { 4981c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting // Non-negative time will always have minutes, eg. "0 minutes 7 seconds", but negative 4991c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting // time must start with non-zero digit, eg. -0m7s will be audible as just "-7 seconds" 5001c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting s.append(String.format( 5011c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting r.getQuantityText(R.plurals.Nseconds_description, seconds).toString(), 5021c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting seconds)); 5031c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting } else if (hours == 0) { 5041c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting s.append(String.format( 5051c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting r.getQuantityText(R.plurals.Nminutes_description, minutes).toString(), 5061c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting minutes)); 5071c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting s.append(" "); 5081c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting s.append(String.format( 5091c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting r.getQuantityText(R.plurals.Nseconds_description, seconds).toString(), 5101c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting seconds)); 5111c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting } else { 5121c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting s.append(String.format( 5131c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting r.getQuantityText(R.plurals.Nhours_description, hours).toString(), 5141c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting hours)); 5151c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting s.append(" "); 5161c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting s.append(String.format( 5171c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting r.getQuantityText(R.plurals.Nminutes_description, minutes).toString(), 5181c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting minutes)); 5191c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting s.append(" "); 5201c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting s.append(String.format( 5211c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting r.getQuantityText(R.plurals.Nseconds_description, seconds).toString(), 5221c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting seconds)); 5231c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting } 5241c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting return s.toString(); 5251c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting } 5261c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting 5274261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting public void setVirtualButtonEnabled(boolean enabled) { 5284261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting mVirtualButtonEnabled = enabled; 5294261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting } 5304261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting 5314261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting private void virtualButtonPressed(boolean pressedOn) { 5324261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting mVirtualButtonPressedOn = pressedOn; 5334261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting invalidate(); 5344261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting } 5354261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting 5364261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting private boolean withinVirtualButtonBounds(float x, float y) { 5374261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting int width = getWidth(); 5384261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting int height = getHeight(); 5394261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting float centerX = width / 2; 5404261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting float centerY = height / 2; 5414261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting float radius = Math.min(width, height) / 2; 5424261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting 5434261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting // Within the circle button if distance to the center is less than the radius. 5444261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting double distance = Math.sqrt(Math.pow(centerX - x, 2) + Math.pow(centerY - y, 2)); 5454261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting return distance < radius; 5464261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting } 5474261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting 5484261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting public void registerVirtualButtonAction(final Runnable runnable) { 5491c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting if (!mAccessibilityManager.isEnabled()) { 5501c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting this.setOnTouchListener(new OnTouchListener() { 5511c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting @Override 5521c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting public boolean onTouch(View v, MotionEvent event) { 5531c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting if (mVirtualButtonEnabled) { 5541c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting switch (event.getAction()) { 5551c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting case MotionEvent.ACTION_DOWN: 5561c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting if (withinVirtualButtonBounds(event.getX(), event.getY())) { 5571c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting virtualButtonPressed(true); 5581c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting return true; 5591c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting } else { 5601c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting virtualButtonPressed(false); 5611c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting return false; 562832a20480e1e76d1df846ac20c0eb1fe702a41f8Sam Blitzstein } 5631c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting case MotionEvent.ACTION_CANCEL: 5641c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting virtualButtonPressed(false); 5654261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting return true; 5661c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting case MotionEvent.ACTION_OUTSIDE: 5674261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting virtualButtonPressed(false); 5684261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting return false; 5691c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting case MotionEvent.ACTION_UP: 5701c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting virtualButtonPressed(false); 5711c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting if (withinVirtualButtonBounds(event.getX(), event.getY())) { 5721c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting runnable.run(); 573832a20480e1e76d1df846ac20c0eb1fe702a41f8Sam Blitzstein } 5741c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting return true; 5751c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting } 5764261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting } 5771c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting return false; 5784261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting } 5791c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting }); 5801c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting } else { 5811c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting this.setOnClickListener(new OnClickListener() { 5821c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting @Override 5831c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting public void onClick(View v) { 5841c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting runnable.run(); 5851c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting } 5861c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting }); 5871c4ab87072b0fb21e05ed221acd28560d6110b12Sara Ting } 5884261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting } 5894261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting 590fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson @Override 591fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson public void onDraw(Canvas canvas) { 5924261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting // Blink functionality. 5934261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting if (!mShowTimeStr && !mVirtualButtonPressedOn) { 5944261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting return; 5954261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting } 5964261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting 597fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson int width = getWidth(); 598fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson if (mRemeasureText && width != 0) { 599fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson setTotalTextWidth(); 600d049a230efed6c04cf7d2ab8cc176d9f4f56e51aYorke Lee width = getWidth(); 601fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson mRemeasureText = false; 602fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson } 603fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson 604fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson int xCenter = width / 2; 605fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson int yCenter = getHeight() / 2; 606fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson 6076a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas float xTextStart = xCenter - mTotalTextWidth / 2; 6086a2ab617a8815be26c7af9ec6bcb9fadb17d5f7bRobyn Coultas float yTextStart = yCenter + mTextHeight/2 - (mTextHeight * FONT_VERTICAL_OFFSET); 6094261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting 6104261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting // Text color differs based on pressed state. 611478b04fa5ebfa1eda1062afa38f057102f32f9afBudi Kusmiantoro final int textColor = mVirtualButtonPressedOn ? mPressedColor : mDefaultColor; 6124261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting mPaintBigThin.setColor(textColor); 6134261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting mPaintMed.setColor(textColor); 6144261870a93db4e92bf5c08a9a253c9c5ff80d41cSara Ting 615fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson if (mHours != null) { 616d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas xTextStart = mBigHours.draw(canvas, mHours, xTextStart, yTextStart); 617fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson } 618fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson if (mMinutes != null) { 619d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas xTextStart = mBigMinutes.draw(canvas, mMinutes, xTextStart, yTextStart); 620fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson } 621fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson if (mSeconds != null) { 622d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas xTextStart = mBigSeconds.draw(canvas, mSeconds, xTextStart, yTextStart); 62393e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas } 62493e1bb511545434e57d2c46e3191cd9f1b6d2a68Robyn Coultas if (mHundredths != null) { 625d27c983901df08a8ef3b839fe6d262073e50fc32Robyn Coultas mMedHundredths.draw(canvas, mHundredths, xTextStart, yTextStart); 626fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson } 62700cb5981c984bc13aa2f6af510a9dd9a784f2af0Sam Blitzstein } 628d049a230efed6c04cf7d2ab8cc176d9f4f56e51aYorke Lee 629c9524f8b8216c7854de4c69c44c9bb63e4097a18Robyn Coultas @Override 630c9524f8b8216c7854de4c69c44c9bb63e4097a18Robyn Coultas protected void onSizeChanged(int w, int h, int oldw, int oldh) { 631c9524f8b8216c7854de4c69c44c9bb63e4097a18Robyn Coultas super.onSizeChanged(w, h, oldw, oldh); 632c9524f8b8216c7854de4c69c44c9bb63e4097a18Robyn Coultas mRemeasureText = true; 633b9accf1c0da8bfb4b7daffb237c581f27f7a0823Robyn Coultas resetTextSize(); 634c9524f8b8216c7854de4c69c44c9bb63e4097a18Robyn Coultas } 635fd544b56e462c0e871441bcd48797e022f61d8efIsaac Katzenelson} 636