summaryrefslogtreecommitdiffstats
path: root/docs/html/training/wearables/apps/always-on.jd
blob: d38497408f364700c0e5a9f436b71ea2b01800bf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
page.title=Keeping Your App Visible
page.tags=wear
helpoutsWidget=true

@jd:body

<div id="tb-wrapper">
<div id="tb">
<h2>This lesson teaches you to</h2>
<ol>
  <li><a href="#EnableAmbient">Enable Ambient Mode in a Wearable App</a></li>
  <li><a href="#UpdateContent">Update Content in Ambient Mode</a></li>
  <li><a href="#BackwardCompatibility">Maintain Backward-compatibility</a></li>
</ol>
<h2>You should also read</h2>
  <ul>
    <li><a href="{@docRoot}design/wear/structure.html">App Structure for Android Wear</a></li>
  </ul>
<h2>Related Samples</h2>
  <ul>
    <li><a href="{@docRoot}samples/AlwaysOn/index.html">AlwaysOn</a></li>
  </ul>
</div>
</div>

<p>Some Wear apps are most useful when they are constantly visible to the user. For example, users
out on a run can glance at their wearable to see the distance covered and time elapsed, or after
recording a grocery list on their wearable, users can quickly see which items are remaining on the
list as they shop at the market. Making an app constantly visible has an impact on battery life,
so you should carefully consider that impact when adding this feature to your app.
</p>

<div class="video-wrapper-left">
<iframe src="https://www.youtube.com/embed/7m6Z9d0fDaM" frameborder="0"
allowfullscreen></iframe>
</div>

<p>Android Wear devices running Android version 5.1 or higher allow apps to remain in the
foreground while saving battery power. Android Wear apps can control what’s displayed on the
wearable device screen while the device is in a low-power ambient mode. Wear apps that run in both
ambient and interactive mode are called <i>always-on</i> apps.
</p>

<p>This lesson describes how to enable your wearable app to be always-on, update the screen
while in ambient mode, and maintain backwards compatibility.
</p>

<h2 id="EnableAmbient">Enable Ambient Mode in a Wearable App</h2>

<p>For new and existing projects, you can add ambient mode support to your Wear app by updating
your development project configuration. After you complete the project configuration, extend the
<a href="{@docRoot}reference/android/support/wearable/activity/WearableActivity.html"><code>WearableActivity</code></a>
class, which provides all the methods you need to enable ambient mode in your app. The following
sections describe these steps in detail.</p>

<h3 id="ConfigureProject">Configure your development project</h3>

<p>In order to support ambient mode in your Wear app, you must update your Android SDK and configure
your development project. Follow these steps to make the necessary changes:</p>

<ul>
  <li>Update your SDK to include the Android 5.1 (API 22) or higher platform, which provides the
  APIs to allow activities to go into ambient mode. For more information on how to update your SDK,
  see
  <a href="{@docRoot}sdk/installing/adding-packages.html#GetTools">Adding SDK Packages</a>.
  </li>
  <li> Create a project or modify an existing project to target Android 5.1 or higher. This means
  you must set the manifest
  <a href="{@docRoot}topics/manifest/uses-sdk-element.html"><code>targetSdkVersion</code></a> to 22
  or higher.</li>
  <li>Set the manifest
  <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html"><code>minSdkVersion</code></a> to
  20 or higher, if you want to support devices on versions prior to Android 5.1. For more
  information on backwards compatibility, see
  <a href="#BackwardCompatibility">Maintain Backward-compatibility</a>.</li>
  </li>
  <li>Add or update the following dependencies to your <code>build.gradle</code> file:
<pre>
dependencies {
    ...
    compile 'com.google.android.support:wearable:1.2.0'
    provided 'com.google.android.wearable:wearable:1.0.0'
}
</pre>
<p class="note"><b>Note:</b> The <code>provided</code> dependency ensures that the classes loaded at
run-time to support ambient mode are also available at compile-time.
</p>
</li>
  <li>Add the wearable shared library entry into the wearable app manifest:
<pre>
&lt;application>
  &lt;uses-library android:name="com.google.android.wearable"
                android:required="false" />
  ...
&lt;/application>
</pre>
  </li>
  <li>Add the
  <a href="{@docRoot}reference/android/Manifest.permission.html#WAKE_LOCK"><code>WAKE_LOCK</code></a>
  permission to the handheld and wearable app manifest:
<pre>
&lt;uses-permission android:name="android.permission.WAKE_LOCK" />
</pre>
  </li>
</ul>

<h3 id="CreateActivity">Create an activity that supports ambient mode</h3>

<p>To enable ambient mode in your activity, use the
<a href="{@docRoot}reference/android/support/wearable/activity/WearableActivity.html"><code>WearableActivity</code></a>
class and methods.
</p>

<ol>
  <li>Create an activity that extends
  <a href="{@docRoot}reference/android/support/wearable/activity/WearableActivity.html"><code>WearableActivity</code></a>.</li>
  <li>In the
  <a href="{@docRoot}reference/android/app/Activity.html#onCreate(android.os.Bundle)"><code>onCreate()</code></a>
  method of your activity, call the
  <a href="{@docRoot}reference/android/support/wearable/activity/WearableActivity.html#setAmbientEnabled()"><code>setAmbientEnabled()</code></a>
  method.</li>
</ol>

<p>Enable ambient mode in your activity as follows:</p>

<pre>
public class MainActivity extends WearableActivity {

&#64;Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    <strong>setAmbientEnabled();</strong>
    ...
}
</pre>

<h3 id="EnableDisable">Handle transitions between modes</h3>

<p>If the user does not interact with your app for a period of time while it is displayed, or if
the user covers the screen with their palm, the system switches the activity to ambient mode.
After the app switches to ambient mode, update the activity UI to a more basic layout to reduce
power consumption. You should use a black background with minimal white graphics and text. To
ease a user into the transition from interactive to ambient mode, try to maintain similar placement
of items on the screen. For more information on presenting content on an ambient screen, see the
<a href="{@docRoot}design/wear/watchfaces.html#DisplayModes">Watch Faces for Android Wear</a>
design guide.
</p>

<p class="note"><b>Note:</b> In ambient mode, disable any interactive elements on the
screen, such as buttons. For more information on how to design user interactions for an always-on
app, see the
<a href="{@docRoot}design/wear/structure.html#AlwaysOn">App Structure for Android Wear</a> design
guide.
</p>

<p>When the activity switches to ambient mode, the system calls the
<a href="{@docRoot}reference/android/support/wearable/activity/WearableActivity.html#onEnterAmbient(android.os.Bundle)"><code>onEnterAmbient()</code></a>
method in your wearable activity. The following code snippet shows how to change the text color to
white and disable anti-aliasing after the system switches to ambient mode:
</p>

<pre>
&#64;Override
public void onEnterAmbient(Bundle ambientDetails) {
    super.onEnterAmbient(ambientDetails);

    mStateTextView.setTextColor(Color.WHITE);
    mStateTextView.getPaint().setAntiAlias(false);
}
</pre>

<p>When the user taps the screen or brings up their wrist, the activity switches from ambient mode
to interactive mode. The system calls the
<a href="{@docRoot}reference/android/support/wearable/activity/WearableActivity.html#onExitAmbient()"><code>onExitAmbient()</code></a>
method. Override this method to update the UI layout so that your app displays in a full-color,
interactive state.</p>

<p>The following code snippet shows how to change the text color to green and enable anti-aliasing
when the system switches to interactive mode:</p>

<pre>
&#64;Override
public void onExitAmbient() {
    super.onExitAmbient();

    mStateTextView.setTextColor(Color.GREEN);
    mStateTextView.getPaint().setAntiAlias(true);
}
</pre>

<h2 id="UpdateContent">Update Content in Ambient Mode</h2>

<p>Ambient mode allows you to update the screen with new information for the user, but you must
carefully balance display updates against the battery life. You should strongly consider only
overriding the
<a href="{@docRoot}reference/android/support/wearable/activity/WearableActivity.html#onUpdateAmbient()"><code>onUpdateAmbient()</code></a>
method to update the screen once a minute in ambient mode. If your app requires more frequent
updates, take into consideration that there is a trade-off between battery life and the frequency of
updates. To realize battery savings, updates should be no more than once every 10 seconds. In
practice, however, you should update your app less frequently than that.
</p>

<h3 id="StandardRefresh">Update once a minute</h3>

<p>In order to preserve battery power, most wear apps should not frequently update the screen while
in ambient mode. We recommend designing your app to update the screen once per minute while
in this mode. The system provides a callback method,
<a href="{@docRoot}reference/android/support/wearable/activity/WearableActivity.html#onUpdateAmbient()"><code>onUpdateAmbient()</code></a>,
that allows you to update the screen at this recommended frequency.</p>

<p>To update your app content, override the
<a href="{@docRoot}reference/android/support/wearable/activity/WearableActivity.html#onUpdateAmbient()"><code>onUpdateAmbient()</code></a>
method in your wearable activity:
</p>

<pre>
&#64;Override
public void onUpdateAmbient() {
    super.onUpdateAmbient();

    // Update the content
}
</pre>

<h3 id="CustomRefresh">Update more frequently</h3>

<p>For apps that require more frequent updates, such as a fitness, time-keeping, and travel
information apps, use an
<a href="{@docRoot}reference/android/app/AlarmManager.html"><code>AlarmManager</code></a>
object to wake the processor and update the screen more frequently.</p>

<p>To implement an alarm that updates content more frequently in ambient mode, follow these steps:
</p>

<ol>
  <li>Prepare the alarm manager.</li>
  <li>Set the frequency of the updates.</li>
  <li>Schedule the next update when the activity switches to ambient mode or is currently in ambient
      mode.</li>
  <li>Cancel the alarm when the activity switches to interactive mode or the activity is stopped
  </li>
</ol>

<p class="note"><b>Note:</b> The alarm manager may create new instances of your activity as they are
triggered. To prevent this situation, ensure that your activity is declared with the
<code>android:launchMode="singleInstance"</code> parameter in the manifest.</p>

<p>The following sections describe these steps in detail.</p>

<h4 id="PrepareAlarm">Prepare the alarm manager</h4>

<p>The alarm manager launches a pending intent that updates the screen and schedules the next alarm.
The following example shows how to declare the alarm manager and the pending intent in the
<a href="{@docRoot}reference/android/app/Activity.html#onCreate(android.os.Bundle)"><code>onCreate()</code></a>
method of your activity:</p>

<pre>
private AlarmManager mAmbientStateAlarmManager;
private PendingIntent mAmbientStatePendingIntent;

&#64;Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setAmbientEnabled();

    mAmbientStateAlarmManager =
        (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    Intent ambientStateIntent =
        new Intent(getApplicationContext(), MainActivity.class);

    mAmbientStatePendingIntent = PendingIntent.getActivity(
        getApplicationContext(),
        0,
        ambientStateIntent,
        PendingIntent.FLAG_UPDATE_CURRENT);
    ...
}
</pre>

<p>When the alarm triggers and launches the pending intent, update the screen and schedule the next
alarm by overriding the
<a href="{@docRoot}reference/android/app/Activity.html#onNewIntent(android.content.Intent)"><code>onNewIntent()</code></a>
method:
</p>

<pre>
&#64;Override
public void onNewIntent(Intent intent) {
    super.onNewIntent(intent);

    setIntent(intent);

    // Described in the following section
    refreshDisplayAndSetNextUpdate();
}
</pre>

<h4 id="ScheduleUpdates">Update screen and schedule data updates</h4>

<p>In this example activity, the alarm manager triggers every 20 seconds in ambient mode. When
the timer ticks, the alarm triggers the intent to update the screen and then sets the delay for the
next update.
</p>

<p>The following example shows how to update information on the screen and set the alarm for the
next update:
</p>

<pre>
// Milliseconds between waking processor/screen for updates
private static final long AMBIENT_INTERVAL_MS = TimeUnit.SECONDS.toMillis(20);

private void refreshDisplayAndSetNextUpdate() {

    if (isAmbient()) {
        // Implement data retrieval and update the screen for ambient mode
    } else {
        // Implement data retrieval and update the screen for interactive mode
    }

    long timeMs = System.currentTimeMillis();

    // Schedule a new alarm
    if (isAmbient()) {
        // Calculate the next trigger time
        long delayMs = AMBIENT_INTERVAL_MS - (timeMs % AMBIENT_INTERVAL_MS);
        long triggerTimeMs = timeMs + delayMs;

        mAmbientStateAlarmManager.setExact(
            AlarmManager.RTC_WAKEUP,
            triggerTimeMs,
            mAmbientStatePendingIntent);

    } else {
        // Calculate the next trigger time for interactive mode
    }
}
</pre>

<h4 id="ScheduleNext">Schedule the next alarm</h4>

<p>Schedule the alarm to update the screen when the activity is entering ambient mode or when the
activity is already in ambient mode by overriding the
<a href="{@docRoot}reference/android/support/wearable/activity/WearableActivity.html#onEnterAmbient(android.os.Bundle)"><code>onEnterAmbient()</code></a>
method and the
<a href="{@docRoot}reference/android/support/wearable/activity/WearableActivity.html#onUpdateAmbient()"><code>onUpdateAmbient()</code></a>
method:</p>

<pre>
&#64;Override
public void onEnterAmbient(Bundle ambientDetails) {
    super.onEnterAmbient(ambientDetails);

    refreshDisplayAndSetNextUpdate();
}

&#64;Override
public void onUpdateAmbient() {
    super.onUpdateAmbient();

    refreshDisplayAndSetNextUpdate();
}
</pre>

<p class="note"><b>Note:</b> In this example, the <code>refreshDisplayAndSetNextUpdate()</code>
method is called whenever the screen needs to be updated. For more examples of when to call this
method, see the <a href="{@docRoot}samples/AlwaysOn/index.html">AlwaysOn</a> sample.
</p>

<h4 id="CancelAlarm">Cancel the alarm</h4>

<p>When the device switches to interactive mode, cancel the alarm in the
<a href="{@docRoot}reference/android/support/wearable/activity/WearableActivity.html#onExitAmbient()"><code>onExitAmbient()</code></a>
method:</p>

<pre>
&#64;Override
public void onExitAmbient() {
    super.onExitAmbient();

    mAmbientStateAlarmManager.cancel(mAmbientStatePendingIntent);
}
</pre>

<p>When the user exits or stops your activity, cancel the alarm in the
<a href="{@docRoot}reference/android/app/Activity.html#onDestroy()"><code>onDestroy()</code></a>
method of your activity:</p>

<pre>
&#64;Override
public void onDestroy() {
    mAmbientStateAlarmManager.cancel(mAmbientStatePendingIntent);
    super.onDestroy();
}
</pre>

<h2 id="BackwardCompatibility">Maintain Backward-compatibility</h2>

<p>Activities that support ambient mode automatically fall back to normal activities on Wear devices
that are on Android versions prior to 5.1 (API level 22). No special app code is required to support
devices on these versions of Android. When the device switches to ambient mode, the device returns
to the home screen and exits your activity.</p>

<p>If your app should not be installed or updated on devices with Android versions prior to 5.1,
update your manifest with the following:</p>

<pre>
&lt;uses-library android:name="com.google.android.wearable" android:required="true" />
</pre>