WHAT’S IN THIS CHAPTER?
WROX.COM CODE DOWNLOADS FOR THIS CHAPTER
The wrox.com code downloads for this chapter are found at www.wrox.com/go/androidwearables
on the Download Code tab. The code is in the Chapter 5 download and the filenames correspond to the code listing numbers noted throughout the chapter.
Unlike notifications, Wear apps behave (almost) like normal Android apps. They are built using a native SDK called Wear SDK, and they run in separate processes on the wearable device, making them completely standalone from your phone. Even though the behavior is similar, you should keep a few points in mind when developing apps for Wear.
The first thing you should consider is the connectivity of your Wear device. It has no built-in connectivity options such as WiFi or USB for you to use when building your apps. Accessing the Internet on your Wear apps is impossible without an attached phone. But this is not a major problem, because you need to build a companion app (or, rather, a master app) for your Wear app. Without it you can’t distribute your new Wear app on Google Play.
Google has published a number of general guidelines that you should keep in mind when creating your Wear app. For example, all Wear interactions should fall into one of two categories that Google calls suggest and demand. This means that everything found on Wear should be contextually connected. Everything you create for Wear, whether a notification or native running app, should interrupt only if absolutely necessary, and it should quickly provide a correct answer depending on the user’s context.
A continuation of this rule of thumb is that you should create apps that don’t require focused attention from your users. They should be able to quickly get the gist of what your app is trying to tell them. Or your apps should promptly suggest actions. Google calls this making the app glanceable.
A reasonable goal when creating Wear apps, or notifications, is that your users should interact with the device for only a few seconds. If they have to spend more time than that, your app could probably be more optimized and streamlined. Always try to focus your app on doing only one thing, and try to do that one thing as quickly as possible by helping the user in any way you can. For example, you can highlight the most plausible action.
A good strategy when helping your users complete actions quickly on such a small screen is to use simple gestures and interactions. Always avoid using complicated or detailed interactions. If users find your app difficult to interact with while on the move, you should redesign the user interface.
With the introduction of Wear, Google added a number of new classes and UI widgets that help you create apps that follow Wear’s design guidelines—and those of other small screens. Table 5.1 summarizes the new widgets.
All of these classes can be found in the android.support.wearable.view
package.
Table 5.1 New Classes and UI Widgets in Wear
WIDGET NAME | DESCRIPTION |
CardFragment |
A fragment that holds a scrollable card. By default the card layout includes a title, descriptive text, and an optional icon. You can also build your own custom layout for this fragment. |
CardFrame |
Creates a frame with a white background and rounded corners for its contents. This is useful if you want your app to have a more detailed background—rather than the standard black—while the content remains readable. |
CardScrollView |
A container for one CardFrame that makes it scrollable. Appropriate for cards that hold more text. |
CircledImageView |
The standard widget for including images in Wear. It has an optional circle that you can give some style. An optional border on the circle supports progress. You can use it for countdowns in your app or to show progress. |
ConfirmationActivity |
A helper class for creating attractive animations as feedback for user actions. |
CrossfadeDrawable |
Lets you fade between two different drawables, creating a nice effect for your UI. |
DelayedConfirmationView |
A subclass to CircledImageview, with the added functionality of performing an action after a set period of time. Often used before you send an action to the mobile so that the user has time to cancel the action if needed. |
DismissOverlayView |
A simple view for adding interactions to dismiss your activity. |
FragmentGridPagerAdapter |
A page adapter that handles fragments. Used together with GridViewPager . |
GridPagerAdapter |
Another adapter for GridViewPager . This one is not for fragments. |
GridViewPager |
A two-dimensional grid of pages that allows the user to scroll in both dimensions. |
InsetActivity |
An activity with built-in support for detecting screen types on Wear devices. A good alternative to using WatchViewStub . |
WatchViewStub |
One of the most important additions in Wear. Use it to detect the device’s screen type—round or square—and then load the correct layout for that device. |
WearableListView |
A list view implementation that is optimized for very small screens. |
WearableListView.Adapter |
An adapter for WearableListView . This is an abstract class, which means you need to subclass it when working with lists. |
When working with Android Wear you need to have Android Studio version 0.8.0 or later installed to have access to the Wear-specific workflow and dialogs.
Follow these steps to create your new Android Wear project:
WatchViewStub
as the main layout file. Click Next.You should now have an Android Studio project that has two application structures within it called mobile and wear. Let’s review some of the news introduced by Android Wear in the project.
Open the mobile gradle file and scroll down to the dependencies. They should look something like Listing 5-1.
Notice the dependencies. These two lines are not present in normal Android app projects. The first line specifies that this particular Android app has a Wear component that is located in the wear folder.
The second line includes the Google Play services repository as part of the project. This part is optional. You may remove it if you don’t plan on using any of the new Wear-specific features such as data sync between the two devices.
If you open the Wear gradle file and look at the dependencies, they should look something like Listing 5-2.
You’ll notice that this project also has two new dependencies specific to Android Wear. First is the wearable support repository, which adds all the new Wear components (see Table 5.1) to the project. The second is the play services repository, which is also optional in the Wear project. If you don’t plan on using any of the functionalities in the Google Play services repository, you may remove this line.
To use the new Wear notifications in your apps, you should also add the support repository to your dependencies. This project doesn’t need it, however, so leave it out for now.
Since Android Wear comes in two different screen shapes, you need to plan your app for both shapes using at least two different layouts.
You have two ways to load the correct layout in Android Wear projects. The default method is to use a normal activity and load a layout with WatchViewStub
. The second way is to use InsetActivity
.
WatchViewStub
is a smart UI widget that can detect the device’s screen shape. Listing 5-3 shows the default main layout. Notice the attributes called rectLayout
and roundLayout
.
The attributes found in the tools namespace are merely for convenience and helping you when you design the app. They are stripped when the application is packaged.
When you design your actual layouts, you should always use the same components. It’s critical to use identical ids when you work with WatchViewStub
.
To get a reference to a UI widget in your layout, you listen for the onLayoutInflated
event on the WatchViewStub
root. Listing 5-4 shows how to add the listener.
When you’ve attached the listener, you can safely load references to the UI widgets, as shown in Listing 5-5.
This example shows the importance of having identical ids in the layouts for round screens and rectangular screens. The alternative way of loading layouts in Wear is a bit more lenient when it comes to ids.
When using InsetActivity
, you don’t need the extra initial layout component, WatchViewStub
. Instead of selecting the correct layout in XML, you load the correct layout directly in your activity. Listing 5-6 shows how to create InsetActivity
.
The benefit of InsetActivity
is that you may use completely different layouts for different screens. You don’t need to make sure that they match in widgets or widget ids.
The biggest catch of InsetActivity
is the loading of the content view. It must be loaded in the life-cycle method onReadyForContent()
. Only in this method does the app know with certainty which screen type the device has. You may then load the correct layout depending on the type of screen the device has—round or rectangular. Using the isRound()
method, you can select the correct layout to load as content view.
Loading references in InsetActivity
is identical to loading references in any normal Android app. Using findViewById()
in the activity, as shown in Listing 5-7, lets you load the correct widget. You’re not required to use identical ids, unlike with WatchViewStub
. But doing so is recommended so that you avoid duplicate code.
I prefer to use a third method for loading the user interface to keep the life-cycle method clean. Doing so also ensures that the two screen types present the same information and enable the same interactions. Listing 5-8 shows how I usually organize my InsetActivity
.
Figure 5.7 shows the application running on both screen types.
Another cool function that InsetActivity
provides is the exit button. Tapping the screen displays a typical exit application button, as shown in Figure 5.8.
Now that you know about some of the basic differences between the Wear app and the mobile app in terms of project structure, let’s explore Wear’s user interface widgets.
When working with Wear-specific UI widgets, it’s important to add another namespace to your layouts. Without it, adding Wear attributes to views would be impossible. Listing 5-9 shows how to add the Wear namespace.
Working with text in Android Wear isn’t so different from normal Android apps. Technically speaking, it’s not the text component that changes; it’s how you should design apps containing text in Wear that changes. Remember that context is important to both notifications and apps. Most often the context is provided with a visual background image and an application icon. Presenting textual information over an image may become a bit messy. Therefore, we strongly recommend that you use a frame of some sort that makes the text more legible.
Luckily Google provides several new classes for dealing with this problem—CardFrame
, CardScrollView
, and CardFragment
.
The most basic of the three components for displaying text, CardFrame
is a simple white card with rounded edges and an optional icon. Listing 5-10 shows how to wrap a simple TextView
within a CardFrame
.
The result is a simple frame around our TextView
, as shown in Figure 5.9. It has rounded corners and a drop shadow, which is difficult to see in these figures. I promise it’s there.
CardFrame
doesn’t give you many other options when it comes to customizing your UI. This is where CardScrollView
comes in handy.
CardScrollView
is basically a container for a single CardFrame
with the added option of adding scroll functionality to the card in two directions, up and down. You also can set the card’s anchor edge to either top or bottom.
CardScrollView
can hold only one CardFrame
at a time, as shown in Listing 5-11.
Table 5.2 lists the properties you can change for CardScrollView
. None of these parameters can be set in XML.
Table 5.2 CardScrollView Properties
PROPERTY | DESCRIPTION | METHOD |
Expansion enabled | Allows or disallows CardFrame from being taller than the screen height. |
setExpansionEnabled(Boolean) |
Expansion direction | The direction in which the child CardFrame expands. When the card is taller than the screen, this edge is also faded to indicate that it is scrollable. |
setExpansionDirection(int) This value can be either CardFrame.EXPAND_UP or CardFrame.EXPAND_DOWN |
Expansion factor | Sets the expansion factor. | setExpansionFactor(float) |
Card gravity | Sets the edge that the CardFrame child anchors to when the content is shorter than the screen’s height. |
setCardGravity(int) This value can be either Gravity.TOP or Gravity.BOTTOM |
CardFragment
is the best option for displaying text (or any other framed content, for that matter) on Wear devices. It combines CardFrame
and CardScrollView
and includes an icon as well.
CardFragment
comes with two handy static builder methods. If the default layout doesn’t suit your needs, you can simply extend CardFragment
and load your own layout. Listing 5-12 shows how to create a simple card using the builder methods.
Because this is a fragment, you need to adjust your layout slightly to create a container for your CardFragment
. Figure 5.10 shows the resulting simple card.
Using your own custom layout for the CardFragment
class is simple. Just extend the CardFragment
class and override the onCreateContentView()
method. Listing 5-13 shows our custom card layout with three TextView
s.
Listing 5-14 shows how to load this custom layout in our own card class.
Showing this custom card is as easy as loading your custom fragment into the container, as shown in Listing 5-15.
Figure 5.11 shows the resulting card.
Table 5.3 shows some of the available properties for CardFragment
.
Table 5.3 CardFragment Properties
PROPERTY | DESCRIPTION |
Scroll position | With the methods scrollToTop() and scrollToBottom() you can scroll the card contents to the very top and very bottom of the card. |
Card gravity | Sets the card’s anchor edge. Can be either Gravity.TOP or Gravity.BOTTOM . |
Expansion direction | Selects in which direction the card expands. Can be either CardFragment.EXPAND_UP or CardFragment.EXPAND_DOWN . |
Expansion state | With the method setExpansionEnabled(), you can allow or disallow the expansion for this CardFragment . |
Expansion factor | Sets the card’s allowed height. It’s adjusted in multiples of the parent container. 1.5 means that CardFragment will be at most 1.5 times the height of its container. |
Images in Android Wear are used slightly differently than in normal Android apps. I like to categorize them into two groups: context images and action images.
Context images are your backgrounds; they provide context for the card currently displayed. It could be a photo of a contact who just sent you a message. Action images are part of the interactions in Wear. All action images in Wear are loaded with the new CircledImageView
, which has special properties related to Wear user interfaces.
The simplest image to load in Wear is the static image. Listing 5-16 is the simplest example of the image with a circled background.
This layout should render a result similar to that shown in Figure 5.12.
With the simple images in Wear, you need to use the limited amount of space wisely. A neat thing about CircledImageView
is the optional progress bar—or countdown timer, depending on how you use it. Imagine a download is under way, and you want to show it on the watch’s user interface. You’d probably create an AsyncTask
, and, in the onProgressUpdate()
method, you’d update the progress of CircledImageView
, as shown in Figure 5.13.
To build the progress bar shown in Figure 5.13, you start by setting the color and weight of the circle border, as shown in Listing 5-17.
To update the progress bar, you use the setProgress()
method, as shown in Listing 5-18. The example isn’t quite as complex as the scenario presented earlier, but it should give you a good idea of how to work with the circular progress bar.
Table 5.4 lists all the possible attributes for the CircledImageView
class.
Table 5.4 CircledImageView Attributes
XML ATTRIBUTE | DESCRIPTION |
circle_color |
Defines the circle’s background color. In the layout file you can use normal RGB values. In Java you use the Color class. This property is required if you want the circle background to be displayed. |
circle_radius |
Sets the size of the background circle. Without it the circle is invisible. |
circle_border_color |
Sets the border’s color. The circle’s border is also the optional progress bar. |
circle_border_width |
Set the border’s stroke weight. This is required if you want the border to show. |
circle_padding |
Sets the border’s padding. |
Just like in standard Android apps, the list is one of the most important aspects of a user interface. In Wear the lists have changed to be easier to interact with while you’re on the move.
You have two options when dealing with lists in Android Wear: WearableListView
and GridView
.
WearableListView
is optimized for small screens. It scrolls vertically and has a snapping effect. To add WearableListView
to your project, you need three things: the layout, the adapter, and the data. Let’s start with the layout of the list (Listing 5-19).
The WearableListView.Adapter
class is slightly different from what you’re probably used to in standard Android. It’s an abstract class, which means you need to create a subclass. It has three methods you need to work with: onCreateViewHolder()
, onBindViewHolder()
, and getItemCount()
. Listing 5-20 shows a simple example of how to use them.
In Wear the adapter has become much simpler than it was in standard Android. For one thing, you don’t need to build your own holders anymore—which is something I occasionally forget. In the method onCreateViewHolder()
you simply inflate a layout for your row. The returning view is the ViewHolder
for your list.
onBindViewHolder()
is where you link your data to the respective UI widgets inside your layout file.
Finally, you return the length of your list data in the getItemCount()
method. Where you store your data is up to you. In this example I chose to pass it as a reference to the constructor of the adapter.
When it’s time to put your list to the test, all you need is three lines of code, as shown in Listing 5-21, the data (in this example a String
array), the list, and the adapter.
Figure 5.14 shows the list in all its glory.
Of course, you also can add click actions to your WearableListView
, just like you can with any other View
. Use the special ClickListener
interface located in the WearableListView
class, as shown in Listing 5-22.
Then simply attach the listener to your list, as shown in Listing 5-23.
As you’ve seen, WearableListView
is very handy. It gives you a list that follows the general guidelines for Wear apps and is very easy to implement. You also have alternatives such as GridViewPager
, also known as 2D Picker.
Much like the list, the grid consists of a layout, an adapter, and data. But the big difference is the data. In a normal list it’s one-dimensional, but in grid view its two-dimensional—the user can scroll in both dimensions freely. This example uses CardFragment
to quickly produce pages, but you can create your own page layout too.
Start by creating your adapter. It should inherit from the GridPagerAdapter
class, as shown in Listing 5-24.
When the Adapter is ready, the next step is to add a GridViewPager
to your layout, as shown in Listing 5-25.
Finally, glue it all together in your activity, as shown in Listing 5-26.
Your result should resemble Figure 5.15.
A key feature of Wear is feedback. It’s critical that you give your users clear and timely feedback within the short period of time that you have their attention. Google provides three kinds of basic animation feedback that you can use as necessary. All of them are launched using the ConfirmationActivity
class:
To use ConfirmationActivity
, you create a subclass and add it to your manifest. Then you start the activity with the correct parameters. You have beautiful animations that run smoothly on your users’ Wear device. Listing 5-27 shows how to subclass ConfirmationActivity
.
Add your new activity to your AndroidManifest.xml file, as shown in Listing 5-28.
After you have registered the class for your app, it must be started with the correct settings. Table 5.5 lists the extra information you need to pass with the intent.
Table 5.5 Extra information for ConfirmationActivity
FIELD | DESCRIPTION |
EXTRA_ANIMATION_TYPE |
The type of the animation. Can be either FAILURE_ANIMATION , OPEN_ON_PHONE_ANIMATION , or SUCCESS_ANIMATION . |
EXTRA_MESSAGE |
A short text message to display along with the animation. |
Listing 5-29 shows how to start the success animation.
Figure 5.16 shows the success animation in all its glory.
Starting the open-on-phone animation is no different, as shown in Listing 5-30.
This animation is slightly different, as shown in Figure 5.17.
The failure feedback is almost identical to the other two; only the type is different. See Listing 5-31.
Your result should look like Figure 5.18. Note that the failure animation stays until the user clicks it away.
This chapter has described the new UI widgets available in Android Wear. You learned how to build apps using some of these new classes.
This chapter also introduced design principles for very small screens and gave you some points to keep in mind when building apps with Android Wear.
The next chapter explores how to add connectivity to Android Wear apps.
https://developer.android.com/design/wear/creative-vision.html
.https://developer.android.com/design/wear/principles.html
.https://developer.android.com/design/wear/patterns.html
.https://developer.android.com/design/wear/style.html
.