blob: 9eca2c33b1f0102c357fb19c030cf6df8139fd67 [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.wearable.watchface;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.graphics.Palette;
import android.support.wearable.complications.ComplicationData;
import android.support.wearable.complications.ComplicationText;
import android.support.wearable.watchface.CanvasWatchFaceService;
import android.support.wearable.watchface.WatchFaceService;
import android.support.wearable.watchface.WatchFaceStyle;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
import android.view.SurfaceHolder;
import java.util.Calendar;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
/**
* Demonstrates two simple complications in a watch face.
*/
public class ComplicationSimpleWatchFaceService extends CanvasWatchFaceService {
private static final String TAG = "SimpleComplicationWF";
// Unique IDs for each complication.
private static final int LEFT_DIAL_COMPLICATION = 0;
private static final int RIGHT_DIAL_COMPLICATION = 1;
// Left and right complication IDs as array for Complication API.
public static final int[] COMPLICATION_IDS = {LEFT_DIAL_COMPLICATION, RIGHT_DIAL_COMPLICATION};
// Left and right dial supported types.
public static final int[][] COMPLICATION_SUPPORTED_TYPES = {
{ComplicationData.TYPE_SHORT_TEXT},
{ComplicationData.TYPE_SHORT_TEXT}
};
/*
* Update rate in milliseconds for interactive mode. We update once a second to advance the
* second hand.
*/
private static final long INTERACTIVE_UPDATE_RATE_MS = TimeUnit.SECONDS.toMillis(1);
@Override
public Engine onCreateEngine() {
return new Engine();
}
private class Engine extends CanvasWatchFaceService.Engine {
private static final int MSG_UPDATE_TIME = 0;
private static final float COMPLICATION_TEXT_SIZE = 38f;
private static final int COMPLICATION_TAP_BUFFER = 40;
private static final float HOUR_STROKE_WIDTH = 5f;
private static final float MINUTE_STROKE_WIDTH = 3f;
private static final float SECOND_TICK_STROKE_WIDTH = 2f;
private static final float CENTER_GAP_AND_CIRCLE_RADIUS = 4f;
private static final int SHADOW_RADIUS = 6;
private Calendar mCalendar;
private boolean mRegisteredTimeZoneReceiver = false;
private boolean mMuteMode;
private int mWidth;
private int mHeight;
private float mCenterX;
private float mCenterY;
private float mSecondHandLength;
private float mMinuteHandLength;
private float mHourHandLength;
// Colors for all hands (hour, minute, seconds, ticks) based on photo loaded.
private int mWatchHandColor;
private int mWatchHandHighlightColor;
private int mWatchHandShadowColor;
private Paint mHourPaint;
private Paint mMinutePaint;
private Paint mSecondPaint;
private Paint mTickAndCirclePaint;
private Paint mBackgroundPaint;
private Bitmap mBackgroundBitmap;
private Bitmap mGrayBackgroundBitmap;
// Variables for painting Complications
private Paint mComplicationPaint;
/* To properly place each complication, we need their x and y coordinates. While the width
* may change from moment to moment based on the time, the height will not change, so we
* store it as a local variable and only calculate it only when the surface changes
* (onSurfaceChanged()).
*/
private int mComplicationsY;
/* Maps active complication ids to the data for that complication. Note: Data will only be
* present if the user has chosen a provider via the settings activity for the watch face.
*/
private SparseArray<ComplicationData> mActiveComplicationDataSparseArray;
private boolean mAmbient;
private boolean mLowBitAmbient;
private boolean mBurnInProtection;
private Rect mPeekCardBounds = new Rect();
private final BroadcastReceiver mTimeZoneReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
mCalendar.setTimeZone(TimeZone.getDefault());
invalidate();
}
};
// Handler to update the time once a second in interactive mode.
private final Handler mUpdateTimeHandler = new Handler() {
@Override
public void handleMessage(Message message) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "updating time");
}
invalidate();
if (shouldTimerBeRunning()) {
long timeMs = System.currentTimeMillis();
long delayMs = INTERACTIVE_UPDATE_RATE_MS
- (timeMs % INTERACTIVE_UPDATE_RATE_MS);
mUpdateTimeHandler.sendEmptyMessageDelayed(MSG_UPDATE_TIME, delayMs);
}
}
};
@Override
public void onCreate(SurfaceHolder holder) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "onCreate");
}
super.onCreate(holder);
mCalendar = Calendar.getInstance();
setWatchFaceStyle(new WatchFaceStyle.Builder(ComplicationSimpleWatchFaceService.this)
.setCardPeekMode(WatchFaceStyle.PEEK_MODE_SHORT)
.setAcceptsTapEvents(true)
.setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)
.setShowSystemUiTime(false)
.build());
initializeBackground();
initializeComplication();
initializeWatchFace();
}
private void initializeBackground() {
mBackgroundPaint = new Paint();
mBackgroundPaint.setColor(Color.BLACK);
mBackgroundBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bg);
}
private void initializeComplication() {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "initializeComplications()");
}
mActiveComplicationDataSparseArray = new SparseArray<>(COMPLICATION_IDS.length);
mComplicationPaint = new Paint();
mComplicationPaint.setColor(Color.WHITE);
mComplicationPaint.setTextSize(COMPLICATION_TEXT_SIZE);
mComplicationPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
mComplicationPaint.setAntiAlias(true);
setActiveComplications(COMPLICATION_IDS);
}
private void initializeWatchFace() {
/* Set defaults for colors */
mWatchHandColor = Color.WHITE;
mWatchHandHighlightColor = Color.RED;
mWatchHandShadowColor = Color.BLACK;
mHourPaint = new Paint();
mHourPaint.setColor(mWatchHandColor);
mHourPaint.setStrokeWidth(HOUR_STROKE_WIDTH);
mHourPaint.setAntiAlias(true);
mHourPaint.setStrokeCap(Paint.Cap.ROUND);
mHourPaint.setShadowLayer(SHADOW_RADIUS, 0, 0, mWatchHandShadowColor);
mMinutePaint = new Paint();
mMinutePaint.setColor(mWatchHandColor);
mMinutePaint.setStrokeWidth(MINUTE_STROKE_WIDTH);
mMinutePaint.setAntiAlias(true);
mMinutePaint.setStrokeCap(Paint.Cap.ROUND);
mMinutePaint.setShadowLayer(SHADOW_RADIUS, 0, 0, mWatchHandShadowColor);
mSecondPaint = new Paint();
mSecondPaint.setColor(mWatchHandHighlightColor);
mSecondPaint.setStrokeWidth(SECOND_TICK_STROKE_WIDTH);
mSecondPaint.setAntiAlias(true);
mSecondPaint.setStrokeCap(Paint.Cap.ROUND);
mSecondPaint.setShadowLayer(SHADOW_RADIUS, 0, 0, mWatchHandShadowColor);
mTickAndCirclePaint = new Paint();
mTickAndCirclePaint.setColor(mWatchHandColor);
mTickAndCirclePaint.setStrokeWidth(SECOND_TICK_STROKE_WIDTH);
mTickAndCirclePaint.setAntiAlias(true);
mTickAndCirclePaint.setStyle(Paint.Style.STROKE);
mTickAndCirclePaint.setShadowLayer(SHADOW_RADIUS, 0, 0, mWatchHandShadowColor);
// Asynchronous call extract colors from background image to improve watch face style.
Palette.from(mBackgroundBitmap).generate(
new Palette.PaletteAsyncListener() {
public void onGenerated(Palette palette) {
/*
* Sometimes, palette is unable to generate a color palette
* so we need to check that we have one.
*/
if (palette != null) {
Log.d("onGenerated", palette.toString());
mWatchHandColor = palette.getVibrantColor(Color.WHITE);
mWatchHandShadowColor = palette.getDarkMutedColor(Color.BLACK);
updateWatchHandStyle();
}
}
});
}
@Override
public void onDestroy() {
mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME);
super.onDestroy();
}
@Override
public void onPropertiesChanged(Bundle properties) {
super.onPropertiesChanged(properties);
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "onPropertiesChanged: low-bit ambient = " + mLowBitAmbient);
}
mLowBitAmbient = properties.getBoolean(PROPERTY_LOW_BIT_AMBIENT, false);
mBurnInProtection = properties.getBoolean(PROPERTY_BURN_IN_PROTECTION, false);
}
/*
* Called when there is updated data for a complication id.
*/
@Override
public void onComplicationDataUpdate(
int complicationId, ComplicationData complicationData) {
Log.d(TAG, "onComplicationDataUpdate() id: " + complicationId);
// Adds/updates active complication data in the array.
mActiveComplicationDataSparseArray.put(complicationId, complicationData);
invalidate();
}
@Override
public void onTapCommand(int tapType, int x, int y, long eventTime) {
Log.d(TAG, "OnTapCommand()");
switch (tapType) {
case TAP_TYPE_TAP:
int tappedComplicationId = getTappedComplicationId(x, y);
if (tappedComplicationId != -1) {
onComplicationTap(tappedComplicationId);
}
break;
}
}
/*
* Determines if tap inside a complication area or returns -1.
*/
private int getTappedComplicationId(int x, int y) {
ComplicationData complicationData;
long currentTimeMillis = System.currentTimeMillis();
for (int i = 0; i < COMPLICATION_IDS.length; i++) {
complicationData = mActiveComplicationDataSparseArray.get(COMPLICATION_IDS[i]);
if ((complicationData != null)
&& (complicationData.isActive(currentTimeMillis))
&& (complicationData.getType() != ComplicationData.TYPE_NOT_CONFIGURED)
&& (complicationData.getType() != ComplicationData.TYPE_EMPTY)) {
Rect complicationBoundingRect = new Rect(0, 0, 0, 0);
switch (COMPLICATION_IDS[i]) {
case LEFT_DIAL_COMPLICATION:
complicationBoundingRect.set(
0, // left
mComplicationsY - COMPLICATION_TAP_BUFFER, // top
(mWidth / 2), // right
((int) COMPLICATION_TEXT_SIZE // bottom
+ mComplicationsY
+ COMPLICATION_TAP_BUFFER));
break;
case RIGHT_DIAL_COMPLICATION:
complicationBoundingRect.set(
(mWidth / 2), // left
mComplicationsY - COMPLICATION_TAP_BUFFER, // top
mWidth, // right
((int) COMPLICATION_TEXT_SIZE // bottom
+ mComplicationsY
+ COMPLICATION_TAP_BUFFER));
break;
}
if (complicationBoundingRect.width() > 0) {
if (complicationBoundingRect.contains(x, y)) {
return COMPLICATION_IDS[i];
}
} else {
Log.e(TAG, "Not a recognized complication id.");
}
}
}
return -1;
}
/*
* Fires PendingIntent associated with complication (if it has one).
*/
private void onComplicationTap(int complicationId) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "onComplicationTap()");
}
ComplicationData complicationData =
mActiveComplicationDataSparseArray.get(complicationId);
if ((complicationData != null) && (complicationData.getTapAction() != null)) {
try {
complicationData.getTapAction().send();
} catch (PendingIntent.CanceledException e) {
Log.e(TAG, "On complication tap action error " + e);
}
invalidate();
} else {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "No PendingIntent for complication " + complicationId + ".");
}
}
}
@Override
public void onTimeTick() {
super.onTimeTick();
invalidate();
}
@Override
public void onAmbientModeChanged(boolean inAmbientMode) {
super.onAmbientModeChanged(inAmbientMode);
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "onAmbientModeChanged: " + inAmbientMode);
}
mAmbient = inAmbientMode;
updateWatchHandStyle();
// Updates complication style
mComplicationPaint.setAntiAlias(!inAmbientMode);
// Check and trigger whether or not timer should be running (only in active mode).
updateTimer();
}
private void updateWatchHandStyle(){
if (mAmbient){
mHourPaint.setColor(Color.WHITE);
mMinutePaint.setColor(Color.WHITE);
mSecondPaint.setColor(Color.WHITE);
mTickAndCirclePaint.setColor(Color.WHITE);
mHourPaint.setAntiAlias(false);
mMinutePaint.setAntiAlias(false);
mSecondPaint.setAntiAlias(false);
mTickAndCirclePaint.setAntiAlias(false);
mHourPaint.clearShadowLayer();
mMinutePaint.clearShadowLayer();
mSecondPaint.clearShadowLayer();
mTickAndCirclePaint.clearShadowLayer();
} else {
mHourPaint.setColor(mWatchHandColor);
mMinutePaint.setColor(mWatchHandColor);
mSecondPaint.setColor(mWatchHandHighlightColor);
mTickAndCirclePaint.setColor(mWatchHandColor);
mHourPaint.setAntiAlias(true);
mMinutePaint.setAntiAlias(true);
mSecondPaint.setAntiAlias(true);
mTickAndCirclePaint.setAntiAlias(true);
mHourPaint.setShadowLayer(SHADOW_RADIUS, 0, 0, mWatchHandShadowColor);
mMinutePaint.setShadowLayer(SHADOW_RADIUS, 0, 0, mWatchHandShadowColor);
mSecondPaint.setShadowLayer(SHADOW_RADIUS, 0, 0, mWatchHandShadowColor);
mTickAndCirclePaint.setShadowLayer(SHADOW_RADIUS, 0, 0, mWatchHandShadowColor);
}
}
@Override
public void onInterruptionFilterChanged(int interruptionFilter) {
super.onInterruptionFilterChanged(interruptionFilter);
boolean inMuteMode = (interruptionFilter == WatchFaceService.INTERRUPTION_FILTER_NONE);
/* Dim display in mute mode. */
if (mMuteMode != inMuteMode) {
mMuteMode = inMuteMode;
mHourPaint.setAlpha(inMuteMode ? 100 : 255);
mMinutePaint.setAlpha(inMuteMode ? 100 : 255);
mSecondPaint.setAlpha(inMuteMode ? 80 : 255);
invalidate();
}
}
@Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
super.onSurfaceChanged(holder, format, width, height);
// Used for complications
mWidth = width;
mHeight = height;
/*
* Find the coordinates of the center point on the screen, and ignore the window
* insets, so that, on round watches with a "chin", the watch face is centered on the
* entire screen, not just the usable portion.
*/
mCenterX = mWidth / 2f;
mCenterY = mHeight / 2f;
/*
* Since the height of the complications text does not change, we only have to
* recalculate when the surface changes.
*/
mComplicationsY = (int) ((mHeight / 2) + (mComplicationPaint.getTextSize() / 2));
/*
* Calculate lengths of different hands based on watch screen size.
*/
mSecondHandLength = (float) (mCenterX * 0.875);
mMinuteHandLength = (float) (mCenterX * 0.75);
mHourHandLength = (float) (mCenterX * 0.5);
/* Scale loaded background image (more efficient) if surface dimensions change. */
float scale = ((float) width) / (float) mBackgroundBitmap.getWidth();
mBackgroundBitmap = Bitmap.createScaledBitmap(mBackgroundBitmap,
(int) (mBackgroundBitmap.getWidth() * scale),
(int) (mBackgroundBitmap.getHeight() * scale), true);
/*
* Create a gray version of the image only if it will look nice on the device in
* ambient mode. That means we don't want devices that support burn-in
* protection (slight movements in pixels, not great for images going all the way to
* edges) and low ambient mode (degrades image quality).
*
* Also, if your watch face will know about all images ahead of time (users aren't
* selecting their own photos for the watch face), it will be more
* efficient to create a black/white version (png, etc.) and load that when you need it.
*/
if (!mBurnInProtection && !mLowBitAmbient) {
initGrayBackgroundBitmap();
}
}
private void initGrayBackgroundBitmap() {
mGrayBackgroundBitmap = Bitmap.createBitmap(
mBackgroundBitmap.getWidth(),
mBackgroundBitmap.getHeight(),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(mGrayBackgroundBitmap);
Paint grayPaint = new Paint();
ColorMatrix colorMatrix = new ColorMatrix();
colorMatrix.setSaturation(0);
ColorMatrixColorFilter filter = new ColorMatrixColorFilter(colorMatrix);
grayPaint.setColorFilter(filter);
canvas.drawBitmap(mBackgroundBitmap, 0, 0, grayPaint);
}
@Override
public void onDraw(Canvas canvas, Rect bounds) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "onDraw");
}
long now = System.currentTimeMillis();
mCalendar.setTimeInMillis(now);
drawBackground(canvas);
drawComplications(canvas, now);
drawWatchFace(canvas);
}
private void drawBackground(Canvas canvas) {
if (mAmbient && (mLowBitAmbient || mBurnInProtection)) {
canvas.drawColor(Color.BLACK);
} else if (mAmbient) {
canvas.drawBitmap(mGrayBackgroundBitmap, 0, 0, mBackgroundPaint);
} else {
canvas.drawBitmap(mBackgroundBitmap, 0, 0, mBackgroundPaint);
}
}
private void drawComplications(Canvas canvas, long currentTimeMillis) {
ComplicationData complicationData;
for (int i = 0; i < COMPLICATION_IDS.length; i++) {
complicationData = mActiveComplicationDataSparseArray.get(COMPLICATION_IDS[i]);
if ((complicationData != null)
&& (complicationData.isActive(currentTimeMillis))
&& (complicationData.getType() == ComplicationData.TYPE_SHORT_TEXT)) {
ComplicationText mainText = complicationData.getShortText();
ComplicationText subText = complicationData.getShortTitle();
CharSequence complicationMessage =
mainText.getText(getApplicationContext(), currentTimeMillis);
/* In most cases you would want the subText (Title) under the mainText (Text),
* but to keep it simple for the code lab, we are concatenating them all on one
* line.
*/
if (subText != null) {
complicationMessage = TextUtils.concat(
complicationMessage,
" ",
subText.getText(getApplicationContext(), currentTimeMillis));
}
//Log.d(TAG, "Comp id: " + COMPLICATION_IDS[i] + "\t" + complicationMessage);
double textWidth =
mComplicationPaint.measureText(
complicationMessage,
0,
complicationMessage.length());
int complicationsX;
if (COMPLICATION_IDS[i] == LEFT_DIAL_COMPLICATION) {
complicationsX = (int) ((mWidth / 2) - textWidth) / 2;
} else {
// RIGHT_DIAL_COMPLICATION calculations
int offset = (int) ((mWidth / 2) - textWidth) / 2;
complicationsX = (mWidth / 2) + offset;
}
canvas.drawText(
complicationMessage,
0,
complicationMessage.length(),
complicationsX,
mComplicationsY,
mComplicationPaint);
}
}
}
private void drawWatchFace(Canvas canvas) {
/*
* Draw ticks. Usually you will want to bake this directly into the photo, but in
* cases where you want to allow users to select their own photos, this dynamically
* creates them on top of the photo.
*/
float innerTickRadius = mCenterX - 10;
float outerTickRadius = mCenterX;
for (int tickIndex = 0; tickIndex < 12; tickIndex++) {
float tickRot = (float) (tickIndex * Math.PI * 2 / 12);
float innerX = (float) Math.sin(tickRot) * innerTickRadius;
float innerY = (float) -Math.cos(tickRot) * innerTickRadius;
float outerX = (float) Math.sin(tickRot) * outerTickRadius;
float outerY = (float) -Math.cos(tickRot) * outerTickRadius;
canvas.drawLine(mCenterX + innerX, mCenterY + innerY,
mCenterX + outerX, mCenterY + outerY, mTickAndCirclePaint);
}
/*
* These calculations reflect the rotation in degrees per unit of time, e.g.,
* 360 / 60 = 6 and 360 / 12 = 30.
*/
final float seconds =
(mCalendar.get(Calendar.SECOND) + mCalendar.get(Calendar.MILLISECOND) / 1000f);
final float secondsRotation = seconds * 6f;
final float minutesRotation = mCalendar.get(Calendar.MINUTE) * 6f;
final float hourHandOffset = mCalendar.get(Calendar.MINUTE) / 2f;
final float hoursRotation = (mCalendar.get(Calendar.HOUR) * 30) + hourHandOffset;
/*
* Save the canvas state before we can begin to rotate it.
*/
canvas.save();
canvas.rotate(hoursRotation, mCenterX, mCenterY);
canvas.drawLine(
mCenterX,
mCenterY - CENTER_GAP_AND_CIRCLE_RADIUS,
mCenterX,
mCenterY - mHourHandLength,
mHourPaint);
canvas.rotate(minutesRotation - hoursRotation, mCenterX, mCenterY);
canvas.drawLine(
mCenterX,
mCenterY - CENTER_GAP_AND_CIRCLE_RADIUS,
mCenterX,
mCenterY - mMinuteHandLength,
mMinutePaint);
/*
* Ensure the "seconds" hand is drawn only when we are in interactive mode.
* Otherwise, we only update the watch face once a minute.
*/
if (!mAmbient) {
canvas.rotate(secondsRotation - minutesRotation, mCenterX, mCenterY);
canvas.drawLine(
mCenterX,
mCenterY - CENTER_GAP_AND_CIRCLE_RADIUS,
mCenterX,
mCenterY - mSecondHandLength,
mSecondPaint);
}
canvas.drawCircle(
mCenterX,
mCenterY,
CENTER_GAP_AND_CIRCLE_RADIUS,
mTickAndCirclePaint);
/* Restore the canvas' original orientation. */
canvas.restore();
/* Draw rectangle behind peek card in ambient mode to improve readability. */
if (mAmbient) {
canvas.drawRect(mPeekCardBounds, mBackgroundPaint);
}
}
@Override
public void onVisibilityChanged(boolean visible) {
super.onVisibilityChanged(visible);
if (visible) {
registerReceiver();
// Update time zone in case it changed while we weren't visible.
mCalendar.setTimeZone(TimeZone.getDefault());
invalidate();
} else {
unregisterReceiver();
}
/* Check and trigger whether or not timer should be running (only in active mode). */
updateTimer();
}
@Override
public void onPeekCardPositionUpdate(Rect rect) {
super.onPeekCardPositionUpdate(rect);
mPeekCardBounds.set(rect);
}
private void registerReceiver() {
if (mRegisteredTimeZoneReceiver) {
return;
}
mRegisteredTimeZoneReceiver = true;
IntentFilter filter = new IntentFilter(Intent.ACTION_TIMEZONE_CHANGED);
ComplicationSimpleWatchFaceService.this.registerReceiver(mTimeZoneReceiver, filter);
}
private void unregisterReceiver() {
if (!mRegisteredTimeZoneReceiver) {
return;
}
mRegisteredTimeZoneReceiver = false;
ComplicationSimpleWatchFaceService.this.unregisterReceiver(mTimeZoneReceiver);
}
/**
* Starts/stops the {@link #mUpdateTimeHandler} timer based on the state of the watch face.
*/
private void updateTimer() {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "updateTimer");
}
mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME);
if (shouldTimerBeRunning()) {
mUpdateTimeHandler.sendEmptyMessage(MSG_UPDATE_TIME);
}
}
/**
* Returns whether the {@link #mUpdateTimeHandler} timer should be running. The timer
* should only run in active mode.
*/
private boolean shouldTimerBeRunning() {
return isVisible() && !mAmbient;
}
}
}