Home | History | Annotate | Download | only in com.example.android.wearable.watchface
      1 /*
      2  * Copyright (C) 2015 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 
     17 package com.example.android.wearable.watchface;
     18 
     19 import android.content.res.Resources;
     20 import android.graphics.Canvas;
     21 import android.graphics.Color;
     22 import android.graphics.Paint;
     23 import android.graphics.Rect;
     24 import android.graphics.Typeface;
     25 import android.os.Bundle;
     26 import android.support.wearable.watchface.CanvasWatchFaceService;
     27 import android.support.wearable.watchface.WatchFaceStyle;
     28 import android.util.Log;
     29 import android.view.SurfaceHolder;
     30 import android.view.WindowInsets;
     31 
     32 /**
     33  * Demonstrates interactive watch face capabilities, i.e., touching the display and registering
     34  * three different events: touch, touch-cancel and tap. The watch face UI will show the count of
     35  * these events as they occur. See the {@code onTapCommand} below.
     36  */
     37 public class InteractiveWatchFaceService extends CanvasWatchFaceService {
     38 
     39     private static final String TAG = "InteractiveWatchFace";
     40 
     41     private static final Typeface BOLD_TYPEFACE =
     42             Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD);
     43     private static final Typeface NORMAL_TYPEFACE =
     44             Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL);
     45 
     46     @Override
     47     public Engine onCreateEngine() {
     48         return new Engine();
     49     }
     50 
     51     private class Engine extends CanvasWatchFaceService.Engine {
     52 
     53         private Paint mTextPaint;
     54         private final Paint mPeekCardBackgroundPaint = new Paint();
     55 
     56         private float mXOffset;
     57         private float mYOffset;
     58         private float mTextSpacingHeight;
     59         private int mScreenTextColor = Color.WHITE;
     60 
     61         private int mTouchCommandTotal;
     62         private int mTouchCancelCommandTotal;
     63         private int mTapCommandTotal;
     64 
     65         private int mTouchCoordinateX;
     66         private int mTouchCoordinateY;
     67 
     68         private final Rect mCardBounds = new Rect();
     69 
     70         /**
     71          * Whether the display supports fewer bits for each color in ambient mode. When true, we
     72          * disable anti-aliasing in ambient mode.
     73          */
     74         private boolean mLowBitAmbient;
     75 
     76         @Override
     77         public void onCreate(SurfaceHolder holder) {
     78             if (Log.isLoggable(TAG, Log.DEBUG)) {
     79                 Log.d(TAG, "onCreate");
     80             }
     81             super.onCreate(holder);
     82 
     83             /** Accepts tap events via WatchFaceStyle (setAcceptsTapEvents(true)). */
     84             setWatchFaceStyle(new WatchFaceStyle.Builder(InteractiveWatchFaceService.this)
     85                     .setCardPeekMode(WatchFaceStyle.PEEK_MODE_VARIABLE)
     86                     .setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)
     87                     .setShowSystemUiTime(false)
     88                     .setAcceptsTapEvents(true)
     89                     .build());
     90 
     91             Resources resources = InteractiveWatchFaceService.this.getResources();
     92             mTextSpacingHeight = resources.getDimension(R.dimen.interactive_text_size);
     93 
     94             mTextPaint = new Paint();
     95             mTextPaint.setColor(mScreenTextColor);
     96             mTextPaint.setTypeface(BOLD_TYPEFACE);
     97             mTextPaint.setAntiAlias(true);
     98 
     99             mTouchCommandTotal = 0;
    100             mTouchCancelCommandTotal = 0;
    101             mTapCommandTotal = 0;
    102 
    103             mTouchCoordinateX = 0;
    104             mTouchCoordinateX = 0;
    105         }
    106 
    107         @Override
    108         public void onApplyWindowInsets(WindowInsets insets) {
    109             if (Log.isLoggable(TAG, Log.DEBUG)) {
    110                 Log.d(TAG, "onApplyWindowInsets: " + (insets.isRound() ? "round" : "square"));
    111             }
    112             super.onApplyWindowInsets(insets);
    113 
    114             /** Loads offsets / text size based on device type (square vs. round). */
    115             Resources resources = InteractiveWatchFaceService.this.getResources();
    116             boolean isRound = insets.isRound();
    117             mXOffset = resources.getDimension(
    118                     isRound ? R.dimen.interactive_x_offset_round : R.dimen.interactive_x_offset);
    119             mYOffset = resources.getDimension(
    120                     isRound ? R.dimen.interactive_y_offset_round : R.dimen.interactive_y_offset);
    121 
    122             float textSize = resources.getDimension(
    123                     isRound ? R.dimen.interactive_text_size_round : R.dimen.interactive_text_size);
    124 
    125             mTextPaint.setTextSize(textSize);
    126         }
    127 
    128         @Override
    129         public void onPeekCardPositionUpdate(Rect bounds) {
    130             super.onPeekCardPositionUpdate(bounds);
    131             if (Log.isLoggable(TAG, Log.DEBUG)) {
    132                 Log.d(TAG, "onPeekCardPositionUpdate: " + bounds);
    133             }
    134             super.onPeekCardPositionUpdate(bounds);
    135             if (!bounds.equals(mCardBounds)) {
    136                 mCardBounds.set(bounds);
    137                 invalidate();
    138             }
    139         }
    140 
    141         @Override
    142         public void onPropertiesChanged(Bundle properties) {
    143             super.onPropertiesChanged(properties);
    144 
    145             boolean burnInProtection = properties.getBoolean(PROPERTY_BURN_IN_PROTECTION, false);
    146             mTextPaint.setTypeface(burnInProtection ? NORMAL_TYPEFACE : BOLD_TYPEFACE);
    147 
    148             mLowBitAmbient = properties.getBoolean(PROPERTY_LOW_BIT_AMBIENT, false);
    149 
    150             if (Log.isLoggable(TAG, Log.DEBUG)) {
    151                 Log.d(TAG, "onPropertiesChanged: burn-in protection = " + burnInProtection
    152                         + ", low-bit ambient = " + mLowBitAmbient);
    153             }
    154         }
    155 
    156         @Override
    157         public void onAmbientModeChanged(boolean inAmbientMode) {
    158             super.onAmbientModeChanged(inAmbientMode);
    159             if (Log.isLoggable(TAG, Log.DEBUG)) {
    160                 Log.d(TAG, "onAmbientModeChanged: " + inAmbientMode);
    161             }
    162 
    163             if (mLowBitAmbient) {
    164                 boolean antiAlias = !inAmbientMode;
    165                 mTextPaint.setAntiAlias(antiAlias);
    166             }
    167             invalidate();
    168         }
    169 
    170         /*
    171          * Captures tap event (and tap type) and increments correct tap type total.
    172          */
    173         @Override
    174         public void onTapCommand(int tapType, int x, int y, long eventTime) {
    175             if (Log.isLoggable(TAG, Log.DEBUG)) {
    176                 Log.d(TAG, "Tap Command: " + tapType);
    177             }
    178 
    179             mTouchCoordinateX = x;
    180             mTouchCoordinateY = y;
    181 
    182             switch(tapType) {
    183                 case TAP_TYPE_TOUCH:
    184                     mTouchCommandTotal++;
    185                     break;
    186                 case TAP_TYPE_TOUCH_CANCEL:
    187                     mTouchCancelCommandTotal++;
    188                     break;
    189                 case TAP_TYPE_TAP:
    190                     mTapCommandTotal++;
    191                     break;
    192             }
    193 
    194             invalidate();
    195         }
    196 
    197         @Override
    198         public void onDraw(Canvas canvas, Rect bounds) {
    199             /** Draws background */
    200             canvas.drawColor(Color.BLACK);
    201 
    202             canvas.drawText(
    203                     "TAP: " + String.valueOf(mTapCommandTotal),
    204                     mXOffset,
    205                     mYOffset,
    206                     mTextPaint);
    207 
    208             canvas.drawText(
    209                     "CANCEL: " + String.valueOf(mTouchCancelCommandTotal),
    210                     mXOffset,
    211                     mYOffset + mTextSpacingHeight,
    212                     mTextPaint);
    213 
    214             canvas.drawText(
    215                     "TOUCH: " + String.valueOf(mTouchCommandTotal),
    216                     mXOffset,
    217                     mYOffset + (mTextSpacingHeight * 2),
    218                     mTextPaint);
    219 
    220             canvas.drawText(
    221                     "X, Y: " + mTouchCoordinateX + ", " + mTouchCoordinateY,
    222                     mXOffset,
    223                     mYOffset + (mTextSpacingHeight * 3),
    224                     mTextPaint
    225             );
    226 
    227             /** Covers area under peek card */
    228             if (isInAmbientMode()) {
    229                 canvas.drawRect(mCardBounds, mPeekCardBackgroundPaint);
    230             }
    231         }
    232     }
    233 }
    234