Chapter 7
Android Wear API

7.1 Google Services and Google Play Services

Google Services include a wide range of Google-powered features and functionalities such as Maps, Location, Drive, Wallet, Games, Google+, Google Cloud Messaging, Android Wear, Google Fit, authentication, and more. Information on Google Services is available at http://developer.android.com/google/index.html.

Both the Android Wear API and the Google Fit API happen to be a part of the Google Play Services and even though Google Play Services provides a wide range of APIs not limited to Android Wear or Google Fit, we will begin this chapter by covering Google Play Services.

Google Play Services helps Apps avail of the latest Google-powered features. Google Play Services also provides system level features such as a dynamic security provider, which provides an OpenSSL implementation that can be updated dynamically, thus helping Apps benefit from timely security patches independently from the OS updates. Google Play Services are available on most Android devices, but is not part of the Android OS.

There is a Google Play Services App available on the Google Play Store at:

https://play.google.com/store/app/details?id=com.google.android.gsm

Once installed on the user’s device, the Google Play Services App runs various services on the Android device some of which work closely with corresponding Google services on the cloud. You will notice that the Google Play Services App has a package name of com.google.android.gsm. “GSM” is generally considered to be an acronym for Google Services for Mobile.

Apps running on a device can connect as clients to these services running on the device and communicate via Android’s IPC mechanisms. You may have noticed the Google Play Services App’s services running on your device when accessing Running Apps under your device’s Settings. The Google Play Services App has an update cycle and versioning that is mostly independent of the Android OS update cycle and versioning. At the time of writing, the current version of Google Play Services is at 6.5 per the versioning scheme for the App that is visible to the end users (Figure 7-1A).

c7-fig-0001

Figure 7-1A Google Play Services running on a handheld device.

Your App will need to depend on the Google Play Services library project in order to connect to the Google Play Services App that is running on the device in order to avail of particular features/APIs.

The Google Play Services library project, which is distinct from, and represents the client side of, the Google Play Services App, can be found under your Android SDK installation home at

<ANDROID_HOME>/extras/google/google_play_services/libproject.

This library uses an integer-based version numbering scheme, which at the time of writing is at 6587000. This differs from but is related to the 6.5 version scheme that users can see.

Figure 7-1B shows the library version of Google Play Services library project (6587000), which is the current version at the time of writing.

c7-fig-0002

Figure 7-1B Google Play Services library project version.

The Google Play Services App includes Android Services running on your device. The Google Play Services library helps your App connect to the Google Play Services’ Android Services running on your device. Your App connects to the Google Play Services via the library over AIDL/IPC. The Google Play Services App that is running on your device can act as a proxy for the Google functionality on the cloud.

Figure 7-2 shows the relationship and interaction between your App, the Google Play Service client library, the Google Play Services’ running Android Service components, and the Google Services on the Cloud.

c7-fig-0003

Figure 7-2 Google Play Services and its relationships with Google Play Services library.

7.1.1 GoogleApiClient class

The GoogleApiClient is the entry point that enables your Apps to make a connection to the Google Play Services and thereafter avail of particular features/APIs (such as Location, Maps, Drive, Wallet, Games, Android Wear, Google Fit, and so on). The GoogleApiClient class provides you with the ability to connect to Google Play Services and perform synchronous and asynchronous calls to any of the various particular services.

Figure 7-3A shows an overview and partial listing of the GoogleApiClient, which resides in the package com.google.android.gms.common. The nested GoogleApiClient.Builder class is used to set up the needed API, specify the scope, and register the various connection callback listeners before build()-ing the GoogleApiClient instance.

c7-fig-0004

Figure 7-3A GoogleApiClient class diagram, partial listing.

Other related classes in the same package include the ConnectionResult class, which is not shown in the diagram. The ConnectionResult encapsulates the success or failure of the attempt at connecting to the Google Play Services. The ConnectionResult also provides useful statues and constants such as API_UNAVAILABLE, SIGN_IN_REQUIRED, DEVELOPER_ERROR, and so on, which can be used in the GoogleApiClient.OnConnectionFailedListener implementation, to determine the reason for the failure when attempting to connect to the Google Play Services from your App.

Figure 7-3B shows a sequence diagram for accessing a particular feature/API from Google Play Services—by using the GoogleApiClient.Builder; the Builder pattern pervades the various Android APIs. The call to addApi() adds the particular feature, while the call to build() returns an instance of GoogleApiClient. Invoking connect() on the GoogleApiClient instance connects it to the Google Play Services. After the client is successfully connected, the particular feature-specific APIs that were added earlier will become available to the App (and the scopes specified earlier will be applicable).

c7-fig-0005

Figure 7-3B Sequence diagram GoogleApiClient, accessing particular feature/API.

In case an App needs multiple features from Google Play Services, it is possible—in general—to add multiple APIs and multiple scopes to the same GoogleApiClient by making multiple calls to addApi() and addScope() before calling connect(). However, particularly for accessing the Wear API using the GoogleApiClient, it is recommended to use a separate instance of the GoogleApiClient exclusively for accessing the Wear API via the Wearable class (covered in the next section). The GoogleApiClient’s attempt to connect will fail if the Android Wear App is not installed on the device. Appending multiple APIs that include the Wear API and other APIs into one GoogleApiClient instance can render the other APIs to become inaccessible, although they are available.

Detailed documentation on Google Play Services is available at

https://developer.android.com/google/play-services/index.html and

http://developer.android.com/reference/com/google/android/gms/common/package-summary.html.

In the year 2014, five versions of Google Play Services (in the series 4.x, 5.x, and 6.x) were released, along with the introduction of new constructs and updated best practices as well as deprecation of some classes and interfaces. These changes are generally accompanied by useful documentation and sample code. If you are using Google Play Services in your App, it is important to keep your App abreast with the latest version of the library and the associated best practices.

7.2 Android Wear Network

At the center of the Android Wear platform and API lies the concept of the Android Wear Network, which is a network of devices or “nodes.” The devices on the Android Wear Network include Wear devices and other devices (such as handheld devices) that the Wear devices connect to and interact with.

In a world of a multitude of devices, there is a dynamic landscape of devices on this Wear Network that appears and disappears over time, as devices join and drop off this network. While servers and computers on a stable wired network are set in a relatively static landscape, wearable devices (which categorize as a body area network) tend to join and drop off the wear network more dynamically due to factors such as their fluctuating proximity to other devices and networks, loss of battery power, and so on. If you happen to walk away from your desk on which your Android handheld device is placed, while wearing your smart watch tethered to it, the connectivity between your handheld device and your wear device is liable to undergo a disruption after some point. In such a backdrop, a given node may have the need to detect other nodes, send messages to them, or sync some data across them—in a secure manner that respects the boundaries and separateness of individual Apps and their data.

7.3 Android Wear API, in depth

The Wear API contains at a high level a Node API, Data API, and Message API. The package documentation is available at

https://developer.android.com/reference/com/google/android/gms/wearable/package-summary.html.

7.3.1 Wear API: wearable package

The Android Wear API’s main package, wearable (com.google.android.gms.wearable), contains about seven interfaces and 10 classes.

Figure 7-4A shows an overview of the interfaces and classes within the wearable package, which includes the Wearable class and key interfaces NodeApi, DataApi, and MessageApi. The NodeApi supports Apps in becoming aware when nodes join and leave the Wear Network. The DataApi helps read, write, and sync App data between nodes. The MessageApi helps Apps send transient messages between nodes.

c7-fig-0006

Figure 7-4A Wear API, overview of main wearable package, partial listing.

7.3.1.1 Node interface

The Node encapsulates basic information about a device or host on the Android Wear Network.

Figure 7-4B shows the Node interface diagram. Conceptually, the Node has two attributes—the display or human readable name (often generated from the Bluetooth device name) and an identifier string.

c7-fig-0007

Figure 7-4B Node interface, complete listing.

7.3.1.2 WearableListenerService

Another key class is the WearableListenerService that supports Apps in receiving node connectivity events and other events via the DataApi and MessageApi, which are covered in detail in the next sections.

Figure 7-4C shows the class diagram for the WearableListenerService, which extends android.app.Service. Applications that are interested in receiving node events or data/message events via the DataApi and MessageApi while in the background will need to extend this class. There can be only one WearableListenerService class in your application. Both your Wear App and the companion handheld Apps will typically implement their own WearableListenerService if each is interested in keeping updated of changes in the Android Wear Network. As it turns out, the handheld device that’s paired and tethered to the Wear device is also a node in the Android Wear Network.

c7-fig-0008

Figure 7-4C WearableListenerService, partial listing.

7.3.1.3 DataEvent

The DataEvent is an interface for receiving data changes via the data change listener in the DataApi or the WearableListenerService.

Figure 7-4D shows the DataEvent (as well as the MessageEvent, which is covered in the next section). The getDataItem() method provides access to the data item, while the getType() method specifies whether the data was changed(TYPE_CHANGED) or deleted(TYPE_DELETED).

c7-fig-0009

Figure 7-4D DataEvent and MessageEvent.

7.3.1.4 MessageEvent

The MessageEvent is an interface for receiving messages via onMessageReceived() in the MessageApi or the WearableListenerService. Figure 7-4D shows the MessageEvent (along with the DataEvent covered in the previous section). The MessageEvent’s getData() method returns the payload of the message.

7.3.2 Wearable class

The Wearable class is the main entry point into the Wear API and contains key static attributes: API, NodeApi, DataApi, and MessageApi. It also contains a nested class WearableOptions.

Figure 7-5A shows the Wearable class and its attributes and nested class WearableOptions. The static attribute API is used in invoking the addApi() method while building the GoogleApiClient instance.

c7-fig-0010

Figure 7-5A Wearable class diagram.

The inner class Wearable.WearableOptions represents the API configuration parameters for the Wear API.

Figure 7-5B shows the Wearable.WearableOptions inner class, which implements the Api. piOptions.ApiOptions interface from the com.google.android.gms.common.api package.

c7-fig-0011

Figure 7-5B Wearable.WearableOptions inner class.

7.3.3 NodeApi

The NodeApi interface supports detecting and learning about nodes as they connect and join the Wear network or disconnect and drop off. The NodeApi can be said to be tuned into the Node connection and disconnection events on the Wear network. When the NodeApi detects these Node connection and disconnection events, it delivers them to the Wear Apps, which have registered interest in these events.

Figure 7-6 shows the class diagram of the NodeApi class and it has the nested interface NodeApi.NodeListener (which helps your App detect that a peer on the Wear Network has connected or disconnected), NodeApi.GetConnectedNodesResult (which helps your App obtain a list of connected nodes on the Wear Network), and NodeApi.GetLocalNodeResult (which helps your App in accessing the node object which represents “this” device, the local device that your App is running on).

c7-fig-0012

Figure 7-6 NodeApi class diagram.

7.3.4 DataApi

The DataApi interface and its associated family of interfaces and classes provide Apps with the ability to read, write, and synchronize data across the devices on an Android Wear network while maintaining the privacy of the data within the App. Fundamentally, the DataApi provides the put and get functionality in order to read and write data to the Wear Network. The DataApi works closely with the DataItem, which encapsulates the data.

Figure 7-7 shows a partial listing of the DataApi interface and its inner interfaces DataApi.DataListener (which can be used to register a listener using the addListener() method), DataApi.DataItemResult (which can be used to read a single DataItem when using the getDataItem() family of calls), DataApi.DeleteDataItemsResult (which is used to verify that number of items deleted upon making the call to deleteDataItems()), and the DataApi.GetFdForAssetResult (which can be used to obtain the file descriptor of an Asset—a binary blob data covered in Section 7.6.1 of this chapter—when making the getFdForAsset() family of calls).

c7-fig-0013

Figure 7-7 DataApi and its related interfaces, classes (partial listing).

Fundamentally, the DataApi provides the ability to add, retrieve, and delete DataItems on the Android Wear Network. It also provides the ability in the nested DataListener to listen for changes in the data. The WearableListenerService, which implements the DataApi and was covered earlier in this chapter, is useful for listening for data changes in the background. Calling the getDataItems() on booting can help keep up to date with changes while the device was offline.

7.4 DataItem, DataMapItem, and DataMap

DataItem, DataItemMap, and DataMap are closely related, and furthermore, they are all related to the PutDataRequest and PutDataMapRequest, which are covered in the very next section.

7.4.1 DataItem

A DataItem is an interface that represents the data that needs to be read and written via the DataApi to the Android Wear network. DataItems are inherently synchronized across all the nodes in the user’s Android Wear Network. DataItems can be set on a local node even while that node is not connected to the Wear network. Whenever such a local node gets connected to the Wear network, the local DataItems that are pending synchronization will get synchronized.

Each DataItem contains a payload, which is a byte array. The payload is intended to be small in size—up to about 100 KB—but in practice you must strive to keep your DataItem’s payload much smaller than this limit. As with all remote procedure calls and interprocess communication, it is best to lean toward the side of being more conservative. Chapter 3 on Android IPC and AIDL has covered some of these constraints on the size of the payloads when performing IPC in general. Assets—covered in a subsequent section—are appropriate for encapsulating larger binary, blob data such as images. Each DataItem is identified by a path or URI on the Wear network in the format wear://<node_id>/<path>, where node_id represents the node that created the data, while the path portion of the URI is defined by the application.

A given DataItem remains private to the App that created it. Although the DataItem is a fundamental block for the persistence and synchronization of data on the Wear network, it does not have a constructor or Builder—the classes that are used when creating and using DataItems in the DataApi operations include the PutDataRequest, DataMapItem, and DataMap; these have been covered in the following sections.

Figure 7-8 shows the DataItem interfaces along with the DataItemMap and DataMap classes.

c7-fig-0014

Figure 7-8 DataItem, DataItemMap, and DataMap.

The DataItem interface extends the Freezable interface from the com.google.android.gms.common.data package. The Freezable interface pertains to transforming volatile data into an immutable representation via its freeze() method. When the application code receives data change events in the listener such as onDataChanged(), it receives a DataEventBuffer of data events. When items in this buffer are used outside of the call scope, freeze() should be invoked on such items.

DataItems are not intended for concurrent modifications and attempting so can result in inconsistent results. Therefore, it becomes the responsibility of the App to implement its concurrent modification strategy. In one approach, only the creator node that originally created the DataItem may modify the data. There are several other approaches, and it is left to the App to use a concurrent update strategy for its DataItems.

7.4.2 DataMapItem

The DataMapItem wraps a DataItem like object and is a structured and serializable representation of a DataItem. The original DataItem is not expected to be modified after the DataMapItem has been created based on it. Figure 7-8 in the previous section includes the class diagram of the DataMapItem.

The DataMapItem is closely associated with the PutDataMapRequest and the DataMap classes, both of which are covered in the following sections.

7.4.3 DataMap

The DataMap provides a key value pair-based support for storing basic data types such as int, long, float, double, byte, as well as arrays and Bundles. Figure 7-8 shows some of the methods available in the DataMap class. While the DataItem works with raw bytes of payload data and requires serialization and deserialization to be handled in the application code, the DataMap provides off-the-shelf support for storing fundamental data types as well as Bundles. The DataMap works along with the PutDataMapRequest class, covered in the following section.

7.5 PutDataRequest and PutDataMapRequest

Both the PutDataRequest and PutDataMapRequest are used for creating new DataItems and adding them to the Android Wear Network by calling the Data API.

7.5.1 PutDataRequest

The PutDataRequest class implements the Parcelable interface and is used to create and encapsulate new DataItems on the Android Wear Network. It has a static create() method which supports creating an instance of PutDataRequest with an associated, encapsulated DataItem instance. The setData() method sets the payload on the encapsulated DataItem instance. The putAsset() method adds an Asset to the associated DataItem. Once the PutDataRequest instance has been populated, it can be added to the Android Wear Network by calling the DataApi’s putDataItem() method.

Figure 7-9 shows class diagram of the PutDataRequest class that shows several of its available methods. The PutDataRequest is the key class that works with the DataApi in order to make the request to put/add DataItems to the Android Wear Network.

c7-fig-0015

Figure 7-9 PutDataRequest class.

7.5.2 PutDataMapRequest

The PutDataMapRequest is a useful utility closely associated with and secondary to the PutDataRequest. The PutDataMapRequest and DataMap classes make it convenient to sync data to the Android Wear Network by using the serialization and de-serialization that’s available off the shelf. The PutDataMapRequest encapsulates a DataMap.

As shown in Figure 7.10, the PutDataMapRequest provides static methods to create its instance. Once instantiated, the getDataMap() method provides access to the encapsulated DataMap. Once the DataMap instance has been set with data as intended, the asPutDataRequest() method creates a PutDataRequest instance with the encapsulated data. After that, calling the DataApi’s putDataItem() method makes the request to add the data to the Android Wear Network. The DataApi does not have a put method that caters to the PutDataMapRequest directly.

c7-fig-0016

Figure 7.10 PutDataMapRequest class diagram.

There are far fewer methods in PutDataMapRequest as compared to PutDataRequest, because it’s the DataMap operations that address the setting of the data.

7.6 Asset and DataItemAsset

Both the Asset and DataItemAsset are similar in that they represent the binary, blob kind of data.

7.6.1 Asset class

The Asset class represents data that may not yet have been added to the Android Wear Network (Figure 7-11A).

c7-fig-0017

Figure 7-11A Asset class diagram.

The Asset class implements the Parcelable interface. The Asset instance can be created via its static create family of methods. A bitmap can be converted into a byte stream, which can be used to create an Asset instance using the static createFromBytes() method. The PutDataRequest covered in the earlier section has a method putAsset(), which can be used to populate the asset into the request. The DataApi has a putDataItem() method, which can be used to make the request to add data to the Android Wear Network. Alternatively, the Asset instance can be added to a DataMap instance via its putAsset() method, and the PutDataMapRequest can be used to create the PutDataRequest eventually.

The getDigest() method returns a digest—a one way hash of the content—which can be used to identify the Asset across devices on the Android Wear Network.

Assets can be received/extracted from data change events in the listener callbacks.

7.6.2 DataItemAsset interface

The DataItemAsset is a reference to an Asset after it has been added to the Android Wear Network as part of a PutDataRequest (Figure 7-11B).

c7-fig-0018

Figure 7-11B DataItemAsset interface diagram.

The getId() method returns a unique identifier for the Asset in the Android Wear Network. The getDataItemKey() returns an identifier for the asset in the context of an existing DataItem.

7.7 MessageApi

The MessageApi supports sending and receiving short, transient messages privately between instances of the same App that reside on different nodes in the Android Wear Network. A given message is private to the App that created it and only receivable on other instances of the App running on other nodes.

Messages are sent on a fire-and-forget basis—messages are delivered only to nodes that are currently connected to the Android Wear Network. As nodes join and leave the Android Wear Network, they will miss the messages that were sent during the time they had dropped off from the Android Wear Network. Therefore, a message pertaining to starting an Intent on the Wear device from the handheld, or a message pertaining to pausing the handheld device’s media player, are examples where messages can be useful.

The MessageApi is suitable only for transient, short messages. On the other hand, the DataApi covered in the earlier section is appropriate for persistence and synchronization of long-lived data.

Figure 7-12 show the MessageApi interface and its nested interfaces MessageApi.SendMessageResult and MessageApi.MessageListener.

c7-fig-0019

Figure 7-12 MessageApi interface diagram.

The sendMessage() method returns a PendingResult via which the asynchronous call back onResult() tells you the outcome of the call. The call to getRequestId() on the MessageApi.SendMessageResult provides a value that is equal to UNKNOWN_REQUEST_ID in case of failure or the ID of the successfully sent message.

The onMessageReceived() callback on the MessageApi.MessageListener is used for listening for MessageEvents, which contain the message payload.

The WearableListenerService, which was covered in Section 7.3.1.2, implements the MessageApi as well as the DataApi. The WearableListenerService is suitable for listening for events when in the background.

7.8 Wearable UI Library

Android Wear represents a unique form factor, and therefore, Wear Apps are significantly different from those for the handheld Android devices, both in terms of overall application design and in terms of user interface (UI).

The Wearable UI library (Figure 7-13A) is a support package that provides UI and supporting component exclusively for Android Wear Apps. It includes classes such as WearableListView, WatchViewStub, CircledImageView, CardFragment, and so on.

c7-fig-0020

Figure 7-13A Wearable UI library package overview.

In order to use the Wearable UI library, you will need to ensure that the ExtrasGoogle Repository Package has been installed via the Android SDK Manager and is up to date. Additionally, your project’s build.gradle file will need to declare compile “com.google.android.support:wearable:+” in the dependencies section.

Detailed documentation on the Wearable UI can be found at:

https://developer.android.com/shareables/training/wearable-support-docs.zip

https://developer.android.com/training/wearables/ui/layouts.html

Figure 7-13B shows the WearableListView, the CircledImageView, and several other classes in the view sub-package.

c7-fig-0021

Figure 7-13B Wearable UI library view package classes.

Figure 7-13C shows the WearableCalendarContract, WatchFaceCompanion, and ConfirmationActivity classes in the provider, companion, and activity sub-packages, respectively.

c7-fig-0022

Figure 7-13C Wearable UI library provider, companion, and activity sub-packages.

Figure 7-13D shows the WatchFaceService and the WatchFaceStyle in the watchface sub-package, respectively.

c7-fig-0023

Figure 7-13D Wearable UI library watchface package classes.

7.9 Wear Interaction Design

Android Wear Apps are meant to be aware of the user’s current context, physical location, activity, time of the day, and so on and provide relevant and timely information to the user. Android Wear is meant to act like a user’s personal assistant. Thus, Wear Apps are meant to launch automatically and insert relevant cards into the context stream, provide simple, “glanceable” information, and require minimal interaction. The Wear design principles focus on not stopping the user and minimize vibration and interruption.

The recommended creative vision and design principles for Android Wear Apps are covered elegantly at

7.10 Accessing Sensors

Some Android Wear devices have built in GPS sensors, thereby providing the Wear device with independent location detection capabilities. Location awareness from within the Wear App can be useful in various contexts including but not limited to fitness. Wear Apps have direct access to the hardware sensors as well as user physical activities and the services that run on Wear device. As with any Android device, the PackageManager class provides the ability to query whether particular features and sensors are available on the device using the hasSystemFeature() method call.

In case the Wear device does not have a built in GPS and happens not to have an intact tethered connection to a handheld device (with location enabled), when it makes a call to access the location, it will encounter an exception and will need to hand that gracefully.

Since Wear devices are paired and tethered to handheld Android devices, they can depend on the handheld devices for various nuggets of information as needed. As long as the tethered connection is intact, a call to access the location on the Wear device from within the Wear App results in the Android OS determining and providing such information in the most optimal and power-efficient manner.

7.11 Production Wear Apps

With regard to the release and distribution of your Wear App, Wear devices do not offer the Google Play Store to the user. Therefore, users cannot browse, list, and install Wear Apps via their Wear devices directly from the Play Store.

In order to release an Android Wear apk to the Google Play Store, it will need to be packaged and embedded within the companion handheld App, which will need to be published to the Google Play Store. The res/raw directory of the handheld App project will need to contain the Wear App’s Apk. Android Studio takes care of this for you when you create an App and target it to the handheld and Android Wear platforms simultaneously.

Wear Apps need to be released to the public via their “companion” handheld Apps published via the Google Play Store. Therefore, it is necessary to build and distribute a “companion” handheld App—with the Wear apk embedded within it. The embedded Wear App will be installed to the paired and tethered Wear device via the companion handheld App. This handheld App can also be useful for supporting the Wear App for accessing the network and providing it other services and functionality such as GPS and location info.

References and Further Reading

  1. https://developer.android.com/google/auth/api-client.html
  2. https://developer.android.com/google/play-services/setup.html
  3. https://developer.android.com/reference/com/google/android/gms/wearable/package-summary.html
  4. https://developer.android.com/training/building-wearables.html
  5. https://developer.android.com/training/wearables/ui/layouts.html
  6. https://developer.android.com/shareables/training/wearable-support-docs.zip
  7. https://developer.android.com/design/wear/creative-vision.html
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.218.129.100