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.app.Activity;
20 import android.app.AlertDialog;
21 import android.content.ComponentName;
22 import android.content.DialogInterface;
23 import android.graphics.Color;
24 import android.net.Uri;
25 import android.os.Bundle;
26 import android.support.wearable.companion.WatchFaceCompanion;
27 import android.util.Log;
28 import android.view.View;
29 import android.widget.AdapterView;
30 import android.widget.Spinner;
31 import android.widget.TextView;
32 
33 import com.google.android.gms.common.ConnectionResult;
34 import com.google.android.gms.common.api.GoogleApiClient;
35 import com.google.android.gms.common.api.ResultCallback;
36 import com.google.android.gms.wearable.DataApi;
37 import com.google.android.gms.wearable.DataItem;
38 import com.google.android.gms.wearable.DataMap;
39 import com.google.android.gms.wearable.DataMapItem;
40 import com.google.android.gms.wearable.Wearable;
41 
42 /**
43  * The phone-side config activity for {@code DigitalWatchFaceService}. Like the watch-side config
44  * activity ({@code DigitalWatchFaceWearableConfigActivity}), allows for setting the background
45  * color. Additionally, enables setting the color for hour, minute and second digits.
46  */
47 public class DigitalWatchFaceCompanionConfigActivity extends Activity
48         implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,
49                 ResultCallback<DataApi.DataItemResult> {
50     private static final String TAG = "DigitalWatchFaceConfig";
51 
52     // TODO: use the shared constants (needs covering all the samples with Gradle build model)
53     private static final String KEY_BACKGROUND_COLOR = "BACKGROUND_COLOR";
54     private static final String KEY_HOURS_COLOR = "HOURS_COLOR";
55     private static final String KEY_MINUTES_COLOR = "MINUTES_COLOR";
56     private static final String KEY_SECONDS_COLOR = "SECONDS_COLOR";
57     private static final String PATH_WITH_FEATURE = "/watch_face_config/Digital";
58 
59     private GoogleApiClient mGoogleApiClient;
60     private String mPeerId;
61 
62     @Override
onCreate(Bundle savedInstanceState)63     protected void onCreate(Bundle savedInstanceState) {
64         super.onCreate(savedInstanceState);
65         setContentView(R.layout.activity_digital_watch_face_config);
66 
67         mPeerId = getIntent().getStringExtra(WatchFaceCompanion.EXTRA_PEER_ID);
68         mGoogleApiClient = new GoogleApiClient.Builder(this)
69                 .addConnectionCallbacks(this)
70                 .addOnConnectionFailedListener(this)
71                 .addApi(Wearable.API)
72                 .build();
73 
74         ComponentName name = getIntent().getParcelableExtra(
75                 WatchFaceCompanion.EXTRA_WATCH_FACE_COMPONENT);
76         TextView label = (TextView)findViewById(R.id.label);
77         label.setText(label.getText() + " (" + name.getClassName() + ")");
78     }
79 
80     @Override
onStart()81     protected void onStart() {
82         super.onStart();
83         mGoogleApiClient.connect();
84     }
85 
86     @Override
onStop()87     protected void onStop() {
88         if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
89             mGoogleApiClient.disconnect();
90         }
91         super.onStop();
92     }
93 
94     @Override // GoogleApiClient.ConnectionCallbacks
onConnected(Bundle connectionHint)95     public void onConnected(Bundle connectionHint) {
96         if (Log.isLoggable(TAG, Log.DEBUG)) {
97             Log.d(TAG, "onConnected: " + connectionHint);
98         }
99 
100         if (mPeerId != null) {
101             Uri.Builder builder = new Uri.Builder();
102             Uri uri = builder.scheme("wear").path(PATH_WITH_FEATURE).authority(mPeerId).build();
103             Wearable.DataApi.getDataItem(mGoogleApiClient, uri).setResultCallback(this);
104         } else {
105             displayNoConnectedDeviceDialog();
106         }
107     }
108 
109     @Override // ResultCallback<DataApi.DataItemResult>
onResult(DataApi.DataItemResult dataItemResult)110     public void onResult(DataApi.DataItemResult dataItemResult) {
111         if (dataItemResult.getStatus().isSuccess() && dataItemResult.getDataItem() != null) {
112             DataItem configDataItem = dataItemResult.getDataItem();
113             DataMapItem dataMapItem = DataMapItem.fromDataItem(configDataItem);
114             DataMap config = dataMapItem.getDataMap();
115             setUpAllPickers(config);
116         } else {
117             // If DataItem with the current config can't be retrieved, select the default items on
118             // each picker.
119             setUpAllPickers(null);
120         }
121     }
122 
123     @Override // GoogleApiClient.ConnectionCallbacks
onConnectionSuspended(int cause)124     public void onConnectionSuspended(int cause) {
125         if (Log.isLoggable(TAG, Log.DEBUG)) {
126             Log.d(TAG, "onConnectionSuspended: " + cause);
127         }
128     }
129 
130     @Override // GoogleApiClient.OnConnectionFailedListener
onConnectionFailed(ConnectionResult result)131     public void onConnectionFailed(ConnectionResult result) {
132         if (Log.isLoggable(TAG, Log.DEBUG)) {
133             Log.d(TAG, "onConnectionFailed: " + result);
134         }
135     }
136 
displayNoConnectedDeviceDialog()137     private void displayNoConnectedDeviceDialog() {
138         AlertDialog.Builder builder = new AlertDialog.Builder(this);
139         String messageText = getResources().getString(R.string.title_no_device_connected);
140         String okText = getResources().getString(R.string.ok_no_device_connected);
141         builder.setMessage(messageText)
142                 .setCancelable(false)
143                 .setPositiveButton(okText, new DialogInterface.OnClickListener() {
144                     public void onClick(DialogInterface dialog, int id) { }
145                 });
146         AlertDialog alert = builder.create();
147         alert.show();
148     }
149 
150     /**
151      * Sets up selected items for all pickers according to given {@code config} and sets up their
152      * item selection listeners.
153      *
154      * @param config the {@code DigitalWatchFaceService} config {@link DataMap}. If null, the
155      *         default items are selected.
156      */
setUpAllPickers(DataMap config)157     private void setUpAllPickers(DataMap config) {
158         setUpColorPickerSelection(R.id.background, KEY_BACKGROUND_COLOR, config,
159                 R.string.color_black);
160         setUpColorPickerSelection(R.id.hours, KEY_HOURS_COLOR, config, R.string.color_white);
161         setUpColorPickerSelection(R.id.minutes, KEY_MINUTES_COLOR, config, R.string.color_white);
162         setUpColorPickerSelection(R.id.seconds, KEY_SECONDS_COLOR, config, R.string.color_gray);
163 
164         setUpColorPickerListener(R.id.background, KEY_BACKGROUND_COLOR);
165         setUpColorPickerListener(R.id.hours, KEY_HOURS_COLOR);
166         setUpColorPickerListener(R.id.minutes, KEY_MINUTES_COLOR);
167         setUpColorPickerListener(R.id.seconds, KEY_SECONDS_COLOR);
168     }
169 
setUpColorPickerSelection(int spinnerId, final String configKey, DataMap config, int defaultColorNameResId)170     private void setUpColorPickerSelection(int spinnerId, final String configKey, DataMap config,
171             int defaultColorNameResId) {
172         String defaultColorName = getString(defaultColorNameResId);
173         int defaultColor = Color.parseColor(defaultColorName);
174         int color;
175         if (config != null) {
176             color = config.getInt(configKey, defaultColor);
177         } else {
178             color = defaultColor;
179         }
180         Spinner spinner = (Spinner) findViewById(spinnerId);
181         String[] colorNames = getResources().getStringArray(R.array.color_array);
182         for (int i = 0; i < colorNames.length; i++) {
183             if (Color.parseColor(colorNames[i]) == color) {
184                 spinner.setSelection(i);
185                 break;
186             }
187         }
188     }
189 
setUpColorPickerListener(int spinnerId, final String configKey)190     private void setUpColorPickerListener(int spinnerId, final String configKey) {
191         Spinner spinner = (Spinner) findViewById(spinnerId);
192         spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
193             @Override
194             public void onItemSelected(AdapterView<?> adapterView, View view, int pos, long id) {
195                 final String colorName = (String) adapterView.getItemAtPosition(pos);
196                 sendConfigUpdateMessage(configKey, Color.parseColor(colorName));
197             }
198 
199             @Override
200             public void onNothingSelected(AdapterView<?> adapterView) { }
201         });
202     }
203 
sendConfigUpdateMessage(String configKey, int color)204     private void sendConfigUpdateMessage(String configKey, int color) {
205         if (mPeerId != null) {
206             DataMap config = new DataMap();
207             config.putInt(configKey, color);
208             byte[] rawData = config.toByteArray();
209             Wearable.MessageApi.sendMessage(mGoogleApiClient, mPeerId, PATH_WITH_FEATURE, rawData);
210 
211             if (Log.isLoggable(TAG, Log.DEBUG)) {
212                 Log.d(TAG, "Sent watch face config message: " + configKey + " -> "
213                         + Integer.toHexString(color));
214             }
215         }
216     }
217 }
218