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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/DigitalWatchFaceConfigListenerService.java b/samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/DigitalWatchFaceConfigListenerService.java
index 725c51aa8..8d99de6cb 100644
--- a/samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/DigitalWatchFaceConfigListenerService.java
+++ b/samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/DigitalWatchFaceConfigListenerService.java
@@ -40,6 +40,11 @@ public class DigitalWatchFaceConfigListenerService extends WearableListenerServi
@Override // WearableListenerService
public void onMessageReceived(MessageEvent messageEvent) {
+
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "onMessageReceived: " + messageEvent);
+ }
+
if (!messageEvent.getPath().equals(DigitalWatchFaceUtil.PATH_WITH_FEATURE)) {
return;
}
diff --git a/samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/FitDistanceWatchFaceService.java b/samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/FitDistanceWatchFaceService.java
index b29a1902d..6dee04e62 100644
--- a/samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/FitDistanceWatchFaceService.java
+++ b/samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/FitDistanceWatchFaceService.java
@@ -62,7 +62,10 @@ import java.util.concurrent.TimeUnit;
*
* Authentication IS a requirement to request distance from Google Fit on Wear. Otherwise, distance
* will always come back as zero (or stay at whatever the distance was prior to you
- * de-authorizing watchface).
+ * de-authorizing watchface). To authenticate and communicate with Google Fit, you must create a
+ * project in the Google Developers Console, activate the Fitness API, create an OAuth 2.0
+ * client ID, and register the public certificate from your app's signed APK. More details can be
+ * found here: https://developers.google.com/fit/android/get-started#step_3_enable_the_fitness_api
*
* In ambient mode, the seconds are replaced with an AM/PM indicator.
*
diff --git a/samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/provider/RandomNumberProviderService.java b/samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/provider/RandomNumberProviderService.java
new file mode 100644
index 000000000..916f90fd9
--- /dev/null
+++ b/samples/browseable/WatchFace/Wearable/src/com.example.android.wearable.watchface/provider/RandomNumberProviderService.java
@@ -0,0 +1,96 @@
+package com.example.android.wearable.watchface.provider;
+
+import android.support.wearable.complications.ComplicationData;
+import android.support.wearable.complications.ComplicationManager;
+import android.support.wearable.complications.ComplicationProviderService;
+import android.support.wearable.complications.ComplicationText;
+import android.util.Log;
+
+import java.util.Locale;
+
+/**
+ * Example Watch Face Complication data provider provides a random number on every update.
+ */
+public class RandomNumberProviderService extends ComplicationProviderService {
+
+ private static final String TAG = "RandomNumberProvider";
+
+ /*
+ * Called when a complication has been activated. The method is for any one-time
+ * (per complication) set-up.
+ *
+ * You can continue sending data for the active complicationId until onComplicationDeactivated()
+ * is called.
+ */
+ @Override
+ public void onComplicationActivated(
+ int complicationId, int dataType, ComplicationManager complicationManager) {
+ Log.d(TAG, "onComplicationActivated(): " + complicationId);
+ super.onComplicationActivated(complicationId, dataType, complicationManager);
+ }
+
+ /*
+ * Called when the complication needs updated data from your provider. There are four scenarios
+ * when this will happen:
+ *
+ * 1. An active watch face complication is changed to use this provider
+ * 2. A complication using this provider becomes active
+ * 3. The period of time you specified in the manifest has elapsed (UPDATE_PERIOD_SECONDS)
+ * 4. You triggered an update from your own class via the
+ * ProviderUpdateRequester.requestUpdate() method.
+ */
+ @Override
+ public void onComplicationUpdate(
+ int complicationId, int dataType, ComplicationManager complicationManager) {
+ Log.d(TAG, "onComplicationUpdate()");
+
+
+ // Retrieve your data, in this case, we simply create a random number to display.
+ int randomNumber = (int) Math.floor(Math.random() * 10);
+
+ String randomNumberText =
+ String.format(Locale.getDefault(), "%d!", randomNumber);
+
+ ComplicationData complicationData = null;
+
+ switch (dataType) {
+ case ComplicationData.TYPE_RANGED_VALUE:
+ complicationData = new ComplicationData.Builder(ComplicationData.TYPE_RANGED_VALUE)
+ .setValue(randomNumber)
+ .setMinValue(0)
+ .setMaxValue(10)
+ .setShortText(ComplicationText.plainText(randomNumberText))
+ .build();
+ break;
+ case ComplicationData.TYPE_SHORT_TEXT:
+ complicationData = new ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT)
+ .setShortText(ComplicationText.plainText(randomNumberText))
+ .build();
+ break;
+ case ComplicationData.TYPE_LONG_TEXT:
+ complicationData = new ComplicationData.Builder(ComplicationData.TYPE_LONG_TEXT)
+ .setLongText(
+ ComplicationText.plainText("Random Number: " + randomNumberText))
+ .build();
+ break;
+ default:
+ if (Log.isLoggable(TAG, Log.WARN)) {
+ Log.w(TAG, "Unexpected complication type " + dataType);
+ }
+ }
+
+ if (complicationData != null) {
+ complicationManager.updateComplicationData(complicationId, complicationData);
+ }
+ }
+
+ /*
+ * Called when the complication has been deactivated. If you are updating the complication
+ * manager outside of this class with updates, you will want to update your class to stop.
+ */
+ @Override
+ public void onComplicationDeactivated(int complicationId) {
+ Log.d(TAG, "onComplicationDeactivated(): " + complicationId);
+ super.onComplicationDeactivated(complicationId);
+ }
+}
\ No newline at end of file
diff --git a/samples/browseable/WearDrawers/AndroidManifest.xml b/samples/browseable/WearDrawers/AndroidManifest.xml
new file mode 100644
index 000000000..3044d1906
--- /dev/null
+++ b/samples/browseable/WearDrawers/AndroidManifest.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/browseable/WearDrawers/_index.jd b/samples/browseable/WearDrawers/_index.jd
new file mode 100644
index 000000000..93327b8f5
--- /dev/null
+++ b/samples/browseable/WearDrawers/_index.jd
@@ -0,0 +1,10 @@
+
+page.tags="WearDrawers"
+sample.group=Wearable
+@jd:body
+
+
+
+A simple sample that demonstrates Navigation and Action Drawers, part of Material Design for Wear.
+
+
diff --git a/samples/browseable/WearDrawers/res/drawable-hdpi/earth.png b/samples/browseable/WearDrawers/res/drawable-hdpi/earth.png
new file mode 100644
index 000000000..13abd77a5
Binary files /dev/null and b/samples/browseable/WearDrawers/res/drawable-hdpi/earth.png differ
diff --git a/samples/browseable/WearDrawers/res/drawable-hdpi/ic_e_white_48dp.png b/samples/browseable/WearDrawers/res/drawable-hdpi/ic_e_white_48dp.png
new file mode 100644
index 000000000..3dc20986f
Binary files /dev/null and b/samples/browseable/WearDrawers/res/drawable-hdpi/ic_e_white_48dp.png differ
diff --git a/samples/browseable/WearDrawers/res/drawable-hdpi/ic_info_outline_black_18dp.png b/samples/browseable/WearDrawers/res/drawable-hdpi/ic_info_outline_black_18dp.png
new file mode 100644
index 000000000..05803bd15
Binary files /dev/null and b/samples/browseable/WearDrawers/res/drawable-hdpi/ic_info_outline_black_18dp.png differ
diff --git a/samples/browseable/WearDrawers/res/drawable-hdpi/ic_j_white_48dp.png b/samples/browseable/WearDrawers/res/drawable-hdpi/ic_j_white_48dp.png
new file mode 100644
index 000000000..03715893b
Binary files /dev/null and b/samples/browseable/WearDrawers/res/drawable-hdpi/ic_j_white_48dp.png differ
diff --git a/samples/browseable/WearDrawers/res/drawable-hdpi/ic_m_white_48dp.png b/samples/browseable/WearDrawers/res/drawable-hdpi/ic_m_white_48dp.png
new file mode 100644
index 000000000..00b9858cc
Binary files /dev/null and b/samples/browseable/WearDrawers/res/drawable-hdpi/ic_m_white_48dp.png differ
diff --git a/samples/browseable/WearDrawers/res/drawable-hdpi/ic_n_white_48dp.png b/samples/browseable/WearDrawers/res/drawable-hdpi/ic_n_white_48dp.png
new file mode 100644
index 000000000..33eceae3f
Binary files /dev/null and b/samples/browseable/WearDrawers/res/drawable-hdpi/ic_n_white_48dp.png differ
diff --git a/samples/browseable/WearDrawers/res/drawable-hdpi/ic_s_white_48dp.png b/samples/browseable/WearDrawers/res/drawable-hdpi/ic_s_white_48dp.png
new file mode 100644
index 000000000..f767c8d91
Binary files /dev/null and b/samples/browseable/WearDrawers/res/drawable-hdpi/ic_s_white_48dp.png differ
diff --git a/samples/browseable/WearDrawers/res/drawable-hdpi/ic_u_white_48dp.png b/samples/browseable/WearDrawers/res/drawable-hdpi/ic_u_white_48dp.png
new file mode 100644
index 000000000..a3ba71b08
Binary files /dev/null and b/samples/browseable/WearDrawers/res/drawable-hdpi/ic_u_white_48dp.png differ
diff --git a/samples/browseable/WearDrawers/res/drawable-hdpi/ic_v_white_48dp.png b/samples/browseable/WearDrawers/res/drawable-hdpi/ic_v_white_48dp.png
new file mode 100644
index 000000000..ddfaffe19
Binary files /dev/null and b/samples/browseable/WearDrawers/res/drawable-hdpi/ic_v_white_48dp.png differ
diff --git a/samples/browseable/WearDrawers/res/drawable-hdpi/jupiter.png b/samples/browseable/WearDrawers/res/drawable-hdpi/jupiter.png
new file mode 100644
index 000000000..891502570
Binary files /dev/null and b/samples/browseable/WearDrawers/res/drawable-hdpi/jupiter.png differ
diff --git a/samples/browseable/WearDrawers/res/drawable-hdpi/mars.png b/samples/browseable/WearDrawers/res/drawable-hdpi/mars.png
new file mode 100644
index 000000000..ac7e4f836
Binary files /dev/null and b/samples/browseable/WearDrawers/res/drawable-hdpi/mars.png differ
diff --git a/samples/browseable/WearDrawers/res/drawable-hdpi/mercury.png b/samples/browseable/WearDrawers/res/drawable-hdpi/mercury.png
new file mode 100644
index 000000000..06329ca6d
Binary files /dev/null and b/samples/browseable/WearDrawers/res/drawable-hdpi/mercury.png differ
diff --git a/samples/browseable/WearDrawers/res/drawable-hdpi/neptune.png b/samples/browseable/WearDrawers/res/drawable-hdpi/neptune.png
new file mode 100644
index 000000000..ce12b3724
Binary files /dev/null and b/samples/browseable/WearDrawers/res/drawable-hdpi/neptune.png differ
diff --git a/samples/browseable/WearDrawers/res/drawable-hdpi/saturn.png b/samples/browseable/WearDrawers/res/drawable-hdpi/saturn.png
new file mode 100644
index 000000000..9f51ca43e
Binary files /dev/null and b/samples/browseable/WearDrawers/res/drawable-hdpi/saturn.png differ
diff --git a/samples/browseable/WearDrawers/res/drawable-hdpi/uranus.png b/samples/browseable/WearDrawers/res/drawable-hdpi/uranus.png
new file mode 100644
index 000000000..0cdf78812
Binary files /dev/null and b/samples/browseable/WearDrawers/res/drawable-hdpi/uranus.png differ
diff --git a/samples/browseable/WearDrawers/res/drawable-hdpi/venus.png b/samples/browseable/WearDrawers/res/drawable-hdpi/venus.png
new file mode 100644
index 000000000..68fee0ed6
Binary files /dev/null and b/samples/browseable/WearDrawers/res/drawable-hdpi/venus.png differ
diff --git a/samples/browseable/WearDrawers/res/drawable-mdpi/ic_info_outline_black_18dp.png b/samples/browseable/WearDrawers/res/drawable-mdpi/ic_info_outline_black_18dp.png
new file mode 100644
index 000000000..bb6095bd0
Binary files /dev/null and b/samples/browseable/WearDrawers/res/drawable-mdpi/ic_info_outline_black_18dp.png differ
diff --git a/samples/browseable/WearDrawers/res/drawable-xhdpi/ic_info_outline_black_18dp.png b/samples/browseable/WearDrawers/res/drawable-xhdpi/ic_info_outline_black_18dp.png
new file mode 100644
index 000000000..4b5ab06e1
Binary files /dev/null and b/samples/browseable/WearDrawers/res/drawable-xhdpi/ic_info_outline_black_18dp.png differ
diff --git a/samples/browseable/WearDrawers/res/drawable-xxhdpi/ic_info_outline_black_18dp.png b/samples/browseable/WearDrawers/res/drawable-xxhdpi/ic_info_outline_black_18dp.png
new file mode 100644
index 000000000..0b465fc75
Binary files /dev/null and b/samples/browseable/WearDrawers/res/drawable-xxhdpi/ic_info_outline_black_18dp.png differ
diff --git a/samples/browseable/WearDrawers/res/drawable-xxxhdpi/ic_info_outline_black_18dp.png b/samples/browseable/WearDrawers/res/drawable-xxxhdpi/ic_info_outline_black_18dp.png
new file mode 100644
index 000000000..3847a9fe7
Binary files /dev/null and b/samples/browseable/WearDrawers/res/drawable-xxxhdpi/ic_info_outline_black_18dp.png differ
diff --git a/samples/browseable/WearDrawers/res/layout/fragment_planet.xml b/samples/browseable/WearDrawers/res/layout/fragment_planet.xml
new file mode 100644
index 000000000..6409eb0ed
--- /dev/null
+++ b/samples/browseable/WearDrawers/res/layout/fragment_planet.xml
@@ -0,0 +1,20 @@
+
+
\ No newline at end of file
diff --git a/samples/browseable/WearDrawers/res/menu/action_drawer_menu.xml b/samples/browseable/WearDrawers/res/menu/action_drawer_menu.xml
new file mode 100644
index 000000000..86060d2a4
--- /dev/null
+++ b/samples/browseable/WearDrawers/res/menu/action_drawer_menu.xml
@@ -0,0 +1,30 @@
+
+
+
\ No newline at end of file
diff --git a/samples/browseable/WearDrawers/res/mipmap-hdpi/ic_launcher.png b/samples/browseable/WearDrawers/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..cde69bccc
Binary files /dev/null and b/samples/browseable/WearDrawers/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/samples/browseable/WearDrawers/res/mipmap-mdpi/ic_launcher.png b/samples/browseable/WearDrawers/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..c133a0cbd
Binary files /dev/null and b/samples/browseable/WearDrawers/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/samples/browseable/WearDrawers/res/mipmap-xhdpi/ic_launcher.png b/samples/browseable/WearDrawers/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..bfa42f0e7
Binary files /dev/null and b/samples/browseable/WearDrawers/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/samples/browseable/WearDrawers/res/mipmap-xxhdpi/ic_launcher.png b/samples/browseable/WearDrawers/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..324e72cdd
Binary files /dev/null and b/samples/browseable/WearDrawers/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/samples/browseable/WearDrawers/res/values/strings.xml b/samples/browseable/WearDrawers/res/values/strings.xml
new file mode 100644
index 000000000..0a0cd87b2
--- /dev/null
+++ b/samples/browseable/WearDrawers/res/values/strings.xml
@@ -0,0 +1,114 @@
+
+
+ Wearable Drawer Layout
+
+
+
+ - mercury
+ - venus
+ - earth
+ - mars
+ - jupiter
+ - saturn
+ - uranus
+ - neptune
+
+
+
+
+ - Mercury
+ - ic_m_white_48dp
+ - mercury
+ - 0 Moons
+ - 0.056 x Earth
+ - 0.147 x Earth
+
+
+
+ - Venus
+ - ic_v_white_48dp
+ - venus
+ - 0 Moons
+ - 0.857 x Earth
+ - 0.902 x Earth
+
+
+
+ - Earth
+ - ic_e_white_48dp
+ - earth
+ - 1 moon
+ - 1,083,206,916,846 km3
+ - 510,064,472 km2
+
+
+
+ - Mars
+ - ic_m_white_48dp
+ - mars
+ - 2 Moons
+ - 0.151 x Earth
+ - 0.283 x Earth
+
+
+
+ - Jupiter
+ - ic_j_white_48dp
+ - jupiter
+ - 67 Moons
+ - 1,321.337 x Earth
+ - 120.414 x Earth
+
+
+
+ - Saturn
+ - ic_s_white_48dp
+ - saturn
+ - 62 moons
+ - 763.594 x Earth
+ - 83.543 x Earth
+
+
+
+ - Uranus
+ - ic_u_white_48dp
+ - uranus
+ - 27 Moons
+ - 63.085 x Earth
+ - 15.847 x Earth
+
+
+
+ - Neptune
+ - ic_n_white_48dp
+ - neptune
+ - 14 Moons
+ - 57.723 x Earth
+ - 14.980 x Earth
+
+
\ No newline at end of file
diff --git a/samples/browseable/WearDrawers/src/com.example.android.wearable.wear.weardrawers/Planet.java b/samples/browseable/WearDrawers/src/com.example.android.wearable.wear.weardrawers/Planet.java
new file mode 100644
index 000000000..67960493c
--- /dev/null
+++ b/samples/browseable/WearDrawers/src/com.example.android.wearable.wear.weardrawers/Planet.java
@@ -0,0 +1,69 @@
+/*
+Copyright 2016 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.wear.weardrawers;
+
+/**
+ * Represents planet for app.
+ */
+public class Planet {
+
+ private String name;
+ private String navigationIcon;
+ private String image;
+ private String moons;
+ private String volume;
+ private String surfaceArea;
+
+ public Planet(
+ String name,
+ String navigationIcon,
+ String image,
+ String moons,
+ String volume,
+ String surfaceArea) {
+
+ this.name = name;
+ this.navigationIcon = navigationIcon;
+ this.image = image;
+ this.moons = moons;
+ this.volume = volume;
+ this.surfaceArea = surfaceArea;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getNavigationIcon() {
+ return navigationIcon;
+ }
+
+ public String getImage() {
+ return image;
+ }
+
+ public String getMoons() {
+ return moons;
+ }
+
+ public String getVolume() {
+ return volume;
+ }
+
+ public String getSurfaceArea() {
+ return surfaceArea;
+ }
+}
\ No newline at end of file
diff --git a/samples/browseable/XYZTouristAttractions/Application/AndroidManifest.xml b/samples/browseable/XYZTouristAttractions/Application/AndroidManifest.xml
index 9d88b3981..762f9cdae 100644
--- a/samples/browseable/XYZTouristAttractions/Application/AndroidManifest.xml
+++ b/samples/browseable/XYZTouristAttractions/Application/AndroidManifest.xml
@@ -55,7 +55,16 @@
-
+
+
+
+
+
+
+
+
diff --git a/samples/browseable/XYZTouristAttractions/Wearable/AndroidManifest.xml b/samples/browseable/XYZTouristAttractions/Wearable/AndroidManifest.xml
index d353b2906..fc086da1a 100644
--- a/samples/browseable/XYZTouristAttractions/Wearable/AndroidManifest.xml
+++ b/samples/browseable/XYZTouristAttractions/Wearable/AndroidManifest.xml
@@ -44,7 +44,14 @@
-
+
+
+
+
+
+
+
+