-
-
Save gabrielemariotti/117b05aad4db251f7534 to your computer and use it in GitHub Desktop.
<service android:name=".ListenerServiceFromWear"> | |
<intent-filter> | |
<action android:name="com.google.android.gms.wearable.BIND_LISTENER" /> | |
</intent-filter> | |
</service> |
dependencies { | |
compile fileTree(dir: 'libs', include: ['*.jar']) | |
wearApp project(':wear') | |
compile 'com.google.android.gms:play-services-wearable:+' | |
} |
public class ListenerServiceFromWear extends WearableListenerService { | |
private static final String HELLO_WORLD_WEAR_PATH = "/hello-world-wear"; | |
@Override | |
public void onMessageReceived(MessageEvent messageEvent) { | |
/* | |
* Receive the message from wear | |
*/ | |
if (messageEvent.getPath().equals(HELLO_WORLD_WEAR_PATH)) { | |
Intent startIntent = new Intent(this, MyActivity.class); | |
startIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | |
startActivity(startIntent); | |
} | |
} | |
} |
<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" /> |
dependencies { | |
compile fileTree(dir: 'libs', include: ['*.jar']) | |
compile "com.google.android.support:wearable:1.0.+" | |
compile 'com.google.android.gms:play-services-wearable:+' | |
} |
public class LaunchActivity extends Activity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener { | |
Node mNode; // the connected device to send the message to | |
GoogleApiClient mGoogleApiClient; | |
private static final String HELLO_WORLD_WEAR_PATH = "/hello-world-wear"; | |
private boolean mResolvingError=false; | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_launch); | |
//Connect the GoogleApiClient | |
mGoogleApiClient = new GoogleApiClient.Builder(this) | |
.addApi(Wearable.API) | |
.addConnectionCallbacks(this) | |
.addOnConnectionFailedListener(this) | |
.build(); | |
//UI elements with a simple CircleImageView | |
final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub); | |
stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() { | |
@Override | |
public void onLayoutInflated(WatchViewStub stub) { | |
CircledImageView mCircledImageView = (CircledImageView) stub.findViewById(R.id.circle); | |
//Listener to send the message (it is just an example) | |
mCircledImageView.setOnClickListener(new View.OnClickListener() { | |
@Override | |
public void onClick(View v) { | |
sendMessage(); | |
} | |
}); | |
} | |
}); | |
} | |
/** | |
* Send message to mobile handheld | |
*/ | |
private void sendMessage() { | |
if (mNode != null && mGoogleApiClient!=null && mGoogleApiClient.isConnected()) { | |
Wearable.MessageApi.sendMessage( | |
mGoogleApiClient, mNode.getId(), HELLO_WORLD_WEAR_PATH, null).setResultCallback( | |
new ResultCallback<MessageApi.SendMessageResult>() { | |
@Override | |
public void onResult(MessageApi.SendMessageResult sendMessageResult) { | |
if (!sendMessageResult.getStatus().isSuccess()) { | |
Log.e("TAG", "Failed to send message with status code: " | |
+ sendMessageResult.getStatus().getStatusCode()); | |
} | |
} | |
} | |
); | |
}else{ | |
//Improve your code | |
} | |
} | |
@Override | |
protected void onStart() { | |
super.onStart(); | |
if (!mResolvingError) { | |
mGoogleApiClient.connect(); | |
} | |
} | |
/* | |
* Resolve the node = the connected device to send the message to | |
*/ | |
private void resolveNode() { | |
Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).setResultCallback(new ResultCallback<NodeApi.GetConnectedNodesResult>() { | |
@Override | |
public void onResult(NodeApi.GetConnectedNodesResult nodes) { | |
for (Node node : nodes.getNodes()) { | |
mNode = node; | |
} | |
} | |
}); | |
} | |
@Override | |
public void onConnected(Bundle bundle) { | |
resolveNode(); | |
} | |
@Override | |
public void onConnectionSuspended(int i) { | |
//Improve your code | |
} | |
@Override | |
public void onConnectionFailed(ConnectionResult connectionResult) { | |
//Improve your code | |
} | |
} |
In line 82 of wear-LaunchActivity.java you set your Node member variable to the last node that is inside the list of all connected Nodes. There should be not more than one connected device with the wear, so this seems correct. However, if you test this code it shows that there is also a "Cloud" Node connected. So what you need is to check, if the Node is nearby with node.isNearby()
. Then you can break the loop.
In your sendMessage
method, you don't need to check, if mGoogleApiClient
is null
because you set it in your onCreate
method. Therefore mGoogleApiClient != null
is always true. Furthermore, what I did in my implementation is that I call Wearable.NodeApi.getConnectedNodes
every time when I want to send a message. So only if there are currently connected nodes that are also nearby, a message will be sent.
I am also not using the MessageApi
to send messages between the devices but the ChannelApi
. I do this because in the MessageApi documentation is written:
Note: A successful result code does not guarantee delivery of the message. If your app requires data reliability, use DataItem objects or the ChannelApi class to send data between devices.
I came here to see how I can start activities from the wear device on the handheld device. Your solution makes sense. So thanks for that 👍
Btw, this is my implementation of the ChannelApi
:
/**
* Send a message to a connected and nearby device.
*
* @param message The text to send to the connected device.
* @param path The path to identify the message on the receivers side.
*/
private void sendMessageToDevice(final String message, final String path) {
Log.d(TAG, "sendMessageToDevice");
Wearable.NodeApi.getConnectedNodes(googleApiClient).setResultCallback(new ResultCallback<NodeApi.GetConnectedNodesResult>() {
@Override
public void onResult(final GetConnectedNodesResult getConnectedNodesResult) {
Log.d(TAG, "sendMessageToDevice: onResult");
final List<Node> nodes = getConnectedNodesResult.getNodes();
for (final Node node : nodes) {
if (node.isNearby()) {
Wearable.ChannelApi.openChannel(googleApiClient, node.getId(), path).setResultCallback(new ResultCallback<ChannelApi.OpenChannelResult>() {
@Override
public void onResult(ChannelApi.OpenChannelResult openChannelResult) {
Log.d(TAG, "sendMessageToDevice: onResult: onResult");
final Channel channel = openChannelResult.getChannel();
channel.getOutputStream(googleApiClient).setResultCallback(new ResultCallback<Channel.GetOutputStreamResult>() {
@Override
public void onResult(final Channel.GetOutputStreamResult getOutputStreamResult) {
Log.d(TAG, "sendMessageToDevice: onResult: onResult: onResult");
OutputStream outputStream = null;
try {
outputStream = getOutputStreamResult.getOutputStream();
outputStream.write(message.getBytes());
Log.d(TAG, "sendMessageToDevice: onResult: onResult: onResult: Message sent: " + message);
} catch (final IOException ioexception) {
Log.w(TAG, "sendMessageToDevice: onResult: onResult: onResult: Could not send message from smartwatch to given node.\n" +
"Node ID: " + channel.getNodeId() + "\n" +
"Path: " + channel.getPath() + "\n" +
"Error message: " + ioexception.getMessage() + "\n" +
"Error cause: " + ioexception.getCause());
} finally {
try {
if (outputStream != null) {
outputStream.close();
}
} catch (final IOException ioexception) {
Log.w(TAG, "sendMessageToDevice: onResult: onResult: onResult: Could not close Output Stream from smartwatch to given node.\n" +
"Node ID: " + channel.getNodeId() + "\n" +
"Path: " + channel.getPath() + "\n" +
"Error message: " + ioexception.getMessage() + "\n" +
"Error cause: " + ioexception.getCause());
} finally {
// Will call onChannelClosed
channel.close(googleApiClient);
}
}
}
});
}
});
break;
}
}
}
});
}
Hope it can help anyone :-)
EDIT:
This inspired me to make my own gist to demonstrate the ChannelApi.
I got burned for a week trying to get this to work only to find out the wear app and mobile app in android studio need to have THE SAME EXACT PACKAGE NAME or the messages won't get received. Great gist!
Thank you for this nice example. Works like a charm!
But please keep in mind: The Manifest IntentFilter BIND_LISTENER is now deprecated. You should not use:
<action android:name="com.google.android.gms.wearable.BIND_LISTENER" />
anymore.
More informations here: http://android-developers.blogspot.de/2016/04/deprecation-of-bindlistener.html
The service declaration in the Manifest should look like this now:
<service android:name=".ListenerServiceFromWear">
<intent-filter>
<action android:name="com.google.android.gms.wearable.MESSAGE_RECEIVED" />
<data android:scheme="wear" android:host="*"
android:path="/hello-world-wear" />
</intent-filter>
</service>
This is the only working app currently on google which call handheld activity from wearable. Thanks.
Nevermind my last comment, I got it working 😄