1page.title=Keeping Your App Visible
2page.tags=wear
3helpoutsWidget=true
4
5@jd:body
6
7<div id="tb-wrapper">
8<div id="tb">
9<h2>This lesson teaches you to</h2>
10<ol>
11  <li><a href="#EnableAmbient">Enable Ambient Mode in a Wearable App</a></li>
12  <li><a href="#UpdateContent">Update Content in Ambient Mode</a></li>
13  <li><a href="#BackwardCompatibility">Maintain Backward-compatibility</a></li>
14</ol>
15<h2>You should also read</h2>
16  <ul>
17    <li><a href="{@docRoot}design/wear/structure.html">App Structure for Android Wear</a></li>
18  </ul>
19<h2>Related Samples</h2>
20  <ul>
21    <li><a href="{@docRoot}samples/AlwaysOn/index.html">AlwaysOn</a></li>
22  </ul>
23</div>
24</div>
25
26<p>Some Wear apps are most useful when they are constantly visible to the user. For example, users
27out on a run can glance at their wearable to see the distance covered and time elapsed, or after
28recording a grocery list on their wearable, users can quickly see which items are remaining on the
29list as they shop at the market. Making an app constantly visible has an impact on battery life,
30so you should carefully consider that impact when adding this feature to your app.
31</p>
32
33<div class="video-wrapper-left">
34<iframe src="https://www.youtube.com/embed/7m6Z9d0fDaM" frameborder="0"
35allowfullscreen></iframe>
36</div>
37
38<p>Android Wear devices running Android version 5.1 or higher allow apps to remain in the
39foreground while saving battery power. Android Wear apps can control what’s displayed on the
40wearable device screen while the device is in a low-power ambient mode. Wear apps that run in both
41ambient and interactive mode are called <i>always-on</i> apps.
42</p>
43
44<p>This lesson describes how to enable your wearable app to be always-on, update the screen
45while in ambient mode, and maintain backwards compatibility.
46</p>
47
48<h2 id="EnableAmbient">Enable Ambient Mode in a Wearable App</h2>
49
50<p>For new and existing projects, you can add ambient mode support to your Wear app by updating
51your development project configuration. After you complete the project configuration, extend the
52<a href="{@docRoot}reference/android/support/wearable/activity/WearableActivity.html"><code>WearableActivity</code></a>
53class, which provides all the methods you need to enable ambient mode in your app. The following
54sections describe these steps in detail.</p>
55
56<h3 id="ConfigureProject">Configure your development project</h3>
57
58<p>In order to support ambient mode in your Wear app, you must update your Android SDK and configure
59your development project. Follow these steps to make the necessary changes:</p>
60
61<ul>
62  <li>Update your SDK to include the Android 5.1 (API 22) or higher platform, which provides the
63  APIs to allow activities to go into ambient mode. For more information on how to update your SDK,
64  see
65  <a href="{@docRoot}studio/intro/update.html#GetTools">Adding SDK Packages</a>.
66  </li>
67  <li> Create a project or modify an existing project to target Android 5.1 or higher. This means
68  you must set the manifest
69  <a href="{@docRoot}topics/manifest/uses-sdk-element.html"><code>targetSdkVersion</code></a> to 22
70  or higher.</li>
71  <li>Set the manifest
72  <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html"><code>minSdkVersion</code></a> to
73  20 or higher, if you want to support devices on versions prior to Android 5.1. For more
74  information on backwards compatibility, see
75  <a href="#BackwardCompatibility">Maintain Backward-compatibility</a>.</li>
76  </li>
77  <li>Add or update the following dependencies to your <code>build.gradle</code> file:
78<pre>
79dependencies {
80    ...
81    compile 'com.google.android.support:wearable:1.2.0'
82    provided 'com.google.android.wearable:wearable:1.0.0'
83}
84</pre>
85<p class="note"><b>Note:</b> The <code>provided</code> dependency ensures that the classes loaded at
86run-time to support ambient mode are also available at compile-time.
87</p>
88</li>
89  <li>Add the wearable shared library entry into the wearable app manifest:
90<pre>
91&lt;application>
92  &lt;uses-library android:name="com.google.android.wearable"
93                android:required="false" />
94  ...
95&lt;/application>
96</pre>
97  </li>
98  <li>Add the
99  <a href="{@docRoot}reference/android/Manifest.permission.html#WAKE_LOCK"><code>WAKE_LOCK</code></a>
100  permission to the handheld and wearable app manifest:
101<pre>
102&lt;uses-permission android:name="android.permission.WAKE_LOCK" />
103</pre>
104  </li>
105</ul>
106
107<h3 id="CreateActivity">Create an activity that supports ambient mode</h3>
108
109<p>To enable ambient mode in your activity, use the
110<a href="{@docRoot}reference/android/support/wearable/activity/WearableActivity.html"><code>WearableActivity</code></a>
111class and methods.
112</p>
113
114<ol>
115  <li>Create an activity that extends
116  <a href="{@docRoot}reference/android/support/wearable/activity/WearableActivity.html"><code>WearableActivity</code></a>.</li>
117  <li>In the
118  <a href="{@docRoot}reference/android/app/Activity.html#onCreate(android.os.Bundle)"><code>onCreate()</code></a>
119  method of your activity, call the
120  <a href="{@docRoot}reference/android/support/wearable/activity/WearableActivity.html#setAmbientEnabled()"><code>setAmbientEnabled()</code></a>
121  method.</li>
122</ol>
123
124<p>Enable ambient mode in your activity as follows:</p>
125
126<pre>
127public class MainActivity extends WearableActivity {
128
129&#64;Override
130public void onCreate(Bundle savedInstanceState) {
131    super.onCreate(savedInstanceState);
132
133    <strong>setAmbientEnabled();</strong>
134    ...
135}
136</pre>
137
138<h3 id="EnableDisable">Handle transitions between modes</h3>
139
140<p>If the user does not interact with your app for a period of time while it is displayed, or if
141the user covers the screen with their palm, the system switches the activity to ambient mode.
142After the app switches to ambient mode, update the activity UI to a more basic layout to reduce
143power consumption. You should use a black background with minimal white graphics and text.
144 To ease a user into the transition from interactive to ambient mode, try to maintain similar
145 placement of items on the screen. For more information on presenting content on an ambient screen,
146 see the
147<a href="{@docRoot}design/wear/watchfaces.html#DisplayModes">Watch Faces for Android Wear</a>
148design guide.</p>
149<p> Note that when your app runs on a device without a hardware button, palming the screen does not
150switch an app into ambient mode. Rather, it causes the app to exit and the home screen to appear.
151This behavior is intended to ensure that users can exit apps gracefully. However, these devices still
152 go to ambient mode when the screen times out.
153</p>
154
155<p class="note"><b>Note:</b> In ambient mode, disable any interactive elements on the
156screen, such as buttons. For more information on how to design user interactions for an always-on
157app, see the
158<a href="{@docRoot}design/wear/structure.html#AlwaysOn">App Structure for Android Wear</a> design
159guide.
160</p>
161
162<p>When the activity switches to ambient mode, the system calls the
163<a href="{@docRoot}reference/android/support/wearable/activity/WearableActivity.html#onEnterAmbient(android.os.Bundle)"><code>onEnterAmbient()</code></a>
164method in your wearable activity. The following code snippet shows how to change the text color to
165white and disable anti-aliasing after the system switches to ambient mode:
166</p>
167
168<pre>
169&#64;Override
170public void onEnterAmbient(Bundle ambientDetails) {
171    super.onEnterAmbient(ambientDetails);
172
173    mStateTextView.setTextColor(Color.WHITE);
174    mStateTextView.getPaint().setAntiAlias(false);
175}
176</pre>
177
178<p>When the user taps the screen or brings up their wrist, the activity switches from ambient mode
179to interactive mode. The system calls the
180<a href="{@docRoot}reference/android/support/wearable/activity/WearableActivity.html#onExitAmbient()"><code>onExitAmbient()</code></a>
181method. Override this method to update the UI layout so that your app displays in a full-color,
182interactive state.</p>
183
184<p>The following code snippet shows how to change the text color to green and enable anti-aliasing
185when the system switches to interactive mode:</p>
186
187<pre>
188&#64;Override
189public void onExitAmbient() {
190    super.onExitAmbient();
191
192    mStateTextView.setTextColor(Color.GREEN);
193    mStateTextView.getPaint().setAntiAlias(true);
194}
195</pre>
196
197<h2 id="UpdateContent">Update Content in Ambient Mode</h2>
198
199<p>Ambient mode allows you to update the screen with new information for the user, but you must
200carefully balance display updates against the battery life. You should strongly consider only
201overriding the
202<a href="{@docRoot}reference/android/support/wearable/activity/WearableActivity.html#onUpdateAmbient()"><code>onUpdateAmbient()</code></a>
203method to update the screen once a minute in ambient mode. If your app requires more frequent
204updates, take into consideration that there is a trade-off between battery life and the frequency of
205updates. To realize battery savings, updates should be no more than once every 10 seconds. In
206practice, however, you should update your app less frequently than that.
207</p>
208
209<h3 id="StandardRefresh">Update once a minute</h3>
210
211<p>In order to preserve battery power, most wear apps should not frequently update the screen while
212in ambient mode. We recommend designing your app to update the screen once per minute while
213in this mode. The system provides a callback method,
214<a href="{@docRoot}reference/android/support/wearable/activity/WearableActivity.html#onUpdateAmbient()"><code>onUpdateAmbient()</code></a>,
215that allows you to update the screen at this recommended frequency.</p>
216
217<p>To update your app content, override the
218<a href="{@docRoot}reference/android/support/wearable/activity/WearableActivity.html#onUpdateAmbient()"><code>onUpdateAmbient()</code></a>
219method in your wearable activity:
220</p>
221
222<pre>
223&#64;Override
224public void onUpdateAmbient() {
225    super.onUpdateAmbient();
226
227    // Update the content
228}
229</pre>
230
231<h3 id="CustomRefresh">Update more frequently</h3>
232
233<p>For apps that require more frequent updates, such as a fitness, time-keeping, and travel
234information apps, use an
235<a href="{@docRoot}reference/android/app/AlarmManager.html"><code>AlarmManager</code></a>
236object to wake the processor and update the screen more frequently.</p>
237
238<p>To implement an alarm that updates content more frequently in ambient mode, follow these steps:
239</p>
240
241<ol>
242  <li>Prepare the alarm manager.</li>
243  <li>Set the frequency of the updates.</li>
244  <li>Schedule the next update when the activity switches to ambient mode or is currently in ambient
245      mode.</li>
246  <li>Cancel the alarm when the activity switches to interactive mode or the activity is stopped
247  </li>
248</ol>
249
250<p class="note"><b>Note:</b> The alarm manager may create new instances of your activity as they are
251triggered. To prevent this situation, ensure that your activity is declared with the
252<code>android:launchMode="singleInstance"</code> parameter in the manifest.</p>
253
254<p>The following sections describe these steps in detail.</p>
255
256<h4 id="PrepareAlarm">Prepare the alarm manager</h4>
257
258<p>The alarm manager launches a pending intent that updates the screen and schedules the next alarm.
259The following example shows how to declare the alarm manager and the pending intent in the
260<a href="{@docRoot}reference/android/app/Activity.html#onCreate(android.os.Bundle)"><code>onCreate()</code></a>
261method of your activity:</p>
262
263<pre>
264private AlarmManager mAmbientStateAlarmManager;
265private PendingIntent mAmbientStatePendingIntent;
266
267&#64;Override
268public void onCreate(Bundle savedInstanceState) {
269    super.onCreate(savedInstanceState);
270
271    setAmbientEnabled();
272
273    mAmbientStateAlarmManager =
274        (AlarmManager) getSystemService(Context.ALARM_SERVICE);
275    Intent ambientStateIntent =
276        new Intent(getApplicationContext(), MainActivity.class);
277
278    mAmbientStatePendingIntent = PendingIntent.getActivity(
279        getApplicationContext(),
280        0,
281        ambientStateIntent,
282        PendingIntent.FLAG_UPDATE_CURRENT);
283    ...
284}
285</pre>
286
287<p>When the alarm triggers and launches the pending intent, update the screen and schedule the next
288alarm by overriding the
289<a href="{@docRoot}reference/android/app/Activity.html#onNewIntent(android.content.Intent)"><code>onNewIntent()</code></a>
290method:
291</p>
292
293<pre>
294&#64;Override
295public void onNewIntent(Intent intent) {
296    super.onNewIntent(intent);
297
298    setIntent(intent);
299
300    // Described in the following section
301    refreshDisplayAndSetNextUpdate();
302}
303</pre>
304
305<h4 id="ScheduleUpdates">Update screen and schedule data updates</h4>
306
307<p>In this example activity, the alarm manager triggers every 20 seconds in ambient mode. When
308the timer ticks, the alarm triggers the intent to update the screen and then sets the delay for the
309next update.
310</p>
311
312<p>The following example shows how to update information on the screen and set the alarm for the
313next update:
314</p>
315
316<pre>
317// Milliseconds between waking processor/screen for updates
318private static final long AMBIENT_INTERVAL_MS = TimeUnit.SECONDS.toMillis(20);
319
320private void refreshDisplayAndSetNextUpdate() {
321
322    if (isAmbient()) {
323        // Implement data retrieval and update the screen for ambient mode
324    } else {
325        // Implement data retrieval and update the screen for interactive mode
326    }
327
328    long timeMs = System.currentTimeMillis();
329
330    // Schedule a new alarm
331    if (isAmbient()) {
332        // Calculate the next trigger time
333        long delayMs = AMBIENT_INTERVAL_MS - (timeMs % AMBIENT_INTERVAL_MS);
334        long triggerTimeMs = timeMs + delayMs;
335
336        mAmbientStateAlarmManager.setExact(
337            AlarmManager.RTC_WAKEUP,
338            triggerTimeMs,
339            mAmbientStatePendingIntent);
340
341    } else {
342        // Calculate the next trigger time for interactive mode
343    }
344}
345</pre>
346
347<h4 id="ScheduleNext">Schedule the next alarm</h4>
348
349<p>Schedule the alarm to update the screen when the activity is entering ambient mode or when the
350activity is already in ambient mode by overriding the
351<a href="{@docRoot}reference/android/support/wearable/activity/WearableActivity.html#onEnterAmbient(android.os.Bundle)"><code>onEnterAmbient()</code></a>
352method and the
353<a href="{@docRoot}reference/android/support/wearable/activity/WearableActivity.html#onUpdateAmbient()"><code>onUpdateAmbient()</code></a>
354method:</p>
355
356<pre>
357&#64;Override
358public void onEnterAmbient(Bundle ambientDetails) {
359    super.onEnterAmbient(ambientDetails);
360
361    refreshDisplayAndSetNextUpdate();
362}
363
364&#64;Override
365public void onUpdateAmbient() {
366    super.onUpdateAmbient();
367
368    refreshDisplayAndSetNextUpdate();
369}
370</pre>
371
372<p class="note"><b>Note:</b> In this example, the <code>refreshDisplayAndSetNextUpdate()</code>
373method is called whenever the screen needs to be updated. For more examples of when to call this
374method, see the <a href="{@docRoot}samples/AlwaysOn/index.html">AlwaysOn</a> sample.
375</p>
376
377<h4 id="CancelAlarm">Cancel the alarm</h4>
378
379<p>When the device switches to interactive mode, cancel the alarm in the
380<a href="{@docRoot}reference/android/support/wearable/activity/WearableActivity.html#onExitAmbient()"><code>onExitAmbient()</code></a>
381method:</p>
382
383<pre>
384&#64;Override
385public void onExitAmbient() {
386    super.onExitAmbient();
387
388    mAmbientStateAlarmManager.cancel(mAmbientStatePendingIntent);
389}
390</pre>
391
392<p>When the user exits or stops your activity, cancel the alarm in the
393<a href="{@docRoot}reference/android/app/Activity.html#onDestroy()"><code>onDestroy()</code></a>
394method of your activity:</p>
395
396<pre>
397&#64;Override
398public void onDestroy() {
399    mAmbientStateAlarmManager.cancel(mAmbientStatePendingIntent);
400    super.onDestroy();
401}
402</pre>
403
404<h2 id="BackwardCompatibility">Maintain Backward-compatibility</h2>
405
406<p>Activities that support ambient mode automatically fall back to normal activities on Wear devices
407that are on Android versions prior to 5.1 (API level 22). No special app code is required to support
408devices on these versions of Android. When the device switches to ambient mode, the device returns
409to the home screen and exits your activity.</p>
410
411<p>If your app should not be installed or updated on devices with Android versions prior to 5.1,
412update your manifest with the following:</p>
413
414<pre>
415&lt;uses-library android:name="com.google.android.wearable" android:required="true" />
416</pre>
417