1 /* 2 * Copyright (C) 2017 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.util; 18 19 import android.graphics.Color; 20 import android.net.Uri; 21 import android.util.Log; 22 23 import com.google.android.gms.common.api.GoogleApiClient; 24 import com.google.android.gms.common.api.ResultCallback; 25 import com.google.android.gms.wearable.DataApi; 26 import com.google.android.gms.wearable.DataItem; 27 import com.google.android.gms.wearable.DataMap; 28 import com.google.android.gms.wearable.DataMapItem; 29 import com.google.android.gms.wearable.NodeApi; 30 import com.google.android.gms.wearable.PutDataMapRequest; 31 import com.google.android.gms.wearable.Wearable; 32 33 import com.example.android.wearable.watchface.watchface.DigitalWatchFaceService; 34 35 public final class DigitalWatchFaceUtil { 36 private static final String TAG = "DigitalWatchFaceUtil"; 37 38 /** 39 * The {@link DataMap} key for {@link DigitalWatchFaceService} background color name. 40 * The color name must be a {@link String} recognized by {@link Color#parseColor}. 41 */ 42 public static final String KEY_BACKGROUND_COLOR = "BACKGROUND_COLOR"; 43 44 /** 45 * The {@link DataMap} key for {@link DigitalWatchFaceService} hour digits color name. 46 * The color name must be a {@link String} recognized by {@link Color#parseColor}. 47 */ 48 public static final String KEY_HOURS_COLOR = "HOURS_COLOR"; 49 50 /** 51 * The {@link DataMap} key for {@link DigitalWatchFaceService} minute digits color name. 52 * The color name must be a {@link String} recognized by {@link Color#parseColor}. 53 */ 54 public static final String KEY_MINUTES_COLOR = "MINUTES_COLOR"; 55 56 /** 57 * The {@link DataMap} key for {@link DigitalWatchFaceService} second digits color name. 58 * The color name must be a {@link String} recognized by {@link Color#parseColor}. 59 */ 60 public static final String KEY_SECONDS_COLOR = "SECONDS_COLOR"; 61 62 /** 63 * The path for the {@link DataItem} containing {@link DigitalWatchFaceService} configuration. 64 */ 65 public static final String PATH_WITH_FEATURE = "/watch_face_config/Digital"; 66 67 /** 68 * Name of the default interactive mode background color and the ambient mode background color. 69 */ 70 public static final String COLOR_NAME_DEFAULT_AND_AMBIENT_BACKGROUND = "Black"; 71 public static final int COLOR_VALUE_DEFAULT_AND_AMBIENT_BACKGROUND = 72 parseColor(COLOR_NAME_DEFAULT_AND_AMBIENT_BACKGROUND); 73 74 /** 75 * Name of the default interactive mode hour digits color and the ambient mode hour digits 76 * color. 77 */ 78 public static final String COLOR_NAME_DEFAULT_AND_AMBIENT_HOUR_DIGITS = "White"; 79 public static final int COLOR_VALUE_DEFAULT_AND_AMBIENT_HOUR_DIGITS = 80 parseColor(COLOR_NAME_DEFAULT_AND_AMBIENT_HOUR_DIGITS); 81 82 /** 83 * Name of the default interactive mode minute digits color and the ambient mode minute digits 84 * color. 85 */ 86 public static final String COLOR_NAME_DEFAULT_AND_AMBIENT_MINUTE_DIGITS = "White"; 87 public static final int COLOR_VALUE_DEFAULT_AND_AMBIENT_MINUTE_DIGITS = 88 parseColor(COLOR_NAME_DEFAULT_AND_AMBIENT_MINUTE_DIGITS); 89 90 /** 91 * Name of the default interactive mode second digits color and the ambient mode second digits 92 * color. 93 */ 94 public static final String COLOR_NAME_DEFAULT_AND_AMBIENT_SECOND_DIGITS = "Gray"; 95 public static final int COLOR_VALUE_DEFAULT_AND_AMBIENT_SECOND_DIGITS = 96 parseColor(COLOR_NAME_DEFAULT_AND_AMBIENT_SECOND_DIGITS); 97 98 /** 99 * Callback interface to perform an action with the current config {@link DataMap} for 100 * {@link DigitalWatchFaceService}. 101 */ 102 public interface FetchConfigDataMapCallback { 103 /** 104 * Callback invoked with the current config {@link DataMap} for 105 * {@link DigitalWatchFaceService}. 106 */ onConfigDataMapFetched(DataMap config)107 void onConfigDataMapFetched(DataMap config); 108 } 109 parseColor(String colorName)110 private static int parseColor(String colorName) { 111 return Color.parseColor(colorName.toLowerCase()); 112 } 113 114 /** 115 * Asynchronously fetches the current config {@link DataMap} for {@link DigitalWatchFaceService} 116 * and passes it to the given callback. 117 * <p> 118 * If the current config {@link DataItem} doesn't exist, it isn't created and the callback 119 * receives an empty DataMap. 120 */ fetchConfigDataMap(final GoogleApiClient client, final FetchConfigDataMapCallback callback)121 public static void fetchConfigDataMap(final GoogleApiClient client, 122 final FetchConfigDataMapCallback callback) { 123 Wearable.NodeApi.getLocalNode(client).setResultCallback( 124 new ResultCallback<NodeApi.GetLocalNodeResult>() { 125 @Override 126 public void onResult(NodeApi.GetLocalNodeResult getLocalNodeResult) { 127 String localNode = getLocalNodeResult.getNode().getId(); 128 Uri uri = new Uri.Builder() 129 .scheme("wear") 130 .path(DigitalWatchFaceUtil.PATH_WITH_FEATURE) 131 .authority(localNode) 132 .build(); 133 Wearable.DataApi.getDataItem(client, uri) 134 .setResultCallback(new DataItemResultCallback(callback)); 135 } 136 } 137 ); 138 } 139 140 /** 141 * Overwrites (or sets, if not present) the keys in the current config {@link DataItem} with 142 * the ones appearing in the given {@link DataMap}. If the config DataItem doesn't exist, 143 * it's created. 144 * <p> 145 * It is allowed that only some of the keys used in the config DataItem appear in 146 * {@code configKeysToOverwrite}. The rest of the keys remains unmodified in this case. 147 */ overwriteKeysInConfigDataMap(final GoogleApiClient googleApiClient, final DataMap configKeysToOverwrite)148 public static void overwriteKeysInConfigDataMap(final GoogleApiClient googleApiClient, 149 final DataMap configKeysToOverwrite) { 150 151 DigitalWatchFaceUtil.fetchConfigDataMap(googleApiClient, 152 new FetchConfigDataMapCallback() { 153 @Override 154 public void onConfigDataMapFetched(DataMap currentConfig) { 155 DataMap overwrittenConfig = new DataMap(); 156 overwrittenConfig.putAll(currentConfig); 157 overwrittenConfig.putAll(configKeysToOverwrite); 158 DigitalWatchFaceUtil.putConfigDataItem(googleApiClient, overwrittenConfig); 159 } 160 } 161 ); 162 } 163 164 /** 165 * Overwrites the current config {@link DataItem}'s {@link DataMap} with {@code newConfig}. 166 * If the config DataItem doesn't exist, it's created. 167 */ putConfigDataItem(GoogleApiClient googleApiClient, DataMap newConfig)168 public static void putConfigDataItem(GoogleApiClient googleApiClient, DataMap newConfig) { 169 PutDataMapRequest putDataMapRequest = PutDataMapRequest.create(PATH_WITH_FEATURE); 170 putDataMapRequest.setUrgent(); 171 DataMap configToPut = putDataMapRequest.getDataMap(); 172 configToPut.putAll(newConfig); 173 Wearable.DataApi.putDataItem(googleApiClient, putDataMapRequest.asPutDataRequest()) 174 .setResultCallback(new ResultCallback<DataApi.DataItemResult>() { 175 @Override 176 public void onResult(DataApi.DataItemResult dataItemResult) { 177 if (Log.isLoggable(TAG, Log.DEBUG)) { 178 Log.d(TAG, "putDataItem result status: " + dataItemResult.getStatus()); 179 } 180 } 181 }); 182 } 183 184 private static class DataItemResultCallback implements ResultCallback<DataApi.DataItemResult> { 185 186 private final FetchConfigDataMapCallback mCallback; 187 DataItemResultCallback(FetchConfigDataMapCallback callback)188 public DataItemResultCallback(FetchConfigDataMapCallback callback) { 189 mCallback = callback; 190 } 191 192 @Override onResult(DataApi.DataItemResult dataItemResult)193 public void onResult(DataApi.DataItemResult dataItemResult) { 194 if (dataItemResult.getStatus().isSuccess()) { 195 if (dataItemResult.getDataItem() != null) { 196 DataItem configDataItem = dataItemResult.getDataItem(); 197 DataMapItem dataMapItem = DataMapItem.fromDataItem(configDataItem); 198 DataMap config = dataMapItem.getDataMap(); 199 mCallback.onConfigDataMapFetched(config); 200 } else { 201 mCallback.onConfigDataMapFetched(new DataMap()); 202 } 203 } 204 } 205 } 206 DigitalWatchFaceUtil()207 private DigitalWatchFaceUtil() { } 208 } 209