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