diff options
23 files changed, 1957 insertions, 136 deletions
diff --git a/core/java/android/hardware/camera2/DngCreator.java b/core/java/android/hardware/camera2/DngCreator.java index 45fa15e043e5..1a51acd6c5ec 100644 --- a/core/java/android/hardware/camera2/DngCreator.java +++ b/core/java/android/hardware/camera2/DngCreator.java @@ -119,8 +119,14 @@ public final class DngCreator implements AutoCloseable { captureTime = timestamp / 1000000 + timeOffset; } + // Create this fresh each time since the time zone may change while a long-running application + // is active. + final DateFormat dateTimeStampFormat = + new SimpleDateFormat(TIFF_DATETIME_FORMAT); + dateTimeStampFormat.setTimeZone(TimeZone.getDefault()); + // Format for metadata - String formattedCaptureTime = sDateTimeStampFormat.format(captureTime); + String formattedCaptureTime = dateTimeStampFormat.format(captureTime); nativeInit(characteristics.getNativeCopy(), metadata.getNativeCopy(), formattedCaptureTime); @@ -467,13 +473,10 @@ public final class DngCreator implements AutoCloseable { private static final String GPS_DATE_FORMAT_STR = "yyyy:MM:dd"; private static final String TIFF_DATETIME_FORMAT = "yyyy:MM:dd HH:mm:ss"; private static final DateFormat sExifGPSDateStamp = new SimpleDateFormat(GPS_DATE_FORMAT_STR); - private static final DateFormat sDateTimeStampFormat = - new SimpleDateFormat(TIFF_DATETIME_FORMAT); private final Calendar mGPSTimeStampCalendar = Calendar .getInstance(TimeZone.getTimeZone("UTC")); static { - sDateTimeStampFormat.setTimeZone(TimeZone.getDefault()); sExifGPSDateStamp.setTimeZone(TimeZone.getTimeZone("UTC")); } diff --git a/docs/html/guide/topics/ui/drag-drop.jd b/docs/html/guide/topics/ui/drag-drop.jd index 4a87cd4938cb..8e4297f8ce1b 100644 --- a/docs/html/guide/topics/ui/drag-drop.jd +++ b/docs/html/guide/topics/ui/drag-drop.jd @@ -321,7 +321,7 @@ DraggableDot.java</a> in <a href="{@docRoot}resources/samples/ApiDemos/index.htm <p> If the listener wants to continue receiving drag events for this operation, it must return boolean <code>true</code> to the system. - <\p> + </p> </td> </tr> <tr> diff --git a/docs/html/guide/topics/ui/multi-window.jd b/docs/html/guide/topics/ui/multi-window.jd index dede557ecc9a..bab582dd0b8c 100644 --- a/docs/html/guide/topics/ui/multi-window.jd +++ b/docs/html/guide/topics/ui/multi-window.jd @@ -215,7 +215,7 @@ android:resizeableActivity=["true" | "false"] Set this attribute in your manifest's <a href= "{@docRoot}guide/topics/manifest/activity-element"><code><activity></code></a> node to indicate whether the activity supports <a href= - "{@docRoot}training/tv/playback/picture-in-picture.jd">Picture-in-Picture</a> + "{@docRoot}training/tv/playback/picture-in-picture.html">Picture-in-Picture</a> display. This attribute is ignored if <code>android:resizeableActivity</code> is false. </p> diff --git a/docs/html/training/monitoring-device-state/battery-monitoring.jd b/docs/html/training/monitoring-device-state/battery-monitoring.jd index db75aaf1f899..bab9c9cf6baf 100644 --- a/docs/html/training/monitoring-device-state/battery-monitoring.jd +++ b/docs/html/training/monitoring-device-state/battery-monitoring.jd @@ -141,10 +141,11 @@ receiver. The receiver is triggered whenever the device battery becomes low or e condition by listening for {@link android.content.Intent#ACTION_BATTERY_LOW} and {@link android.content.Intent#ACTION_BATTERY_OKAY}.</p> -<pre><receiver android:name=".BatteryLevelReceiver"> -<intent-filter> - <action android:name="android.intent.action.ACTION_BATTERY_LOW"/> - <action android:name="android.intent.action.ACTION_BATTERY_OKAY"/> +<pre> +<receiver android:name=".BatteryLevelReceiver"> + <intent-filter> + <action android:name="android.intent.action.BATTERY_LOW"/> + <action android:name="android.intent.action.BATTERY_OKAY"/> </intent-filter> </receiver></pre> diff --git a/docs/html/wear/images/partners/mkors.png b/docs/html/wear/images/partners/mkors.png Binary files differnew file mode 100644 index 000000000000..2f1e8ec3aad4 --- /dev/null +++ b/docs/html/wear/images/partners/mkors.png diff --git a/docs/html/wear/images/partners/nixon.png b/docs/html/wear/images/partners/nixon.png Binary files differnew file mode 100644 index 000000000000..8674da27974d --- /dev/null +++ b/docs/html/wear/images/partners/nixon.png diff --git a/docs/html/wear/images/partners/polar.png b/docs/html/wear/images/partners/polar.png Binary files differnew file mode 100644 index 000000000000..2faeb063e1ff --- /dev/null +++ b/docs/html/wear/images/partners/polar.png diff --git a/docs/html/wear/index.jd b/docs/html/wear/index.jd index f9bdef5ce6ce..1eb08bec612c 100644 --- a/docs/html/wear/index.jd +++ b/docs/html/wear/index.jd @@ -267,6 +267,9 @@ nonavpage=true <div class="col-4"> <img src="/wear/images/partners/mips.png" alt="MIPS"> </div> + <div class="col-4"> + <img src="/wear/images/partners/mkors.png" alt=Michael Kors"> + </div> <div class="col-4"> <img src="/wear/images/partners/mobvoi.png" alt="Mobvoi"> </div> @@ -277,6 +280,12 @@ nonavpage=true <img src="/wear/images/partners/nb.png" alt="New Balance"> </div> <div class="col-4"> + <img src="/wear/images/partners/nixon.png" alt="Nixon"> + </div> + <div class="col-4"> + <img src="/wear/images/partners/polar.png" alt="Polar"> + </div> + <div class="col-4"> <img src="/wear/images/partners/qualcomm.png" alt="Qualcomm"> </div> <div class="col-4"> diff --git a/docs/html/wear/preview/features/app-distribution.jd b/docs/html/wear/preview/features/app-distribution.jd new file mode 100644 index 000000000000..319efa6b6554 --- /dev/null +++ b/docs/html/wear/preview/features/app-distribution.jd @@ -0,0 +1,325 @@ +page.title=App Distribution +meta.keywords="wear-preview" +page.tags="wear-preview" +page.image=images/cards/card-n-sdk_2x.png +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + +<h2>In this document</h2> + + <ul> + <li><a href="#publish">Publish Your APKs</a></li> + <li><a href="#targeting">Setting Up Targeting for a Watch</a></li> + <li><a href="#console">Using the Play Developer Console</a></li> + </ul> + +</div> +</div> + + <p> + With Android Wear 2.0, a user can visit the Play Store on a watch and + download a Wear app directly to the watch. + </p> + + <p> + Generally, a Wear 2.0 app in the Play Store needs + a minimum and target API level of 24 or higher in + the Android manifest file. The minimum SDK level can be 23 + only if you are using the same APK + for Wear 1.0 and 2.0 (and thus have an embedded Wear 1.0 APK). + </p> + + <h2 id="publish"> + Publish Your APKs + </h2> + + <p> + To make your app appear in the on-watch Play Store, upload + the watch APK in the Play Developer Console just as you would any other + APK. If you only have a watch APK and no phone APK, no other steps + are required. + </p> + + <p> + If you have a phone APK in addition to a watch APK, you must use the + <a href="https://developer.android.com/google/play/publishing/multiple-apks.html">Multi-APK delivery method</a>. + </p> + + <p> + <a href= + "https://developer.android.com/training/permissions/requesting.html">Run-time + permissions</a> are required. + </p> + + <p> + Also see + <a href="{@docRoot}wear/preview/features/standalone-apps.html"> + Standalone Apps</a>. + </p> + + <h3> + Distribution to Wear 2.0 watches + </h3> + + <p> + If you only want your app to be distributed to Wear 2.0 watches, + it is unnecessary to embed the watch APK inside the the phone APK. + </p> + + <p> + If you want your app to + be distributed to Wear 1.0 watches, you need to embed the + watch APK inside the phone APK, as described directly below. + </p> + + <h3> + Distribution to Wear 1.0 and 2.0 watches + </h3> + + <p> + If you are already distributing your app to Wear 1.0 watches, + follow these steps: + </p> + + <ol> + <li>Provide a Wear 2.0 (standalone) version of your watch APK that can be made + available in the Play Store on Wear. + </li> + + <li>Continue embedding a Wear 1.0 APK in your phone APK, + for use by watches that do not have Wear 2.0. + </li> + </ol> + + <h3> + Specifying a version code + </h3> + + <p> + To ensure that a standalone APK acts as an upgrade to an embedded Wear APK, the + standalone Wear APK's <a href= + "https://developer.android.com/google/play/publishing/multiple-apks.html#VersionCodes"> + version code</a> generally should be higher than the embedded Wear APK's version code. + (A phone APK's version code scheme can be independent from that of a watch + APK, although they must be unique.) However, the version codes + of the standalone APK and the embedded Wear APK can be the same if + the APKs are equivalent. If the APKs are not equivalent, + but the version code is the same, then when a watch updates from Wear 1.0 + to 2.0, the watch may get the new APK only after waiting for a + longer-than-expected period of time. + </p> + + <p> + Note that it currently is not possible to create a single APK that works + on a phone and watch. + </p> + + <h3> + Support in the Gradle file + </h3> + + <p> + If you have a Wear app that is intended for both Wear 1.0 and Wear 2.0, + consider using <a href= + "https://developer.android.com/studio/build/build-variants.html#product-flavors"> + product flavors</a>. For example, + if you want to target both SDK version 23 and version 24, + update your Wear module's <code>build.gradle</code> file to include + the following if an existing embedded app has a minimum SDK version of 23: + </p> + +<pre> +android { + ... + defaultConfig + { + // This is the minSdkVersion of the Wear 1.0 embedded app + minSdkVersion 23 + ... + } + buildTypes {...} + productFlavors { + wear1 { + // Use the defaultConfig value + } + wear2 { + minSdkVersion 24 + } + } +</pre> + + <p> + Then update your phone module’s <code>build.gradle</code> file, replacing + <code>wearApp</code> as follows: + </p> + +<pre> +dependencies { + ... + wearApp project(path: ':wearable', configuration: 'wear1Release') +} +</pre> + + <p> + A <a href= + "https://developer.android.com/studio/build/build-variants.html#product-flavors"> + build variant</a> is a combination of the product flavor and build type. + In Android Studio, select the appropriate build variant when + debugging or publishing your app. For example, if <code>wear2</code> is a + product flavor, select <strong>wear2Release</strong> as the + release build variant. + </p> + + <p> + For purposes of code that is Wear 2.0-specific or Wear 1.0-specific, + consider <a href= + "https://developer.android.com/studio/build/build-variants.html#sourcesets"> + source sets for build variants</a>. + </p> + + + <h2 id="targeting"> + Setting Up Targeting for a Watch + </h2> + + <p> + In your Android Manifest file, you must specify the following feature + restriction: the <code>uses-feature</code> element is set to + <code>android.hardware.type.watch</code>. Do not set + the <code>required</code> attribute to <code>false</code>. + A single APK for Wear and non-Wear devices presently is not supported. + </p> + + <p> + Thus, if an APK has the following setting, Google Play provides the APK + to watches only: + </p> + +<pre> +<manifest package="com.example.standalone" + xmlns:android="http://schemas.android.com/apk/res/android"> + <uses-feature + android:name="android.hardware.type.watch" + ... +</manifest> +</pre> + + <p> + The <code>android.hardware.type.watch</code> setting above can be + combined with other criteria such as SDK version, screen resolution, and + CPU architecture. Thus, different Wear APKs can target different hardware + configurations. + </p> + + <h2 id="console"> + Using the Play Developer Console + </h2> + + <p> + Below is an introduction to <a href= + "https://support.google.com/googleplay/android-developer/answer/113469">uploading</a> + a standalone Wear APK to an application listing using the Play Developer + Console. + </p> + + <p> + If your app supports both Wear 1.0 and Wear 2.0, continue embedding the + Wear 1.0 APK (minimum SDK version of 20, 21, or 22, or 23) in the phone + APK and upload the phone APK. In addition, upload your standalone Wear + 2.0 APK (which has a minimum SDK version of 24). + </p> + + <p> + Also see <a href= + "https://developer.android.com/google/play/publishing/multiple-apks.html"> + Multiple APK Support</a> and <a href= + "https://developer.android.com/distribute/googleplay/developer-console.html#manage"> + Manage Your App</a>. + Before uploading an APK as described below, the APK + must be <a href= + "https://developer.android.com/studio/publish/app-signing.html#release-mode"> + signed</a>. + </p> + + <h3 id="uploading-apk"> + Uploading your APK + </h3> + + <p> + Go to the <a href="https://play.google.com/apps/publish">Play Developer + Console</a>, navigate to your application listing, and select + <strong>APK</strong> in the left-navigation panel. An APK screen similar to + the following is displayed: + </p> + <img src="../images/apk-tabs.png" width="" alt="alt_text"> + + <p> + You may need to use advanced mode for uploads, as follows: + </p> + + <ul> + <li>Advanced mode is unnecessary if you only have a Wear 2.0 app and no + phone app. Instead of advanced mode, use simple mode.</li> + + <li>Use advanced mode if you support Wear 1.0 or have a phone app.</li> + </ul> + + <p> + Therefore, on the above APK screen, to determine whether to click + the <strong>Switch to advanced mode</strong> + button, consider the following: + </p> + + <ul> + <li>If your app does not support Wear 1.0, and only has a watch APK, + upload it using simple mode. + </li> + + <li>If your app does not support Wear 1.0 and has both a watch APK and a + phone APK, click <strong>Switch to advanced mode</strong> + to upload the watch and phone APKs. + </li> + </ul> + + <p> + See <a href= + "https://developer.android.com/google/play/publishing/multiple-apks.html#SimpleAndAdvanced"> + Simple mode and advanced mode</a> for more information about toggling + between modes. + </p> + + <p> + Select the appropriate tab (<strong>Production</strong>, <strong>Beta + Testing</strong>, or <strong>Alpha Testing</strong>) for your upload. + Then click + the <strong>Upload New APK</strong> button and select your standalone + Wear APK for upload. + </p> + + <h3> + Reviewing and publishing + </h3> + + <p> + After you upload your standalone Wear APK and scroll down the resulting + page, the APK is shown in the <strong>Current APK</strong> table, with a + version number, in a similar way to the following: + </p> + <img src="../images/current-apk.png" width="" alt="alt_text"> + + <p> + Finally, in the <strong>Current APK</strong> table above, click the line + with the <strong>Version</strong> to review the APK. The <strong>APK + Details</strong> panel is displayed. You can verify, for example, that + the number in the <strong>Supported Android Devices</strong> line is far + fewer than the number would be for a typical phone APK: + </p> + <img src="../images/apk-details.png" width="" alt="alt_text"> + + <p> + When you are ready, <a href= + "https://support.google.com/googleplay/android-developer/answer/6334282">publish</a> + your app. + </p> diff --git a/docs/html/wear/preview/features/bridger.jd b/docs/html/wear/preview/features/bridger.jd index b7be093ed298..2d879caeccc2 100644 --- a/docs/html/wear/preview/features/bridger.jd +++ b/docs/html/wear/preview/features/bridger.jd @@ -6,19 +6,26 @@ page.tags="wear-preview" <div id="qv-wrapper"> <div id="qv"> - <ol> + <ul> <li> <a href= - "#preventing_bridging_with_the_bridging_mode_feature">Preventing - Bridging with the Bridging Mode Feature</a> + "#using-an-entry-in-the-manifest-file">Specifying a Bridging Configuration in the Manifest File</a> </li> <li> <a href= - "#using_a_dismissal_id_to_sync_notification_dismissals">Using a - Dismissal ID to Sync Notification Dismissals</a> + "#specifying-a-bridging-configuration-at-runtime">Specifying a Bridging Configuration at Runtime</a> </li> - </ol> + <li> + <a href= + "#existing-method-of-preventing-bridging">Existing Method of Preventing Bridging</a> + </li> + + <li> + <a href= + "#using_a_dismissal_id_to_sync_notification_dismissals">Using a Dismissal ID to Sync Notification Dismissals</a> + </li> + </ul> </div> </div> @@ -27,19 +34,20 @@ page.tags="wear-preview" "{@docRoot}training/wearables/notifications/index.html">are bridged (shared)</a> from an app on a companion phone to the watch. If you build a standalone watch app and have a companion phone app, they may duplicate - notifications. The Android Wear 2.0 Preview includes a Bridging mode - feature to handle this problem of repeated notifications. + notifications. The Android Wear 2.0 Preview includes + features to handle this problem of repeated notifications. </p> <p> - With the Android Wear 2.0 Preview, developers can change the - behavior of notifications with the following: + With the Android Wear 2.0 Preview, developers can change the behavior of + notifications with one or more of the following: </p> <ul> - <li>Specifying in the standalone app's Android manifest file that - notifications from the corresponding phone app should not be - bridged to the watch + <li>Specifying a bridging configuration in the manifest file + </li> + + <li>Specifying a bridging configuration at runtime </li> <li>Setting a dismissal ID so notification dismissals are synced across @@ -47,43 +55,201 @@ page.tags="wear-preview" </li> </ul> - <h2 id="preventing_bridging_with_the_bridging_mode_feature"> - Preventing Bridging with the Bridging Mode Feature + <h2 id="using-an-entry-in-the-manifest-file"> + Specifying a Bridging Configuration in the Manifest File </h2> <p> - To prevent bridging of notifications from a phone app, you can use an + An app's Android manifest file can indicate that notifications from the + corresponding phone app should not be bridged to the watch. Specifically, + to prevent bridging of notifications from a phone app, you can use a + <code><meta-data></code> entry in the manifest file of the watch app (e.g. the standalone watch app), as follows: </p> - <pre> +<pre> com.google.android.wearable.notificationBridgeMode - </pre> +</pre> <p> Setting that entry to <code>NO_BRIDGING</code> will prevent bridging: </p> - <pre> -<meta-data android:name="com.google.android.wearable.notificationBridgeMode" - android:value="NO_BRIDGING" /> +<pre> +<meta-data android:name="com.google.android.wearable.notificationBridgeMode" + android:value="NO_BRIDGING" /> </pre> + <p> - The default bridging behavior occurs if you do not include the entry or + The default bridging behavior occurs if you do not + include the <code><meta-data></code> entry or if you specify a value of <code>BRIDGING</code> instead of <code>NO_BRIDGING</code>. </p> - <h3 id="existing_method_of_preventing_bridging"> - Existing method of preventing bridging + <p> + For an existing app, if you are using + Google Cloud Messaging (GCM) or Firebase Cloud + Messaging (FCM) to send notification alerts to devices, + you may already have disabled bridging in case a phone is not + connected at the time of receiving an alert. + In this case, you may still want to dismiss the notification + across other devices when it is dismissed in a watch app. + </p> + + <p> + The bridging configuration that is set in the manifest takes effect as + soon as a watch app is installed. + </p> + + <h2 id="specifying-a-bridging-configuration-at-runtime"> + Specifying a Bridging Configuration at Runtime + </h2> + + <p> + This section describes how to specify a bridging configuration at runtime + using the <code>BridgingManager</code> class + <code>(android.support.wearable.notifications.BridgingManager)</code>. + </p> + + <p> + You can set a bridging mode, and optionally set tags for notifications + that are exempt from the bridging mode, using a + <code>BridgingManager</code> object. Specifically, create a + <code>BridgingConfig</code> object and set it as shown in this section, + optionally using the <code>setBridgingEnabled</code> method. If you + specify a bridging configuration at runtime, then if the + <code>setBridgingEnabled</code> method is not set, bridging is enabled by + default. + </p> + + <p> + Specifying a bridging configuration at runtime overrides a + bridging-related setting in the Android manifest file. + </p> + + <h3 id="disable-bridging-for-all-notifications"> + Disable bridging for all notifications + </h3> + + <p> + You can use the <code>setBridgingEnabled</code> method, as follows: + </p> + +<pre> +BridgingManager.setConfig(context, + new BridgingConfig.Builder(context) + .setBridgingEnabled(false) + .build()); +</pre> + <p> + If the above setter is not called, the bridging mode defaults to true. + Here is an example of setting tags without using the + <code>setBridgingEnabled</code> method, excluding notifications with a + tag of <code>foo</code> or <code>bar</code>: + </p> + +<pre> +BridgingManager.setConfig(context, + new BridgingConfig.Builder(context) + .addExcludedTag("foo") + .addExcludedTag("bar") + .build()); +</pre> + <h3 id="exempt-notifications-that-are-tagged"> + Exempt notifications that are tagged </h3> <p> + You can disable bridging for all notifications except those with certain + tags. + </p> + + <p> + For example, you can disable bridging, except for notifications tagged as + <code>foo</code> or <code>bar,</code> with the following: + </p> + +<pre> +BridgingManager.setConfig(context, + new BridgingConfig.Builder(context) + .setBridgingEnabled(false) + .addExcludedTag("foo") + .addExcludedTag("bar") + .build()); +</pre> + + <p> + As another example, you can disable bridging for all notifications except + for notifications tagged as <code>foo</code>, <code>bar</code> or + <code>baz</code>. + </p> + + <pre> +BridgingManager.setConfig(context, + new BridgingConfig.Builder(context) + .setBridgingEnabled(false) + .addExcludedTags(Arrays.asList("foo", "bar", "baz")) + .build()); +</pre> + <h3 id="enable-bridging-except-for-notifications-with-certain-tags"> + Enable bridging except for notifications with certain tags + </h3> + + <p> + You can enable bridging for all notifications except those with certain + tags. + </p> + + <p> + For example, you can enable bridging for all notifications, except for + notifications tagged as <code>foo</code> or <code>bar</code>, with the + following: + </p> + +<pre> +BridgingManager.setConfig(context, + new BridgingConfig.Builder(context) + .setBridgingEnabled(true) + .addExcludedTag("foo") + .addExcludedTag("bar") + .build()); +</pre> + + <h3 id="setting-a-bridge-tag"> + Setting a bridge tag + </h3> + + <p> + A bridge tag can be set on a notification by calling the + <code>setNotificationBridgeTag</code> method as follows: + </p> + +<pre> +BridgingManager.setNotificationBridgeTag(<NotificationCompat.Builder>, <String>); +</pre> + + <p> + For example: + </p> + +<pre> +NotificationCompat.Builder builder = new NotificationCompat.Builder(context) +<set other fields>; +BridgingManager.setNotificationBridgeTag(builder, "foo"); +Notification notification = builder.build(); +</pre> + + <h2 id="existing-method-of-preventing-bridging"> + Existing Method of Preventing Bridging + </h2> + + <p> An existing way to prevent bridging is with the <code>Notification.Builder</code> class; specify <code>true</code> in the <a href= - "{@docRoot}reference/android/app/Notification.Builder.html#setLocalOnly(boolean)"> + "http://developer.android.com/reference/android/app/Notification.Builder.html#setLocalOnly(boolean)"> setLocalOnly</a> method. </p> @@ -95,12 +261,6 @@ com.google.android.wearable.notificationBridgeMode the watch app may not be installed on all of them. </p> - <p> - Thus, if bridging should be prevented when the watch app - is installed, use the <a href= - "#preventing_bridging_with_the_bridging_mode_feature">Bridging mode - feature</a>. - </p> <h2 id="using_a_dismissal_id_to_sync_notification_dismissals"> Using a Dismissal ID to Sync Notification Dismissals @@ -110,7 +270,7 @@ com.google.android.wearable.notificationBridgeMode If you prevent bridging with the Bridging mode feature, dismissals (cancellations) of notifications are not synced across a user's devices. However, the following methods of the <a href= - "{@docRoot}reference/android/support/v4/app/NotificationCompat.WearableExtender.html"> + "http://developer.android.com/reference/android/support/v4/app/NotificationCompat.WearableExtender.html"> NotificationCompat.WearableExtender</a> class enable you to use dismissal IDs: </p> @@ -118,7 +278,7 @@ com.google.android.wearable.notificationBridgeMode <pre> public WearableExtender setDismissalId(String dismissalId) public String getDismissalId() - </pre> +</pre> <p> To enable a dismissal to be synced, use the <code>setDismissalId()</code> method. For each notification, pass a globally unique ID, as a string, @@ -135,12 +295,12 @@ public String getDismissalId() <pre> NotificationCompat.WearableExtender wearableExtender = -new NotificationCompat.WearableExtender().setDismissalId(“abc123”); +new NotificationCompat.WearableExtender().setDismissalId("abc123"); Notification notification = new NotificationCompat.Builder(context) <set other fields> .extend(wearableExtender) .build(); - </pre> +</pre> <p> Dismissal IDs work if a watch is paired to an Android phone, but not if a watch is paired to an iPhone. diff --git a/docs/html/wear/preview/features/complications.jd b/docs/html/wear/preview/features/complications.jd index 3334cb79b143..c8661188eb0a 100644 --- a/docs/html/wear/preview/features/complications.jd +++ b/docs/html/wear/preview/features/complications.jd @@ -13,6 +13,13 @@ page.image=/wear/preview/images/complications-main-image.png Complications to a Watch Face</a> </li> <li> + <a href="#permissions-for-complication-data">Permissions + for Complication Data</a> + </li> + <li> + <a href="#default-providers">Default Providers for Watch Faces</a> + </li> + <li> <a href="#exposing_data_to_complications">Exposing Data to Complications</a> </li> @@ -27,12 +34,14 @@ page.image=/wear/preview/images/complications-main-image.png <a href="#api_additions">API Additions</a> </li> </ol> + <h2>See Also</h2> <ol> <li><a class="external-link" href="https://github.com/googlesamples/android-WatchFace">Watch Face sample app with complications</a></li> </ol> + </div> </div> @@ -56,9 +65,12 @@ page.image=/wear/preview/images/complications-main-image.png </p> <p> - Along with reviewing this page, download the Android Wear 2.0 Preview - Reference (see the Complications API <a href= - "#api_additions">additions</a>) and review the Javadoc for complications. + You can review the Javadoc for complications by downloading + the Android Wear 2.0 Preview + Reference. Also see the <a href="#api_additions">API additions for + complications</a> and the + <a href="https://developer.android.com/wear/preview/behavior-changes.html"> + behavior changes</a> for Wear 2.0. </p> <p> @@ -117,8 +129,8 @@ page.image=/wear/preview/images/complications-main-image.png <code>WatchFaceService.Engine</code> class, with a list of watch face complication IDs. A watch face creates these IDs to uniquely identify slots on the watch face where complications can appear, and passes them - to the <code>createProviderChooserIntent</code> method (of the - <code>ProviderChooserIntent</code> class) to allow the user to decide + to the <code>createProviderChooserIntent</code> method + to allow the user to decide which complication should go in which slot. </p> @@ -186,6 +198,406 @@ page.image=/wear/preview/images/complications-main-image.png where possible. </p> + <h2 id="permissions-for-complication-data"> + Permissions for Complication Data + </h2> + + <p> + A watch face must have the following <a href= + "https://developer.android.com/training/permissions/requesting.html">permission</a> + to receive complication data and open the provider chooser: + </p> + +<pre> +com.google.android.wearable.permission.RECEIVE_COMPLICATION_DATA +</pre> + + <h3 id="opening-the-provider-chooser"> + Opening the provider chooser + </h3> + + <p> + A watch face that was not granted the above permission will be unable to + start the provider chooser. + </p> + + <p> + To make it easier to request the permission and start the chooser, the + <code>ComplicationHelperActivity</code> class is available in the + wearable support library. This class should be used instead of + <code>ProviderChooserIntent</code> to start the chooser in almost all + cases. + </p> + + <h4 id="requesting-the-necessary-permission"> + Requesting the necessary permission + </h4> + + <p> + To use <code>ComplicationHelperActivity</code>, add it to the watch face + in the <a href= + "https://developer.android.com/guide/topics/manifest/manifest-intro.html"> + manifest file</a>: + </p> + +<pre> +<activity android:name="android.support.wearable.complications.ComplicationHelperActivity"/> +</pre> + + <p> + To start the provider chooser, call the + <code>ComplicationHelperActivity.createProviderChooserHelperIntent</code> + method, to obtain an intent. + </p> + + <p> + The new intent can be used with either <code>startActivity</code> or + <code>startActivityForResult</code> to launch the chooser. + </p> + + <p> + Here is an example of using the new intent with + <code>startActivityForResult</code>: + </p> + + <pre> +startActivityForResult( + ComplicationHelperActivity.createProviderChooserHelperIntent( + getActivity(), + watchFace, + complicationId, + ComplicationData.TYPE_LARGE_IMAGE), + PROVIDER_CHOOSER_REQUEST_CODE); +</pre> + <p> + When the helper activity is started, the helper activity checks if the + permission was granted. If the permission was not granted, the helper + activity makes a runtime permission request. If the permission request is + accepted (or is unneeded), the provider chooser is shown. + </p> + + <p> + If <code>startActivityForResult</code> was used with the intent, the + result delivered back to the calling Activity will have a result code of + <code>RESULT_OK</code> if a provider was successfully set, or a result + code of <code>RESULT_CANCELLED</code> if no provider was set. + </p> + + <p> + In the case where a provider was set, + <code>ComplicationProviderInfo</code> for the chosen provider will be + included in the data intent of the result, as an extra with the key + <code>ProviderChooserIntent#EXTRA_PROVIDER_INFO</code>. + </p> + + <h3 id="receiving-complication-data"> + Receiving complication data + </h3> + + <p> + In general, watch faces need the above permission in order to receive + complication data, but there are some exceptions. Specifically, a watch + face can only receive data from a provider if one of the following is + true: + </p> + + <ul> + <li>The provider is a "safe" system provider, + </li> + + <li>The provider and watch face are from the same app, + </li> + + <li>The provider whitelists the watch face as a "safe" watch face, or + </li> + + <li>The watch face has the permission + </li> + </ul> + + <h4 id="lack-of-appropriate-permission"> + Lack of appropriate permission + </h4> + + <p> + If none of the above is true, then when <code>ComplicationData</code> + normally would be sent by a provider to a watch face, the system instead + sends data of the type <code>TYPE_NO_PERMISSION</code>. This type + includes an icon (an exclamation mark) and short text ("--") to allow it + to be rendered as if it were of the short text type or icon type, for + convenience. + </p> + + <p> + When a watch face receives data of <code>TYPE_NO_PERMISSION</code>, the + watch face should render this appropriately, so the user can see that + action is needed for the complication to work. If possible, a tap on a + complication in this state should launch a permission request. This can + be done using + <code>ComplicationHelperActivity.createPermissionRequestHelperIntent</code>, + if the helper activity was added to the watch face app. + </p> + + <p> + If a user accepts the permission request created by the helper activity, + updates are requested for all the active complications on the watch face + automatically, allowing the <code>TYPE_NO_PERMISSION</code> data to be + replaced by real data. + </p> + + <h4 id="safe-providers"> + Safe providers + </h4> + + <p> + Some system providers are considered "safe", because they only supply + information that the watch face already could obtain itself. + </p> + + <p> + These providers are listed in the new <code>SystemProviders</code> class + in the wearable support library. Whether a system provider is safe is + stated in the Javadoc (in the Android Wear 2.0 Preview Reference). Also + see <a href="#system-providers">System providers</a> for a list. + </p> + + <h4 id="provider-specified-safe-watch-faces"> + Provider-specified safe watch faces + </h4> + + <p> + Providers can specify certain watch faces as "safe" to receive their + data. This is intended to be used only when the watch face will attempt + to use the provider as a default (see below), + and the provider trusts the watch face app. + </p> + + <p> + To declare watch faces as safe, the provider adds metadata with a key of + <code>android.support.wearable.complications.SAFE_WATCH_FACES</code>. The + metadata value should be a comma-separated list (whitespace is ignored). + Entries in the list can be component names (of + <code>WatchFaceServices</code>, given as if + <code>ComponentName.flattenToString()</code> had been called), or they + can be package names (of apps, in which case every watch face within a + specified app is considered safe). + </p> + + <p> + For example: + </p> + +<pre> +<meta-data + android:name="android.support.wearable.complications.SAFE_WATCH_FACES" + android:value=" + com.app.watchface/com.app.watchface.MyWatchFaceService, + com.anotherapp.anotherwatchface/com.something.WatchFaceService, + com.something.text + "/> +</pre> + + <h2 id="default-providers"> + Default Providers for Watch Faces + </h2> + + <p> + Watch faces can specify default providers that are used until a user + selects a provider. + </p> + + <h3 id="setting-default-providers"> + Setting default providers + </h3> + + <p> + Set default providers using the + <code>setDefaultComplicationProvider</code> method in + <code>WatchFaceService.Engine</code>. This method may be called at any + time, but it does nothing if the user already chose a provider for the + given complication. + </p> + + <h3 id="safe-providers2"> + Safe providers + </h3> + + <p> + For most providers, the <code>RECEIVE_COMPLICATION_DATA</code> permission + must be granted to a watch face before data can flow to it. However, some + system providers are considered "safe", and do not require the watch face + to have the permission for data to be sent (see <a href= + "#safe-providers">Safe Providers</a> and <a href= + "#system-providers">System providers</a>). These providers may be + preferable to use as defaults, as they can supply data immediately. + </p> + + <p> + Alternatively, if a watch face has a partnership with a certain provider + and wishes to use it as a default, it can request that the provider list + it as a safe watch face (see <a href= + "#provider-specified-safe-watch-faces">Provider-specified safe watch + faces</a>). + </p> + + <h3 id="system-providers"> + System providers + </h3> + + <p> + The system includes providers that can be used as defaults. These are + listed in the <code>SystemProviders</code> class in the wearable support + library. + </p> + + <p> + The following table has details about providers that are considered safe: + </p> + + <table> + <tr> + <th> + Method name in the SystemProviders class + </th> + <th> + Safety + </th> + <th> + Can be the default + </th> + <th> + Notes + </th> + </tr> + + <tr> + <td> + <code>dateProvider()</code> + </td> + <td> + Yes + </td> + <td> + Yes + </td> + <td> + The standard system date provider. Tapping opens the standard Agenda + app. + </td> + </tr> + + <tr> + <td> + <code>currentTimeProvider()</code> + </td> + <td> + Yes + </td> + <td> + Yes + </td> + <td> + The standard system "time and date" provider. No tap action. + </td> + </tr> + + <tr> + <td> + <code>batteryProvider()</code> + </td> + <td> + Yes + </td> + <td> + Yes + </td> + <td> + The standard system battery provider. No tap action. + </td> + </tr> + + <tr> + <td> + <code>stepCountProvider()</code> + </td> + <td> + Yes + </td> + <td> + Yes + </td> + <td> + Shows a daily total of steps, as reported by + <code>readDailyTotal</code>. + </td> + </tr> + + <tr> + <td> + <code>unreadCountProvider()</code> + </td> + <td> + Yes + </td> + <td> + Yes + </td> + <td> + Shows the number of unread notifications in the stream. + </td> + </tr> + + <tr> + <td> + <code>worldClockProvider()</code> + </td> + <td> + Yes + </td> + <td> + Yes + </td> + <td> + Will default to London or New York. Can be tapped to change the time + zone. + </td> + </tr> + + <tr> + <td> + <code>appsProvider()</code> + </td> + <td> + Yes + </td> + <td> + Yes + </td> + <td> + Will show an "apps" icon at first, which can be tapped to choose an + app. + </td> + </tr> + + <tr> + <td> + <code>nextEventProvider()</code> + </td> + <td> + No + </td> + <td> + Yes (but not a safe provider) + </td> + <td> + The standard system "next event" provider. Tapping opens + the standard Agenda app. + </p> + </td> + </tr> + </table> + + <h2 id="exposing_data_to_complications"> Exposing Data to Complications </h2> @@ -203,6 +615,11 @@ page.image=/wear/preview/images/complications-main-image.png be used to send data back to the system. </p> + <p class="note"><strong>Note:</strong> When you provide data as a + complication data provider, the watch face receives the raw values + you send so it can draw them on the watch face. + </p> + <p> In your app's manifest, declare the service and add an intent filter for the following: @@ -210,7 +627,8 @@ page.image=/wear/preview/images/complications-main-image.png <pre> android.support.wearable.complications.ACTION_COMPLICATION_UPDATE_REQUEST -</pre> + </pre> + <p> The service's manifest entry should also include an <code>android:icon</code> attribute. The provided icon should be a @@ -227,6 +645,21 @@ android.support.wearable.complications.ACTION_COMPLICATION_UPDATE_REQUEST <a href="#api_additions">API Additions</a>). </p> + <p> + Additionally, a permission for provider services ensures that only the Android Wear system + can bind to provider services. Only the Android Wear system can have this + permission. + </p> + + <p> + Provider services should add the following to their service declarations + in the manifest: + </p> + +<pre> +android:permission="com.google.android.wearable.permission.BIND_COMPLICATION_PROVIDER" +</pre> + <h3 id="update_period"> Update period </h3> @@ -371,6 +804,11 @@ METADATA_KEY_PROVIDER_CONFIG_ACTION <p> The following table describes the types and fields of the <code>ComplicationData</code> object. + If a watch face requests a field that is invalid for a complication type, + a default value for the field is returned. + For example, if a watch face tries to access a <code>Long text</code> + field in a <code>SHORT_TEXT</code> type, the default value for the + <code>Long text</code> field is returned. </p> <table> @@ -489,56 +927,80 @@ METADATA_KEY_PROVIDER_CONFIG_ACTION </table> <p> - In addition, the following two types have no fields. These two types may - be sent for any complication slot and do not need to be included in a - list of supported types: + In addition, the types in the table below are for empty data and + may be sent for any complication slot. These types have no fields + and do not need to be included in a + list of supported types. These types enable watch + faces to differentiate among the following three cases: + </p> + + <ul> + <li>No provider was chosen + </li> + + <li>The user has selected "empty" for a slot + </li> + + <li>A provider has no data to send + </li> + </ul> + + <p> + Providers should not send <code>TYPE_EMPTY</code> in response to + update requests. Providers should send <code>TYPE_NO_DATA</code> instead. + </p> + + <p> + Details on the complication types for "empty" data are in the + following table: </p> <table> <tr> - <th style="width:175px"> - Type - </th> - <th style="width:175px"> - Required fields + <th>Complication type </th> - <th style="width:175px"> - Optional fields - </th> - <th> - Notes + <th>Description </th> </tr> <tr> <td> - NOT_CONFIGURED - </td> - <td> - None - </td> - <td> - None + <code>TYPE_NOT_CONFIGURED</code> </td> <td> - Sent when a provider has not yet been chosen for a complication. + Sent by the system when a complication is activated but the user has + not selected a provider, and no default was set. + <p> + Cannot be sent by providers. + </p> </td> </tr> <tr> <td> - EMPTY + <code>TYPE_EMPTY</code> </td> <td> - None + Sent by the system when a complication is activated and the user has + chosen "empty" instead of a provider, or when the watch face has + chosen no provider, and this type, as the default. + <p> + Cannot be sent by providers. + </p> </td> + </tr> + + <tr> <td> - None + <code>TYPE_NO_DATA</code> </td> <td> - Sent by a provider when there is no data to display in a - complication, or sent by the system when nothing should be shown in a - complication. + Sent by the system when a complication (that has a provider) is + activated, to clear the complication before actual data is received + from the provider. + <p> + Should be sent by providers if they have no actual data to send. + </p> </td> </tr> </table> @@ -700,8 +1162,8 @@ METADATA_KEY_PROVIDER_CONFIG_ACTION </h2> <p> - The Complications API includes new classes in the Wearable Support - Library. For more information, download the <a href= + The Complications API includes new classes in the wearable support + library. For more information, download the <a href= "{@docRoot}wear/preview/start.html#get_the_preview_reference_documentation"> Android Wear 2.0 Preview Reference</a>. </p> @@ -722,14 +1184,26 @@ METADATA_KEY_PROVIDER_CONFIG_ACTION </li> <li> - <code>ComplicationText</code> + <code>ComplicationHelperActivity</code> <ul> - <li>Used to supply text-based values in a - <code>ComplicationData</code> object + <li>Used to request the following permission: <br> +<code>com.google.android.wearable.permission.RECEIVE_COMPLICATION_DATA</code> </li> - <li>Includes options for time-dependent values, whose text value - depends on the current time + <li>Used instead of <code>ProviderChooserIntent</code> + to start the chooser in almost all cases + </li> + </ul> + </li> + + <li> + <code>ComplicationManager</code> + <ul> + <li>A wrapper for the complication manager service, for use by + providers + </li> + + <li>Allows providers to send complication data to the system </li> </ul> </li> @@ -747,13 +1221,14 @@ METADATA_KEY_PROVIDER_CONFIG_ACTION </li> <li> - <code>ComplicationManager</code> + <code>ComplicationText</code> <ul> - <li>A wrapper for the complication manager service, for use by - providers + <li>Used to supply text-based values in a + <code>ComplicationData</code> object </li> - <li>Allows providers to send complication data to the system + <li>Includes options for time-dependent values, whose text value + depends on the current time </li> </ul> </li> @@ -761,11 +1236,8 @@ METADATA_KEY_PROVIDER_CONFIG_ACTION <li> <code>ProviderChooserIntent</code> <ul> - <li>Non-instantiable utility class - </li> - - <li>Includes a method that a watch face can call for starting a - provider chooser (to allow a user to configure complications) + <li>Non-instantiable utility class that is not commonly used; use + <code>ComplicationHelperActivity</code> instead </li> </ul> </li> @@ -789,6 +1261,16 @@ METADATA_KEY_PROVIDER_CONFIG_ACTION </li> </ul> </li> + + <li> + <code>SystemProviders</code> + <ul> + <li>Lists system providers that are considered "safe", + because they only supply information that the watch face + already could obtain itself + </li> + </ul> + </li> </ul> <p> diff --git a/docs/html/wear/preview/features/notifications.jd b/docs/html/wear/preview/features/notifications.jd index dcc09709deb3..b546978a8b9c 100644 --- a/docs/html/wear/preview/features/notifications.jd +++ b/docs/html/wear/preview/features/notifications.jd @@ -1,6 +1,5 @@ page.title=Notification Changes in Android Wear 2.0 -meta.tags="wear", "wear-preview", "notifications" -page.tags="wear" +meta.tags="wear", "wear-preview", "notifications" page.tags="wear" page.image=/wear/preview/images/expanded_diagram.png @@ -12,6 +11,7 @@ page.image=/wear/preview/images/expanded_diagram.png <h2>This document includes</h2> <ol> <li><a href="#visual">Visual Updates</a></li> + <li><a href="#inline">Inline Action</a></li> <li><a href="#expanded">Expanded Notifications</a></li> <li><a href="#messaging">MessagingStyle</a></li> </ol> @@ -67,7 +67,8 @@ material design</a> visual changes. We recommended that you don't set color for bridged notifications. When Wear apps post local notifications, you can work around this by checking - <a href="{@docRoot}training/basics/supporting-devices/platforms.html#version-codes">the API level of the device</a> they're running on and using an appropriate color + <a href="{@docRoot}training/basics/supporting-devices/platforms.html#version-codes">the API level of the device</a> + they're running on and using an appropriate color for Wear 1.x and a different color for Wear 2.0. </li> @@ -77,6 +78,85 @@ material design</a> visual changes. you must update the text of your notification. </li> </ul> + +<h2 id="inline">Inline Action</h3> + +<img src="{@docRoot}wear/preview/images/inline_action.png" style="float:right;margin:10px 20px 0 0"> +<p> + Wear 2.0 now supports inline action, which allows users to take actions on a + notification from within the notification stream card. On Wear, the inline + action appears as an additional button displayed at the bottom of the notification. +</p> +<p> + Inline actions are optional but recommended for cases in which users are likely + to take an action on a notification after viewing the contents in the + notification stream card (without going to the + <a href= "{@docRoot}wear/preview/features/notifications.html#expanded">expanded notification</a>). + Examples of good use cases for inline action on a notification include: replying to a + text message, stopping a fitness activity, and archiving an email message. +</p> + +<p> + A notification can provide only one inline action. + To display the inline action as an additional button in the notification, set + the <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Action.WearableExtender.html#setHintDisplayActionInline(boolean)">{@code setHintDisplayActionInline()}</a> + method to true. When a user taps the inline action, the system invokes + the intent that you specified in the notification action. +</p> + +<h3>Adding an inline action</h3> +<p> + The following code example shows how to create a notification with an inline + reply action: +</p> + +<ol> + <li>Create an instance of + <a href="https://developer.android.com/reference/android/support/v4/app/RemoteInput.Builder.html">{@code RemoteInput.Builder}</a></code> + that you can add to your notification action. This class's constructor accepts a + string that the system uses as the key for the text input. Later, your app + uses that key to retrieve the text of the input. + +<pre> +String[] choices = context.getResources().getStringArray(R.array.notification_reply_choices); + choices = WearUtil.addEmojisToCannedResponse(choices); + RemoteInput remoteInput = new RemoteInput.Builder(Intent.EXTRA_TEXT) + .setLabel(context.getString(R.string.notification_prompt_reply)) + .setChoices(choices) + .build(); +</pre> + + </li> + + <li> + Use the <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Action.Builder.html#addRemoteInput(android.support.v4.app.RemoteInput)">{@code addRemoteInput()}</a> + method to attach the <ahref="https://developer.android.com/reference/android/support/v4/app/RemoteInput.html">{@code RemoteInput}</a> + object to an action. + +<pre> +NotificationCompat.Action.Builder actionBuilder = new NotificationCompat.Action.Builder( + R.drawable.ic_full_reply, R.string.notification_reply, replyPendingIntent); + actionBuilder.addRemoteInput(remoteInput); + actionBuilder.setAllowGeneratedReplies(true); +</pre> + </li> + + <li> + Add a hint to display the reply action inline, and use the + <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.WearableExtender.html#addAction(android.support.v4.app.NotificationCompat.Action)">{@code addAction}</a> + method to add this action to the notification. + +<pre> +// Android Wear 2.0 requires a hint to display the reply action inline. + Action.WearableExtender actionExtender = + new Action.WearableExtender() + .setHintLaunchesActivity(true) + .setHintDisplayActionInline(true); + wearableExtender.addAction(actionBuilder.extend(actionExtender).build()); +</pre> + </li> +</ol> + <h2 id="expanded">Expanded Notifications</h2> <p>Android Wear 2.0 introduces <i>expanded notifications</i>, which provide substantial additional content and actions for each notification. @@ -152,51 +232,52 @@ action in the notification unless a different action is specified using </p> <h2 id="messaging">MessagingStyle</h2> -<p>If you have a chat messaging app, your notifications should use -<a href="{@docRoot}preview/features/notification-updates.html#style">{@code Notification.MessagingStyle}</a>, - which is new in Android N. Wear 2.0 uses the chat messages included - in a <a href="{@docRoot}preview/features/notification-updates.html#style">{@code MessagingStyle}</a> notification - - (see <a href="{@docRoot}preview/features/notification-updates.html#style">{@code addMessage()}</a>) to provide - a rich chat app-like experience in the expanded notification. +<p> + If you have a chat messaging app, your notifications should use + <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.html">{@code NotificationCompat.MessagingStyle}</a>, + which is new in Android 7.0. Wear 2.0 uses the chat messages included in a + {@code MessagingStyle} notification + (see <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.html#addMessage(android.support.v4.app.NotificationCompat.MessagingStyle.Message)">{@code addMessage()}</a>) + to provide a rich chat app-like experience in the expanded notification. </p> -<p class="note">Note: <a href="{@docRoot}preview/features/notification-updates.html#style">{@code MessagingStyle}</a> +<p class="note">Note: <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.html">{@code MessagingStyle}</a> expanded notifications require that you have at least version 1.5.0.2861804 of the <a href="https://play.google.com/store/apps/details?id=com.google.android.wearable.app">Android Wear app</a> - on your paired Android phone. That version will be available within the next - few weeks in the Play Store. + on your paired Android phone. </p> <h3 id="smart-reply">Smart Reply</h3> <img src="{@docRoot}wear/preview/images/messaging_style.png" height="420" style="float:right;margin:10px 20px 0 0" /> -<p>Wear 2.0 also introduces <i>Smart Reply</i> -for <a href="{@docRoot}preview/features/notification-updates.html#style">{@code MessagingStyle}</a> notifications. +<p>Wear 2.0 also introduces <i>Smart Reply</i> for + <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.html">{@code MessagingStyle}</a> notifications. Smart Reply provides the user with contextually relevant, touchable choices in the expanded notification and in {@code RemoteInput}. These augment the fixed list of choices that the developer provides in - <a href="http://developer.android.com/reference/android/support/v4/app/RemoteInput.html">{@code RemoteInput}</a> - using the - <a href="{@docRoot}reference/android/support/v4/app/RemoteInput.Builder.html#setChoices(java.lang.CharSequence[])">{@code setChoices()}</a> method. + <a href="http://developer.android.com/reference/android/support/v4/app/RemoteInput.html">{@code RemoteInput}</a> + using the + <a href="{@docRoot}reference/android/support/v4/app/RemoteInput.Builder.html#setChoices(java.lang.CharSequence[])">{@code setChoices()}</a> method. </p> -<p>By enabling Smart Reply for your MessagingStyle notifications, - you provide users with a fast (single tap), discreet (no speaking aloud), and - reliable way to respond to chat messages. +<p> Smart Reply provides users with a fast (single tap), discreet (no speaking aloud), + private (messages received by a user never leave the watch), and reliable (no + internet connection needed) way to respond to chat messages. </p> -<p>Responses generated by Smart Reply are shown in addition to those set using the - <a href="{@docRoot}reference/android/support/v4/app/RemoteInput.Builder.html#setChoices(java.lang.CharSequence[])">{@code setChoices()}</a> method. +<p> + Smart Reply responses are generated by an entirely on-watch machine learning + model using the context provided by the MessagingStyle notification. No user + notification data is sent to Google servers to generate Smart Reply responses. </p> + <p>To enable Smart Reply for your notification action, you need to do the following: </p> <ol> - <li>Use <a href="{@docRoot}preview/features/notification-updates.html#style">{@code Notification.MessagingStyle}</a>. + <li>Use <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.html">{@code NotificationCompat.MessagingStyle}</a>. </li> - <li>Call the method {@code setAllowGeneratedReplies()} for the notification action. - For more information, see the downloadable - <a href="{@docRoot}preview/setup-sdk.html#docs-dl">API reference</a>. + <li>Call the method <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Action.Builder.html#setAllowGeneratedReplies(boolean)">{@code setAllowGeneratedReplies(true)}</a> + for the notification action. </li> <li>Ensure that the notification action has a <a href="{@docRoot}reference/android/app/RemoteInput.html">{@code RemoteInput}</a> @@ -236,3 +317,29 @@ Notification noti = new NotificationCompat.Builder() // 3) add an action with RemoteInput .extend(new WearableExtender().addAction(action)).build(); </pre> + +<h3 id="images">Adding images to a MessagingStyle notification</h3> +<p> + You can add images to a notification message by setting the appropriate MIME + type and placing the URI to the image in {@code NotificationCompat.MessagingStyle.Message.} + <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.Message.html#setData(java.lang.String, android.net.Uri)">{@code setData()}</a> method. +</p> +<p> + Here is the code snippet to set data of type image in a notification: +</p> +<pre> +NotificationCompat.MessagingStyle.Message message = new Message("sticker", 1, "Jeff") + .setData("image/png", stickerUri); + + NotificationCompat notification = new NotificationCompat.Builder() + .setStyle(new NotificationComapt.MessagingStyle("Me") + .addMessage(message) + .build()); + +</pre> +<p> + In the above code snippet the variable <code>stickerUri </code>is a Uri that + points to a publicly-accessible location, as described <a + href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.Message.html">here + </a>. +</p>
\ No newline at end of file diff --git a/docs/html/wear/preview/features/standalone-apps.jd b/docs/html/wear/preview/features/standalone-apps.jd new file mode 100644 index 000000000000..5c1930dedf86 --- /dev/null +++ b/docs/html/wear/preview/features/standalone-apps.jd @@ -0,0 +1,499 @@ +page.title=Standalone Apps +meta.keywords="wear-preview" +page.tags="wear-preview" +page.image=images/cards/card-n-sdk_2x.png + +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + +<h2>In this document</h2> + + <ul> + <li><a href="#planning_apps">Planning Your Phone and Watch Apps</a></li> + <li><a href="#network_access">Network Access and Cloud Messaging</a></li> + <li><a href="#background_services">Using Background Services</a></li> + <li><a href="#fcm">Cloud Notifications Using FCM</a></li> + <li><a href="#fcm-phone">Notifications from a Companion Phone</a></li> + </ul> + +</div> +</div> + + <p> + In Android Wear 2.0, apps can work independently of a phone. Users can + complete more tasks on a watch, without access to an Android or iOS + phone. + </p> + + <h2 id="planning_apps"> + Planning Your Phone and Watch Apps + </h2> + + <p> + A watch APK targeting Wear 2.0 should not be embedded in a phone APK. + For more information, see + <a href="{@docRoot}wear/preview/features/app-distribution.html"> + App Distribution</a>. + </p> + + <p> + Generally, the minimum and target API level for a standalone app, and + for Wear 2.0, is level 24. The minimum SDK level can be 23 + only if you are using the same APK + for Wear 1.0 and 2.0 (and thus have an embedded Wear 1.0 APK). + </p> + + <p> + If you build a standalone Wear 2.0 APK and will continue to have a + Wear 1.0 APK, please do both of the following: + </p> + + <ul> + <li>Provide a standalone version of the Wear APK, and + </li> + + <li>Continue embedding a version of the Wear APK in your phone APK + </li> + </ul> + + <p> + <strong>Caution</strong>: For the Wear 2.0 Developer Preview, if you + publish an update to your production phone APK that has removed an embedded + Wear APK, production users who update the phone APK before installing + your standalone Wear APK will lose their existing Wear app and its data. + Therefore, it's important that you continue to embed + your watch APK into your phone APK. + </p> + + <p> + <a href= + "https://developer.android.com/training/articles/wear-permissions.html"> + Run-time permissions</a> are required for standalone apps. + </p> + + <h3> + Shared code and data storage + </h3> + + <p> + Code can be shared between a Wear app and a phone app. Optionally, code + that is specific to a form factor can be in a separate module. + </p> + + <p> + For example, common code for networking can be in a shared library. + </p> + + <p> + You can use standard Android storage APIs to store data locally. + For example, you can use + the <a href= + "https://developer.android.com/reference/android/content/SharedPreferences.html"> + SharedPreferences APIs</a>, SQLite, or internal storage (as you would in + the case of a phone). + </p> + + <h3> + Detecting your phone app or watch app + </h3> + + <p> + If a user of your watch app needs your phone app, your watch app can + detect if the phone app is available. Using the <a href= + "https://developers.google.com/android/reference/com/google/android/gms/wearable/CapabilityApi"> + CapabilityApi</a>, your phone app or watch app can advertise its presence + to a paired device. It can do so statically and dynamically. When an app + is on a node in a user's Wear network (i.e., on a phone, paired watch, or + in the cloud), the <code>CapabilityApi</code> enables another + app to detect if it is installed. For more information, see <a href= + "https://developer.android.com/training/wearables/data-layer/messages.html#AdvertiseCapabilities"> + Advertise capabilities</a>. + </p> + + <p> + If your phone app is unavailable, your can check if the Play Store is + available on the phone, as described below, before directing the user to + go to the Play Store (to install your phone app). + </p> + + <h4> + Checking for Play Store availability on a phone + </h4> + + <p> + iPhones and some Android phones lack the Play Store. A standalone Wear + app can check if the paired phone has the Play Store, before directing a + user to go there to install your phone app. The + <code>PlayStoreAvailability</code> class contains a + <code>getPlayStoreAvailabilityOnPhone()</code> method that enables your + Wear app to check if a companion phone has the Play Store. + </p> + + <p> + More information about the <code>PlayStoreAvailability</code> class is + available when you <a href= + "https://developer.android.com/wear/preview/start.html#get_the_preview_reference_documentation"> + download the Android Wear 2.0 Preview Reference</a>. Here is a snippet + that uses the <code>getPlayStoreAvailabilityOnPhone()</code> method to + determine if the paired phone has the Play Store: + </p> + +<pre> +int playStoreAvailabilityOnPhone = +PlayStoreAvailability.getPlayStoreAvailabilityOnPhone(context); +</pre> + + <p> + The value returned by the <code>getPlayStoreAvailabilityOnPhone()</code> + method is one of the following: + </p> + + <table> + <tr> + <th> + <strong>Return value</strong> + </th> + <th> + <strong>Description</strong> + </th> + </tr> + + <tr> + <td> + <code>PLAY_STORE_ON_PHONE_AVAILABLE</code> + </td> + <td> + The Play Store is available on the companion phone. + </td> + </tr> + + <tr> + <td> + <code>PLAY_STORE_ON_PHONE_UNAVAILABLE</code> + </td> + <td> + The Play Store is not available on the companion phone. + </td> + </tr> + + <tr> + <td> + <code>PLAY_STORE_ON_PHONE_ERROR_UNKNOWN</code> + </td> + <td> + An error occurred in the check for the Play Store; another check + should be made later. + </td> + </tr> + </table> + + <h2 id="network_access"> + Network Access and Cloud Messaging + </h2> + + <p> + Android Wear apps can make their own network requests. When a watch has a + Bluetooth connection to a phone, the watch's network traffic is proxied + through the phone. When a phone is unavailable, Wi-Fi and cellular + networks are used, depending on the hardware. The Wear platform handles + transitions between networks. A watch's network access thus does not + require the <a href= + "https://developer.android.com/training/wearables/data-layer/index.html"> + Wearable Data Layer API</a>. + </p> + + <p> + For sending notifications, apps can directly use Firebase Cloud Messaging + (FCM), which replaces Google Cloud Messaging, or continue to use GCM. + </p> + + <p> + No APIs for network access or FCM are specific to Android Wear. + Refer to the existing documentation about <a href= + "https://developer.android.com/training/basics/network-ops/connecting.html"> + connecting to a network</a> and <a href= + "https://developers.google.com/cloud-messaging/">cloud messaging</a>. + </p> + + <p> + You can use protocols such as HTTP, TCP, and UDP. However, + the <a href="https://developer.android.com/reference/android/webkit/package-summary.html"> + android.webkit</a> APIs are not available. Therefore, + use of cookies is available by reading and writing headers on + requests and responses, but the <a href= + "https://developer.androidcom/reference/android/webkit/CookieManager.html"> + CookieManager</a> class is not available. + </p> + + <p> + FCM works well with + <a href="https://developer.android.com/training/monitoring-device-state/doze-standby.html"> + Doze</a>. + </p> + + <p> + Additionally, we recommend using the following: + </p> + + <ul> + <li>The <a href= + "https://developer.android.com/reference/android/app/job/JobScheduler.html"> + JobScheduler</a> API for asynchronous jobs, including polling at + regular intervals (described below) + </li> + + <li>Multi-networking APIs if you need to connect to specific network + types; see <a href= + "https://developer.android.com/about/versions/android-5.0.html#Wireless"> + Multiple Network Connections</a> + </li> + </ul> + + <p> + For foreground use cases, we currently recommend that you make a + request for an unmetered network. Here is an example of using + the multi-networking APIs to request an unmetered network: + </p> + +<pre> +ConnectivityManager.NetworkCallback networkCallback = + new ConnectivityManager.NetworkCallback() { + @Override + public void onAvailable(Network network) { + // access network + } + }; +ConnectivityManager connectivityManager = + (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + +connectivityManager.requestNetwork(new NetworkRequest.Builder() + .addCapability(NET_CAPABILITY_NOT_METERED) + .build(), networkCallback); +</pre> + + <p> + We also recommend setting a timer for frontend scenarios + to prevent a user from potentially waiting for a long time. + When the network is no longer needed, or if the timer fires, + the network callback needs to be unregistered: + </p> + +<pre> +connectivityManager.unregisterNetworkCallback(networkCallback): +</pre> + + <p> + A Wear app can communicate with a phone app using the <a href= + "https://developer.android.com/training/wearables/data-layer/index.html">Wearable + Data Layer API</a>, but connecting to a network using that API is + discouraged. + </p> + + <h3 id="necessary_data"> + Obtaining only the necessary data + </h3> + + <p> + When obtaining data from the cloud, get only the necessary data. + Otherwise, you may introduce unnecessary latency, memory use, and battery + use. + </p> + + <p> + When a watch is connected over a Bluetooth LE connection, your app may + have access to a bandwidth of only 10 kilobytes per second. Therefore, + the following steps are recommended: + </p> + + <ul> + <li>Audit your network requests and responses for extra data that only is + for a phone app + </li> + + <li>Shrink large images before sending them over a network to a watch + </li> + </ul> + + <h2 id="background_services"> + Using Background Services + </h2> + + <p> + To ensure that background tasks are correctly executed, they must account + for <a href= + "https://developer.android.com/training/monitoring-device-state/doze-standby.html"> + Doze</a>. In Android 6.0, Doze and App Standby resulted in significant + improvements to battery life by allowing devices to enter deep sleep when + idle and stationary. + </p> + + <p> + Doze is <a href= + "https://developer.android.com/preview/behavior-changes.html#doze">enhanced</a> + in Android Nougat and Android Wear 2.0. When a screen turns off or enters + ambient mode for a long enough time, a subset of Doze can occur and + background tasks may be deferred for certain periods. Later, when a + device is stationary for an extended time, regular Doze occurs. + </p> + + <p> + You should schedule jobs with the <a href= + "https://developer.android.com/reference/android/app/job/JobScheduler.html"> + JobScheduler</a> API, which enables your app to register for Doze-safe + code execution. When scheduling jobs, you can select constraints such as + periodic execution and the need for connectivity or device charging. + It is important to configure jobs in a way that does not adversely + impact battery life. Jobs should use a + <a href="https://developer.android.com/reference/android/app/job/JobInfo.Builder.html"> + JobInfo.Builder</a> object to provide constraints and metadata, e.g. with + one or more of the following methods for a task: + </p> + + <ul> + <li>To schedule a task that requires networking, use + <code>setRequiredNetworkType(int networkType)</code>, specifying + <code>NETWORK_TYPE_ANY</code> or <code>NETWORK_TYPE_UNMETERED</code>; + note that <code>NETWORK_TYPE_UNMETERED</code> is for large data transfers + while <code>NETWORK_TYPE_ANY</code> is for small transfers + </li> + + <li>To schedule a task while charging, use + <code>setRequiresCharging(boolean requiresCharging)</code> + </li> + + <li>For specifying that a device is idle for a task, use + <code>setRequiresDeviceIdle(boolean requiresDeviceIdle)</code>; this + method can be useful for lower-priority background work or + synchronization, especially when used with + <code>setRequiresCharging</code> + </li> + </ul> + + <p> + Note that some low-bandwidth networks, such as Bluetooth LE, are + considered metered. + </p> + + <h3> + Scheduling with constraints + </h3> + + <p> + You can schedule a task that requires constraints. In the example below, + a <code>JobScheduler</code> object activates <code>MyJobService</code> + when the following constraints are met: + </p> + + <ul> + <li>Unmetered networking + </li> + + <li>Device charging + </li> + </ul> + + <p> + You can use the builder method <code>setExtras</code> to attach a bundle + of app-specific metadata to the job request. When your job executes, this + bundle is provided to your job service. Note the <code>MY_JOB_ID</code> + value passed to the <code>JobInfo.Builder</code> constructor. This + <code>MY_JOB_ID</code> value is an app-provided identifier. Subsequent + calls to cancel, and subsequent jobs created with that same value, will + update the existing job: + </p> + +<pre> +JobInfo jobInfo = new JobInfo.Builder(MY_JOB_ID, + new ComponentName(this, MyJobService.class)) + .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) + .setRequiresCharging(true) + .setExtras(extras) + .build(); +((JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE)) + .schedule(jobInfo); +</pre> + + <p> + Below is an implementation of <a href= + "https://developer.android.com/reference/android/app/job/JobService.html"> + JobService</a> to handle the job above. When the job executes, a + <code>JobParameters</code> object is passed into the + <code>onStartJob</code> method. The <code>JobParameters</code> object + enables you to get the job ID value along with any extras bundle provided + when scheduling the job. The <code>onStartJob</code> method is called on + the main application thread, and therefore any expensive logic should be + run from a separate thread. In the example, an <code>AsyncTask</code> is + used to run code in the background. When work is complete, you would call + the <code>jobFinished</code> method to notify <code>JobScheduler</code> + that the task is done: + </p> + +<pre> +public class MyJobService extends JobService { + @Override public boolean onStartJob(JobParameters params) { + new JobAsyncTask().execute(params); + return true; + } + + private class JobAsyncTask extends AsyncTask +</pre> + + <h2 id="fcm"> + Cloud Notifications Using FCM + </h2> + + <p> + FCM is the recommended way to send notifications to a watch. + </p> + + <p> + Provide for messages from FCM by collecting a registration token for a + device when your Wear app runs. Then include the token as part of the + destination when your server sends messages to the FCM REST endpoint. FCM + sends messages to the device identified by the token. + </p> + + <p> + An FCM message is in JSON format and can include one or both of the + following payloads: + </p> + + <ul> + <li> + <strong>Notification payload.</strong> When a notification payload is + received by a watch, the data is displayed to a user directly in the + notification stream. When the user taps the notification, your app is + launched. + </li> + + <li> + <strong>Data payload</strong>. The payload has a set of custom + key/value pairs. The payload and is delivered as data to your Wear app. + </li> + </ul> + + <p> + For more information and examples of payloads, see <a href= + "https://firebase.google.com/docs/cloud-messaging/concept-options">About + FCM Messages</a>. + </p> + + <h2 id="fcm-phone"> + Notifications from a Companion Phone + </h2> + + <p> + By default, notifications are bridged (shared) from a phone app to a + watch. If you have a standalone Wear app and a corresponding phone app, + duplicate notifications can occur. For example, the same notification + from FCM, received by both a phone and a watch, could be + displayed by both devices independently. + </p> + + <p> + For information about preventing duplicate notifications, see <a href= + "https://developer.android.com/wear/preview/features/bridger.html">Bridging + Mode for Notifications</a>. + </p> diff --git a/docs/html/wear/preview/features/wearable-recycler-view.jd b/docs/html/wear/preview/features/wearable-recycler-view.jd new file mode 100644 index 000000000000..f28a4722377e --- /dev/null +++ b/docs/html/wear/preview/features/wearable-recycler-view.jd @@ -0,0 +1,223 @@ + +page.title=Curved Layout +meta.tags="wear", "wear-preview", "RecyclerView" +page.tags="wear" + +@jd:body + + +<div id="qv-wrapper"> +<div id="qv"> + + <h2>In this document</h2> + <ol> + <li><a href="#creating">Creating a Curved Layout</a></li> + <li><a href="#adding">Adding a Circular Scrolling Gesture</a></li> + <li><a href="#aligning">Anchoring Children to the Curve</a></li> + </ol> + +</div> +</div> + + +<p> + Wear 2.0 introduces the {@code WearableRecyclerView} class for displaying + and manipulating a vertical list of items optimized for round displays. + {@code WearableRecyclerView} extends the existing + <a href="{@docRoot}reference/android/support/v7/widget/RecyclerView.html">{@code RecyclerView}</a> + class to provide a curved layout and a circular scrolling gesture in wearable apps. +</p> +<img src="https://android-dot-devsite.googleplex.com/wear/preview/images/wrv_new.png" + style="float:right;margin:10px 20px 0 0"> + +<p> + You can adapt to this interface in your wearable app by creating a new + {@code WearableRecyclerView} container. +</p> + +<p> + You should decide whether to use a {@code WearableRecyclerView}, based on + the kind of user experience you want to provide. We recommend using the + {@code WearableRecyclerView} for a simple, long list of items, such as an + application launcher, or a list contacts. Each item might have a short string + and an associated icon. Alternatively, each item might have only a string or + an icon. We do not recommend using a {@code WearableRecyclerView} for short + or complex lists. +</p> + +<p> + This document describes how to create a curved layout for your scrollable items + and properly align them along the curve. +</p> + + +<h2 id="creating">Creating a Curved Layout</h2> +<p>To create a curved layout for scrollable items in your wearable app: +</p> +<ul> + <li>Use {@code WearableRecyclerView} as your main container in the relevant + xml layout. + </li> + + <li>By default, {@code WearableRecyclerView} uses the {@code + DefaultOffsettingHelper} class to offset items in a curved layout on round + devices. If you wish to implement your own offsetting logic, you can extend the + abstract {@code WearableRecyclerView.OffsettingHelper} class and attach it to + the {@code WearableRecyclerView} using {@code + WearableRecyclerView.setOffsettingHelper} method. + + <pre> + CircularOffsettingHelper circularHelper = new CircularOffsettingHelper(); + mRecyclerView.setOffsettingHelper(circularHelper); + </pre> + + <pre> + public class CircularOffsettingHelper extends OffsettingHelper { + + @Override + public void updateChild(View child, WearableRecyclerView parent) { + int progress = child.getTop() / parent.getHeight(); + child.setTranslationX(-child.getHeight() * progress); + } + } + </pre> + + </li> + +</ul> + +<p class="note"> + <strong>Note:</strong> {@code DefaultOffsettingHelper} class + offsets the child items + along a predefined UX curve, but the operation can cut off part of the child + view if it is not scaled down accordingly. This is because the default curve + attempts to fit 5 items on the screen, regardless of their size. + If you do not wish to scale your items, you should consider additional padding. +</p> + +<h3>Examples</h3> +<p> + The following code example demonstrates how to add {@code WearableRecyclerView} + to a layout: +</p> +<pre> +<android.support.wearable.view.WearableRecyclerView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/recycler_launcher_view" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:scrollbars="vertical" /> + </pre> + + +<p> + To customize the appearance of the children while scrolling (for example, + scale the icons and text while the items scroll away from the center), extend + the {@code DefaultOffsettingHelper} and override the {@code updateChild } + method. It is important to call the {@code super.updateChild(child, parent)} to + offset the children along the curve. However, if for any particular child you do + not wish them to follow a curve, you can chose not to call the super method for + that particular child. +</p> + +<pre> + +public class MyOffsettingHelper extends DefaultOffsettingHelper { + + /** How much should we scale the icon at most. */ + private static final float MAX_ICON_PROGRESS = 0.65f; + + private float mProgressToCenter; + + public OffsettingHelper() {} + + @Override + + public void updateChild(View child, WearableRecyclerView parent) { + super.updateChild(child, parent); + + + // Figure out % progress from top to bottom + float centerOffset = ((float) child.getHeight() / 2.0f) / (float) mParentView.getHeight(); + float yRelativeToCenterOffset = (child.getY() / mParentView.getHeight()) + centerOffset; + + // Normalize for center + mProgressToCenter = Math.abs(0.5f - yRelativeToCenterOffset); + // Adjust to the maximum scale + mProgressToCenter = Math.min(mProgressToCenter, MAX_ICON_PROGRESS); + + child.setScaleX(1 - mProgressToCenter); + child.setScaleY(1 - mProgressToCenter); + } +} + + +</pre> + + +<h2 id="adding">Adding a Circular Scrolling Gesture</h2> + +<p> + By default, circular scrolling is disabled in the {@code + WearableRecyclerView}. If you want to enable circular scrolling gesture + in your child view, use the {@code WearavleRecyclerView}’s {@code + setCircularScrollingGestureEnabled()} method. You can also customize the + circular scrolling gesture by defining one or both of the following: +</p> + +<ul> + <li>How many degrees the user has to rotate by to scroll through one screen height. + This effectively influences the speed of the scolling - + {@code setScrollDegreesPerScreen} - the default value is set at 180 degrees. + </li> + + <li> + The width of a virtual ‘bezel’ near the the edge of the screen in which the + gesture will be recognized - {@code setBezelWidth} - the default value is set + at 1. This is expressed as a fraction of the radius of the view. +</ul> + + +<p>The following code snippet shows how to set these methods:</p> + +<pre> + setCircularScrollingGestureEnabled(true); + setBezelWidth(0.5f); + setScrollDegreesPerScreen(90); +</pre> + +<h2 id="aligning"> Anchoring Children to the Curve </h2> + +<p> + To ensure that the layout for WearableRecyclerView is adaptable to different + types of child views, the WearableRecyclerView class, by default, chooses the + middle left edge (X=0, Y=Half the child height) as the anchor coordinates for + the child item. Using the default anchor coordinates can result in offsetting + the child items from the left edge of the watch face. To customize the anchor + coordinates of your child view along the curve, you can overwrite the + {@code adjustAnchorOffsetXY()} method. You can calculate the X (horizontal) + and Y (vertical) offset of the child item, and set it using the + {@code adjustAnchorOffsetXY()} method to properly align items + along the curve. The coordinates should be with relation to the child view. +</p> + +<p><img src="{@docRoot}wear/preview/images/alignment.png"/></p> +<p><b>Figure 1</b>. Imaginary UX curve and anchor points on the curve.</p> + +<p> + The code snippet below, calculates the X offset for a child item in which the + width of the icon is same as the height of the child item. In this case, the + anchor coordinates for the child item are at the center of the icon. + +</p> +<img src="{@docRoot}wear/preview/images/center_align.png" style="float:left;margin:10px 20px 0 0"/> + +<pre> + @Override + protected void adjustAnchorOffsetXY(View child, float[] anchorOffsetXY) { + anchorOffsetXY[0] = child.getHeight() / 2.0f; + } +</pre> + + diff --git a/docs/html/wear/preview/images/alignment.png b/docs/html/wear/preview/images/alignment.png Binary files differnew file mode 100644 index 000000000000..525b3341789a --- /dev/null +++ b/docs/html/wear/preview/images/alignment.png diff --git a/docs/html/wear/preview/images/apk-details.png b/docs/html/wear/preview/images/apk-details.png Binary files differnew file mode 100644 index 000000000000..eb3b8591f53f --- /dev/null +++ b/docs/html/wear/preview/images/apk-details.png diff --git a/docs/html/wear/preview/images/apk-tabs.png b/docs/html/wear/preview/images/apk-tabs.png Binary files differnew file mode 100644 index 000000000000..949b98f75b7d --- /dev/null +++ b/docs/html/wear/preview/images/apk-tabs.png diff --git a/docs/html/wear/preview/images/center_align.png b/docs/html/wear/preview/images/center_align.png Binary files differnew file mode 100644 index 000000000000..ca88ad77bac4 --- /dev/null +++ b/docs/html/wear/preview/images/center_align.png diff --git a/docs/html/wear/preview/images/current-apk.png b/docs/html/wear/preview/images/current-apk.png Binary files differnew file mode 100644 index 000000000000..2545f925f608 --- /dev/null +++ b/docs/html/wear/preview/images/current-apk.png diff --git a/docs/html/wear/preview/images/inline_action.png b/docs/html/wear/preview/images/inline_action.png Binary files differnew file mode 100644 index 000000000000..7ecaafeb2544 --- /dev/null +++ b/docs/html/wear/preview/images/inline_action.png diff --git a/docs/html/wear/preview/images/wrv_new.png b/docs/html/wear/preview/images/wrv_new.png Binary files differnew file mode 100644 index 000000000000..c413c59a77c3 --- /dev/null +++ b/docs/html/wear/preview/images/wrv_new.png diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index e5ddfd09d82b..b6cecc94aecb 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -1147,14 +1147,15 @@ class PackageManagerShellCommand extends ShellCommand { private int doWriteSplit(int sessionId, String inPath, long sizeBytes, String splitName, boolean logSuccess) throws RemoteException { final PrintWriter pw = getOutPrintWriter(); - if ("-".equals(inPath)) { - inPath = null; - } else if (inPath != null) { - final File file = new File(inPath); - if (file.isFile()) { - sizeBytes = file.length(); - } + if (sizeBytes <= 0) { + pw.println("Error: must specify a APK size"); + return 1; + } + if (inPath != null && !"-".equals(inPath)) { + pw.println("Error: APK content must be streamed"); + return 1; } + inPath = null; final SessionInfo info = mInterface.getPackageInstaller().getSessionInfo(sessionId); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index c2ffa9bbab15..45014ec07178 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -496,6 +496,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } }); } + // STOPSHIP: Remove this code once all dogfood devices are fixed. See b/31754835 + if (Intent.ACTION_BOOT_COMPLETED.equals(action) && !mOwners.hasDeviceOwner() + && !isBackupServiceEnabledInternal()) { + setBackupServiceEnabledInternal(true); + Slog.w(LOG_TAG, "Fix backup for device that is not in Device Owner mode."); + } if (Intent.ACTION_USER_UNLOCKED.equals(action) || Intent.ACTION_USER_STARTED.equals(action) || KeyChain.ACTION_STORAGE_CHANGED.equals(action)) { @@ -8981,8 +8987,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (!isDeviceOwnerManagedSingleUserDevice()) { mInjector.securityLogSetLoggingEnabledProperty(false); Slog.w(LOG_TAG, "Security logging turned off as it's no longer a single user device."); - setBackupServiceEnabledInternal(false); - Slog.w(LOG_TAG, "Backup is off as it's a managed device that has more that one user."); + if (mOwners.hasDeviceOwner()) { + setBackupServiceEnabledInternal(false); + Slog.w(LOG_TAG, "Backup is off as it's a managed device that has more that one user."); + } } } @@ -9317,12 +9325,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } synchronized (this) { getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); - try { - IBackupManager ibm = mInjector.getIBackupManager(); - return ibm != null && ibm.isBackupServiceActive(UserHandle.USER_SYSTEM); - } catch (RemoteException e) { - throw new IllegalStateException("Failed requesting backup service state.", e); - } + return isBackupServiceEnabledInternal(); + } + } + private boolean isBackupServiceEnabledInternal() { + try { + IBackupManager ibm = mInjector.getIBackupManager(); + return ibm != null && ibm.isBackupServiceActive(UserHandle.USER_SYSTEM); + } catch (RemoteException e) { + throw new IllegalStateException("Failed requesting backup service state.", e); } } } |