Skip to content

Commit

Permalink
Send request from wear device to phone on startup
Browse files Browse the repository at this point in the history
On phone the dataservice is triggered every 3 hours and
most of the times there is no change in the data. Hence, wear
doesn't recieve any updates about the data. If the data is not stored
on the wear device while the very first sync is made, it'll never recieve the
data unless it is updated. Hence adding a simple timstamp to the data. This
has its own downsides but atleast the wear device recieves the data.
  • Loading branch information
Protino committed Feb 28, 2017
1 parent cddbca3 commit 2aad9c6
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 7 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/def8b5a8b1dd416ea8e4878b8af239b5)](https://www.codacy.com/app/gurupadmamadapur/Go-Ubiquitous?utm_source=github.com&utm_medium=referral&utm_content=Protino/Go-Ubiquitous&utm_campaign=Badge_Grade)

Go-Ubiquitous
=============
* [About](#about)
Expand Down Expand Up @@ -61,7 +63,7 @@ What Will I Learn?
- [ ] Add configuration to change background. `Partially complete`.
- [x] Make battery saving optimizations.
- [x] Test for rubric specifications.
- [ ] Implement listener of phone and make wearable request data.
- [x] Implement listener on phone and make wearable request data on startup.
- [ ] Add simple animations.

### LICENSE
Expand Down
14 changes: 11 additions & 3 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@
<!-- Permissions required to access location -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

<!-- Wear app permission -->
<uses-permission android:name="PROVICE"/>

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
Expand Down Expand Up @@ -184,6 +181,17 @@

<!-- Wearable Google Wearable Api Data Service -->
<service android:name=".wearable.WearableDataService"/>

<!-- Data layer listener service -->
<service android:name=".wearable.DataLayerListenerService">
<intent-filter>
<action android:name="com.google.android.gms.wearable.MESSAGE_RECEIVED"/>
<data
android:host="*"
android:path="@string/wearable_data_update_request_path"
android:scheme="wear"/>
</intent-filter>
</service>
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2016 Gurupad Mamadapur
*
* 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 io.github.protino.wearable;

import android.content.Intent;
import android.util.Log;

import com.google.android.gms.wearable.MessageEvent;
import com.google.android.gms.wearable.WearableListenerService;

import static io.github.protino.fragment.ForecastFragment.LOG_TAG;

/**
* Listen to data update requests from nodes and start
* {@link io.github.protino.wearable.WearableDataService}
*/
public class DataLayerListenerService extends WearableListenerService {
@Override
public void onMessageReceived(MessageEvent messageEvent) {
super.onMessageReceived(messageEvent);
Log.d(LOG_TAG, "onMessageReceived: ");
startService(new Intent(this, WearableDataService.class));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ private DataMap fetchData() throws Exception {
String formattedMaxTemp = Utility.formatTemperature(context, maxTemp);
String formattedMinTemp = Utility.formatTemperature(context, minTemp);

dataMap.putInt("timestamp", (int) (System.currentTimeMillis() / 1e3));
dataMap.putInt("weather_id", weatherId);
dataMap.putString("max_temp", formattedMaxTemp);
dataMap.putString("min_temp", formattedMinTemp);
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -193,4 +193,6 @@
<!--Related to attributions-->
<string name="attribution_text">Powered by Google</string>

<string name="wearable_data_update_request_path">/request_for_weather_data</string>

</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ public void onDataChanged(DataEventBuffer dataEventBuffer) {
if (event.getType() == DataEvent.TYPE_DELETED) {
Log.d(LOG_TAG, "DataItem deleted: " + event.getDataItem());
} else if (event.getType() == DataEvent.TYPE_CHANGED) {
Log.d(LOG_TAG, "onDataChanged: ");
DataItem dataItem = event.getDataItem();
DataMap dataMap = DataMapItem.fromDataItem(dataItem).getDataMap();

SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putInt(weatherIdPrefKey, dataMap.getInt(weatherIdPrefKey));
editor.putString(maxTempPrefKey, dataMap.getString(maxTempPrefKey));
Expand Down
93 changes: 91 additions & 2 deletions wear/src/main/java/io/github/protino/SunshineWatchFaceService.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,20 @@
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.wearable.watchface.CanvasWatchFaceService;
import android.support.wearable.watchface.WatchFaceStyle;
import android.util.Log;
import android.view.SurfaceHolder;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.wearable.MessageApi;
import com.google.android.gms.wearable.Node;
import com.google.android.gms.wearable.NodeApi;
import com.google.android.gms.wearable.Wearable;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
Expand All @@ -64,9 +74,11 @@ public Engine onCreateEngine() {
}

private class Engine extends CanvasWatchFaceService.Engine
implements SharedPreferences.OnSharedPreferenceChangeListener {
implements SharedPreferences.OnSharedPreferenceChangeListener, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
private static final int MSG_UPDATE_TIME = 0;
private static final String colon = " : ";
private static final String REQUEST_PATH = "/request_for_weather_data";
private final String LOG_TAG = Engine.class.getSimpleName();
/* Handler to update the time periodically in interactive mode.*/
@SuppressLint("HandlerLeak")
private final Handler updateTimeHandler = new Handler() {
Expand Down Expand Up @@ -148,11 +160,21 @@ public void onReceive(Context context, Intent intent) {
private boolean lowBitAmbient;
private boolean registeredReceiver;

/* Google Api Client */
private GoogleApiClient googleApiClient;
private boolean shouldSendMessageToDevice = true;

//Lifecycle start
@Override
public void onCreate(SurfaceHolder holder) {
super.onCreate(holder);

googleApiClient = new GoogleApiClient.Builder(context)
.addApi(Wearable.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();

sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
sharedPreferences.registerOnSharedPreferenceChangeListener(this);
weatherIdPrefKey = getString(R.string.WEATHER_ID_PREF_KEY);
Expand Down Expand Up @@ -201,7 +223,16 @@ public void onCreate(SurfaceHolder holder) {
lowTempTextPaint = createTextPaint(lowTempTextColor, NORMAL_TYPEFACE);
lowTempTextPaint.setTextSize(lowTempTextSize);

//If weatherIconId is -1 request update
weatherIconId = sharedPreferences.getInt(weatherIdPrefKey, -1);
if (weatherIconId == -1) {
shouldSendMessageToDevice = true;
Log.d(LOG_TAG, "onCreate: ");
googleApiClient.connect();
} else {
shouldSendMessageToDevice = false;
googleApiClient.disconnect();
}
weatherIconBitmap = getWeatherIconBitmapFromId(resources, weatherIconId);
highTempText = sharedPreferences.getString(maxTempPrefKey, "");
lowTempText = sharedPreferences.getString(minTempPrefKey, "");
Expand Down Expand Up @@ -378,8 +409,14 @@ public void onVisibilityChanged(boolean visible) {
/* the watch face became visible or invisible */
if (visible) {
registerReceiver();
if (googleApiClient != null && shouldSendMessageToDevice && !googleApiClient.isConnected()) {
googleApiClient.connect();
}
} else {
unregisterReceiver();
if (googleApiClient != null && googleApiClient.isConnected()) {
googleApiClient.disconnect();
}
}
updateTimer();
}
Expand Down Expand Up @@ -466,9 +503,61 @@ private void switchPaintColor(Paint paint, int ambientColor, int interactiveColo
paint.setColor(inAmbientMode ? ambientColor : interactiveColor);
}


private String formatTwoDigitNumber(int time) {
return String.format(twoDigitFormat, time);
}

/*
* Google API client listeners
*/
@Override
public void onConnected(@Nullable Bundle bundle) {
Log.d(LOG_TAG, "onConnected: ");
if (shouldSendMessageToDevice) {
requestDataFromDevice(REQUEST_PATH, "");
}
}

@Override
public void onConnectionSuspended(int i) {
}

@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
}

private void requestDataFromDevice(String requestPath, String message) {
Log.d(LOG_TAG, "requestDataFromDevice: ");
new SendToDataLayerThread(requestPath, message).start();
}

private class SendToDataLayerThread extends Thread {
private final String LOG_TAG = SendToDataLayerThread.class.getSimpleName();
private final String path;
private final String message;

public SendToDataLayerThread(String requestPath, String message) {
path = requestPath;
this.message = message;
}

@Override
public void run() {
// TODO: 01-Mar-17 Make sure if this is the right way
NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
Log.d(LOG_TAG, "run: " + nodes.getNodes());
for (Node node : nodes.getNodes()) {
MessageApi.SendMessageResult result = Wearable.MessageApi.sendMessage(
googleApiClient, node.getId(), path, message.getBytes()).await();
if (result.getStatus().isSuccess()) {
Log.d(LOG_TAG, "run: message successfully sent to " + node.getDisplayName());
} else {
Log.e(LOG_TAG, "run: error sending message to node " + node.getDisplayName());
}
}
shouldSendMessageToDevice = false;
googleApiClient.disconnect();
}
}
}
}

0 comments on commit 2aad9c6

Please sign in to comment.