A basic sample showing how to support ambient mode for native Android Wear apps.
WearableActivity offers methods for supporting your native app staying on the screen when the Wear device enters ambient mode.
This example extends WearableActivity and overrides onEnterAmbient, onUpdateAmbient, and onExitAmbient to allow the simple native Wear app to support ambient mode.
In ambient mode, this app follows best practices by keeping most pixels black, avoiding large blocks of white pixels, using only black and white, and disabling anti-aliasing (following the design guidelines for Watch Faces).
In addition and most importantly, the app sleeps while in ambient mode for 20 seconds between any updates to conserving battery life (processor allowed to sleep). If you can hold off on updates for a full minute, you can throw away the Handler and just use onUpdateAmbient to save even more battery life.
As always, you will still want to apply the performance guidelines outlined in the Watch Faces documention to your app.
This sample uses the Gradle build system. To build this project, use the "gradlew build" command or use "Import Project" in Android Studio.
If you've found an error in this sample, please file an issue: https://github.com/googlesamples/android-AlwaysOn
Patches are encouraged, and may be submitted by forking this project and submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details.
Copyright 2017 The Android Open Source Project, Inc.
Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
Demonstrates support for Ambient Mode by attaching ambient mode support to the activity, and listening for ambient mode updates (onEnterAmbient, onUpdateAmbient, and onExitAmbient) via a named AmbientCallback subclass. *
Also demonstrates how to update the display more frequently than every 60 seconds, which is the default frequency, using an AlarmManager. The Alarm code is only necessary for the custom refresh frequency; it can be ignored for basic ambient mode support where you can simply rely on calls to onUpdateAmbient() by the system. *
There are two modes: ambient and active. To trigger future display updates, we use a custom Handler for active mode and an Alarm for ambient mode. *
Why not use just one or the other? Handlers are generally less battery intensive and can be triggered every second. However, they can not wake up the processor (common in ambient mode). *
Alarms can wake up the processor (what we need for ambient move), but they are less efficient compared to Handlers when it comes to quick update frequencies. *
Therefore, we use Handler for active mode (can trigger every second and are better on the battery), and we use an Alarm for ambient mode (only need to update once every 10 seconds and they can wake up a sleeping processor). *
The activity waits 10 seconds between doing any processing (getting data, updating display etc.) while in ambient mode to conserving battery life (processor allowed to sleep). If your app can wait 60 seconds for display updates, you can disregard the Alarm code and simply use onUpdateAmbient() to save even more battery life. *
As always, you will still want to apply the performance guidelines outlined in the Watch Faces documentation to your app. *
Finally, in ambient mode, this activity follows the same best practices outlined in the Watch Faces API documentation: keeping most pixels black, avoiding large blocks of white pixels, using only black and white, disabling anti-aliasing, etc.
Custom 'what' for Message sent to Handler.
Milliseconds between updates based on state.
Action for updating the display in ambient mode, per our custom refresh cycle.
Number of pixels to offset the content rendered in the display to prevent screen burn-in.
Ambient mode controller attached to this display. Used by Activity to see if it is in ambient mode.
If the display is low-bit in ambient mode. i.e. it requires anti-aliased fonts.
If the display requires burn-in protection in ambient mode, rendered pixels need to be intermittently offset to avoid screen burn-in.
Since the handler (used in active mode) can't wake up the processor when the device is in ambient mode and undocked, we use an Alarm to cover ambient mode updates when we need them more frequently than every minute. Remember, if getting updates once a minute in ambient mode is enough, you can do away with the Alarm code and just rely on the onUpdateAmbient() callback.
This custom handler is used for updates in "Active" mode. We use a separate static class to help us avoid memory leaks.
Loads data/updates screen (via method), but most importantly, sets up the next refresh (active mode = Handler and ambient mode = Alarm).
Updates display based on Ambient state. If you need to pull data, you should do it here.
Prepares the UI for ambient mode.
Updates the display in ambient mode on the standard interval. Since we're using a custom refresh cycle, this method does NOT update the data in the display. Rather, this method simply updates the positioning of the data in the screen to avoid burn-in, if the display requires it.
Restores the UI to active (non-ambient) mode.
Handler separated into static class to avoid memory leaks.