Building your first Android Wear Application

Kyle Mew

February 2016

One of the most exciting new directions that Android has gone in recently, is the extension of the platform from phones and tablets to televisions, car dashboards and wearables such as watches. These new devices allow us to provide added functionality to our existing apps, as well as creating wholly original apps designed specifically for these new environments.

This article is really concerned with explaining the idiosyncrasies of each platform and the guidelines Google is keen for us to follow. This is particularly vital when it comes to developing apps that people will use when driving, as safety has to be of prime importance. There are also certain technical issues that need to be addressed when developing wearable apps, such as the pairing of the device with a handset and the entirely different UI and methods of use.

In this article, you will:

  • Create wearable AVDs
  • Connect a wearable emulator to a handset with adb commands
  • Connect a wearable emulator to a handset emulator
  • Create a project with both mobile and wearable modules
  • Use the Wearable UI Library
  • Create shape-aware layouts
  • Create and customize cards for wearables
  • Understand wearable design principles

(For more resources related to this topic, see here.)

Android Wear

Creating or adapting apps for wearables is probably the most complicated factors and requires a little more setting up than the other projects. However, wearables often give us access to one of the more fun new sensors, the heart rate monitor. In seeing how this works, we also get to see, how to manage sensors in general.

Do not worry if you do not have access to an Android wearable device, as we will be constructing AVDs. You will ideally have an actual Android 5 handset, if you wish to pair it with the AVD. If you do not, it is still possible to work with two emulators but it is a little more complex to set up. Bearing this in mind, we can now prepare our first wearable app.

Constructing and connecting to a wearable AVD

It is perfectly possible to develop and test wearable apps on the emulator alone, but if we want to test all wearable features, we will need to pair it with a phone or a tablet. The next exercise assumes that you have an actual device. If you do not, still complete tasks 1 through 4 and we will cover how the rest can be achieved with an emulator a little later on.

  1. Open Android Studio. You do not need to start a project at this point.

    Start the SDK Manager and ensure you have the relevant packages installed.

  2. Open the AVD Manager.
  3. Create two new Android Wear AVDs, one round and one square, like so:
  4. Ensure USB Debugging is selected on your handset.
  5. Install the Android Wear app from the Play Store at this URL:
    https://play.google.com/store/apps/details?id=com.google.android.wearabl.... Connect it to your computer and start one of the AVDs we just created.
  6. Locate and open the folder containing the adb.exe file. It will probably be something like user\AppData\Local\Android\sdk\platform-tools\.
  7. Using Shift + right-click, select Open command window here.
  8. In the command window, issue the following command:
    • adb -d forward tcp:5601 tcp:5601
  9. Launch the companion app and follow the instructions to pair the two devices.

Being able to connect a real-world device to an AVD is a great way to develop form factors without having to own the devices. The wearable companion app simplifies the process of connecting the two. If you have had the emulator running for any length of time, you will have noticed that many actions, such as notifications, are sent to the wearable automatically. This means that very often our apps will link seamlessly with a wearable device, without us having to include code to pre-empt this.

The adb.exe (Android Debug Bridge) is a vital part of our development toolkit. Most of the time, the Android Studio manages it for us. However, it is useful to know that it is there and a little about how to interact with it. We used it here to manually open a port between our wearable AVD and our handset.

There are many adb commands that can be issued from the command prompt and perhaps the most useful is adb devices, which lists all currently debuggable devices and emulators, and is very handy when things are not working, to see if an emulator needs restarting. Switching the ADB off and on can be achieved using adb kill-server and adb start-server respectively. Using adb help will list all available commands.

The port forwarding command we used in Step 10, needs to be issued every time the phone is disconnected from the computer.

Without writing any code as such, we have already seen some of the features that are built into an Android Wear device and the way that the Wear UI differs from most other Android devices.

Even if you usually develop with the latest Android hardware, it is often still a good idea to use an emulator, especially for testing the latest SDK updates and pre-releases. If you do not have a real device, then the next, small section will show you how to connect your wearable AVD to a handset AVD.

Connecting a wearable AVD with another emulator

Pairing two emulators is very similar to pairing with a real device. The main difference is the way we install the companion app without access to the Play Store. Follow these steps to see how it is done:

  1. Start up, an AVD. This will need to be targeting Google APIs as seen here:
  2. Download the com.google.android.wearable.app-2.apk. There are many places online where it can be found with a simple search, I used www.file-upload.net/download.
  3. Place the file in your sdk/platform-tools directory.
  4. Shift + right-click in this folder and select Open command window here.
  5. Enter the following command:
    adb install com.google.android.wearable.app-2.apk.
  6. Start your wearable AVD.
  7. Enter adb devices into the command prompt, making sure that both emulators are visible with an output similar to this:
    List of devices attached
    
    emulator-5554 device
    
    emulator-5555   device
  8. Enter adb telnet localhost 5554 at the command prompt, where 5554 is the phone emulator.
  9. Next, enter adb redir add tcp:5601:5601.
  10. You can now use the Wear app on the handheld AVD to connect to the watch.

As we've just seen, setting up a Wear project takes a little longer than some of the other exercises we have performed. Once set up though, the process is very similar to that of developing for other form factors, and something we can now get on with.

Creating a wearable project

All of the apps that we have developed so far, have required just a single module, and this makes sense as we have only been building for single devices. In this next step, we will be developing across two devices and so will need two modules. This is very simple to do, as you will see in these next steps.

  1. Start a new project in the Android Studio and call it something like Wearable App.
  2. On the Target Android Devices screen, select both Phone and Tablet and Wear, like so:
  3. You will be asked to add two Activities. Select Blank Activity for the Mobile Activity and Blank Wear Activity for Wear.
  4. Everything else can be left as it is.
  5. Run the app on both round and square virtual devices.

The first thing you will have noticed is the two modules, mobile and wear. The first is the same as we have seen many times, but there are a few subtle differences with the wear module and it is worth taking a little look at. The most important difference is the WatchViewStub class. The way it is used can be seen in the activity_main.xml and MainActivity.java files of the wear module.

This frame layout extension is designed specifically for wearables and detects the shape of the device, so that the appropriate layout is inflated. Utilizing the WatchViewStub is not quite as straightforward, as one might imagine, as the appropriate layout is only inflated after the WatchViewStub has done its thing. This means that, to access any views within the layout, we need to employ a special listener that is called once the layout has been inflated. How this OnLayoutInflatedListener() works can be seen by opening the MainActivity.java file in the wear module and examining the onCreate() method, which will look like this:

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final WatchViewStub stub = (WatchViewStub)
   findViewById(R.id.watch_view_stub);
stub.setOnLayoutInflatedListener(new
   WatchViewStub.OnLayoutInflatedListener() {
   @Override
   public void onLayoutInflated(WatchViewStub stub) {
     mTextView = (TextView) stub.findViewById(R.id.text);
   }
});
}

Other than the way that wearable apps and devices are set up for developing, the other significant difference is the UI. The widgets and layouts that we use for phones and tablets are not suitable, in most cases, for the diminished size of a watch screen. Android provides a whole new set of UI components, that we can use and this is what we will look at next.

Designing a UI for wearables

As well as having to consider the small size of wearable when designing layouts, we also have the issue of shape. Designing for a round screen brings its own challenges, but fortunately the Wearable UI Library makes this very simple. As well as the WatchViewStub, that we encountered in the previous section that inflates the correct layout, there is also a way to design a single layout that inflates in such a way, that it is suitable for both square and round screens.

Designing the layout

The project setup wizard included this library for us automatically in the build.gradle (Module: wear) file as a dependency:

compile 'com.google.android.support:wearable:1.1.0'

The following steps demonstrate how to create a shape-aware layout with a BoxInsetLayout:

  1. Open the project we created in the last section.
  2. You will need three images that must be placed in the drawable folder of the wear module: one called background_image of around 320x320 px and two of around 50x50 px, called right_icon and left_icon.
  3. Open the activity_main.xml file in the wear module.
  4. Replace its content with the following code:
    <android.support.wearable.view.BoxInsetLayout
      xmlns:android=
        "http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:background="@drawable/background_image"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:padding="15dp">
    
    </android.support.wearable.view.BoxInsetLayout>
  5. Inside the BoxInsetLayout, add the following FrameLayout:
    <FrameLayout
      android:id="@+id/wearable_layout"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:padding="5dp"
      app:layout_box="all">
    
    </FrameLayout>
  6. Inside this, add these three views:
    <TextView
      android:gravity="center"
      android:layout_height="wrap_content"
      android:layout_width="match_parent"
      android:text="Weather warning"
      android:textColor="@color/black" />
    
    <ImageView
      android:layout_gravity="bottom|left"
      android:layout_height="60dp"
      android:layout_width="60dp"
      android:src="@drawable/left_icon" />
    
    <ImageView
      android:layout_gravity="bottom|right"
      android:layout_height="60dp"
      android:layout_width="60dp"
      android:src="@drawable/right_icon" />
  7. Open the MainActivity.java file in the wear module.
  8. In the onCreate() method, delete all lines after the line setContentView(R.layout.activity_main);.
  9. Now, run the app on both square and round emulators.

As we can see, the BoxInsetLayout does a fine job of inflating our layout regardless of screen shape. How it works is very simple. The BoxInsetLayout creates a square region, that is as large as can fit inside the circle of a round screen. This is set with the app:layout_box="all" instruction, which can also be used for positioning components, as we will see in a minute.

We have also set the padding of the BoxInsetLayout to 15 dp and that of the FrameLayout to 5 dp. This has the effect of a margin of 5 dp on round screens and 15 dp on square ones.

Whether you use the WatchViewStub and create separate layouts for each screen shape or BoxInsetLayout and just one layout file depends entirely on your preference and the purpose and design of your app. Whichever method you choose, you will no doubt want to add Material Design elements to your wearable app, the most common and versatile of these being the card. In the following section, we will explore the two ways that we can do this, the CardScrollView and the CardFragment.

Adding cards

The CardFragment class provides a default card view, providing two text views and an image. It is beautifully simple to set up, has all the Material Design features such as rounded corners and a shadow, and is suitable for nearly all purposes. It can be customized, as we will see, although the CardScrollView is often a better option. First, let us see, how to implement a default card for wearables:

  1. Open the activity_main.xml file in the wear module of the current project.
  2. Delete or comment out the the text view and two image views.
  3. Open the MainActivity.java file in the wear module.
  4. In the onCreate() method, add the following code:
    FragmentManager fragmentManager = getFragmentManager();
    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
    CardFragment cardFragment = CardFragment.create("Short title", "with a longer description");
    fragmentTransaction.add(R.id.wearable_layout, cardFragment);
    fragmentTransaction.commit();
  5. Run the app on one or other of the wearable emulators to see how the default card looks.

The way we created the CardFragment itself, is also very straightforward. We used two string parameters here, but there is a third, drawable parameter and if the line is changed to CardFragment cardFragment = CardFragment.create("TITLE", "with description and drawable", R.drawable.left_icon); then we will get the following output:

This default implementation for cards on wearable is fine for most purposes and it can be customized by overriding its onCreateContentView() method. However, the CardScrollView is a very handy alternative, and this is what we will look at next.

Customizing cards

The CardScrollView is defined from within our layout and furthermore it detects screen shape and adjusts the margins to suit each shape. To see how this is done, follow these steps:

  1. Open the activity_main.xml file in the wear module.
  2. Delete or comment out every element, except the root BoxInsetLayout.
  3. Place the following CardScrollView inside the BoxInsetLayout:
    <android.support.wearable.view.CardScrollView
      android:id="@+id/card_scroll_view"
      android:layout_height="match_parent"
      android:layout_width="match_parent"
      app:layout_box="bottom">
    
    </android.support.wearable.view.CardScrollView>
  4. Inside this, add this CardFrame:
    <android.support.wearable.view.CardFrame
       android:layout_width="match_parent"
       android:layout_height="wrap_content">
    
    </android.support.wearable.view.CardFrame>
  5. Inside the CardFrame, add a LinearLayout.
  6. Add some views to this, so that the preview resembles the layout here:
  7. Open the MainActivity.java file.
  8. Replace the code we added to the onCreate() method with this:
    CardScrollView cardScrollView = (CardScrollView)
       findViewById(R.id.card_scroll_view);
    cardScrollView.setCardGravity(Gravity.BOTTOM);
  9. You can now test the app on an emulator, which will produce the following result:

As can be seen in the previous image, the Android Studio has preview screens for both wearable shapes. Like some other previews, these are not always what you will see on a device, but they allow us to put layouts together very quickly, by dragging and dropping widgets.

As we can see, the CardScrollView and CardFrame are even easier to implement than the CardFragment and also far more flexible, as we can design almost any layout we can imagine. We assigned app:layout_box here again, only this time using bottom, causing the card to be placed as low on the screen as possible.

It is very important, when designing for such small screens, to keep our layouts as clean and simple as possible. Google's design principles state that wearable apps should be glanceable. This means that, as with a traditional wrist watch, the user should be able to glance at our app and immediately take in the information and return to what they were doing.

Another of Google's design principle—Zero to low interaction—is only a single tap or swipe a user needs to do to interact with our app. With these principles in mind, let us create a small app, with some actual functionality. In the next section, we will take advantage of the new heart rate sensor found in many wearable devices and display current beats-per-minute on the display.

Accessing sensor data

The location of an Android Wear device on the user's wrist, makes it the perfect piece of hardware for fitness apps, and not surprisingly, these apps are immensely popular. As with most features of the SDK, accessing sensors is pleasantly simple, using classes such as managers and listeners and requiring only a few lines of code, as you will see by following these steps:

  1. Open the project we have been working on in this article.
  2. Replace the background image with one that might be suitable for a fitness app. I have used a simple image of a heart.
  3. Open the activity_main.xml file.
  4. Delete everything, except the root BoxInsetLayout.
  5. Place this TextView inside it:
    <TextView
       android:id="@+id/text_view"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:layout_gravity="center_vertical"
       android:gravity="center"
       android:text="BPM"
       android:textColor="@color/black"
       android:textSize="42sp" />
  6. Open the Manifest file in the wear module.
  7. Add the following permission inside the root manifest node:
    <uses-permission
      android:name="android.permission.BODY_SENSORS" />
  8. Open the MainActivity.java file in the wear module.
  9. Add the following fields:
    private TextView textView;
    private SensorManager sensorManager;
    private Sensor sensor;
  10. Implement a SensorEventListener on the Activity:
    public class MainActivity extends Activity implements
      SensorEventListener {
  11. Implement the two methods required by the listener.
  12. Edit the onCreate() method, like this:
    @Override
    protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
    textView = (TextView) findViewById(R.id.text_view);
    sensorManager = ((SensorManager)
       getSystemService(SENSOR_SERVICE));
    sensor =
       sensorManager.getDefaultSensor(Sensor.TYPE_HEART_RATE);
    }
  13. Add this onResume() method:
    protected void onResume() {
       super.onResume();
    
    sensorManager.registerListener(this, this.sensor, 3);
    }
  14. And this onPause() method:
    @Override
    protected void onPause() {
       super.onPause();
    
       sensorManager.unregisterListener(this);
    }
  15. Edit the onSensorChanged() callback, like so:
    @Override
    public void onSensorChanged(SensorEvent event) {
    textView.setText("" + (int) event.values[0]);
    }
  16. If you do not have access to a real device, you can download a sensor simulator from here:
  17. The app is now ready to test.

We began by adding a permission in the AndroidManifest.xml file in the appropriate module; this is something we have done before and need to do any time we are using features, that require the user's permission before installing.

The inclusion of a background image may seem necessary, but an appropriate background is a real aid to glancability as the user can tell instantly which app they are looking at.

It should be clear, from the way the SensorManager and the Sensor are set up in the onCreate() method, that all sensors are accessed in the same way and different sensors can be accessed with different constants. We used TYPE_HEART_RATE here, but any other sensor can be started with the appropriate constant, and all sensors can be managed with the same basic structures as we found here, the only real difference being the way each sensor returns SensorEvent.values[]. A comprehensive
list of all sensors, and descriptions of the values they produce can be found at
http://developer.android.com/reference/android/hardware/Sensor.html.

As with any time our apps utilize functions that run in the background, it is vital that we unregister our listeners, whenever they are no longer needed, in our Activity's onPause() method. We didn't use the onAccuracyChanged() callback here, but its purpose should be clear and there are many possible apps where its use is essential.

This concludes our exploration of wearable apps and how they are put together. Such devices continue to become more prevalent and the possibility of ever more imaginative uses is endless. Providing we consider why and how people use smart watches, and the like, and develop to take advantage of the location of these devices by programming glanceable interfaces that require the minimum of interactivity, Android Wear seems certain to grow in popularity and use, and the developers will continue to produce ever more innovative apps.

Summary

In this article, we have explored Android wearable apps and how they are put together. Despite their diminutive size and functionality, wearables offer us an enormous range of possibilities. We know now how to create and connect wearable AVDs and how to develop easily for both square and round devices. We then designed the user interface for both round and square screens.

To learn more about Android UI interface designing and developing android applications, the following books published by Packt Publishing (https://www.packtpub.com/) are recommended:

Resources for Article:


Further resources on this subject:

You've been reading an excerpt of:

Android 5 Programming by Example

Explore Title