/*
* Copyright 2015 Google Inc.
*
* 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 net.nurik.roman.formwatchface.common.config;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Build;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.wearable.DataItem;
import com.google.android.gms.wearable.DataItemBuffer;
import com.google.android.gms.wearable.DataMap;
import com.google.android.gms.wearable.DataMapItem;
import com.google.android.gms.wearable.NodeApi;
import com.google.android.gms.wearable.PutDataMapRequest;
import com.google.android.gms.wearable.Wearable;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.TimeUnit;
public class ConfigHelper {
private static final String TAG = "ConfigHelper";
public static final String KEY_THEME = "pref_theme";
public static final String KEY_SHOW_NOTIFICATION_COUNT = "pref_show_notification_count";
public static final String KEY_SHOW_DATE = "pref_show_date";
public static final String KEY_SHOW_SECONDS = "pref_show_seconds";
private static final Set<String> STRING_CONFIG_KEYS = new HashSet<>(Arrays.asList(
KEY_THEME
));
private static final Set<String> BOOLEAN_CONFIG_KEYS = new HashSet<>(Arrays.asList(
KEY_SHOW_NOTIFICATION_COUNT,
KEY_SHOW_DATE,
KEY_SHOW_SECONDS
));
private final Context mContext;
private GoogleApiClient mGoogleApiClient;
public ConfigHelper(Context context) {
mContext = context;
}
public boolean connect() {
if (mGoogleApiClient != null) {
return true;
}
if (ConnectionResult.SUCCESS != GooglePlayServicesUtil.isGooglePlayServicesAvailable(mContext)
|| Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN_MR1) {
return false;
}
mGoogleApiClient = new GoogleApiClient.Builder(mContext)
.addApi(Wearable.API)
.build();
ConnectionResult connectionResult = mGoogleApiClient.blockingConnect(5, TimeUnit.SECONDS);
if (!connectionResult.isSuccess()) {
Log.e(TAG, "Failed to connect to GoogleApiClient: " + connectionResult.getErrorCode());
mGoogleApiClient = null;
return false;
}
return true;
}
public String getLocalNodeId() {
NodeApi.GetLocalNodeResult localNodeResult = Wearable.NodeApi.getLocalNode(mGoogleApiClient).await();
if (!localNodeResult.getStatus().isSuccess()) {
Log.e(TAG, "Error getting local node info: " + localNodeResult.getStatus().getStatusMessage());
}
return localNodeResult.getNode().getId();
}
public void disconnect() {
if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
mGoogleApiClient = null;
}
}
public void putConfigSharedPrefsToDataLayer() {
DataMap newDataMap = readConfigDataMapFromSharedPrefs();
if (newDataMap == null) {
return;
}
DataMap currentDataMap = readConfigDataMapFromDataLayer();
boolean dirty = true;
if (currentDataMap != null) {
dirty = false;
for (String key : newDataMap.keySet()) {
Object newValue = newDataMap.get(key);
if (newValue != null && !newValue.equals(currentDataMap.get(key))) {
dirty = true;
break;
}
}
}
if (dirty) {
putConfigDataMapToDataLayer(newDataMap);
}
disconnect();
}
public void readConfigSharedPrefsFromDataLayer() {
// Read all DataItems
DataMap configDataMap = readConfigDataMapFromDataLayer();
if (configDataMap != null) {
putConfigDataMapToSharedPrefs(configDataMap);
}
disconnect();
}
private void putConfigDataMapToDataLayer(DataMap configDataMap) {
PutDataMapRequest dataMapRequest = PutDataMapRequest.create("/config");
dataMapRequest.getDataMap().putDataMap("config", configDataMap);
// NOTE: Need to use timestamps because there's a separate data item for the companion
// and the wearable
// TODO: find a better way to get cross-device timestamps
dataMapRequest.getDataMap().putLong("timestamp", Calendar.getInstance().getTimeInMillis());
Wearable.DataApi.putDataItem(mGoogleApiClient, dataMapRequest.asPutDataRequest()).await();
}
// Assumes connect() has been called
private DataMap readConfigDataMapFromDataLayer() {
long latestTimestamp = 0;
DataItemBuffer dataItemBuffer = Wearable.DataApi.getDataItems(mGoogleApiClient).await();
if (!dataItemBuffer.getStatus().isSuccess()) {
Log.e(TAG, "Error getting all data items: " + dataItemBuffer.getStatus().getStatusMessage());
}
DataMap configDataMap = null;
Iterator<DataItem> dataItemIterator = dataItemBuffer.singleRefIterator();
while (dataItemIterator.hasNext()) {
DataItem dataItem = dataItemIterator.next();
if (!dataItem.getUri().getPath().equals("/config")) {
continue;
}
DataMapItem dataMapItem = DataMapItem.fromDataItem(dataItem);
DataMap dataMap = dataMapItem.getDataMap();
long timestamp = dataMap.getLong("timestamp");
if (timestamp >= latestTimestamp) {
configDataMap = dataMapItem.getDataMap().getDataMap("config");
latestTimestamp = timestamp;
}
}
dataItemBuffer.release();
return configDataMap;
}
public static boolean isConfigPrefKey(String key) {
return BOOLEAN_CONFIG_KEYS.contains(key) || STRING_CONFIG_KEYS.contains(key);
}
private DataMap readConfigDataMapFromSharedPrefs() {
DataMap dataMap = new DataMap();
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
for (String key : BOOLEAN_CONFIG_KEYS) {
if (sp.contains(key)) {
dataMap.putBoolean(key, sp.getBoolean(key, false));
}
}
for (String key : STRING_CONFIG_KEYS) {
String value = sp.getString(key, null);
if (value != null) {
dataMap.putString(key, value);
}
}
return dataMap;
}
private void putConfigDataMapToSharedPrefs(DataMap dataMap) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
SharedPreferences.Editor editor = sp.edit();
for (String key : BOOLEAN_CONFIG_KEYS) {
if (dataMap.containsKey(key)) {
boolean value = dataMap.getBoolean(key);
if (sp.getBoolean(key, false) != value) {
editor.putBoolean(key, value);
}
}
}
for (String key : STRING_CONFIG_KEYS) {
if (dataMap.containsKey(key)) {
String value = dataMap.getString(key);
if (!TextUtils.equals(sp.getString(key, null), value)) {
editor.putString(key, dataMap.getString(key));
}
}
}
editor.apply();
}
}