Tip:
Highlight text to annotate it
X
Hi, I'm Will Haldean Brown, and I'm
a software engineer on the Android Wear team.
Today, I'm going to talk about writing
full screen, immersive apps for Android Wear.
Many technical aspects of designing apps for Wear
will be very familiar to you, as they work the same way
that normal Android apps work.
However, there are two big differences
I'm going to discuss.
How users leave your app.
And how to design and implement your app
to look great on a round screen.
Let's start by talking about how users
leave apps on Android Wear.
On a phone or a tablet, users would use the back button
or home button to exit an app.
But those buttons are not present on Android Wear
devices.
Instead, there are two ways users can leave your app.
By swiping from the left edge, and by long
pressing on the app.
With Android Wear, we're introducing a new window
attribute, window swipe to dismiss.
This window attribute can be specified
in the theme of your activity.
When the window swipe to dismiss attribute is set to true,
your activity will be dismissible when swiping from
left to right.
This swipe dismissal works similarly
to how a viewpager works.
If the content inside the activity
is itself capable of scrolling, the window
will not be dismissed until the user scrolls
to the edge of that content, and then swipes again.
This allows you to create awesome, stream-like
experiences that are still dismissible by swiping.
All Android Wear apps should either
use the device default theme, or a theme that inherits from it.
This will insure a number of styles
are set correctly on your app to make it look great on Wear.
It also enables swipe to dismiss.
We recognize that some apps are not
going to be able to use swipe dismissal.
For example, a maps app with an infinite canvas
will never reach an edge.
If you don't want to use the swipe gesture,
you can disable it in your theme by setting the window swipe
to dismiss attribute to false.
For apps that aren't swipe dismissible,
we recommend that you use a long press in your app,
as a gesture to bring up an exit button.
To inform users that your app supports long press to dismiss,
you should show users a long press hint
when your app is starting for the first time.
As you can see here, a long press anywhere on the screen
brings up an exit button overlaid upon the app.
Tapping that button finishes the activity,
which brings the user back home.
To make it as easy as possible to add long press dismiss
to your app, we've made a view that implements much of the UI
logic for you called dismiss overlay view.
To integrate it into your app, start
by adding it to your activities layout XML.
Make sure it's added in a place that
will cause it to be drawn over all
the other views in the layout.
You should also ensure that the view
is sized to cover the full screen.
Here, I had it as the last child of a frame layout,
and set it's height and width to match parent.
This will ensure that it draws full screen
and over everything.
Now let's look at your activity class.
In its onCreate, pull the dismiss overlay view out
of your layout, and set it's intro text.
This is text that will display the first time your activity
runs, as an overlay on the rest of your content,
and should tell the user that they can long
press to go back to home.
Then, call showIntroIfNecessary.
That will display the intro overlay
only if this is the first time the app has run.
Next, we need to wire it up to display
when your activity is long pressed.
Using a GestureDetector and a SimpleOnGestureListener.
Using these framework classes will
ensure that the timing around the gesture
feels consistent across all apps.
When you get the long press callback,
call show on your dismiss overlay.
That will display the Exit button.
If the user clicks the button, your activity will be finished.
But if they don't click the button,
the dismissal overlay will hide itself,
and wait for the next show call.
Finally, still in your activity, override
the onTouchEvent method, and pass
receiveTouchEvents into the GestureDetector.
If the GestureDetector returns true,
you should return true, and not pass the event
to the normal activity onTouchEvent method.
If the GestureDetector returns false,
use the normal activity touch handling.
Now, let's talk about something different.
How to make your apps look beautiful
on the round screen of the Moto 360.
First, let's take a look at the screen dimensions of the 360.
It's a circle with a diameter of 320 pixels,
with a 30 pixel chin at the bottom.
The system therefore reports its size as 320 by 290 pixels.
As we learned during our own development process,
the chain can cause some unintended results
importing existing layouts.
Looking at the action cards in the stream, for example,
we want to place the action icon in the center of the screen.
But when we set the layout gravity to center vertical,
the blue circle is offset by 15 pixels.
We decided that it would be best to preserve
the expectation of the center of a layout
be in the center of the screen circle.
In our device default theme mentioned earlier,
the windowOverscan attribute is set.
Now the root of the view hierarchy
is therefore measured at 320 by 320 pixels.
This causes your apps top-level view
to be measured at the same 320 by 320, instead of 320 by 290.
And centering in your layout works as expected.
How can you detect that your activity
is running on a round screen?
Your views can request to apply window insets,
and get a call back with a window insets object.
That tells you the shape of the screen, and on the Moto 360,
it tells you that the bottom inset is 30 pixels.
You should use this value wherever
you need to lay out around the chin.
Using the insets past in here well ensure
that your app looks great on any future device.
To save you from writing all this boilerplate code,
we added a view called WatchViewStub,
which allows you to inflate one of two different layouts,
depending on whether your app is running
on a rectangular or round device.
You can use a WatchViewStub as the root of any view hierarchy
you want to look different on round screens.
To use it, create a new stub in your activity or fragments
onCreate.
Once you've done that, you'll need
to give your stub two layouts.
One to inflate for round devices,
and one to inflate on rectangular devices.
There's one snag, though.
Because these layouts aren't inflated
until the view is attached to the hierarchy,
you can't access the child's views yet.
Instead, attach an OnLayoutInflatedListener,
which will be called when the appropriate inner layout has
been inflated.
Both dismiss overlay view, and this WatchViewStub
can be found in the wearable support library, which
also provides a new layout manager called box inset
layout.
It extends frame layout, and allows developers
to use the same layout on both rectangular and round screens.
In this example, we have a text view at the top left,
a cancel button at the bottom left,
and an OK button at the bottom right.
When the same layout is used on a round screen,
we want the view elements to be placed
on the edge of the circle, not the square.
This is achieved by adding the wearable layout_box
attribute to your layout.
It defines the set of edges, left, top, right, and bottom,
to be aligned with the inside box of the circle.
This makes it easy to have backgrounds bleed
into a full circle, but contain other elements
to non-clipped areas.
Here, you can see a text view boxed
into the center square of the round screen.
On a square screen, the layout box parameter is ignored.
I'm really excited about the platform,
and I hope you all are too.
I can't wait to see what apps you build.