package com.tutsplus.androidwearwatchface.service; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Canvas; import android.graphics.Color; 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.wearable.watchface.CanvasWatchFaceService; import android.support.wearable.watchface.WatchFaceStyle; import android.text.format.Time; import android.view.SurfaceHolder; import android.view.WindowInsets; import com.tutsplus.androidwearwatchface.R; import java.util.TimeZone; import java.util.concurrent.TimeUnit; /** * Created by paulruiz on 3/25/15. */ public class CustomWatchFaceService extends CanvasWatchFaceService { @Override public Engine onCreateEngine() { return new WatchFaceEngine(); } private class WatchFaceEngine extends Engine { //Member variables private Typeface WATCH_TEXT_TYPEFACE = Typeface.create( Typeface.SERIF, Typeface.NORMAL ); private static final int MSG_UPDATE_TIME_ID = 42; private static final long DEFAULT_UPDATE_RATE_MS = 1000; private long mUpdateRateMs = 1000; private Time mDisplayTime; private Paint mBackgroundColorPaint; private Paint mTextColorPaint; private boolean mHasTimeZoneReceiverBeenRegistered = false; private boolean mIsInMuteMode; private boolean mIsLowBitAmbient; private float mXOffset; private float mYOffset; private int mBackgroundColor = Color.parseColor( "black" ); private int mTextColor = Color.parseColor( "red" ); final BroadcastReceiver mTimeZoneBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { mDisplayTime.clear( intent.getStringExtra( "time-zone" ) ); mDisplayTime.setToNow(); } }; private final Handler mTimeHandler = new Handler() { @Override public void handleMessage(Message msg) { switch( msg.what ) { case MSG_UPDATE_TIME_ID: { invalidate(); if( isVisible() && !isInAmbientMode() ) { long currentTimeMillis = System.currentTimeMillis(); long delay = mUpdateRateMs - ( currentTimeMillis % mUpdateRateMs ); mTimeHandler.sendEmptyMessageDelayed( MSG_UPDATE_TIME_ID, delay ); } break; } } } }; //Overridden methods @Override public void onCreate(SurfaceHolder holder) { super.onCreate(holder); setWatchFaceStyle( new WatchFaceStyle.Builder( CustomWatchFaceService.this ) .setBackgroundVisibility( WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE ) .setCardPeekMode( WatchFaceStyle.PEEK_MODE_VARIABLE ) .setShowSystemUiTime( false ) .build() ); initBackground(); initDisplayText(); mDisplayTime = new Time(); } @Override public void onDestroy() { mTimeHandler.removeMessages( MSG_UPDATE_TIME_ID ); super.onDestroy(); } @Override public void onVisibilityChanged( boolean visible ) { super.onVisibilityChanged(visible); if( visible ) { if( !mHasTimeZoneReceiverBeenRegistered ) { IntentFilter filter = new IntentFilter( Intent.ACTION_TIMEZONE_CHANGED ); CustomWatchFaceService.this.registerReceiver( mTimeZoneBroadcastReceiver, filter ); mHasTimeZoneReceiverBeenRegistered = true; } mDisplayTime.clear( TimeZone.getDefault().getID() ); mDisplayTime.setToNow(); } else { if( mHasTimeZoneReceiverBeenRegistered ) { CustomWatchFaceService.this.unregisterReceiver( mTimeZoneBroadcastReceiver ); mHasTimeZoneReceiverBeenRegistered = false; } } updateTimer(); } @Override public void onApplyWindowInsets(WindowInsets insets) { super.onApplyWindowInsets(insets); mYOffset = getResources().getDimension( R.dimen.y_offset ); if( insets.isRound() ) { mXOffset = getResources().getDimension( R.dimen.x_offset_round ); } else { mXOffset = getResources().getDimension( R.dimen.x_offset_square ); } } @Override public void onPropertiesChanged(Bundle properties) { super.onPropertiesChanged(properties); if( properties.getBoolean( PROPERTY_BURN_IN_PROTECTION, false ) ) { mIsLowBitAmbient = properties.getBoolean( PROPERTY_LOW_BIT_AMBIENT, false ); } } @Override public void onTimeTick() { super.onTimeTick(); invalidate(); } @Override public void onAmbientModeChanged(boolean inAmbientMode) { super.onAmbientModeChanged(inAmbientMode); if( inAmbientMode ) { mTextColorPaint.setColor( Color.parseColor( "white" ) ); } else { mTextColorPaint.setColor( Color.parseColor( "red" ) ); } if( mIsLowBitAmbient ) { mTextColorPaint.setAntiAlias( !inAmbientMode ); } invalidate(); updateTimer(); } @Override public void onInterruptionFilterChanged(int interruptionFilter) { super.onInterruptionFilterChanged(interruptionFilter); boolean isDeviceMuted = ( interruptionFilter == android.support.wearable.watchface.WatchFaceService.INTERRUPTION_FILTER_NONE ); if( isDeviceMuted ) { mUpdateRateMs = TimeUnit.MINUTES.toMillis( 1 ); } else { mUpdateRateMs = DEFAULT_UPDATE_RATE_MS; } if( mIsInMuteMode != isDeviceMuted ) { mIsInMuteMode = isDeviceMuted; int alpha = ( isDeviceMuted ) ? 100 : 255; mTextColorPaint.setAlpha( alpha ); invalidate(); } updateTimer(); } @Override public void onDraw(Canvas canvas, Rect bounds) { super.onDraw(canvas, bounds); mDisplayTime.setToNow(); drawBackground( canvas, bounds ); drawTimeText( canvas ); } //Utility methods private void initBackground() { mBackgroundColorPaint = new Paint(); mBackgroundColorPaint.setColor( mBackgroundColor ); } private void initDisplayText() { mTextColorPaint = new Paint(); mTextColorPaint.setColor( mTextColor ); mTextColorPaint.setTypeface( WATCH_TEXT_TYPEFACE ); mTextColorPaint.setAntiAlias( true ); mTextColorPaint.setTextSize( getResources().getDimension( R.dimen.text_size ) ); } private void updateTimer() { mTimeHandler.removeMessages( MSG_UPDATE_TIME_ID ); if( isVisible() && !isInAmbientMode() ) { mTimeHandler.sendEmptyMessage( MSG_UPDATE_TIME_ID ); } } private void drawBackground( Canvas canvas, Rect bounds ) { canvas.drawRect( 0, 0, bounds.width(), bounds.height(), mBackgroundColorPaint ); } private void drawTimeText( Canvas canvas ) { String timeText = getHourString() + ":" + String.format( "%02d", mDisplayTime.minute ); if( isInAmbientMode() || mIsInMuteMode ) { timeText += ( mDisplayTime.hour < 12 ) ? "AM" : "PM"; } else { timeText += String.format( ":%02d", mDisplayTime.second); } canvas.drawText( timeText, mXOffset, mYOffset, mTextColorPaint ); } private String getHourString() { if( mDisplayTime.hour % 12 == 0 ) return "12"; else if( mDisplayTime.hour <= 12 ) return String.valueOf( mDisplayTime.hour ); else return String.valueOf( mDisplayTime.hour - 12 ); } } }