Project Rome developers have had a month to play with Project Rome for Android SDK (Android SDK), and we hope you are as excited about its capabilities as we are! In this month’s release, we are thrilled to bring you support for app services. Before, we offered the ability to launch a URI from an Android device onto a Windows device. However, the SDK was limited to sending a URI. With the introduction of app services, now you can easily message between Android and Windows devices.
What are App Services?
In short, app services allow your app to provide services that can be interacted with from other applications. This enables an Android application to invoke an app service on a Windows application to perform tasks behind the scenes. This blog post is focused on how to use app services between Android to Windows devices. For a deeper look at app services on Windows, go here.
Messaging Between Connected Devices
Let’s circle back to the example in the original blog post. Paul is an app developer that has integrated the Android SDK into his app. He had created his Contoso Music App, giving users the ability to launch the app across devices, without skipping a beat. That experience was enabled using the RemoteLaunch APIs. It has been a great feature for his app. Paul has an Android phone and listens to music while he goes out for a run. When he gets home, he can easily launch the app on his Xbox—with surround sound speakers—to continue playing with a higher quality sound.
As Paul moves about the home he often finds it frustrating that he has to go back to the Xbox to control the music. On a typical day he loads a playlist but finds himself jumping around from song to song, depending on his mood. This is where app services comes in.
Now, Paul can add the ability to control the music app running on his Xbox from his Android phone. This works very well for Paul because he’s always carrying his phone with him, so it’s much more convenient than having to go to the Xbox every time he wants to change the song. Once the Android app establishes an AppServiceClientConnection, messaging can flow between devices.
Here’s a look at the Android SDK app services in code.
First, you must discover devices, using RemoteSystemDiscovery for the connectionRequest:
[code lang=”csharp”]
// Create a RemoteSystemDiscovery object with a Builder
RemoteSystemDiscovery.Builder discoveryBuilder;
// Implement the IRemoteSystemDiscoveryListener to be used for the callback
discoveryBuilder = new RemoteSystemDiscovery.Builder().setListener(new IRemoteSystemDiscoveryListener() {
@Override
public void onRemoteSystemAdded(RemoteSystem remoteSystem) {
Log.d(TAG, "RemoveSystemAdded = " + remoteSystem.getDisplayName());
devices.add(new Device(remoteSystem));
}
});
// Start discovering devices
startDiscovery();
[/code]
Second, establish an AppServiceClientConnection. The IAppServiceClientConnectionListener handles the status of the connection, while the IAppServiceResponseListener handles the response to the message.
AppServiceClientConnection
[code lang=”csharp”]
// Create an AppServiceClientConnection
private void connectAppService(Device device) {
_appServiceClientConnection = new AppServiceClientConnection(APP_SERVICE,
APP_IDENTIFIER,
new RemoteSystemConnectionRequest(device.getSystem()),
new AppServiceClientConnectionListener(),
new AppServiceResponseListener());
[/code]
AppServiceClientConnection callback
[code lang=”csharp”]
// Implement the IAppServiceClientConnectionListener used to callback
// the AppServiceClientConnection
private class AppServiceClientConnectionListener implements IAppServiceClientConnectionListener {
// Handle the cases for success, error, and closed connections
@Override
public void onSuccess() {
Log.i(TAG, "AppService connection opened successful");
}
@Override
public void onError(AppServiceClientConnectionStatus status) {
Log.e(TAG, "AppService connection error status = " + status.toString());
}
@Override
public void onClosed() {
Log.i(TAG, "AppService connection closed");
}
}
[/code]
AppServiceClientResponse callback
[code lang=”csharp”]
// Implement the IAppServiceResponseListener used to callback
// the AppServiceClientResponse
private class AppServiceResponseListener implements IAppServiceResponseListener() {
@Override
public void responseReceived(AppServiceClientResponse response) {
AppServiceResponseStatus status = response.getStatus();
if (status == AppServiceResponseStatus.SUCCESS)
{
Bundle bundle = response.getMessage();
Log.i(TAG, "Received successful AppService response");
String dateStr = bundle.getString("CreationDate");
DateFormat df = new SimpleDateFormat(DATE_FORMAT);
try {
Date startDate = df.parse(dateStr);
Date nowDate = new Date();
long diff = nowDate.getTime() – startDate.getTime();
runOnUiThread(new SetPingText(Long.toString(diff)));
} catch (ParseException e) {
e.printStackTrace();
}
}
else
{
Log.e(TAG, "Did not receive successful AppService response);
}
}
}
[/code]
Xamarin
That’s not all: we have updated the Xamarin for Android sample with app services, too.
From the sample, these two functions are used in the RemoteSystemActivity class to connect, and then ping, via app services.
AppServiceClientConnection
[code lang=”csharp”]
private async void ConnectAppService(string appService, string appIdentifier, RemoteSystemConnectionRequest connectionRequest)
{
// Create AppServiceClientConnection
this.appServiceClientConnection = new AppServiceClientConnection(appService, appIdentifier, connectionRequest);
this.id = connectionRequest.RemoteSystem.Id;
try
{
// OpenRemoteAsync returns a Task<AppServiceClientConnectionStatus>
var status = await this.appServiceClientConnection.OpenRemoteAsync();
Console.WriteLine("App Service connection returned with status " + status.ToString());
}
catch (ConnectedDevicesException e)
{
Console.WriteLine("Failed during attempt to create AppServices connection");
e.PrintStackTrace();
}
}
[/code]
SendMessageAsync
[code lang=”csharp”]
private async void SendPingMessage()
{
// Create the message to send
Bundle message = new Bundle();
message.PutString("Type", "ping");
message.PutString("CreationDate", DateTime.Now.ToString(CultureInfo.InvariantCulture));
message.PutString("TargetId", this.id);
try
{
var response = await this.appServiceClientConnection.SendMessageAsync(message);
AppServiceResponseStatus status = response.Status;
if (status == AppServiceResponseStatus.Success)
{
// Create the response to the message
Bundle bundle = response.Message;
string type = bundle.GetString("Type");
DateTime creationDate = DateTime.Parse(bundle.GetString("CreationDate"));
string targetId = bundle.GetString("TargetId");
DateTime nowDate = DateTime.Now;
int diff = nowDate.Subtract(creationDate).Milliseconds;
this.RunOnUiThread(() =>
{
SetPingText(this as Activity, diff.ToString());
});
}
}
catch (ConnectedDevicesException e)
{
Console.WriteLine("Failed to send message using AppServices");
e.PrintStackTrace();
}
}
[/code]
All documentation and code for both Java and Xamarin can be found on our GitHub here.
Staying Connected with Project Rome
The power of the Project Rome platform is centered around connecting devices (both Windows and Android). With the introduction of app services functionality into the Android SDK, we continue to provide the tools developers need to create highly compelling experiences.
To learn more about the capabilities of the Android SDK, browse sample code and get additional resources related to the platform, check out the information below:
- Project Rome for Android SDK
- GitHub for Project Rome for Android SDK
- MSDN Communicate with a remote app service
The Windows team would love to hear your feedback. Please keep the feedback coming using our Windows Developer UserVoice site. If you have a direct bug, please use the Windows Feedback tool built directly into Windows 10.