Android Wear OS Application Development

Ayush Agrawal
9 min readJun 16, 2020

--

Most often, developing mobile applications, we build them for only two types of devices — smartphones and tablets. And every time we start a new Android Studio project we come across the proposed templates for other types of devices. Unless necessary, developers wouldn’t use those templates especially if there are no corresponding physical devices at hand. But the situation may change when it is required so by the app development project itself.

The actual task was to build a wearable app within a short period of time and make it as simple as possible. So, the basic issues we had to face first were: Wear OS capabilities, the way the Wear OS app would interact with the phone app and the component interdependencies inside the project. In this article we would like to share some development aspects for Wear OS we had to take into consideration down the road.

Creating a Module for Smartwatches

Development of a wearable app suggests that we add a separate module to the existing project.

To do so, we should proceed as follows:

Step 1. Add a new module to an existing project.

  1. In Android Studio click: File → New Module → Wear OS Module.
  2. Type all the necessary values, click Finish — now we have another module in the project (named Wear).

Step 2. Add dependencies

In the newly created module named ‘Wear’ we should update the dependencies section to include the following:

dependencies { 
implementation ‘com.google.android.support:wearable:2.3.0’ implementation ‘com.android.support:wear:28.0.0’ compileOnly ‘com.google.android.wearable:wearable:2.3.0’
}

This way we’re adding the Wearable Support Library to our watch module.

Step 3. General classes for the phone app and smartwatch app modules

Since we are using one and the same code base between the modules of the phone application and the smartwatch app, we’re adding a common module which is added to the project as a library. To use this module we should declare the following dependencies of the phone and watch app modules:

implementation project(path: ‘:common’)

Step 4. Linking the phone and smartwatch app module

To link the watch module to the existing project we should declare the following dependencies in the build.gradle of the phone app module:

wearApp project(path: ‘:wear’)

Wear API

To create a wearable application we use the same components as for smartphone apps with only several exceptions: your Activity may extend WearableActivity — a special class which allows for setting the behaviour of the display when idle. The setAmbientEnabled() method, which is called for in the extended Activity when it is created, allows for switching to ambient mode instead of blocking the watch display.

Communication Between the Phone and the Smartwatch

Interaction between devices is ensured by the special component — Wearable Listener Service which has a special priority in the system.

To add the component you should:

  1. Extend the class by changing necessary data channel callbacks in order to get them (in our case we’ve used the data channel only, so we have overridden the onDataChanged() callback).
  2. Declare it in the manifest by adding an action that will be processed by this service (DATA_CHANGED), as well as data filters which will be used by the phone application to know what request the smartwatch has sent.

How it actually looks:

<service android:name=”.system.wearable.WearableService”> 
<intent-filter>
<action android:name=”com.google.android.gms.wearable.DATA_CHANGED” />
<data android:host=”*” android:pathPrefix=”/balanceRequest” android:scheme=”wear” />
<data android:host=”*” android:pathPrefix=”/drinkEvent” android:scheme=”wear” />
<data android:host=”*” android:pathPrefix=”/weeklyBalanceRequest” android:scheme=”wear” />
<data android:host=”*” android:pathPrefix=”/addDrinkEventRequest” android:scheme=”wear” />
</intent-filter>
</service>

When the application is unloaded from memory, the WearableListenerService will continue and will accumulate the data coming to the callback which will be delivered to the destination at the next active state of the application.

In order to get the data in the callbacks one should register as a data client and a capability client in the smartwatch module using the following methods:

Wearable.getCapabilityClient(context) .addListener(this, Uri.parse(“wear://”), CapabilityClient.FILTER_REACHABLE),

and implement the callbacks themselves

Capabilities. Pairing Status Check-up.

To check the status of the smartwatch pairing with the smartphone you’ll need to take a couple of steps.

First up, we shall set the strings with random entries in the the wear.xml file of the phone application module for the smartwatch to be able to check if the device with such Capabilities is paired. Wear content.xml looks like this:

<?xml version=”1.0" encoding=”utf-8"?>
<resources>
<string-array name=”android_wear_capabilities” translatable=”false”> <item>water_balance_capability</item>
</string-array>
</resources>

Then in the smartwatch module itself we shall set a string constant with the same entry as in the capability indicated above. With the help of this constant in the callback onCapabilityChanged()of the smartwatch module we will determine if the state we receive relates to the state of our device (connected to our phone app). After verifying that we’ve received the pairing status of the appropriate device, we shall be busy with the following check-up:

capabilityInfo.nodes.isEmpty() && capabilityInfo.nodes.first().isNearby

The result of this check-up will show whether there is an actual connection with the device. It should be noted that we cannot request the pairing status directly, only through the callback, which implies some delay between the actual disconnection of the device and the callback trigger.

Data Exchange Between Devices

To transfer data from your smartphone to your smartwatch and vice versa you should use the bundle com.google.android.gms.wearable.DataMap which is created simultaneously with the com.google.android.gms.wearable.PutDataMapRequest, calling a static method PutDataMapRequest#create, which should have one of the paths declared in the manifest as an input:

val putDataMapRequest = PutDataMapRequest.create(“/weeklyBalanceRequest”)

To add all necessary data to the DataMap bundle you can use a range of methods. For example, to send the current timestamp with a query you should call the following method:

putDataMapRequest.dataMap.putLong(“TIMESTAMP”, System.currentTimeMillis())

Then comes the chain of transformations of our request into a task (com.google.android.gms.tasks.Task) — the end point before processing of our data by the Google services library.

For our request to be processed and could reach the paired device, it is necessary to:

  1. present this request as a the PutDataRequest through the simple call val request:
val request = putDataMapRequest.asPutDataRequest()

2. get DataClient:

val dataClient = Wearable.getDataClient(context)

3. pass our request to DataClient and finally get the Task:

val task: Task<DataItem> = dataClient.putDataItem(request)

4. Task execution is carried out with the await static method of the Tasks class:

val dataItem = Tasks.await(dataItemTask)

The Task execution is blocked until the result is obtained synchronously. This operation must be performed in a separate thread.

Usually the data for the watch is not delivered immediately, in order to optimize the use of resources and save battery life it is time-lagged and the lag as the documents say is 30 minutes. To instantly deliver the data for the watch you must use the setUrgent()method for the PutDataRequest class object which ensures that there is a minimum delay between sending and receiving data.

Receipt of Data

As described above, the data is received through the WearableListenerService#onDataChanged callback which gets the DataEventBuffer object as an input after the execution of each task and which should be parsed using the keys that we have defined in the application manifest. It looks like this:

override fun onDataChanged(dataEvents: DataEventBuffer?) { dataEvents?.let { events -> for (event in events) { 
when (event.dataItem.uri.path) {
“/requestBalance” -> // proceed request “/requestweeklyBalance” -> // proceed request “/drinkEvent” -> {
val dataItem = DataMapItem.fromDataItem(event.dataItem) val value = dataItem.dataMap.getDouble(“drinkEventValue”) val drinkId = dataItem.dataMap.getInt(“drinkEventDrinkId”)
}}

On receipt of the “/drinkEvent” we parse it using the keys of the dictionary.

Wearable App Offline Operation

The devices pair with each other via Bluetooth, so the offline operation of the smartwatch means that there is no pairing between the smartphone and the watch. If the task is sent to be carried out with no pairing, its execution will not take long when connection is there again. Thus, working with the smartwatch in an offline mode, all scheduled tasks will be performed and the data on both devices will be synchronised.

Layouts for Different Smartwatch Screen Form Factors

Developing applications for smartwatches one should borne in mind that they come in different shapes and sizes with circular and square faces. Moreover certain watches might also have an inset called chin which is usually located at the bottom of the display. To determine the resource only for circular face watches, you should add -round or not-round to those directories that you want to override.

We used BoxInsetLayout to create the screen layouts — it allows to place the content in the center of the display of the circular face watch — the content will be sized to fit into the round display (Fig. 1). This effect is achieved by using the app:boxedEdges=”all” attribute (you can also use left, top, right and bottom values to size to only fit into a specific side).

To support a chinned smartwatch, one should add the fitsSystemWindows=true attribute which will raise the markup above the chin so that it would not be overlapped (Fig.2).

Figure 1 — UI screen for the circular and rectangular face watches

Figure 2-UI for the circular face with an inset (chin)

Releasing the Application Through Google Play

Our smartwatch app is for Wear OS 1 version.x and 2.x thus, Wearable API lets us exclude the smartwatch APK from the app APK and release two separate APKs to Google Play. One should remember that APK versions should be unique. Google suggests that we follow the the below approach to app versioning:

  1. The first two digits are reserved for the targetSdkVersion, for example, 28.
  2. The next three digits represent the version of the application that is visible to the user. For example, the application version is “2.4.3”, so the next three digits are 243.
  3. The next-two digits specify the build number, for example, 01.
  4. The last two digits will point to a build variant. For example, the smartphone version will be 00 and the watch version will be 01.

To distribute the app on Google Play, as we know, it is necessary to prepare a signed build of the application. Building the release version of the smartphone APK in our case we should also build the watch APK, which at the end of the process can be found in the directory /build/outputs/apk/<flavor>/release in each of the modules both for the smartphone and the watch. These APKs should be included in one and the same release of any of the channels (production, beta, alpha) as if you were downloading multiple APKs for different device configurations (Multi-APK delivery method).

It is worth noting that you can submit your wearable app for review for Google to qualify it as a Wear OS app. To do this in the developer console, you need to:

  1. Upload the watch APK.
  2. Upload at least one watch screenshot.
  3. Click Stage presence → Pricing & Distribution, find the Device categories section, tick Wear OS by Google and click Submit update.

Conclusion

In this article we have tried to cover all the aspects that might turn important to developers of wearable apps, especially to those who are just starting out with Wear OS. We very much hope that the points outlined here will facilitate your acquaintance with this operating system. Our experience has shown that development for Wear OS is not much different from the development of smartphone applications. However, developing Wear OS apps you should remember about the guidelines, since, for example, the navigation inside smartwatch apps is somewhat different from the usual one in the apps for “larger” devices. Check out the following link to learn more about the guidelines — design guidelines.

--

--