diff options
Diffstat (limited to 'docs/html/training')
65 files changed, 2170 insertions, 349 deletions
diff --git a/docs/html/training/articles/security-ssl.jd b/docs/html/training/articles/security-ssl.jd index 0639fb0..7f43d9c 100644 --- a/docs/html/training/articles/security-ssl.jd +++ b/docs/html/training/articles/security-ssl.jd @@ -22,6 +22,7 @@ page.article=true <li><a href="#Blacklisting">Blacklisting</a></li> <li><a href="#Pinning">Pinning</a></li> <li><a href="#ClientCert">Client Certificates</a></li> + <li><a href="#nogotofail">Nogotofail: Network Security Testing</a></li> </ol> @@ -511,8 +512,42 @@ See the discussion about creating a custom {@link javax.net.ssl.KeyManager} in t +<h2 id="nogotofail"> + Nogotofail: A Network Traffic Security Testing Tool +</h2> +<p> + Nogotofail is a tool gives you an easy way to confirm that your apps are safe + against known TLS/SSL vulnerabilities and misconfigurations. It's an + automated, powerful, and scalable tool for testing network security issues on + any device whose network traffic could be made to go through it. </p> + <p>Nogotofail is useful for three main use cases: +</p> + +<ul> + <li>Finding bugs and vulnerabilities. + </li> + + <li>Verifying fixes and watching for regressions. + </li> + + <li>Understanding what applications and devices are generating what traffic. + </li> +</ul> + +<p> + Nogotofail works for Android, iOS, Linux, Windows, Chrome OS, OSX, in fact + any device you use to connect to the Internet. There’s an easy-to-use client + to configure the settings and get notifications on Android and Linux, as well + as the attack engine itself which can be deployed as a router, VPN server, or + proxy. +</p> + +<p> + You can access the tool at the <a href= + "https://github.com/google/nogotofail">Nogotofail open source project</a>. +</p> diff --git a/docs/html/training/articles/wear-location-detection.jd b/docs/html/training/articles/wear-location-detection.jd new file mode 100644 index 0000000..b0d9755 --- /dev/null +++ b/docs/html/training/articles/wear-location-detection.jd @@ -0,0 +1,375 @@ +page.title=Detecting Location on Android Wear +page.tags="gps" + +page.article=true +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> +<h2>In this document</h2> +<ol class="nolist"> + <li><a href="#Connect">Connect to Google Play Services</a></li> + <li><a href="#Request">Request Location Updates</a></li> + <li><a href="#DetectGPS">Detect On-Board GPS</a></li> + <li><a href="#Disconnection">Handle Disconnection Events</a></li> + <li><a href="#Notify">Handle Location Not Found</a></li> + <li><a href="#Synchronize">Synchronize Data</a></li> +</ol> +<!-- Required platform, tools, add-ons, devices, knowledge, etc. --> +<h2>Dependencies and prerequisites</h2> +<ul> + <li>Android 4.3 (API Level 18) or higher on the handset device</li> + <li><a href="{@docRoot}google/play-services/index.html">Google Play services</a> 6.1 or higher</li> + <li>An Android Wear device</li> +</ul> +<h2>See also</h2> +<ul> + <li><a href="{@docRoot}training/location/index.html">Making Your App Location-Aware + </a></li> +</ul> +</div></div> + +<p>Location awareness on wearable devices enables you to create apps that give users a better +understanding of their geographic position, movement and what's around them. With the small form +factor and glanceable nature of a wearable device, you can build low-friction apps that record and +respond to location data.</p> + +<p>Some wearable devices include a GPS sensor that can retrieve location data without another +tethered device. However, when you request location data in a wearable app, you don't have to worry +about where the location data originates; the system retrieves the location updates using the most +power-efficient method. Your app should be able to handle loss of location data, in case the wear +device loses connection with its paired device and does not have a built-in GPS sensor.</p> + +<p>This document shows you how to check for on-device location sensors, receive location data, and +monitor tethered data connections.</p> + +<p class="note"><b>Note:</b> The article assumes that you know how to use the Google Play services +API to retrieve location data. For more information, see <a href="{@docRoot}training/ +location/index.html">Making Your App Location-Aware</a>.</p> + +<h2 id="Connect">Connect to Google Play Services</h2> + +<p>Location data on wearable devices is obtained though the Google Play services location APIs. You +use the <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html"> +<code>FusedLocationProviderApi</code></a> and its accompanying classes to obtain this data. +To access location services, create an instance of +<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html"> +<code>GoogleApiClient</code></a>, which is +the main entry point for any of the Google Play services APIs. +</p> + +<p class="caution"><b>Caution:</b> Do not use the existing <a href="{@docRoot}reference/android/location/package-summary.html">Location</a> +APIs in the Android framework. The best practice for retrieving location updates is through the +Google Play services API as outlined in this article.</p> + +<p>To connect to Google Play services, configure your app to create an instance of +<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html"> +<code>GoogleApiClient</code></a>:</p> + +<ol> + <li>Create an activity that specifies an implementation for the interfaces <a +href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html" +>{@code ConnectionCallbacks}</a>, <a href="{@docRoot}reference/com/google/android/gms/common/api/ +GoogleApiClient.OnConnectionFailedListener.html">{@code OnConnectionFailedListener}</a>, and <a +href="{@docRoot}reference/com/google/android/gms/location/LocationListener.html">{@code +LocationListener}</a>.</li> + <li>In your activity's {@link android.app.Activity#onCreate onCreate()} method, create an instance +of <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html"><code> +GoogleApiClient</code></a> and add the Location service. + </li> + <li>To gracefully manage the lifecycle of the connection, call <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html#connect()"> + {@code connect()}</a> in the {@link android.app.Activity#onResume onResume()} method and + <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html#disconnect()"> + {@code disconnect()}</a> in the {@link android.app.Activity#onPause onPause()} method. + </li> +</ol> + +<p>The following code example shows an implementation of an activity that implements the +<a href="{@docRoot}reference/com/google/android/gms/location/LocationListener.html"> +{@code LocationListener}</a> interface:</p> + +<pre> +public class WearableMainActivity extends Activity implements + GoogleApiClient.ConnectionCallbacks, + GoogleApiClient.OnConnectionFailedListener, + LocationListener { + + private GoogleApiClient mGoogleApiClient; + ... + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + ... + mGoogleApiClient = new GoogleApiClient.Builder(this) + .addApi(LocationServices.API) + .addApi(Wearable.API) // used for data layer API + .addConnectionCallbacks(this) + .addOnConnectionFailedListener(this) + .build(); + } + + @Override + protected void onResume() { + super.onResume(); + mGoogleApiClient.connect(); + ... + } + + @Override + protected void onPause() { + super.onPause(); + ... + mGoogleApiClient.disconnect(); + } +} +</pre> + +<p>For more information on connecting to Google Play services, see <a href="{@docRoot}google/auth +/api-client.html">Accessing Google APIs</a>.</p> + +<h2 id="Request">Request Location Updates</h2> + +<p>After your app has connected to the Google Play services API, it is ready to start receiving +location updates. When the system invokes the +<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)"> +<code>onConnected()</code></a> callback for your client, you build the location data request as +follows:</p> + +<ol> + <li>Create a <a +href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html" +>{@code LocationRequest}</a> object and set any options using methods like <a +href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setPriority(int)" +>{@code setPriority()}</a>. + </li> + <li>Request location updates using <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#requestLocationUpdates(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.location.LocationRequest, com.google.android.gms.location.LocationListener)"> + <code>requestLocationUpdates()</code></a>. + </li> + <li>Remove location updates using <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#removeLocationUpdates(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.location.LocationListener)"> + <code>removeLocationUpdates()</code></a> in the {@link android.app.Activity#onPause + onPause()} method. + </li> +</ol> + +<p>The following example shows how to retrieve and remove location updates:</p> + +<pre> +@Override +public void onConnected(Bundle bundle) { + LocationRequest locationRequest = LocationRequest.create() + .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) + .setInterval(UPDATE_INTERVAL_MS) + .setFastestInterval(FASTEST_INTERVAL_MS); + + LocationServices.FusedLocationApi + .requestLocationUpdates(mGoogleApiClient, locationRequest, this) + .setResultCallback(new ResultCallback<Status>() { + + @Override + public void onResult(Status status) { + if (status.getStatus().isSuccess()) { + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "Successfully requested location updates"); + } + } else { + Log.e(TAG, + "Failed in requesting location updates, " + + "status code: " + + status.getStatusCode() + + ", message: " + + status.getStatusMessage()); + } + } + }); +} + +@Override +protected void onPause() { + super.onPause(); + if (mGoogleApiClient.isConnected()) { + LocationServices.FusedLocationApi + .removeLocationUpdates(mGoogleApiClient, this); + } + mGoogleApiClient.disconnect(); +} + +@Override +public void onConnectionSuspended(int i) { + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "connection to location client suspended"); + } +} + +</pre> + +<p>Now that you have enabled location updates, the system calls the {@link android.location.LocationListener#onLocationChanged +onLocationChanged()} method with the updated location at the interval specified in <a +href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setInterval(long)"> +{@code setInterval()}</a> +</p> + +<h2 id="DetectGPS">Detect On-Board GPS</h2> + +<p>Not all wearables have a GPS sensor. If your user goes out for a run and leaves their phone at +home, your wearable app cannot receive location data through a tethered connection. If the +wearable device does not have a sensor, you should detect this situation and warn the user that +location functionality is not available. + +<p>To determine whether your Android Wear device has a built-in GPS sensor, use the +{@link android.content.pm.PackageManager#hasSystemFeature hasSystemFeature()} +method. The following code detects whether the device has built-in GPS when you start an activity: +</p> + +<pre> + +protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.main_activity); + if (!hasGps()) { + Log.d(TAG, "This hardware doesn't have GPS."); + // Fall back to functionality that does not use location or + // warn the user that location function is not available. + } + + ... +} + +private boolean hasGps() { + return getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION_GPS); +} +</pre> + +<h2 id="Disconnection">Handle Disconnection Events</h2> + +<p>Wearable devices relying on a tethered connection for location data may lose their connections +abruptly. If your wearable app expects a constant stream of data, you must handle the +disconnection based upon where that data is interrupted or unavailable. On a wearable device with no +onboard GPS sensor, loss of location data occurs when the device loses its tethered data connection. +</p> + +<p>In cases where your app depends on a tethered data connection for location data and the wear +device does not have a GPS sensor, you should detect the loss of that connection, warn the user, and +gracefully degrade the functionality of your app.</p> + +<p>To detect the loss of a tethered data connection:</p> + +<ol> + <li>Extend a <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"> + <code>WearableListenerService</code></a> that lets you listen for important data layer events. + </li> + <li>Declare an intent filter in your Android manifest to notify the system about your + <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code> + WearableListenerService</code></a>. + This filter allows the system to bind your service as needed. +<pre> +<service android:name=".NodeListenerService"> + <intent-filter> + <action android:name="com.google.android.gms.wearable.BIND_LISTENER" /> + </intent-filter> +</service> +</pre> + </li> + <li>Implement the <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html#onPeerDisconnected(com.google.android.gms.wearable.Node)"> + <code>onPeerDisconnected()</code></a> method and handle cases of whether or not the device has + built-in + GPS. +<pre> +public class NodeListenerService extends WearableListenerService { + + private static final String TAG = "NodeListenerService"; + + @Override + public void onPeerDisconnected(Node peer) { + Log.d(TAG, "You have been disconnected."); + if(!hasGPS()) { + // Notify user to bring tethered handset + // Fall back to functionality that does not use location + } + } + ... +} +</pre> + </li> +</ol> + +For more information, read the <a href="{@docRoot}training/wearables/data-layer/events.html#Listen"> +Listen for Data Layer Events</a> guide. + +<h2 id="Notify">Handle Location Not Found</h2> + +<p>When the GPS signal is lost, you can still retrieve the last known location using +<a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#getLastLocation(com.google.android.gms.common.api.GoogleApiClient)"> +<code>getLastLocation()</code></a>. This method can be helpful in situations where you are unable to +get a GPS fix, or when your wearable doesn't have built-in GPS and loses its connection with the +phone.</p> + +<p>The following code uses <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#getLastLocation(com.google.android.gms.common.api.GoogleApiClient)"> +<code>getLastLocation()</code></a> to retrieve the last known location if available: +</p> + +<pre> +Location location = LocationServices.FusedLocationApi + .getLastLocation(mGoogleApiClient); +</pre> + +<h2 id="Synchronize">Synchronize Data</h2> + +<p>If your wearable app records data using the built-in GPS, you may want to synchronize +the location data with the handset. With the {@link android.location.LocationListener}, you +implement the {@link android.location.LocationListener#onLocationChanged onLocationChanged()} +method to detect and record the location as it changes. + +<p>The following code for wearable apps detects when the location changes and uses the data layer +API to store the data for later retrieval by your phone app:</p> + +<pre> +@Override +public void onLocationChanged(Location location) { + ... + addLocationEntry(location.getLatitude(), location.getLongitude()); + +} + +private void addLocationEntry(double latitude, double longitude) { + if (!mSaveGpsLocation || !mGoogleApiClient.isConnected()) { + return; + } + + mCalendar.setTimeInMillis(System.currentTimeMillis()); + + // Set the path of the data map + String path = Constants.PATH + "/" + mCalendar.getTimeInMillis(); + PutDataMapRequest putDataMapRequest = PutDataMapRequest.create(path); + + // Set the location values in the data map + putDataMapRequest.getDataMap() + .putDouble(Constants.KEY_LATITUDE, latitude); + putDataMapRequest.getDataMap() + .putDouble(Constants.KEY_LONGITUDE, longitude); + putDataMapRequest.getDataMap() + .putLong(Constants.KEY_TIME, mCalendar.getTimeInMillis()); + + // Prepare the data map for the request + PutDataRequest request = putDataMapRequest.asPutDataRequest(); + + // Request the system to create the data item + Wearable.DataApi.putDataItem(mGoogleApiClient, request) + .setResultCallback(new ResultCallback<DataApi.DataItemResult>() { + @Override + public void onResult(DataApi.DataItemResult dataItemResult) { + if (!dataItemResult.getStatus().isSuccess()) { + Log.e(TAG, "Failed to set the data, " + + "status: " + dataItemResult.getStatus() + .getStatusCode()); + } + } + }); +} +</pre> + +<p>For more information on how to use the Data Layer API, see the <a href="{@docRoot}training/ +wearables/data-layer/index.html">Sending and Syncing Data</a> +guide.</p> diff --git a/docs/html/training/auto/audio/index.jd b/docs/html/training/auto/audio/index.jd new file mode 100644 index 0000000..aa25769 --- /dev/null +++ b/docs/html/training/auto/audio/index.jd @@ -0,0 +1,475 @@ +page.title=Providing Audio Playback for Auto +page.tags="auto", "car", "automotive", "audio" +page.article=true + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + <h2>Dependencies and Prerequisites</h2> + <ul> + <li>Android 5.0 (API level 21) or higher</li> + </ul> + + <h2>This class teaches you how to</h2> + + <ol> + <li><a href="#overview">Provide Audio Services</a></li> + <li><a href="#config_manifest">Configure Your Manifest</a></li> + <li><a href="#implement_browser">Build a Browser Service</a></li> + <li><a href="#implement_callback">Implement Play Controls</a></li> + </ol> + + <h2>Related Samples</h2> + + <ul> + <li><a href="{@docRoot}samples/MediaBrowserService/index.html"> + MediaBrowserService</a></li> + </ul> + + <h2>See Also</h2> + + <ul> + <li> + <a href="{@docRoot}shareables/auto/AndroidAuto-media-apps.pdf"> + User Experience Guidelines: Media Apps</a> + </li> + <li><a href="{@docRoot}training/managing-audio/index.html">Managing Audio + Playback</a></li> + <li><a href="{@docRoot}guide/topics/media/exoplayer.html">ExoPlayer</a> + </li> + </ul> + +</div> +</div> + +<a class="notice-developers-video wide" +href="https://www.youtube.com/watch?v=Q96Sw6v4ULg"> +<div> + <h3>Video</h3> + <p>Devbytes: Android Auto Audio</p> +</div> +</a> + +<p> + Drivers want to access their music and other audio content on the road. Audio books, podcasts, + sports commentary, and recorded talks can make a long trip educational, inspirational, and + enjoyable. The Android framework allows you to extend your audio app so users can listen to their + favorite tunes and audio content using a simpler, safer user interface. +</p> + +<p> + Apps running on mobile devices with Android 5.0 or higher can provide audio services for + dashboard systems running Android Auto. By configuring your app with a few settings and + implementing a service for accessing music tracks, you can enable Auto devices to discover your + app and provide a browse and playback interface for your app's audio content. +</p> + +<p> + This class assumes that you have built an app that plays audio through an Android device's + integrated speakers or connected headphones. It describes how to extend your app to allow Auto + devices to browse your content listings and play it through a car stereo system. +</p> + + +<h2 id="overview">Provide Audio Services</h2> + +<p> + Audio apps do not directly control a car dashboard device that runs Android Auto. When the user + connects an Android mobile device into a dashboard system, Android Auto discovers your app through + manifest entries that indicate what audio services your app can provide. The dashboard system + displays a launcher icon for your app as a music provider and the user can choose to use your + app's services. If the user launches your app, the Auto device queries your app to see what + content is available, displays your content items to the user, and sends requests to your app to + control playback with actions such as play, pause, or skip track. +</p> + +<p>To enable your app to provide audio content for Auto devices, you need to: +</p> + +<ul> + <li>Configure your app manifest to do the following:</li> + <ul> + <li>Declare that your app can provide audio content for Auto devices.</li> + <li>Define a service that provides a browsable list of your audio tracks.</li> + </ul> + </li> + <li>Build a service that provides audio track listing information extending + {@link android.service.media.MediaBrowserService}.</li> + <li>Register a {@link android.media.session.MediaSession} object and implement the + {@link android.media.session.MediaSession.Callback} object to enable playback controls.</li> +</ul> + + +<h2 id="config_manifest">Configure Your Manifest</h2> + +<p> + When a user plugs an Android mobile device into a dashboard device running Auto, the system + requests a list of installed apps that include <a href= + "{@docRoot}guide/topics/manifest/manifest-intro.html">app manifest</a> entries to indicate they + support services for Auto devices and how to access them. This section describes how to configure + your app manifest to indicate your app supports audio services for Auto devices, and allow + dashboard system to connect with your app. +</p> + + +<h3 id="manifest-car-app">Declare Auto audio support</h3> + +<p> + You indicate that your app supports cars capabilities using the following manifest entry: +</p> + +<pre> +<application> + ... + <meta-data android:name="com.google.android.gms.car.application" + android:resource="@xml/automotive_app_desc"/> + ... +<application> +</pre> + +<p> + This manifest entry refers to a secondary XML file, where you declare what Auto capabilities your + app supports. For an app that supports audio for cars, add an XML file to the {@code res/xml/} + resources directory as {@code automotive_app_desc.xml}, with the following content: +</p> + +<pre> +<automotiveApp> + <uses name="media"/> +</automotiveApp> +</pre> + +<p> + For more information about declaring capabilities for Auto devices, see <a href= + "{@docRoot}training/auto/start/index.html#auto-metadata">Getting Started with Auto</a>. +</p> + + +<h3 id="manifest-service">Declare your media browser service</h3> + +<p> + Auto devices expect to connect to a service in order to browse audio track + listings. You declare this service in your manifest to allow the dashboard system to discover + this service and connect to your app. +</p> + +<p>The following code example shows how to declare this listing browser service in your manifest:</p> + +<pre> +<application> + ... + <service android:name="<em>.MyMediaBrowserService</em>" + android:exported="true"> + <intent-filter> + <strong><action android:name=</strong> + <strong>"android.media.browse.MediaBrowserService"/></strong> + </intent-filter> + </service> + ... +<application> +</pre> + +<p> + The service your app provides for browsing audio tracks must extend the + {@link android.service.media.MediaBrowserService}. The implementation of this service is discussed + in the <a href="#implement_browser">Build a Browser Service</a> section. +</p> + +<p class="note"> + <strong>Note:</strong> Other clients can also contact your app's browser service aside from Auto + devices. These media clients might be other apps on a user's mobile device, or they might be other + remote clients. +</p> + +<h3 id="manifest-icon">Specify a notification icon</h3> + +<p> + The Auto user interface shows notifications about your audio app to the user during the course + of operation. For example, if the user has a navigation app running, and one song finishes + and a new song starts, the Auto device shows the user a notification to indicate the change with + an icon from your app. You can specify an icon that is used to represent your app for these + notifications using the following manifest declaration: +</p> + +<pre> +<application> + ... + <meta-data android:name="com.google.android.gms.car.notification.SmallIcon" + android:resource="@drawable/ic_notification" /> + ... +<application> +</pre> + +<p class="note"><strong>Note:</strong> The icon you provide should have transparency enabled, so the +icon's background gets filled in with the app's primary color.</p> + + +<h2 id="implement_browser">Build a Browser Service</h2> + +<p>Auto devices interact with your app by contacting its implementation of a + {@link android.service.media.MediaBrowserService}, which +you declare in your app manifest. This service allows Auto devices to find out what content your app +provides. Connected Auto devices can also query your app's media browser service to contact the +{@link android.media.session.MediaSession} provided by your app, which handles content playback +commands.</p> + +<p>You create a media browser service by extending the +{@link android.service.media.MediaBrowserService} class. +Connected Auto devices can contact your service to do the following:</p> + +<ul> + <li>Browse your app's content hierarchy, in order to present a menu to the + user</li> + <li>Get the token for your app's {@link android.media.session.MediaSession} + object, in order to control audio playback</li> +</ul> + + +<h3 id="browser_workflow">Media browser service workflow</h3> + +<ol> + +<li>When your app's audio services are requested by a user through a connected Auto device, the +dashboard system contacts your app's media browser service. +In your implementation of the {@link android.service.media.MediaBrowserService#onCreate() +onCreate()} method, you must create and register a {@link +android.media.session.MediaSession} object and its callback object.</li> + +<li>The Auto device calls the browser service's {@link +android.service.media.MediaBrowserService#onGetRoot onGetRoot()} method to get the top node of +your content hierarchy. The node retrieved by this call is not used as a menu item, it is only used +to retrieve its child nodes, which are subsequently displayed as the top menu items. +</li> + +<li>Auto invokes the {@link android.service.media.MediaBrowserService#onLoadChildren +onLoadChildren()} method to get the children of the root node, and uses this information to +present a menu to the user.</li> + +<li>If the user selects a submenu, Auto invokes +{@link android.service.media.MediaBrowserService#onLoadChildren +onLoadChildren()} again to retrieve the child nodes of the selected menu item.</li> + +<li>If the user begins playback, Auto invokes the appropriate media session +callback method to perform that action. For more information, see the section about how to +<a href="#implement_callback">Implement Playback Controls</a>. </li> + +</ol> + + +<h3 id="build_hierarchy">Building your content hierarchy</h3> + +<p>Auto devices acting as audio clients call your app's {@link +android.service.media.MediaBrowserService} to find out what content you have +available. You need to implement two methods in your browser service to support +this: {@link android.service.media.MediaBrowserService#onGetRoot +onGetRoot()} and {@link +android.service.media.MediaBrowserService#onLoadChildren +onLoadChildren()}.</p> + +<p>Each node in your content hierarchy is represented by a {@link +android.media.browse.MediaBrowser.MediaItem} object. Each of these objects is +identified by a unique ID string. The client treats these ID strings as +opaque tokens. When a client wants to browse to a submenu, or play a content +item, it passes the ID token. Your app is responsible for associating the ID +token with the appropriate menu node or content item.</p> + +<p class="note"><strong>Note:</strong> You should consider providing different content +hierarchies depending on what client is making the query. In particular, Auto +applications have strict limits on how large a menu they can display. This is +intended to prevent distracting the driver, and to make it easy for the driver +to operate the app via voice commands. For more information on the Auto user +experience restrictions, see the <a href="{@docRoot}shareables/auto/AndroidAuto-media-apps.pdf"> +Auto Media Apps</a> guidelines.</p> + +<p>Your implementation of {@link android.service.media.MediaBrowserService#onGetRoot +onGetRoot()} returns information about the root node of the menu +hierarchy. This root node is the parent of the top items your browse hierarchy. +The method is passed information about the calling client. You can use this +information to decide if the client should have access to your content at all. +For example, if you want to limit your app's content to a list of approved +clients, you can compare the passed {@code clientPackageName} to your whitelist. +If the caller isn't an approved package, you can return null to deny access to +your content.</p> + +<p>A typical implementation of {@link +android.service.media.MediaBrowserService#onGetRoot onGetRoot()} might +look like this:</p> + +<pre> +@Override +public BrowserRoot onGetRoot(String clientPackageName, int clientUid, + Bundle rootHints) { + + // To ensure you are not allowing any arbitrary app to browse your app's + // contents, you need to check the origin: + if (!PackageValidator.isCallerAllowed(this, clientPackageName, clientUid)) { + // If the request comes from an untrusted package, return null. + // No further calls will be made to other media browsing methods. + LogHelper.w(TAG, "OnGetRoot: IGNORING request from untrusted package " + + clientPackageName); + return null; + } + if (ANDROID_AUTO_PACKAGE_NAME.equals(clientPackageName)) { + // Optional: if your app needs to adapt ads, music library or anything + // else that needs to run differently when connected to the car, this + // is where you should handle it. + } + return new BrowserRoot(MEDIA_ID_ROOT, null); +} +</pre> + +<p> + The Auto device client builds the top-level menu by calling {@link + android.service.media.MediaBrowserService#onLoadChildren onLoadChildren()} + with the root node object and getting it's children. The client builds + submenus by calling the same method with other child nodes. The following + example code shows a simple implementation of {@link + android.service.media.MediaBrowserService#onLoadChildren onLoadChildren()} method: +</p> + +<pre> +@Override +public void onLoadChildren(final String parentMediaId, + final Result<List<MediaItem>> result) { + + // Assume for example that the music catalog is already loaded/cached. + + List<MediaBrowser.MediaItem> mediaItems = new ArrayList<>(); + + // Check if this is the root menu: + if (MEDIA_BROWSER_ROOT.equals(parentMediaId)) { + + // build the MediaItem objects for the top level, + // and put them in the <result> list + } else { + + // examine the passed parentMediaId to see which submenu we're at, + // and put the children of that menu in the <result> list + } +} +</pre> + + +<h2 id="implement_callback">Enable Playback Control</h2> + +<p> + Auto devices use {@link android.media.session.MediaSession} objects to pass playback control + commands to an app that is providing audio services. Your audio app must create an instance of + this object to pass to the dashboard device and implement callback methods to enable remote + control of audio playback. +</p> + +<h3 id="registering_mediasession">Register a media session</h3> + +<p>An Auto device using your app as audio service needs to obtain a {@link +android.media.session.MediaSession} object from your app. The Auto device uses the session object +to send playback commands requested by the Auto user back to your app.</p> + +<p>When you initialize your browser service, you register that session object with your {@link +android.service.media.MediaBrowserService} by calling the {@link +android.service.media.MediaBrowserService#setSessionToken setSessionToken()} method. This step +allows clients such as an Auto device to retrieve that object by calling your browser service's +{@link android.service.media.MediaBrowserService#getSessionToken getSessionToken()} method.</p> + +<p>In your browser service's {@link +android.service.media.MediaBrowserService#onCreate() onCreate()} method, +create a {@link android.media.session.MediaSession}. You can then query +the {@link android.media.session.MediaSession} to get its token, and register +the token with your browser service:</p> + +<pre> +public void onCreate() { + super.onCreate(); + + ... + // Start a new MediaSession + MediaSession mSession = new MediaSession(this, "session tag"); + setSessionToken(mSession.getSessionToken()); + + // Set a callback object to handle play control requests, which + // implements MediaSession.Callback + mSession.setCallback(new MyMediaSessionCallback()); + + ... +</pre> + +<p> + When you create the media session object, you set a callback object that is used to handle + playback control requests. You create this callback object by providing an implementation of the + {@link android.media.session.MediaSession.Callback} class for your app. The next section + discusses how to implement this object. +</p> + + +<h3 id="playback-commands">Implement play commands</h3> + +<p>When an Auto device requests playback of an audio track from your app, it uses the +{@link android.media.session.MediaSession.Callback} class from your app's +{@link android.media.session.MediaSession} object, which it obtained from your app's +media browse service. When an Auto user wants to play content or control content playback, +such as pausing play or skipping to the next track, Auto invokes one +of the callback object's methods.</p> + +<p>To handle content playback, your app must extend the abstract {@link +android.media.session.MediaSession.Callback} class and implement the methods +that your app supports. The most important callback methods are as follows:</p> + +<dl> + +<dt>{@link android.media.session.MediaSession.Callback#onPlay onPlay()}</dt> +<dd>Invoked if the user chooses play without choosing a specific item. Your +app should play its default content. If playback was paused with +{@link android.media.session.MediaSession.Callback#onPause onPause()}, your +app should resume playback.</dd> + +<dt>{@link android.media.session.MediaSession.Callback#onPlayFromMediaId +onPlayFromMediaId()}</dt> +<dd>Invoked when the user chooses to play a specific item. The method is passed +the item's media ID, which you assigned to the item in the content +hierarchy.</dd> + +<dt>{@link android.media.session.MediaSession.Callback#onPlayFromSearch +onPlayFromSearch()}</dt> +<dd>Invoked when the user chooses to play from a search query. The app should +make an appropriate choice based on the passed search string.</dd> + +<dt>{@link android.media.session.MediaSession.Callback#onPause onPause()}</dt> +<dd>Pause playback.</dd> + +<dt>{@link android.media.session.MediaSession.Callback#onSkipToNext +onSkipToNext()}</dt> +<dd>Skip to the next item.</dd> + +<dt>{@link android.media.session.MediaSession.Callback#onSkipToPrevious +onSkipToPrevious()}</dt> +<dd>Skip to the previous item.</dd> + +<dt>{@link android.media.session.MediaSession.Callback#onStop onStop()}</dt> +<dd>Stop playback.</dd> + +</dl> + +<p>Your app should override these methods to provide any desired functionality. +In some cases you might not implement a method if it is not supported by your app. +For example, if your app plays a live stream (such as a sports +broadcast), the skip to next function might not make sense. In that case, you +could simply use the default implementation of +{@link android.media.session.MediaSession.Callback#onSkipToNext +onSkipToNext()}.</p> + +<p>When your app receives a request to play content, it should play audio the same way it +would in a non-Auto situation (as if the user was listening through a device speaker +or connected headphones). The audio content is automatically sent to the dashboard system +to be played over the car's speakers.</p> + +<p>For more information about playing audio content, see +<a href="{@docRoot}guide/topics/media/mediaplayer.html">Media Playback</a>, +<a href="{@docRoot}training/managing-audio/index.html">Managing Audio Playback</a>, and +<a href="{@docRoot}guide/topics/media/exoplayer.html">ExoPlayer</a>. + + +(for example, by using a {@link +android.media.MediaPlayer} or <a +href="{@docRoot}guide/topics/media/exoplayer.html">ExoPlayer</a>). If the phone +is connected to an Auto device, .</p> diff --git a/docs/html/training/auto/index.jd b/docs/html/training/auto/index.jd new file mode 100644 index 0000000..26eee32 --- /dev/null +++ b/docs/html/training/auto/index.jd @@ -0,0 +1,9 @@ +page.title=Building Apps for Auto +page.trainingcourse=true +page.metaDescription=Starting point for building apps for Auto, with guidelines, information, and examples. +page.image=design/tv/images/focus.png +@jd:body + + + +<p>These classes teach you how to build and extend apps to work with Auto devices.</p>
\ No newline at end of file diff --git a/docs/html/training/auto/messaging/index.jd b/docs/html/training/auto/messaging/index.jd new file mode 100644 index 0000000..2405d83 --- /dev/null +++ b/docs/html/training/auto/messaging/index.jd @@ -0,0 +1,535 @@ +page.title=Providing Messaging for Auto +page.tags="auto", "car", "automotive", "messaging" +page.article=true + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + <h2>Dependencies and Prerequisites</h2> + <ul> + <li>Android 5.0 (API level 21) or higher</li> + </ul> + + <h2>This class teaches you to:</h2> + + <ul> + <li><a href="#overview">Provide Messaging Services</a></li> + <li><a href="#manifest">Configure Your Manifest</a></li> + <li><a href="#support-lib">Import Support Library for Messaging</a></li> + <li><a href="#messaging">Notify Users of Messages</a></li> + <li><a href="#handle_actions">Handle User Actions</a></li> + </ul> + + <h2>Related Samples</h2> + + <ul> + <li><a href="{@docRoot}samples/MessagingService/index.html"> + MessagingService</a></li> + </ul> + + <h2>See Also</h2> + + <ul> + <li><a href="{@docRoot}shareables/auto/AndroidAuto-messaging-apps.pdf"> + User Experience Guidelines: Messaging Apps</a></li> + <li><a href="{@docRoot}guide/topics/ui/notifiers/notifications.html"> + Notifications</a></li> + </ul> +</div> +</div> + +<a class="notice-developers-video wide" + href="https://www.youtube.com/watch?v=gSVLuaOTIPk"> +<div> + <h3>Video</h3> + <p>DevBytes: Android Auto Messaging</p> +</div> +</a> + +<p> + Staying connected through text messages is important to many drivers. Chat apps can let users + know if a child need to be picked up, or if a dinner location has been changed. Apps that provide + sports information might tell the user who just won the big game, and let the user ask questions + about other games being played. The Android framework enables messaging apps to extend their + services into car dashboards using a standard user interface that lets drivers keep their eyes + on the road. +</p> + +<p> + Apps that support messaging can be extended to pass messaging notifications to Auto + dashboard systems, alerting them to new messages and allowing them to respond. You can configure + your messaging app to provide these services when an Android mobile device with your app + installed is connected to an Auto dashboard. Once connected, your app can provide text + information to users and allow them to respond. The Auto dashboard system handles displaying the + notification and the interface for replies. +</p> + +<p> + This lesson assumes that you have built an app that displays messages to the user and receive the + user's replies, such as a chat app. It shows you how to extend your app to hand those messages + off to an Auto device for display and replies. +</p> + + +<h2 id="overview">Provide Messaging Services</h2> + +<p> + Messaging apps do not run directly on the Android dashboard hardware. They are installed on + separate, Android mobile device. When the mobile device is plugged into a dashboard, + the installed messaging apps can offer services for viewing and responding to messages + through the Auto user interface. +</p> + +<p>To enable your app to provide messaging services for Auto devices:</p> + +<ul> + <li>Configure your app manifest to indicate that your app provides messaging services which are + compatible with Android Auto dashboard devices. + </li> + <li>Build and send a specific type of <a href= + "{@docRoot}guide/topics/ui/notifiers/notifications.html">notification</a> for display on Auto + devices. + </li> + <li>Configure your app to receive {@link android.content.Intent} objects that indicate a user + has read or replied to a message. +</ul> + + +<h2 id="#manifest">Configure Your Manifest</h2> + +<p> + You configure your app <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a> + to indicate that it supports messaging services for Auto devices and handle message actions. This + section describes what changes to make to your manifest to support messaging for Auto devices. +</p> + + +<h3 id="manifest-messaging">Declare Auto messaging support</h3> + +<p> + When a user connects a Android mobile device to a dashboard running Android, the dashboard + device looks for apps that declare support for vehicle services, such as messaging. You indicate + that your app supports cars capabilities using the following manifest entry: +</p> + +<pre> +<application> + ... + <meta-data android:name="com.google.android.gms.car.application" + android:resource="@xml/automotive_app_desc" /> + ... +<application> +</pre> + +<p> + This manifest entry refers to a secondary xml file, where you declare what Auto capabilities your + app supports. For an app that supports messaging for Auto devices, add an xml file to the {@code + res/xml/} your app's development project directory as {@code automotive_app_desc.xml}, with the + following content: +</p> + +<pre> +<automotiveApp> + <uses name="notification"/> +</automotiveApp> +</pre> + +<p> + For more information about declaring capabilities for Auto devices, see <a href= + "{@docRoot}training/auto/start/index.html#auto-metadata">Getting Started with Auto</a>. +</p> + + +<h3 id="manifest-intent">Define read and reply intent filters</h3> + +<p> + Auto devices use {@link android.content.Intent} objects that indicate a user has read or replied + to a message provided by your app. Your app defines intent types for reading and replying to + messages and adds this information to messaging notifications for Auto devices, so that the + dashboard system can notify your app when a user takes one of these actions. +</p> + +<p> + You define the read action and reply action intents types for your app and the {@link + android.content.BroadcastReceiver} classes that handle them in the manifest. The following code + example demonstrates how to declare these intents and their associated receivers. +</p> + +<pre> +<application> + ... + <receiver android:name="<em>.MyMessageReadReceiver</em>"> + <intent-filter> + <action android:name="<em>com.myapp.messagingservice.ACTION_MESSAGE_HEARD</em>"/> + </intent-filter> + </receiver> + + <receiver android:name="<em>.MyMessageReplyReceiver</em>"> + <intent-filter> + <action android:name="<em>com.myapp.messagingservice.ACTION_MESSAGE_REPLY</em>"/> + </intent-filter> + </receiver> + ... +</application> +</pre> + +<p> + The definition of the {@link android.content.BroadcastReceiver} classes shown in this example + is discussed in <a href="#handle_actions">Handle User Actions</a>. +</p> + + +<h2 id="support-lib">Import Support Library for Messaging</h3> + +<p> + Building notifications for use with Auto devices requires classes from the + <a href="{@docRoot}tools/support-library/features.html#v4">v4 support library</a>. Use the + <a href="{@docRoot}tools/help/sdk-manager.html">Android SDK Manager</a> to update the + <em>Extras > Android Support Repository</em> to version 9 or higher and the + <em>Extras > Android Support Library</em> to version 21.0.2 or higher. +</p> + +<p> + After you have updated the support libraries, import them into your Android Studio development + project by adding this dependency to your + <a href="{@docRoot}sdk/installing/studio-build.html#configBuild">build.gradle</a> file: +</p> + +<pre> +dependencies { + ... + compile 'com.android.support:support-v4:21.0.+' +} +</pre> + +<p> + For information about importing the support library into development projects for other + development environments, see <a href="{@docRoot}tools/support-library/setup.html">Support + Library Setup</a>. +</p> + + + +<h2 id="messaging">Notify Users of Messages</h2> + +<p> + A messaging app provides messages to a connected Auto dashboard using the <a href= + "{@docRoot}guide/topics/ui/notifiers/notifications.html">notifications</a> framework. When your + messaging app has a message for a user, you build a specially configured notification that is + received by the dashboard system and presented to the user. The Auto device manages the + presentation on the dashboard screen and may play the message via text-to-speech. The dashboard + system also handles voice interaction if the user replies to a message using verbal input. +</p> + +<p> + The messaging user interface for Auto presents users with two levels of information about + messages. The first level of notification tells users what <em>conversations</em> are + available, and who they are with, but not the content of the messages. Typically, a + conversation is one or more messages from another user to the Auto user. +</p> + +<p> + The second level of the notification is the actual content of messages in the conversation. If a + user indicates they want to hear the messages in a conversation, the Auto user interface plays + the messages using text-to-speech. +</p> + +<p> + This section describes how to notify Auto users that conversations are available and + provide the content of messages in those conversations. +</p> + + +<h3 id="build_conversation">Build message conversations</h4> + +<p> + Messaging notifications for Auto organize messages into conversations using the {@link + android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation} class, + that represents an unread or new + portion of a conversation from a particular sender. It contains a list of messages from the + sender. +</p> + +<p> + Use the {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder} class to create an unread conversation object, + as shown in the following example code: +</p> + +<pre> +// Build a RemoteInput for receiving voice input in a Car Notification +RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY) + .setLabel(getApplicationContext().getString(R.string.notification_reply)) + .build(); + +// Create an unread conversation object to organize a group of messages +// from a particular sender. +UnreadConversation.Builder unreadConvBuilder = + new UnreadConversation.Builder(participantName) + .setReadPendingIntent(msgHeardPendingIntent) + .setReplyAction(replyPendingIntent, remoteInput); +</pre> + +<p> + This conversation object includes a {@link android.app.PendingIntent}, which allows the Auto + device to signal your app that the conversation has been read by the Auto user. The construction + of this intent is discussed in the <a href="#conversation-intents">Creating conversation read and + reply intents</a> section. +</p> + +<p> + If your app supports replying to a conversation, you must call the {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder#setReplyAction setReplyAction()} + method and provide a pending intent to pass that user action back to your app. The + {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation} + object you create must also include a {@link + android.support.v4.app.RemoteInput} object. When the Auto user + receiving this conversation speaks a reply, the remote input objects lets your app get a text + version of the voice reply. +</p> + + +<h4 id="conversation-messages">Associate messages with conversations</h4> + +<p> + Messages provided for Auto must be associated with a conversation using the + {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation} + class. The following code example shows how + to associate individual messages with a conversation object. +</p> + +<pre> +// Note: Add messages from oldest to newest to the UnreadConversation.Builder +for (Iterator<String> messages = conversation.getMessages().iterator(); + messages.hasNext(); ) { + String message = messages.next(); + unreadConvBuilder.addMessage(message); +} +</pre> + +<p> + When a new message arrives in a particular conversation, your app should check if there is + already a conversation object for that particular conversation. If there is, associate the new + message with the existing conversation instead of building a new one. +</p> + + +<h4 id="conversation-intents">Create conversation read and reply intents</h4> + +<p> + Unread conversation objects contain intents for reading and replying to a conversation. You + create a {@link android.app.PendingIntent} object for each of these actions, so the Auto device + can notify your app of action taken by the Auto user on a particular conversation. +</p> + +<p> + The following example code demonstrates how to define a {@link android.app.PendingIntent} to let + your app know if a conversation was listened to by the Auto user: +</p> + +<pre> +Intent msgHeardIntent = new Intent() + .addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES) + .setAction(<em>com.myapp.messagingservice.ACTION_MESSAGE_HEARD</em>) + .putExtra("conversation_id", <em>conversationId</em>); + +PendingIntent msgHeardPendingIntent = + PendingIntent.getBroadcast(getApplicationContext(), + <em>conversationId</em>, + msgHeardIntent, + PendingIntent.FLAG_UPDATE_CURRENT); +</pre> + +<p> + In this example, {@code conversationId} is an integer that identifies the current conversation. + The value of {@link android.content.Intent#setAction setAction()} is an intent filter identifier for heard messages which is + defined in your app manifest, as shown in <a href="#manifest-intent">Define read and reply intent + filters</a>. +</p> + +<p> + If your app supports replying to conversations, you also create a {@link + android.app.PendingIntent} for each conversation to notify your app that the user has replied. + The following code example shows you how to build this intent for use with a particular + conversation: +</p> + +<pre> +Intent msgReplyIntent = new Intent() + .addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES) + .setAction(<em>com.myapp.messagingservice.ACTION_MESSAGE_REPLY</em>) + .putExtra("conversation_id", <em>conversationId</em>); + +PendingIntent msgReplyPendingIntent = PendingIntent.getBroadcast( + getApplicationContext(), + <em>conversationId</em>, + msgReplyIntent, + PendingIntent.FLAG_UPDATE_CURRENT); +</pre> + +<p> + Once again, {@code conversationId} is an integer that uniquely identifies this conversation. The + value of {@link android.content.Intent#setAction setAction()} is an intent filter identifier for replies which is defined in your + app manifest, as shown in <a href="#manifest-intent">Define read and reply intent filters</a>. +</p> + + +<h3 id="sending_messages">Sending Messages</h4> + +<p> + When a message arrives for a conversation, you take the following steps to dispatch it as a + notification to Auto. +</p> + +<p>First, add the message to the {@link +android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder} +for this conversation, and update its timestamp:</p> + +<pre> +unreadConvBuilder.addMessage(<em>messageString</em>) + .setLatestTimestamp(<em>currentTimestamp</em>); +</pre> + +<p>Then create a {@link android.support.v4.app.NotificationCompat.Builder} +object that you'll use to build the actual notification. You'll need to use the +pending intents you created in the previous step.</p> + +<pre> +NotificationCompat.Builder notificationBuilder = + new NotificationCompat.Builder(getApplicationContext()) + .setSmallIcon(R.drawable.<em>notification_icon</em>) + .setLargeIcon(<em>icon_bitmap</em>) + .setContentText(<em>messageString</em>) + .setWhen(<em>currentTimestamp</em>) + .setContentTitle(<em>participant_name</em>) + .setContentIntent(msgHeardPendingIntent); + +</pre> + +<p>You'll also need to extend the {@link +android.support.v4.app.NotificationCompat.Builder} with the {@link +android.support.v4.app.NotificationCompat.CarExtender}. This is where you +actually create the {@link android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation} object using the builder you +just created, and attach it to the {@link +android.support.v4.app.NotificationCompat.CarExtender}:</p> + +<pre> +notificationBuilder.extend(new CarExtender() + .setUnreadConversation(unreadConvBuilder.build()); +</pre> + +<p>Once you've done all this, you use your app's {@link +android.support.v4.app.NotificationManagerCompat} to send the notification:</p> + +<pre> +NotificationManagerCompat msgNotificationManager = + NotificationManagerCompat.from(context); +msgNotificationManager.notify(<em>notificationId</em>, notificationBuilder.build()); +</pre> + +<h2 id="handle_actions">Handle User Actions</h2> + +<p> + When your create and dispatch a notification for messaging, you specify intents to be triggered + when the Auto user hears the message and when the user dictates a reply. Your app indicates to + the Android framework that it handles these intends by registering them through it's manifest, as + discussed in <a href="#manifest-intent">Define read and reply intent filters</a>. +</p> + +<p> + In addition to registering these intent filters, your app must provide code to handle these + actions. Your app can do this by providing a service or {@link android.content.BroadcastReceiver} + objects that handle these intents.</p> + +<p> + For more information about intents, see <a href= + "{@docRoot}guide/components/intents-filters.html">Intents and Intent Filters</a>. +</p> + + +<h3 id="handling_msg_heard">Handling a message heard action</h3> + +<p> + When a user listens to a messaging conversation through the Auto user interface, the dashboard + device sends a read intent based on how your app defined the messaging notification. Your app + catches that intent and invokes the broadcast receiver class associated with it, or the service + method set up to handle that action. +</p> + +<p> + The following code example shows how to define a {@link android.content.BroadcastReceiver} class + to handle a received message heard intent: +</p> + +<pre> +public class MessageHeardReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + + // If you set up the intent as described in + // "Create conversation read and reply intents", + // you can get the conversation ID by calling: + int conversationId = intent.getIntExtra("conversation_id", -1); + + // Remove the notification to indicate it has been read + // and update the list of unread conversations in your app. + } +} +</pre> + +<p> + Once a notification is read, your app can remove it by calling + {@link android.support.v4.app.NotificationManagerCompat#cancel} with the notification ID. + Within your app, you should mark the messages provided in the notification as read. +</p> + + +<p class="note"> + <strong>Note:</strong> An alternative to this implementation is to use a service in a + {@link android.app.PendingIntent}. +</p> + + +<h3 id="handling_reply">Handling a reply action</h3> + +<p> + When a user replies to a messaging conversation through the Auto user interface, the dashboard + system sends a reply intent based on how your app defined the messaging notification. Your app + catches that intent and invokes the broadcast receiver class associated with it, or the service + method set up to handle that action. +</p> + +<p> + The following code example shows how to define a {@link android.content.BroadcastReceiver} class + to handle a received message reply intent: +</p> + +<pre> + public class MessageReplyReceiver extends BroadcastReceiver { + + + @Override + public void onReceive(Context context, Intent intent) { + // If you set up the intent as described in + // "Create conversation read and reply intents", + // you can get the conversation ID by calling: + int conversationId = intent.getIntExtra("conversation_id", -1). + + } + + /** + * Get the message text from the intent. + * Note that you should call + * RemoteInput.getResultsFromIntent() to process + * the RemoteInput. + */ + private CharSequence getMessageText(Intent intent) { + Bundle remoteInput = + RemoteInput.getResultsFromIntent(intent); + if (remoteInput != null) { + return remoteInput.getCharSequence("extra_voice_reply"); + } + return null; + } + +}</pre> diff --git a/docs/html/training/auto/start/index.jd b/docs/html/training/auto/start/index.jd new file mode 100644 index 0000000..8abe5c5 --- /dev/null +++ b/docs/html/training/auto/start/index.jd @@ -0,0 +1,211 @@ +page.title=Getting Started with Auto +page.tags="auto", "car", "automotive" +page.article=true +page.image=auto/images/assets/icons/auto_app_in_simulator.png + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + <h2>Dependencies and Prerequisites</h2> + <ul> + <li>Android 5.0 (API level 21) or higher</li> + </ul> + + <h2>This class teaches you how to</h2> + <ol> + <li><a href="#dev-project">Set Up an Auto Project</a></li> + <li><a href="#build-it">Build Auto Apps</a></li> + <li><a href="#test-it">Run and Test Auto Apps</a></li> + </ol> + + <h2>You should also read</h2> + <ul> + <li><a href="{@docRoot}design/auto/index.html">Designing for Auto</a></li> + <li><a href="{@docRoot}training/auto/audio/index.html">Providing Audio Playback with Auto</a></li> + <li><a href="{@docRoot}training/auto/messaging/index.html">Providing Messaging for Auto</a></li> + </ul> +</div> +</div> + +<p>Android Auto extends the Android platform into the car. When users connect +their handheld devices running Android 5.0 or higher to a compatible vehicle, +the Auto user interface provides a car-optimized Android experience on the +vehicle's screen. Users interact with compatible apps and services through +voice actions and the vehicle's input controls (like a touchscreen or dashboard +buttons).</p> + +<p>Auto currently supports two types of apps:</p> + +<ul> +<li><em>Audio apps</em> that allow users to browse and play music and spoken +audio content in the car.</li> +<li><em>Messaging apps</em> that receive incoming notifications, read messages + aloud via text-to-speech, and send replies via voice input in the car.</li> +</ul> + +<p>You can enable your existing audio and messaging apps developed for +phones and tablets to work in the car, without having to worry about +vehicle-specific hardware differences. To enable your app for Auto, your +app must target Android 5.0 (API level 21) or higher. Your app’s manifest must +also declare the car capabilities that it uses, such as audio playback or +messaging services. </p> + +<p>This lesson describes how to start building apps for Auto, including +setting up your development environment and meeting the the minimum requirements +to enable an app to communicate with Auto.</p> + +<p class="note"><strong>Important:</strong> If you are planning to develop +apps for Auto, you are encouraged to begin enabling and testing your +apps now. However, Auto-enabled apps cannot be published at this time. +Join the +<a href="http://g.co/AndroidAutoDev" class="external-link">Auto +Developers Google+ community</a> for updates on when you will be able to submit +your Auto-enabled apps.</p> + +<h2 id="dev-project">Set Up an Auto Project</h2> +<p>This section describes how to create a new app or modify an existing app to +communicate with Auto.</p> + +<h3 id="prerequisites">Prerequisites</h3> +<p>Before you begin building apps for Auto, you must:</p> + +<ul> +<li><strong><a href="{@docRoot}sdk/installing/create-project.html">Create or +update your app project</a></strong> - Android 5.0 (API level 21) provides new +APIs for implementing audio playback and messaging that is compatible with Auto. +To access the new APIs, create a project or modify an existing project to target +Android 5.0 (API level 21) or higher. This means you must set the manifest +<a href="{@docRoot}topics/manifest/uses-sdk-element.html">{@code targetSdkVersion}</a> +to 21 or higher. +</li> +<li><strong><a href="{@docRoot}tools/support-library/setup.html">Install the +support library</a></strong> - If you are building messaging apps for Auto, you +need the {@link android.support.v4.app.NotificationCompat.CarExtender} class +contained in the +<a href="{@docRoot}tools/support-library/features.html#v4">v4 support library</a>. +This class allows you to create notifications that are compatible with Auto +devices.</li> +</ul> + +<h3 id="auto-metadata">Declare Auto capabilities</h3> +<p>The Auto features that your app can access are controlled +by the settings in your app manifest and a separate XML configuration file. +Before adding Auto features to your app, you must first define the Auto +XML configuration file and add a manifest entry referencing your XML file.</p> + +<h4 id="auto_xml">Define the Auto XML configuration file</h4> +<p>Specify the car capabilities that your app uses in an XML file that you +place in your project’s resources directory ({@code res/xml/}). For example, to +extend an audio application for Auto, create a file called +{@code automotive_app_desc.xml} and store it under your projects’s +{@code res/xml/} folder. The {@code automotive_app_desc.xml} file contains the +following metadata:</p> +<pre> +<automotiveApp> + <uses name="media" /> +</automotiveApp> +</pre> +<p>The {@code <uses>} element declares the Auto capability your app +intends to use. Multiple {@code <uses>} tags can be added if your +application uses multiple car capabilities. The {@code name} attribute indicates +the specific capability your app uses. The values supported are:</p> +<ul> +<li>{@code media} - The app uses the Android framework APIs to play music in +a vehicle. Set this value if you are enabling an audio app for Auto.</li> +<li>{@code notification} - The app displays message notifications in the car’s +Overview screen, allows users select a message to be read aloud, and lets them +respond through voice input. Set this value if you are enabling a messaging +app for Auto. +</ul> + +<h4 id="auto_xml">Add a manifest entry</h4> +<p>In your app’s manifest ({@code AndroidManifest.xml}), provide a reference to +the Auto XML configuration file you created in the previous section. Add a +{@code "com.google.android.gms.car.application"} metadata entry under the +<a href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application>}</a> +element that references your Auto XML configuration file. Omit the {@code .xml} +file extension when specifying the configuration filename.</p> +<p>The following code snippet shows how to include this reference in your +manifest.</p> +<pre> +<application> + + ... + <meta-data android:name="com.google.android.gms.car.application" + android:resource="@xml/automotive_app_desc"/> + +</application> +</pre> + +<h2 id="build-it">Add Auto Features to Your Apps</h2> +<p>After you have completed the steps described above, you're ready to add Auto +features to your apps. See these additional topics to help you build apps for +Auto:</p> + +<ul> +<li><a href="{@docRoot}training/auto/audio/index.html">Providing Audio Playback for Auto</a> +- Create apps that let users browse and play music in the car.</li> +<li><a href="{@docRoot}training/auto/messaging/index.html">Providing Messaging for Auto</a> +- Enable users to receive and reply to messages in the car.</li> +</ul> + +<p class="caution"><strong>Important:</strong> Google takes driver distraction +very seriously. There are specific design requirements your app must meet to +qualify as an Auto app on Google Play. By adhering to these +requirements, you can reduce the effort for building and testing your app. For +more information, see +<a href="{@docRoot}distribute/essentials/quality/auto.html">Auto App Quality</a>.</p> + +<h2 id="test-it">Run and Test Auto Apps</h2> + +<p>As you prepare to publish your app, make sure that your app looks correct +when projected on the Auto user interface. Use the Android Media Browser +simulator and Android Messaging simulators to view and test your audio or +messaging apps in a screen that looks similar to what is projected on Auto.</p> + +<p>To get the simulators, open the +<a href="{@docRoot}tools/help/sdk-manager.html">SDK Manager</a> and download +them from <strong>Extras > Android Auto API Simulators</strong>.</p> + +<p>Before you begin testing, compile your app in your development environment. +Install your app and the Android simulator for the features you want to test +(that is, audio or messaging) on a physical or virtual device running Android +5.0 (API level 21) or higher. To check the version of Android on the device, go +to <strong>Settings > About > Android Version</strong>.</p> + +<h3 id="testing-audio-apps">Testing audio apps</h3> +<p>To run and test audio apps:</p> + +<ol> +<li>Install the Android Media Browser simulator +({@code media-browser-simulator.apk}) on the test device. You can do this using +the <a href="{@docRoot}tools/help/adb.html#move">adb</a> command line tool.</li> +<li>Enable <a href="{@docRoot}tools/device.html#device-developer-options"> +developer options</a> on the test device.</li> +<li>Install your app on the test device.</li> +<li>Launch the Android Media Browser simulator to see how your audio app +appears in Auto. If your app does not appear, stop the simulator from +<strong>Settings > Apps</strong> then restart it.</li> +</ol> + +<h3 id="testing-messaging-apps">Testing messaging apps</h3> +<p>To run and test messaging apps:</p> + +<ol> +<li>Install the Android Messaging simulator ({@code messaging-simulator.apk}) +on the test device. You can do this using the +<a href="{@docRoot}tools/help/adb.html#move">adb</a> command line tool.</li> +<li>Enable the simulator to read notifications posted on the system: +<ol type="a"> + <li>Enable <a href="{@docRoot}tools/device.html#device-developer-options"> +developer options</a> on the test device.</li> + <li>Click <strong>Settings > Sounds & Notifications > Notification + Access</strong> and check the box labeled + <strong>Messaging Simulator</strong>.</li> +</ol> +<li>Install your app on the test device.</li> +<li>Launch the Android Messaging Simulator to see how your messaging app appears +in Auto. If your app does not appear, stop the simulator from +<strong>Settings > Apps</strong> then restart it.</li> +</ol> diff --git a/docs/html/training/basics/activity-lifecycle/index.jd b/docs/html/training/basics/activity-lifecycle/index.jd index 127c1c2..afeab86 100644 --- a/docs/html/training/basics/activity-lifecycle/index.jd +++ b/docs/html/training/basics/activity-lifecycle/index.jd @@ -1,9 +1,9 @@ page.title=Managing the Activity Lifecycle +page.tags=activity lifecycle +helpoutsWidget=true trainingnavtop=true startpage=true -next.title=Launching an Activity -next.link=starting.html @jd:body diff --git a/docs/html/training/basics/activity-lifecycle/pausing.jd b/docs/html/training/basics/activity-lifecycle/pausing.jd index f656fce..de2c92a 100644 --- a/docs/html/training/basics/activity-lifecycle/pausing.jd +++ b/docs/html/training/basics/activity-lifecycle/pausing.jd @@ -1,12 +1,8 @@ page.title=Pausing and Resuming an Activity -parent.title=Managing the Activity Lifecycle -parent.link=index.html +page.tags=activity lifecycle +helpoutsWidget=true trainingnavtop=true -previous.title=Starting an Activity -previous.link=starting.html -next.title=Stopping and Restarting an Activity -next.link=stopping.html @jd:body diff --git a/docs/html/training/basics/activity-lifecycle/recreating.jd b/docs/html/training/basics/activity-lifecycle/recreating.jd index 71fd5dd..a52d5fd 100644 --- a/docs/html/training/basics/activity-lifecycle/recreating.jd +++ b/docs/html/training/basics/activity-lifecycle/recreating.jd @@ -1,10 +1,8 @@ page.title=Recreating an Activity -parent.title=Managing the Activity Lifecycle -parent.link=index.html +page.tags=activity lifecycle +helpoutsWidget=true trainingnavtop=true -previous.title=Stopping and Restarting an Activity -previous.link=stopping.html @jd:body diff --git a/docs/html/training/basics/activity-lifecycle/starting.jd b/docs/html/training/basics/activity-lifecycle/starting.jd index 9046599..2501f38 100644 --- a/docs/html/training/basics/activity-lifecycle/starting.jd +++ b/docs/html/training/basics/activity-lifecycle/starting.jd @@ -1,10 +1,8 @@ page.title=Starting an Activity -parent.title=Managing the Activity Lifecycle -parent.link=index.html +page.tags=activity lifecycle +helpoutsWidget=true trainingnavtop=true -next.title=Pausing and Resuming an Activity -next.link=pausing.html @jd:body diff --git a/docs/html/training/basics/activity-lifecycle/stopping.jd b/docs/html/training/basics/activity-lifecycle/stopping.jd index d56c921..51c95ea 100644 --- a/docs/html/training/basics/activity-lifecycle/stopping.jd +++ b/docs/html/training/basics/activity-lifecycle/stopping.jd @@ -1,12 +1,8 @@ page.title=Stopping and Restarting an Activity -parent.title=Managing the Activity Lifecycle -parent.link=index.html +page.tags=activity lifecycle +helpoutsWidget=true trainingnavtop=true -previous.title=Pausing and Resuming an Activity -previous.link=pausing.html -next.title=Recreating an Activity -next.link=recreating.html @jd:body diff --git a/docs/html/training/basics/firstapp/building-ui.jd b/docs/html/training/basics/firstapp/building-ui.jd index 179b3ac..0430cdd 100644 --- a/docs/html/training/basics/firstapp/building-ui.jd +++ b/docs/html/training/basics/firstapp/building-ui.jd @@ -1,12 +1,8 @@ page.title=Building a Simple User Interface -parent.title=Building Your First App -parent.link=index.html - trainingnavtop=true -previous.title=Running Your App -previous.link=running-app.html -next.title=Starting Another Activity -next.link=starting-activity.html + +page.tags=ui +helpoutsWidget=true @jd:body diff --git a/docs/html/training/basics/firstapp/creating-project.jd b/docs/html/training/basics/firstapp/creating-project.jd index c4cb362..2e06103 100644 --- a/docs/html/training/basics/firstapp/creating-project.jd +++ b/docs/html/training/basics/firstapp/creating-project.jd @@ -1,6 +1,7 @@ page.title=Creating an Android Project -parent.title=Building Your First App -parent.link=index.html + +page.tags=project setup +helpoutsWidget=true trainingnavtop=true next.title=Running Your App diff --git a/docs/html/training/basics/firstapp/index.jd b/docs/html/training/basics/firstapp/index.jd index 1b49096..ac8e64a 100644 --- a/docs/html/training/basics/firstapp/index.jd +++ b/docs/html/training/basics/firstapp/index.jd @@ -3,8 +3,9 @@ page.metaDescription=If you're new to Android app development, this where you sh trainingnavtop=true startpage=true -next.title=Creating an Android Project -next.link=creating-project.html + +page.tags=sdk tools +helpoutsWidget=true @jd:body @@ -47,6 +48,3 @@ not apply to earlier versions.</p> <p>This class uses a tutorial format that incrementally builds a small Android app that teaches you some fundamental concepts about Android development, so it's important that you follow each step.</p> - -<p><strong><a href="creating-project.html">Start the first lesson ›</a></strong></p> - diff --git a/docs/html/training/basics/firstapp/running-app.jd b/docs/html/training/basics/firstapp/running-app.jd index 23cedba..96b7172 100644 --- a/docs/html/training/basics/firstapp/running-app.jd +++ b/docs/html/training/basics/firstapp/running-app.jd @@ -3,10 +3,9 @@ parent.title=Building Your First App parent.link=index.html trainingnavtop=true -previous.title=Creating a Project -previous.link=creating-project.html -next.title=Building a Simple User Interface -next.link=building-ui.html + +page.tags=emulator +helpoutsWidget=true @jd:body diff --git a/docs/html/training/basics/firstapp/starting-activity.jd b/docs/html/training/basics/firstapp/starting-activity.jd index 27d2c10..71f66dd 100644 --- a/docs/html/training/basics/firstapp/starting-activity.jd +++ b/docs/html/training/basics/firstapp/starting-activity.jd @@ -3,8 +3,9 @@ parent.title=Building Your First App parent.link=index.html trainingnavtop=true -previous.title=Building a Simpler User Interface -previous.link=building-ui.html + +page.tags=intents +helpoutsWidget=true @jd:body diff --git a/docs/html/training/basics/fragments/communicating.jd b/docs/html/training/basics/fragments/communicating.jd index b30045d..8c1ae21 100644 --- a/docs/html/training/basics/fragments/communicating.jd +++ b/docs/html/training/basics/fragments/communicating.jd @@ -1,4 +1,6 @@ page.title=Communicating with Other Fragments +page.tags=fragments +helpoutsWidget=true trainingnavtop=true diff --git a/docs/html/training/basics/fragments/creating.jd b/docs/html/training/basics/fragments/creating.jd index 377adfc..7afb149 100644 --- a/docs/html/training/basics/fragments/creating.jd +++ b/docs/html/training/basics/fragments/creating.jd @@ -1,4 +1,6 @@ page.title=Creating a Fragment +page.tags=fragments +helpoutsWidget=true trainingnavtop=true diff --git a/docs/html/training/basics/fragments/fragment-ui.jd b/docs/html/training/basics/fragments/fragment-ui.jd index 4fa5b70..1061c15 100644 --- a/docs/html/training/basics/fragments/fragment-ui.jd +++ b/docs/html/training/basics/fragments/fragment-ui.jd @@ -1,4 +1,6 @@ page.title=Building a Flexible UI +page.tags=fragments +helpoutsWidget=true trainingnavtop=true diff --git a/docs/html/training/basics/fragments/index.jd b/docs/html/training/basics/fragments/index.jd index e78b694..aba6459 100644 --- a/docs/html/training/basics/fragments/index.jd +++ b/docs/html/training/basics/fragments/index.jd @@ -1,5 +1,6 @@ page.title=Building a Dynamic UI with Fragments page.tags=fragments,user interface,support library +helpoutsWidget=true trainingnavtop=true startpage=true diff --git a/docs/html/training/basics/fragments/support-lib.jd b/docs/html/training/basics/fragments/support-lib.jd index 1d538af..a1d781b 100644 --- a/docs/html/training/basics/fragments/support-lib.jd +++ b/docs/html/training/basics/fragments/support-lib.jd @@ -1,5 +1,6 @@ page.title=Using the Support Library page.tags=support library +helpoutsWidget=true trainingnavtop=true diff --git a/docs/html/training/basics/intents/filters.jd b/docs/html/training/basics/intents/filters.jd index 10bf43d..221e31b 100644 --- a/docs/html/training/basics/intents/filters.jd +++ b/docs/html/training/basics/intents/filters.jd @@ -1,10 +1,8 @@ page.title=Allowing Other Apps to Start Your Activity -parent.title=Interacting with Other Apps -parent.link=index.html +page.tags=intents +helpoutsWidget=true trainingnavtop=true -previous.title=Getting a Result from an Activity -previous.link=result.html @jd:body diff --git a/docs/html/training/basics/intents/index.jd b/docs/html/training/basics/intents/index.jd index aa0232a..d584161 100644 --- a/docs/html/training/basics/intents/index.jd +++ b/docs/html/training/basics/intents/index.jd @@ -1,5 +1,6 @@ page.title=Interacting with Other Apps page.tags=intents,activity +helpoutsWidget=true trainingnavtop=true startpage=true diff --git a/docs/html/training/basics/intents/result.jd b/docs/html/training/basics/intents/result.jd index 64fbb8b..b521488 100644 --- a/docs/html/training/basics/intents/result.jd +++ b/docs/html/training/basics/intents/result.jd @@ -1,12 +1,8 @@ page.title=Getting a Result from an Activity -parent.title=Interacting with Other Apps -parent.link=index.html +page.tags=intents +helpoutsWidget=true trainingnavtop=true -previous.title=Sending the User to Another App -previous.link=sending.html -next.title=Allowing Other Apps to Start Your Activity -next.link=filters.html @jd:body diff --git a/docs/html/training/basics/intents/sending.jd b/docs/html/training/basics/intents/sending.jd index 2a4dae7..4698ba1 100644 --- a/docs/html/training/basics/intents/sending.jd +++ b/docs/html/training/basics/intents/sending.jd @@ -1,10 +1,8 @@ page.title=Sending the User to Another App -parent.title=Interacting with Other Apps -parent.link=index.html +page.tags=intents +helpoutsWidget=true trainingnavtop=true -next.title=Getting a Result from an Activity -next.link=result.html @jd:body diff --git a/docs/html/training/basics/supporting-devices/index.jd b/docs/html/training/basics/supporting-devices/index.jd index 6f339f4..4644c31 100644 --- a/docs/html/training/basics/supporting-devices/index.jd +++ b/docs/html/training/basics/supporting-devices/index.jd @@ -1,5 +1,5 @@ page.title=Supporting Different Devices -page.tags=resources,screens,versions,localization +page.tags=layouts,resources,screens,localization trainingnavtop=true startpage=true diff --git a/docs/html/training/basics/supporting-devices/languages.jd b/docs/html/training/basics/supporting-devices/languages.jd index aab1e38..098b556 100644 --- a/docs/html/training/basics/supporting-devices/languages.jd +++ b/docs/html/training/basics/supporting-devices/languages.jd @@ -1,11 +1,9 @@ page.title=Supporting Different Languages parent.title=Supporting Different Devices -page.tags=localizing,localization,resources,formats,l10n -parent.link=index.html +page.tags=strings,localizing,localization,resources,formats,l10n +helpoutsWidget=true trainingnavtop=true -next.title=Supporting Different Screens -next.link=screens.html @jd:body diff --git a/docs/html/training/basics/supporting-devices/platforms.jd b/docs/html/training/basics/supporting-devices/platforms.jd index 60aaf6a..9890c98 100644 --- a/docs/html/training/basics/supporting-devices/platforms.jd +++ b/docs/html/training/basics/supporting-devices/platforms.jd @@ -1,11 +1,9 @@ page.title=Supporting Different Platform Versions page.metaDescription=Training on how to declare support for minimum and target API levels. -parent.title=Supporting Different Devices -parent.link=index.html +page.tags=styles +helpoutsWidget=true trainingnavtop=true -previous.title=Supporting Different Screens -previous.link=screens.html @jd:body diff --git a/docs/html/training/basics/supporting-devices/screens.jd b/docs/html/training/basics/supporting-devices/screens.jd index e52ee70..4b54de8 100644 --- a/docs/html/training/basics/supporting-devices/screens.jd +++ b/docs/html/training/basics/supporting-devices/screens.jd @@ -1,12 +1,8 @@ page.title=Supporting Different Screens -parent.title=Supporting Different Devices -parent.link=index.html +page.tags=layouts +helpoutsWidget=true trainingnavtop=true -previous.title=Supporting Different Languages -previous.link=languages.html -next.title=Supporting Different Platform Versions -next.link=platforms.html @jd:body diff --git a/docs/html/training/in-app-billing/preparing-iab-app.jd b/docs/html/training/in-app-billing/preparing-iab-app.jd index 47fcbbd..344693a 100644 --- a/docs/html/training/in-app-billing/preparing-iab-app.jd +++ b/docs/html/training/in-app-billing/preparing-iab-app.jd @@ -78,14 +78,16 @@ next.link=list-iab-products.html <ol> <li>Copy the {@code IInAppBillingService.aidl} file to your Android project. <ul> - <li>If you are using Eclipse: Import the {@code IInAppBillingService.aidl} file into your {@code /src} directory.</li> - <li>If you are developing in a non-Eclipse environment: Create the following directory {@code /src/com/android/vending/billing} and copy the {@code IInAppBillingService.aidl} file into this directory.</li> + <li>In Android Studio: Create a directory named {@code aidl} under {@code src/main}, add a new + package {@code com.android.vending.billing} in this directory, and import the + {@code IInAppBillingService.aidl} file into this package.</li> + <li>In Eclipse: Import the {@code IInAppBillingService.aidl} file into your {@code /src} directory.</li> + <li>In other dev environments: Create the following directory {@code /src/com/android/vending/billing} and copy the {@code IInAppBillingService.aidl} file into this directory.</li> </ul> </li> <li>Build your application. You should see a generated file named {@code IInAppBillingService.java} in the {@code /gen} directory of your project.</li> <li>Add the helper classes from the {@code /util} directory of the {@code TrivialDrive} sample to your project. Remember to change the package name declarations in those files accordingly so that your project compiles correctly.</li> </ol> - <p>Your project should now contain the In-app Billing Version 3 library.</p> <h2 id="SetPermission">Set the Billing Permission</h2> @@ -106,7 +108,7 @@ IabHelper mHelper; public void onCreate(Bundle savedInstanceState) { // ... String base64EncodedPublicKey; - + // compute your public key and store it in base64EncodedPublicKey mHelper = new IabHelper(this, base64EncodedPublicKey); } @@ -120,15 +122,15 @@ mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() { if (!result.isSuccess()) { // Oh noes, there was a problem. Log.d(TAG, "Problem setting up In-app Billing: " + result); - } - // Hooray, IAB is fully set up! + } + // Hooray, IAB is fully set up! } }); </pre> <p>If the setup completed successfully, you can now use the {@code mHelper} reference to communicate with the Google Play service. When your application is launched, it is a good practice to query Google Play to find out what in-app items are owned by a user. This is covered further in the <a href="{@docRoot}training/in-app-billing/purchase-iab-products.html#QueryPurchases">Query Purchased Items</a> section.</p> -<p class="note"><strong>Important:</strong> Remember to unbind from the In-app Billing service when you are done with your activity. If you don’t unbind, the open service connection could cause your device’s performance to degrade. To unbind and free your system resources, call the {@code IabHelper}'s {@code dispose} method when your {@code Activity} gets destroyed.</p> +<p class="note"><strong>Important:</strong> Remember to unbind from the In-app Billing service when you are done with your activity. If you don’t unbind, the open service connection could cause your device’s performance to degrade. To unbind and free your system resources, call the {@code IabHelper}'s {@code dispose} method when your {@code Activity} is destroyed.</p> <pre> @Override diff --git a/docs/html/training/location/index.jd b/docs/html/training/location/index.jd index 249c42d..f0024e2 100644 --- a/docs/html/training/location/index.jd +++ b/docs/html/training/location/index.jd @@ -21,7 +21,8 @@ startpage=true <h2>You should also read</h2> <ul> <li> - <a href="{@docRoot}google/play-services/setup.html">Setup Google Play Services SDK</a> + <a href="{@docRoot}google/play-services/setup.html">Set Up Google Play + Services SDK</a> </li> </ul> @@ -29,68 +30,75 @@ startpage=true </div> <p> - One of the unique features of mobile applications is location awareness. Mobile users bring - their devices with them everywhere, and adding location awareness to your app offers users a - more contextual experience. The new Location Services API available in Google Play services - facilitates adding location awareness to your app with automated location tracking, - geofencing, and activity recognition. This API adds significant advantages over the plaform's - location API. + One of the unique features of mobile applications is location awareness. + Mobile users take their devices with them everywhere, and adding location + awareness to your app offers users a more contextual experience. The location + APIs available in Google Play services facilitate adding location awareness to + your app with automated location tracking, geofencing, and activity + recognition. </p> + +<p>The + <a href="{@docRoot}reference/com/google/android/gms/location/package-summary.html">Google + Play services location APIs</a> are preferred over the Android framework + location APIs + (<a href="{@docRoot}reference/android/location/package-summary.html">android.location</a>) + as a way of adding location awareness to your app. If you are currently using + the Android framework location APIs, you are strongly encouraged to switch to + the Google Play services location APIs as soon as possible. +</p> + <p> - This class shows you how to use Location Services in your app to get the current location, - get periodic location updates, look up addresses, create and monitor geofences, and - detect user activities. The class includes sample apps and code snippets that you can use as a - starting point for adding location awareness to your own app. + This class shows you how to use the Google Play services location APIs in your + app to get the current location, get periodic location updates, look up + addresses, create and monitor geofences, and detect user activities. The class + includes sample apps and code snippets that you can use as a starting point + for adding location awareness to your app. </p> + <p class="note"> - <strong>Note:</strong> Since this class is based on the Google Play services client library, - make sure you install the latest version before using the sample apps or code snippets. To learn - how to set up the client library with the latest version, see - <a href="{@docRoot}google/play-services/setup.html">Setup</a> in the Google Play services guide. + <strong>Note:</strong> Since this class is based on the Google Play services + client library, make sure you install the latest version before using the + sample apps or code snippets. To learn how to set up the client library with + the latest version, see + <a href="{@docRoot}google/play-services/setup.html">Setup</a> in the Google + Play services guide. </p> <h2>Lessons</h2> <dl> - <dt> - <b><a href="retrieve-current.html">Retrieving the Current Location</a></b> - </dt> - <dd> - Learn how to retrieve the user's current location. - </dd> - <dt> - <b><a href="receive-location-updates.html">Receiving Location Updates</a></b> - </dt> - <dd> - Learn how to request and receive periodic location updates. - </dd> - <dt> - <b><a href="display-address.html">Displaying a Location Address</a></b> - </dt> - <dd> - Learn how to convert a location's latitude and longitude into an address (reverse - geocoding). - </dd> - <dt> - <b> - <a href="geofencing.html">Creating and Monitoring Geofences</a> - </b> - </dt> - <dd> - Learn how to define one or more geographic areas as locations of interest, called geofences, - and detect when the user is close to or inside a geofence. - </dd> - <dt> - <b><a href="activity-recognition.html">Recognizing the User's Current Activity</a></b> - </dt> - <dd> - Learn how to recognize the user's current activity, such as walking, bicycling, - or driving a car, and how to use this information to modify your app's location strategy. - </dd> - <dt> - <b><a href="location-testing.html">Testing Using Mock Locations</a></b> - </dt> - <dd> - Learn how to test a location-aware app by injecting mock locations into Location - Services. In mock mode, Location Services sends out mock locations that you inject instead - of sensor-based locations. - </dd> + <dt> + <b><a href="retrieve-current.html">Retrieving the Current Location</a></b> + </dt> <dd> + Learn how to retrieve the user's current location. + </dd> <dt> + <b><a href="receive-location-updates.html">Receiving Location + Updates</a></b> + </dt> <dd> + Learn how to request and receive periodic location updates. + </dd> <dt> + <b><a href="display-address.html">Displaying a Location Address</a></b> + </dt> <dd> + Learn how to convert a location's latitude and longitude into an address + (reverse geocoding). + </dd> <dt> + <b> + <a href="geofencing.html">Creating and Monitoring Geofences</a> + </b> + </dt> <dd> + Learn how to define one or more geographic areas as locations of interest, + called geofences, and detect when the user is close to or inside a geofence. + </dd> <dt> + <b><a href="activity-recognition.html">Recognizing the User's Current + Activity</a></b> + </dt> <dd> + Learn how to recognize the user's current activity, such as walking, + bicycling, or driving a car, and how to use this information to modify your + app's location strategy. + </dd> <dt> + <b><a href="location-testing.html">Testing Using Mock Locations</a></b> + </dt> <dd> + Learn how to test a location-aware app by injecting mock locations into + Location Services. In mock mode, Location Services sends out mock locations + that you inject instead of sensor-based locations. + </dd> </dl> diff --git a/docs/html/training/material/animations.jd b/docs/html/training/material/animations.jd index e8291b8..efc0ee3 100644 --- a/docs/html/training/material/animations.jd +++ b/docs/html/training/material/animations.jd @@ -84,12 +84,14 @@ int cx = (myView.getLeft() + myView.getRight()) / 2; int cy = (myView.getTop() + myView.getBottom()) / 2; // get the final radius for the clipping circle -int finalRadius = myView.getWidth(); +int finalRadius = Math.max(myView.getWidth(), myView.getHeight()); -// create and start the animator for this view -// (the start radius is zero) +// create the animator for this view (the start radius is zero) Animator anim = ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0, finalRadius); + +// make the view visible and start the animation +myView.setVisibility(View.VISIBLE); anim.start(); </pre> diff --git a/docs/html/training/material/compatibility.jd b/docs/html/training/material/compatibility.jd index 5e03450..49ef7f7 100644 --- a/docs/html/training/material/compatibility.jd +++ b/docs/html/training/material/compatibility.jd @@ -131,9 +131,9 @@ href="{@docRoot}/sdk/installing/studio-build.html#dependencies">Gradle dependenc <pre> dependencies { - compile 'com.android.support:appcompat-v7:+' - compile 'com.android.support:cardview-v7:+' - compile 'com.android.support:recyclerview-v7:+' + compile 'com.android.support:appcompat-v7:21.0.+' + compile 'com.android.support:cardview-v7:21.0.+' + compile 'com.android.support:recyclerview-v7:21.0.+' } </pre> diff --git a/docs/html/training/material/drawables.jd b/docs/html/training/material/drawables.jd index 8d7f453..fd21e3d 100644 --- a/docs/html/training/material/drawables.jd +++ b/docs/html/training/material/drawables.jd @@ -73,7 +73,7 @@ app's module:</p> <pre> dependencies { ... - compile 'com.android.support:palette-v7:+' + compile 'com.android.support:palette-v7:21.0.+' } </pre> diff --git a/docs/html/training/material/images/shadows-depth.png b/docs/html/training/material/images/shadows-depth.png Binary files differindex 26b6b4a..d28ac79 100644 --- a/docs/html/training/material/images/shadows-depth.png +++ b/docs/html/training/material/images/shadows-depth.png diff --git a/docs/html/training/material/index.jd b/docs/html/training/material/index.jd index 542a941..4eb7911 100644 --- a/docs/html/training/material/index.jd +++ b/docs/html/training/material/index.jd @@ -1,6 +1,6 @@ page.title=Creating Apps with Material Design page.type=design -page.image=design/material/images/MaterialLight.png +page.image=images/material.png page.metaDescription=Learn how to apply material design to your apps. diff --git a/docs/html/training/material/lists-cards.jd b/docs/html/training/material/lists-cards.jd index eb45f0d..e7bdfe0 100644 --- a/docs/html/training/material/lists-cards.jd +++ b/docs/html/training/material/lists-cards.jd @@ -260,7 +260,7 @@ app's module:</p> <pre> dependencies { ... - compile 'com.android.support:cardview-v7:+' - compile 'com.android.support:recyclerview-v7:+' + compile 'com.android.support:cardview-v7:21.0.+' + compile 'com.android.support:recyclerview-v7:21.0.+' } </pre> diff --git a/docs/html/training/material/shadows-clipping.jd b/docs/html/training/material/shadows-clipping.jd index f58d780..c1cd374 100644 --- a/docs/html/training/material/shadows-clipping.jd +++ b/docs/html/training/material/shadows-clipping.jd @@ -18,28 +18,36 @@ page.title=Defining Shadows and Clipping Views </div> </div> -<p>Material design introduces depth for UI elements. Depth helps users understand the relative -importance of each element and focus their attention to the task at hand.</p> +<p>Material design introduces elevation for UI elements. Elevation helps users understand the +relative importance of each element and focus their attention to the task at hand.</p> -<p>The elevation of a view, represented by the Z property, determines the size of its shadow: -views with higher Z values cast bigger shadows. Views only cast shadows on the Z=0 plane; they -don't cast shadows on other views placed below them and above the Z=0 plane.</p> +<p>The elevation of a view, represented by the Z property, determines the visual appearance of its +shadow: views with higher Z values cast larger, softer shadows. Views with higher Z values occlude +views with lower Z values; however, the Z value of a view does not affect the view's size.</p> -<p>Views with higher Z values occlude views with lower Z values. However, the Z value of a view -does not affect the view's size.</p> +<p>Shadows are drawn by the parent of the elevated view, and thus subject to standard view clipping, +clipped by the parent by default.</p> <p>Elevation is also useful to create animations where widgets temporarily rise above the view plane when performing some action.</p> +<p>For more information about elevation in material design, see +<a href="http://www.google.com/design/spec/what-is-material/objects-in-3d-space.html">Objects +in 3D space</a>.</p> + <h2 id="Elevation">Assign Elevation to Your Views</h2> -<p>The Z value for a view has two components, elevation and translation. The elevation is the -static component, and the translation is used for animations:</p> +<p>The Z value for a view has two components: + +<ul> +<li>Elevation: The static component.</li> +<li>Translation: The dynamic component used for animations.</li> +</ul> <p><code>Z = elevation + translationZ</code></p> -<img src="{@docRoot}training/material/images/shadows-depth.png" width="680" height="177" alt=""/> +<img src="{@docRoot}training/material/images/shadows-depth.png" width="580" height="261" alt=""/> <p class="img-caption"><strong>Figure 1</strong> - Shadows for different view elevations.</p> <p>To set the elevation of a view in a layout definition, use the <code>android:elevation</code> @@ -59,9 +67,9 @@ guide.</p> <p>You can also use a {@link android.animation.StateListAnimator} to specify these animations in a declarative way. This is especially useful for cases where state changes trigger animations, like when a user presses a button. For more information, see -<a href="{@docRoot}training/material/animations.html#ViewState">Animate View State Changes</a></p>. +<a href="{@docRoot}training/material/animations.html#ViewState">Animate View State Changes</a>.</p> -<p>The Z values are measured in the same units as the X and Y values.</p> +<p>The Z values are measured in dp (density-independent pixels).</p> <h2 id="Shadows">Customize View Shadows and Outlines</h2> diff --git a/docs/html/training/search/index.jd b/docs/html/training/search/index.jd index 612e8e8..66874bb 100644 --- a/docs/html/training/search/index.jd +++ b/docs/html/training/search/index.jd @@ -49,5 +49,5 @@ startpage=true <dt><b><a href="backward-compat.html">Remaining Backward Compatible</a></b></dt> - <dd>Learn how to keep search features backward compatible with older devices by using.</dd> + <dd>Learn how to keep search features backward compatible with older devices.</dd> </dl> diff --git a/docs/html/training/sync-adapters/running-sync-adapter.jd b/docs/html/training/sync-adapters/running-sync-adapter.jd index 8fb7e80..194e94b 100644 --- a/docs/html/training/sync-adapters/running-sync-adapter.jd +++ b/docs/html/training/sync-adapters/running-sync-adapter.jd @@ -396,13 +396,11 @@ public class MainActivity extends FragmentActivity { // Account public static final String ACCOUNT = "default_account"; // Sync interval constants - public static final long MILLISECONDS_PER_SECOND = 1000L; public static final long SECONDS_PER_MINUTE = 60L; public static final long SYNC_INTERVAL_IN_MINUTES = 60L; public static final long SYNC_INTERVAL = SYNC_INTERVAL_IN_MINUTES * - SECONDS_PER_MINUTE * - MILLISECONDS_PER_SECOND; + SECONDS_PER_MINUTE; // Global variables // A content resolver for accessing the provider ContentResolver mResolver; @@ -419,7 +417,7 @@ public class MainActivity extends FragmentActivity { ContentResolver.addPeriodicSync( ACCOUNT, AUTHORITY, - null, + Bundle.EMPTY, SYNC_INTERVAL); ... } diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs index 0fee771..7a0e413 100644 --- a/docs/html/training/training_toc.cs +++ b/docs/html/training/training_toc.cs @@ -131,7 +131,7 @@ include the action bar on devices running Android 2.1 or higher." Creating a Fragment </a> </li> - <li><a href="<?cs var:toroot ?>training/basics/fragments/fragment-ui.html"> + <li><a href="<?cs var:toroot ?>training/basics/fragments/fragment-ui.html" zh-cn-lang="构建灵活的界面"> Building a Flexible UI </a> </li> @@ -834,6 +834,12 @@ include the action bar on devices running Android 2.1 or higher." </li> </ul> </li> + <li> + <a href="<?cs var:toroot ?>training/articles/wear-location-detection.html" + description= + "How to detect location data on Android Wear devices." + >Detecting Location</a> + </li> </ul> </li> <!-- End Building for wearables --> @@ -933,6 +939,36 @@ include the action bar on devices running Android 2.1 or higher." <!-- End: Building for TV --> + <!-- Start: Building for Auto --> + <li class="nav-section"> + <div class="nav-section-header"> + <a href="<?cs var:toroot ?>training/auto/index.html"> + <span class="small">Building Apps for</span><br/> + Auto + </a> + </div> + <ul> + <li> + <a href="<?cs var:toroot ?>training/auto/start/index.html" + description="How to start building or extending apps that work + with Auto devices."> + Getting Started with Auto</a> + </li> + <li> + <a href="<?cs var:toroot ?>training/auto/audio/index.html" + description="How to extend audio apps to play content on Auto devices."> + Playing Audio for Auto</a> + </li> + <li> + <a href="<?cs var:toroot ?>training/auto/messaging/index.html" + description="How to extend text messaging apps to work with Auto devices."> + Messaging for Auto</a> + </li> + </ul> + </li> + <!-- End: Building for Auto --> + + <li class="nav-section"> <div class="nav-section-header"> <a href="<?cs var:toroot ?>training/best-ux.html"> diff --git a/docs/html/training/tv/discovery/index.jd b/docs/html/training/tv/discovery/index.jd index fbc8c9f..5849149 100644 --- a/docs/html/training/tv/discovery/index.jd +++ b/docs/html/training/tv/discovery/index.jd @@ -1,4 +1,5 @@ -page.title=Helping Users Find Content on TV +page.title=Helping Users Find Your Content on TV +page.tags="tv", "leanback" startpage=true diff --git a/docs/html/training/tv/games/index.jd b/docs/html/training/tv/games/index.jd index 29b055b..5276d7f 100644 --- a/docs/html/training/tv/games/index.jd +++ b/docs/html/training/tv/games/index.jd @@ -1,5 +1,7 @@ page.title=Building TV Games -page.tags="controller" +page.tags="tv", "games", "controller" +page.image=images/games/game-controller-buttons_2x_crop.png +page.metaDescription=How to bring your games to Android TV, including recommendations and examples. page.article=true @jd:body @@ -31,7 +33,7 @@ page.article=true </p> -<h3 id="shared-display">Shared display</h3> +<h3 id="shared-display">Consider the shared display</h3> <p> A living-room TV poses design challenges for multiplayer games, in that all players can see @@ -57,7 +59,7 @@ page.article=true </ul> -<h3 id="landscape-display">Landscape display</h3> +<h3 id="landscape-display">Support landscape display</h3> <p> A TV is always sideways: You can’t turn it, and there is no portrait orientation. Always design @@ -69,19 +71,19 @@ page.article=true <p> TVs don't have touch interfaces, so it's even more important to get your controls right and make - sure that players find them intuitive and fun to use. The separation of controller from device - also introduces some other issues to pay attention to, like keeping track of multiple players' + sure players find them intuitive and fun to use. Handling controllers + also introduces some other issues to pay attention to, like keeping track of multiple controllers, and handling disconnects gracefully. </p> -<h3 id="d-pad">D-pad</h3> +<h3 id="d-pad">Support D-pad controls</h3> <p> Plan your control scheme around a directional pad (D-pad) control, since this control set is the default for Android TV devices. The player needs to be able to use a D-Pad in all aspects of the - game–not just controlling core gameplay, but also navigating menus and ads. For this reason, you - should also ensure that your Android TV game does not refer to a touch interface: For example, an - Android TV game should not tell a player to <strong>Tap here to skip</strong>. + game—not just controlling core gameplay, but also navigating menus and ads. For this reason, you + should also ensure that your Android TV game does not refer to a touch interface. For example, an + Android TV game should not tell a player to "<em>Tap</em> here to continue." </p> <p> @@ -91,35 +93,35 @@ page.article=true <ul> <li> - <strong>Communicate Controller Requirements up Front</strong> - Use your Play Store description + <strong>Communicate Controller Requirements up Front</strong>. Use your Google Play description to communicate to the player any expectations about controllers. If a game is better suited to a gamepad with a joystick than one with only a D-pad, make this fact clear. A player who uses - an ill-suited controller for a game is likely to have a subpar experience–and penalize your + an ill-suited controller for a game is likely to have a subpar experience and penalize your game in the ratings. </li> <li> - <strong>Use Consistent Button Mapping</strong> - Intuitive and flexible button mapping is key - to a good user experience. For example, you can adhere to accepted custom by using the A button - to <code>Accept</code>, and the B button to <code>Cancel</code>. You can also offer flexibility - in the form of remappability. For more information on button mapping, see <a href= + <strong>Use Consistent Button Mapping</strong>. Intuitive and flexible button mapping is key + to a good user experience. For example, you should adhere to accepted customs by using the A button + to <em>Accept</em>, and the B button to <em>Cancel</em>. You can also offer flexibility + in the form of remappability. For more information about button mapping, see <a href= "http://developer.android.com/training/game-controllers/controller-input.html">Handling Controller Actions</a>. </li> <li> - <strong>Detect Controller Capabilities and Adjust Accordingly</strong> - Query the controller + <strong>Detect Controller Capabilities and Adjust Accordingly</strong>. Query the controller about its capabilities in order to optimize the match between controller and game. For example, you may intend for a player to steer an object by waving the controller in the air. If a player's controller lacks accelerometer and gyroscope hardware, however, waving will not work. - When, however, your game queries the controller and discovers that motion detection is not - supported, it can switch over to an alternative, available control scheme. For more information - on querying controller capabilities, see <a href= + So, your game should query the controller and if motion detection is not + supported, switch over to an alternative, available control scheme. For more information + about querying controller capabilities, see <a href= "http://developer.android.com/training/game-controllers/compatibility.html">Supporting Controllers Across Android Versions</a>. </li> </ul> -<h3 id="back-button">Back-button behavior</h3> +<h3 id="back-button">Provide appropriate Back-button behavior</h3> <p> The Back button should never act as a toggle. For example, do not use it to both open and close a @@ -139,18 +141,18 @@ page.article=true </p> -<h3 id="multiple-controllers">Handling multiple controllers</h3> +<h3 id="multiple-controllers">Handle multiple controllers</h3> <p> When multiple players are playing a game, each with his or her own controller, it is important to - map each player-controller pair. For information on how to implement controller-number + map each player-controller pair. For information about how to implement controller-number identification, see <a href= "http://developer.android.com/reference/android/view/InputDevice.html#getControllerNumber">Input Devices</a>. </p> -<h3 id="handle-disconnect">Handling disconnects</h3> +<h3 id="handle-disconnect">Handle controller disconnects</h3> <p> When a controller is disconnected in the middle of gameplay, the game should pause, and a dialog @@ -159,7 +161,7 @@ page.article=true <p> The dialog should also offer troubleshooting tips (for example, a pop-up dialog telling the - player to "Check your Bluetooth connection"). For more information on implementing input-device + player to "Check your Bluetooth connection"). For more information about implementing input-device support, see <a href= "http://developer.android.com/training/game-controllers/controller-input.html">Handling Controller Actions</a>. Specific information about Bluetooth connections is at <a href= @@ -167,25 +169,53 @@ page.article=true </p> +<h3 id="ControllerHelp">Show controller instructions</h3> + +<p>If your game provides visual game control instructions, the +controller image should be free of branding and include only <a +href="{@docRoot}training/game-controllers/controller-input.html#button" +>buttons compatible with Android</a>.</p> + +<p>For sample images of an Android-compatible controller, download the +<a href="http://storage.googleapis.com/androiddevelopers/design/android_tv_gamepad_template-2014-10.zip" +>Android TV Gamepad Template (ZIP)</a>. +It includes a white controller on black background and a black controller on white background +(shown in figure 1), as a PNG file and an Adobe® Illustrator® file.</p> + +<img itemprop="image" src="{@docRoot}images/games/game-controller-buttons_2x.png" width="700" + srcset="{@docRoot}images/games/game-controller-buttons_2x.png 2x, + {@docRoot}images/games/game-controller-buttons.png 1x" /> +<p class="img-caption"><b>Figure 1.</b> Example controller instructions using the +<a href="http://storage.googleapis.com/androiddevelopers/design/android_tv_gamepad_template-2014-10.zip" +>Android TV Gamepad Template (ZIP)</a>. + + + + <h2 id="manifest">Manifest</h2> +<p>There are a some special things games should include in the Android manifest.</p> + +<h3 id="Launcher">Show your game on the home screen</h3> <p> - The Android TV launcher home screen displays games in a separate row from regular apps. The TV - framework uses the <code>android:isGame</code> manifest attribute to differentiate games from - non-game apps. Set this value to <code>true</code> in your game's app manifest, as shown in the - following code example: + The Android TV home screen displays games in a separate row from regular apps. + To make your game appear in the list of games, set the + <a href="{@docRoot}guide/topics/manifest/application-element.html#isGame"> + {@code android:isGame}</a> attribute to <code>"true"</code> in your app manifest's + <a href="{@docRoot}guide/topics/manifest/application-element.html"><code><application></code> + </a> tag. For example: </p> <pre class="fragment"> -<application> - ... - < meta-data android:name="isGame" android:value="true" > - ... -</application> +<application + ... + android:isGame="true" + ... +> </pre> -<h3 id="gamepad">Game Controllers</h3> +<h3 id="gamepad">Declare support for game controllers</h3> <p> Games controllers may not be available or active for users of a TV device. In order to properly @@ -215,7 +245,9 @@ page.article=true <h2 id="gpgs">Google Play Game Services</h2> <p> - If your game integrates Google Play Game Services, you should keep in mind a number of + If your game integrates <a + href="https://developers.google.com/games/services/">Google Play Game services</a>, + you should keep in mind a number of considerations pertaining to achievements, sign-in, saving games, and multiplayer play. </p> @@ -224,7 +256,7 @@ page.article=true <p> Your game should include at least five (earnable) achievements. Only a user controlling gameplay - from a supported input device should be able to earn achievements. For more information on + from a supported input device should be able to earn achievements. For more information about achievements and how to implement them, see <a href= "https://developers.google.com/games/services/android/achievements">Achievements in Android</a>. </p> @@ -262,7 +294,7 @@ page.article=true <p> A game offering a multiplayer experience must allow at least two players to enter a room. For - further information on multiplayer games in Android, see the <a href= + further information about multiplayer games in Android, see the <a href= "https://developers.google.com/games/services/android/realtimeMultiplayer">Real-time Multiplayer</a> and <a href="">Turn-based Multiplayer</a> documentation on the Android developer site. diff --git a/docs/html/training/tv/index.jd b/docs/html/training/tv/index.jd index 56667a9..d52e1e8 100644 --- a/docs/html/training/tv/index.jd +++ b/docs/html/training/tv/index.jd @@ -1,8 +1,11 @@ page.title=Building Apps for TV page.trainingcourse=true - +page.metaDescription=Starting point for building apps and games for Android TV, with guidelines, information, and examples. +page.image=design/tv/images/focus.png @jd:body -<p>These classes teach you how to build apps for TV devices.</p>
\ No newline at end of file +<p>These classes teach you how to build apps for TV devices.</p> + +<p class="note"><strong>Note:</strong> For details on how to publish your TV apps in Google Play, see <a href="{docRoot}distribute/googleplay/tv.html">Distributing to Android TV</a>.</p>
\ No newline at end of file diff --git a/docs/html/training/tv/playback/index.jd b/docs/html/training/tv/playback/index.jd index 118fc6c..09c3f24 100644 --- a/docs/html/training/tv/playback/index.jd +++ b/docs/html/training/tv/playback/index.jd @@ -1,5 +1,5 @@ page.title=Building TV Playback Apps -page.tags="leanback" +page.tags="tv","leanback" startpage=true diff --git a/docs/html/training/tv/start/hardware.jd b/docs/html/training/tv/start/hardware.jd index 33d396b..fc52602 100644 --- a/docs/html/training/tv/start/hardware.jd +++ b/docs/html/training/tv/start/hardware.jd @@ -85,27 +85,27 @@ if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) </tr> <tr> <td>Touchscreen</td> - <td>android.hardware.touchscreen</td> + <td>{@code android.hardware.touchscreen}</td> </tr> <tr> <td>Telephony</td> - <td>android.hardware.telephony</td> + <td>{@code android.hardware.telephony}</td> </tr> <tr> <td>Camera</td> - <td>android.hardware.camera</td> + <td>{@code android.hardware.camera}</td> </tr> <tr> <td>Near Field Communications (NFC)</td> - <td>android.hardware.nfc</td> + <td>{@code android.hardware.nfc}</td> </tr> <tr> <td>GPS</td> - <td>android.hardware.location.gps</td> + <td>{@code android.hardware.location.gps}</td> </tr> <tr> <td>Microphone</td> - <td>android.hardware.microphone</td> + <td>{@code android.hardware.microphone}</td> </tr> </table> @@ -142,20 +142,17 @@ if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) android:required="false"/> </pre> -<p class="caution"> - <strong>Caution:</strong> Declaring an unavailable hardware feature as required by setting its - value to {@code true} in your app manifest prevents your app from being installed on TV - devices or appearing in the Android TV home screen launcher. +<p> + All apps intended for use on TV devices must declare that the touch screen feature is not required + as described in <a href="{@docRoot}training/tv/start/start.html#no-touchscreen">Get Started with + TV Apps</a>. If your app normally uses one or more of the features listed above, change the + {@code android:required} attribute setting to {@code false} for those features in your manifest. </p> <p class="caution"> - <strong>Caution:</strong> Some <a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">{@code uses-permission}</a> manifest declarations <em>imply hardware use</em>, which can also - prevent your app from being installed and used on TV devices. For example, requesting the - {@link android.Manifest.permission#RECORD_AUDIO} permission in your app implies the - {@code android.hardware.microphone} hardware feature requirement. In which case, you must declare - the microphone feature as not required ({@code android:required="false"}) in your app manifest. - For a list of permission requests that imply a hardware feature requirement, see <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html#permissions-features"> - {@code uses-feature}</a> guide. + <strong>Caution:</strong> Declaring a hardware feature as required by setting its + value to {@code true} prevents your app from being installed on TV + devices or appearing in the Android TV home screen launcher. </p> <p> @@ -172,6 +169,52 @@ if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) </p> +<h3 id="hardware-permissions">Declaring permissions that imply hardware features</h3> + +<p> + Some <a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">{@code uses-permission}</a> + manifest declarations <em>imply hardware features</em>. This behavior means that requesting some + permissions in your app manifest can exclude your app from from being installed and used on TV + devices. The following commonly requested permissions create an implicit hardware feature + requirement: +</p> + +<table> + <tr> + <th>Permission</th> + <th>Implied hardware feature</th> + </tr> + <tr> + <td>{@link android.Manifest.permission#RECORD_AUDIO}</td> + <td>{@code android.hardware.microphone}</td> + </tr> + <tr> + <td>{@link android.Manifest.permission#CAMERA}</td> + <td>{@code android.hardware.camera} <em>and</em> <br> + {@code android.hardware.camera.autofocus}</td> + </tr> + <tr> + <td>{@link android.Manifest.permission#ACCESS_COARSE_LOCATION}</td> + <td>{@code android.hardware.location} <em>and</em> <br> + {@code android.hardware.location.network}</td> + </tr> + <tr> + <td>{@link android.Manifest.permission#ACCESS_FINE_LOCATION}</td> + <td>{@code android.hardware.location} <em>and</em> <br> + {@code android.hardware.location.gps}</td> + </tr> +</table> + +<p> + For a complete list of permission requests that imply a hardware feature requirement, see + <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html#permissions-features">{@code + uses-feature}</a> guide. If your app requests one of the features listed above, include a + <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code uses-feature}</a> + declaration in your manifest for the implied hardware feature that indicates it is not + required ({@code android:required="false"}). +</p> + + <h3 id="check-features">Checking for hardware features</h2> <p> diff --git a/docs/html/training/tv/start/index.jd b/docs/html/training/tv/start/index.jd index ceefea1..fb478a8 100644 --- a/docs/html/training/tv/start/index.jd +++ b/docs/html/training/tv/start/index.jd @@ -1,4 +1,5 @@ page.title=Building TV Apps +page.tags="tv", "leanback" startpage=true @jd:body diff --git a/docs/html/training/tv/start/start.jd b/docs/html/training/tv/start/start.jd index bebeedd..aab1a39 100644 --- a/docs/html/training/tv/start/start.jd +++ b/docs/html/training/tv/start/start.jd @@ -11,6 +11,7 @@ startpage=true <h2>This lesson teaches you how to</h2> <ol> <li><a href="#dev-project">Setup a TV Project</a></li> + <li><a href="#tv-libraries">Add TV Support Libraries</a></li> <li><a href="#build-it">Build TV Apps</a></li> <li><a href="#run">Run TV Apps</a></li> </ol> @@ -86,21 +87,15 @@ startpage=true <p>An application intended to run on TV devices must declare a launcher activity for TV in its manifest using a {@link android.content.Intent#CATEGORY_LEANBACK_LAUNCHER} intent filter. - This filter identifies your app as being enabled for TV, allowing it to be considered a TV app - in Google Play. Declaring this intent also identifies which activity + This filter identifies your app as being enabled for TV, and is required for your app to be + considered a TV app in Google Play. Declaring this intent also identifies which activity in your app to launch when a user selects its icon on the TV home screen.</p> -<p class="caution"> - <strong>Caution:</strong> If you do not include the {@link android.content.Intent#CATEGORY_LEANBACK_LAUNCHER} intent filter in - your app, it is not visible to users running the Google Play store on TV devices. Also, if your - app does not have this filter when you load it onto a TV device using developer tools, the app - does not appear in the TV user interface. -</p> - <p>The following code snippet shows how to include this intent filter in your manifest:</p> <pre> -<application> +<application + android:banner="@drawable/banner" > ... <activity android:name="com.example.android.MainActivity" @@ -131,6 +126,14 @@ startpage=true launch on a TV device. </p> +<p class="caution"> + <strong>Caution:</strong> If you do not include the + {@link android.content.Intent#CATEGORY_LEANBACK_LAUNCHER} intent filter in + your app, it is not visible to users running the Google Play store on TV devices. Also, if your + app does not have this filter when you load it onto a TV device using developer tools, the app + does not appear in the TV user interface. +</p> + <p> If you are modifying an existing app for use on TV, your app should not use the same activity layout for TV that it does for phones and tablets. The user interface of your TV app (or @@ -142,7 +145,61 @@ startpage=true </p> -<h3 id="tv-libraries">Add TV support libraries</h3> +<h3 id="no-touchscreen">Declare touchscreen not required</h3> + +<p> + Applications that are intended to run on TV devices do not rely on touch screens for input. In + order to make this clear, the manifest of your TV app must declare that a the {@code + android.hardware.touchscreen} feature is not required. This setting identifies your app as being + able to work on a TV device, and is required for your app to be considered a TV app in Google + Play. The following code example shows how to include this manifest declaration: +</p> + +<pre> +<manifest> + <strong><uses-feature android:name="android.hardware.touchscreen" + android:required="false" /></strong> + ... +</manifest> +</pre> + +<p class="caution"> + <strong>Caution:</strong> You must declare that a touch screen is not required in your app + manifest, as shown this example code, or your app cannot appear in the Google Play store on TV + devices. +</p> + +<h3 id="banner">Provide a home screen banner</h3> + +<p> + An application must provide a home screen banner if it includes a Leanback launcher intent + filter. The banner is the app launch point that appears on the home screen in the apps and + games rows. Desribe the banner in the manifest as follows: +</p> + +<pre> +<application + ... + android:banner="@drawable/banner" > + + ... +</application> +</pre> + +<p> + Use the <a href="{@docRoot}guide/topics/manifest/application-element.html#banner">{@code android:banner}</a> + attribute with the <a href="{@docRoot}guide/topics/manifest/application.html"><code><application></code></a> + tag to supply a default banner for all application activities, or with the + <a href="{@docRoot}guide/topics/manifest/activity-element.html"><code><activity></code></a> + tag to supply a banner for a specific activity. +</p> + +<p> + See <a href="{@docRoot}design/tv/patterns.html#banner">Banners</a> in the UI Patterns for TV + design guide. +</p> + +<h2 id="tv-libraries">Add TV Support Libraries</h3> <p> The Android SDK includes support libraries that are intended for use with TV apps. These diff --git a/docs/html/training/tv/tif/index.jd b/docs/html/training/tv/tif/index.jd index 4746e42..cde8ba7 100644 --- a/docs/html/training/tv/tif/index.jd +++ b/docs/html/training/tv/tif/index.jd @@ -1,5 +1,5 @@ page.title=Building Live TV Apps -page.tags=tif +page.tags="tv", "tif" page.article=true @jd:body diff --git a/docs/html/training/wearables/apps/bt-debugging.jd b/docs/html/training/wearables/apps/bt-debugging.jd index 8d09c43..7569e7e 100644 --- a/docs/html/training/wearables/apps/bt-debugging.jd +++ b/docs/html/training/wearables/apps/bt-debugging.jd @@ -19,7 +19,7 @@ page.title=Debugging over Bluetooth </div> </div> -<p>You can debug your wearable over Bluetooth by routing it's debug output to the +<p>You can debug your wearable over Bluetooth by routing its debug output to the handheld device that's connected to your development machine.</p> <h2 id="SetupDevices">Setup Devices for Debugging</h2> @@ -58,7 +58,8 @@ Target: connected </li> <li>Connect the handheld to your machine over USB and run: <pre> -adb forward tcp:4444 localabstract:/adb-hub; adb connect localhost:4444 +adb forward tcp:4444 localabstract:/adb-hub +adb connect localhost:4444 </pre> <p class="note"><b>Note</b>: You can use any available port that you have access to.</p> @@ -89,4 +90,4 @@ adb -e <command> adb -e logcat adb -e shell adb -e bugreport -</pre>
\ No newline at end of file +</pre> diff --git a/docs/html/training/wearables/apps/creating.jd b/docs/html/training/wearables/apps/creating.jd index 7252ada..018d9f7 100644 --- a/docs/html/training/wearables/apps/creating.jd +++ b/docs/html/training/wearables/apps/creating.jd @@ -92,6 +92,11 @@ types of screen shapes, which is useful for testing.</p> <li>Leave the Android Wear app open on your phone.</li> <li>Connect the wearable to your machine through USB, so you can install apps directly to it as you develop. A message appears on both the wearable and the Android Wear app prompting you to allow debugging.</li> + <p class="note"><strong>Note:</strong> If you can not connect your wearable to your machine via USB, + follow the directions on + <a href="{@docRoot}training/wearables/apps/bt-debugging.html">Debugging over + Bluetooth</a>. + </p> <li>On the Android Wear app, check <strong>Always allow from this computer</strong> and tap <strong>OK</strong>.</li> </ol> diff --git a/docs/html/training/wearables/apps/index.jd b/docs/html/training/wearables/apps/index.jd index 7d961b7..4bdd6bf 100644 --- a/docs/html/training/wearables/apps/index.jd +++ b/docs/html/training/wearables/apps/index.jd @@ -1,5 +1,6 @@ page.title=Creating Wearable Apps -page.image=wear/images/notifications.png +page.tags="wear","wearable","app" +page.image=wear/images/01_create.png @jd:body @@ -63,7 +64,7 @@ in ADT. The rest of this training assumes you're using Android Studio. <dd>Learn how to create and display custom layouts for notifications and activities.</dd> <dt><a href="{@docRoot}training/wearables/apps/voice.html">Adding Voice Capabilities</a></dt> - <dd>Learn how to launch an activity with a voice actions and how to start the + <dd>Learn how to launch an activity with voice actions and how to start the system speech recognizer app to obtain free-form voice input.</dd> <dt><a href="{@docRoot}training/wearables/apps/packaging.html">Packaging Wearable Apps</a></dt> <dd>Learn how to package a wearable app inside a diff --git a/docs/html/training/wearables/apps/layouts.jd b/docs/html/training/wearables/apps/layouts.jd index e62d3e5..a35acb0 100644 --- a/docs/html/training/wearables/apps/layouts.jd +++ b/docs/html/training/wearables/apps/layouts.jd @@ -90,9 +90,10 @@ PendingIntent notificationPendingIntent = PendingIntent.getActivity(this, 0, not </ol> <h2 id="UiLibrary">Create Layouts with the Wearable UI Library</h2> <p> -There's an unofficial UI library that is automatically included when you create your wearable -app with the Android Studio Project Wizard. You can also add the library to your <code>build.gradle</code> +The Wearable UI Library is automatically included when you create your wearable +app with the Android Studio Project Wizard. You can also add this library to your <code>build.gradle</code> file with the following dependency declaration: +</p> <pre> dependencies { @@ -101,8 +102,11 @@ dependencies { compile 'com.google.android.gms:play-services-wearable:+' } </pre> -This library helps you build UIs that are designed for wearables. Here are some of the major classes: -</p> + +<p>This library helps you build UIs that are designed for wearables. For more information, see +<a href="{@docRoot}training/wearables/ui/index.html">Creating Custom UIs for Wear Devices</a>.</p> + +<p>Here are some of the major classes in the Wearable UI Library:</p> <ul> <li><code>BoxInsetLayout</code> - A FrameLayout that's aware of screen shape and can box its diff --git a/docs/html/training/wearables/data-layer/accessing.jd b/docs/html/training/wearables/data-layer/accessing.jd index 896a698..0c0a2d5 100644 --- a/docs/html/training/wearables/data-layer/accessing.jd +++ b/docs/html/training/wearables/data-layer/accessing.jd @@ -12,15 +12,15 @@ page.title=Accessing the Wearable Data Layer <h2>Dependencies and Prerequisites</h2> <ol> - <li><a href="{@docRoot}training/wearables/apps/environment.html">Creating - Wearable Apps > Setting up Your Environment</a></li> - <li><a href="{@docRoot}training/wearables/apps/creating.html">Creating + <li><a href="{@docRoot}training/wearables/apps/creating.html#SetupEmulator">Creating + Wearable Apps > Set Up an Android Wear Emulator or Device</a></li> + <li><a href="{@docRoot}training/wearables/apps/creating.html#CreateProject">Creating Wearable Apps > Creating a Project</a></li> </ol> </div> </div> -<p>To call the data layer API, create an instance of +<p>To call the Data Layer API, create an instance of <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html"><code>GoogleApiClient</code></a>, the main entry point for any of the Google Play services APIs. </p> @@ -37,12 +37,12 @@ for more information about creating a <a href="{@docRoot}reference/com/google/an implementing its callbacks, and handling error cases.</p> <pre style="clear:right"> -GoogleApiClient mGoogleAppiClient = new GoogleApiClient.Builder(this) +GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this) .addConnectionCallbacks(new ConnectionCallbacks() { @Override public void onConnected(Bundle connectionHint) { Log.d(TAG, "onConnected: " + connectionHint); - // Now you can use the data layer API + // Now you can use the Data Layer API } @Override public void onConnectionSuspended(int cause) { @@ -55,13 +55,26 @@ GoogleApiClient mGoogleAppiClient = new GoogleApiClient.Builder(this) Log.d(TAG, "onConnectionFailed: " + result); } }) + // Request access only to the Wearable API .addApi(Wearable.API) .build(); </pre> +<p class="caution"> +<strong>Important:</strong> To avoid client connection errors on devices that do not have the +<a href="https://play.google.com/store/apps/details?id=com.google.android.wearable.app&hl=en">Android +Wear app</a> installed, use a separate <a +href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html">{@code +GoogleApiClient}</a> instance to access only the <a +href="{@docRoot}reference/com/google/android/gms/wearable/Wearable.html">{@code +Wearable}</a> API. For more information, see <a +href="{@docRoot}google/auth/api-client.html#WearableApi">Access the Wearable API</a>.</p> + <p>Before you use the data layer API, start a connection on your client by calling the -<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html#connect()">connect()</a> +<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html#connect()"> +<code>connect()</code></a> method, as described in -<a href="{@docRoot}google/auth/api-client.html#Starting">Accessing Google Play services APIs</a>. -When the system invokes the <code>onConnected()</code> callback for your client, you're ready -to use the data layer API.</p>
\ No newline at end of file +<a href="{@docRoot}google/auth/api-client.html#Starting">Start a Connection</a>. +When the system invokes the +<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)"> +<code>onConnected()</code></a> callback for your client, you're ready to use the Data Layer API.</p> diff --git a/docs/html/training/wearables/data-layer/assets.jd b/docs/html/training/wearables/data-layer/assets.jd index 5dc11cb..719ccbc 100644 --- a/docs/html/training/wearables/data-layer/assets.jd +++ b/docs/html/training/wearables/data-layer/assets.jd @@ -16,18 +16,18 @@ page.title=Transferring Assets <p> To send large blobs of binary data over the Bluetooth transport, such as images, attach an -<a href="{@docRoot}reference/com/google/android/gms/wearable/Asset.html">Asset</a> to a +<a href="{@docRoot}reference/com/google/android/gms/wearable/Asset.html"><code>Asset</code></a> to a data item and the put the data item into the replicated data store. </p> <p>Assets automatically handle caching of data to prevent retransmission and conserve Bluetooth bandwidth. A common pattern is for a handheld app to download an image, shrink it to an appropriate size -for display on the wearable, and transmit it to the wearable app as an Asset. The following examples -demonstrates this pattern. +for display on the wearable, and transmit it to the wearable app as an asset. The following examples +demonstrate this pattern. </p> -<p class="note"><b>Note:</b> Although the size of data items are limited to 100KB, -assets can be as large as desired. However, transferring large assets affect the +<p class="note"><b>Note:</b> Although the size of data items is limited to 100KB, +assets can be as large as desired. However, transferring large assets affects the user experience in many cases, so test your apps to ensure that they perform well if you're transferring large assets. <p> @@ -49,7 +49,6 @@ private static Asset createAssetFromBitmap(Bitmap bitmap) { </pre> <p>When you have an asset, attach it to a data item with the <code>putAsset()</code> method in - <a href="{@docRoot}reference/com/google/android/gms/wearable/DataMap.html"><code>DataMap</code></a> or <a href="{@docRoot}reference/com/google/android/gms/wearable/PutDataRequest.html"><code>PutDataRequest</code></a> @@ -77,12 +76,13 @@ PendingResult<DataApi.DataItemResult> pendingResult = Wearable.DataApi .putDataItem(mGoogleApiClient, request); </pre> + <h2 id="ReceiveAsset">Receive assets</h2> <p> When an asset is created, you probably want to read and extract it on other side of the connection. Here's an example of how to implement the -callback to detect an asset change and extract the Asset: +callback to detect an asset change and extract the asset: </p> <pre> diff --git a/docs/html/training/wearables/data-layer/data-items.jd b/docs/html/training/wearables/data-layer/data-items.jd index 63c32ea..12babbf 100644 --- a/docs/html/training/wearables/data-layer/data-items.jd +++ b/docs/html/training/wearables/data-layer/data-items.jd @@ -15,9 +15,9 @@ page.title=Syncing Data Items </div> <p> -A <a href="@{docRoot}reference/com/google/android/gms/wearable/DataItem.html"><code>DataItem</code></a> +A <a href="{@docRoot}reference/com/google/android/gms/wearable/DataItem.html"><code>DataItem</code></a> defines the data interface that the system uses to synchronize data between handhelds -and wearables. A <a href="@{docRoot}reference/com/google/android/gms/wearable/DataItem.html"><code>DataItem</code></a> generally +and wearables. A <a href="{@docRoot}reference/com/google/android/gms/wearable/DataItem.html"><code>DataItem</code></a> generally consists of the following items:</p> <ul> <li><b>Payload</b> - A byte array, which you can set with whatever data you wish, allowing you @@ -28,15 +28,15 @@ consists of the following items:</p> </ul> <p> -You normally don't implement <a href="@{docRoot}reference/com/google/android/gms/wearable/DataItem.html"><code>DataItem</code></a> +You normally don't implement <a href="{@docRoot}reference/com/google/android/gms/wearable/DataItem.html"><code>DataItem</code></a> directly. Instead, you: <ol> <li>Create a <a href="{@docRoot}reference/com/google/android/gms/wearable/PutDataRequest.html"><code>PutDataRequest</code></a> object, specifying a string path to uniquely identify the item. </li> - <li>Call <a href="{@docRoot}reference/com/google/android/gms/wearable/PutDataRequest.html#setData(byte[])">setData()</a> to set - the payload. + <li>Call <a href="{@docRoot}reference/com/google/android/gms/wearable/PutDataRequest.html#setData(byte[])"> + <code>setData()</code></a> to set the payload. </li> <li>Call <a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.html#putDataItem(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.PutDataRequest)"><code>DataApi.putDataItem()</code></a> to request the system to create the data item. </li> @@ -47,14 +47,15 @@ directly. Instead, you: <p> However, instead of working with raw bytes using <a href="{@docRoot}reference/com/google/android/gms/wearable/PutDataRequest.html#setData(byte[])">setData()</a>, -we recommend you <a href="#data-map">use a data map</a>, which exposes +we recommend you <a href="#SyncData">use a data map</a>, which exposes a data item in an easy-to-use {@link android.os.Bundle}-like interface. </p> + <h2 id="SyncData">Sync Data with a Data Map</h2> <p> -When possible, use the <a href="{@docRoot}reference/com/google/android/gms/wearable/DataMap.html"><code>DataMap</code></a> class, -which lets you work with data items in the form of an Android {@link android.os.Bundle}, +When possible, use the <a href="{@docRoot}reference/com/google/android/gms/wearable/DataMap.html"><code>DataMap</code></a> class. +This approach lets you work with data items in the form of an Android {@link android.os.Bundle}, so object serialization and de-serialization is done for you, and you can manipulate data with key-value pairs. </p> @@ -67,7 +68,7 @@ object, setting the path of the data item. <p class="note"><b>Note:</b> The path string is a unique identifier for the data item that allows you to access it from either side of the connection. The path must begin with a forward slash. If you're using hierarchical data in your -app, you should create a path scheme that matches the structure of the data. +app, you should create a path scheme that matches the structure of the data. </p> </li> <li>Call @@ -82,12 +83,12 @@ app, you should create a path scheme that matches the structure of the data. <li>Call <a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.html#putDataItem(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.PutDataRequest)"><code>DataApi.putDataItem()</code></a> to request the system to create the data item. <p class="note"><b>Note:</b> If the handset and wearable devices are disconnected, - the data is buffered and and synced when the connection is re-established. + the data is buffered and synced when the connection is re-established. </p> </li> </ol> -<p>The following example shows how to create a data map, set data on it, and create it:</p> +<p>The following example shows how to create a data map and put data on it:</p> <pre> PutDataMapRequest dataMap = PutDataMapRequest.create("/count"); @@ -103,7 +104,7 @@ to be notified of any changes on the other side of the connection. You can do this by implementing a listener for data item events. <p>For example, here's what a typical callback looks like to carry out certain actions -when data changes.</p> +when data changes:</p> <pre> @Override @@ -120,5 +121,6 @@ public void onDataChanged(DataEventBuffer dataEvents) { <p> This is just a snippet that requires more implementation details. Learn about how to implement a full listener service or activity in -<a href="{@docRoot}training/wearables/data-layer/events.html">Listening for Data Layer Events</a>. +<a href="{@docRoot}training/wearables/data-layer/events.html#Listen">Listen for Data Layer +Events</a>. </p>
\ No newline at end of file diff --git a/docs/html/training/wearables/data-layer/events.jd b/docs/html/training/wearables/data-layer/events.jd index 9e8acbc..6a3949a 100644 --- a/docs/html/training/wearables/data-layer/events.jd +++ b/docs/html/training/wearables/data-layer/events.jd @@ -14,14 +14,14 @@ page.title=Handling Data Layer Events </div> </div> -<p>When you make calls with the data layer, you can receive the status +<p>When you make calls to the Data Layer API, you can receive the status of the call when it completes as well as listen for any changes that the call ends up making with listeners. </p> <h2 id="Wait">Wait for the Status of Data Layer Calls</h2> -<p>You'll notice that calls to the data layer API sometimes return a +<p>You'll notice that calls to the Data Layer API sometimes return a <a href="{@docRoot}reference/com/google/android/gms/common/api/PendingResult.html"><code>PendingResult</code></a>, such as <a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.html#putDataItem(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.PutDataRequest)"><code>putDataItem()</code></a>. @@ -33,9 +33,9 @@ after the operation completes, so the lets you wait for the result status, either synchronously or asynchronously. </p> -<h3 id="async-waiting">Asynchronously waiting</h3> -<p>If your code is running on the main UI thread, do not making blocking calls -to the data layer API. You can run the calls asynchronously by adding a callback +<h3 id="async-waiting">Asynchronous calls</h3> +<p>If your code is running on the main UI thread, do not make blocking calls +to the Data Layer API. You can run the calls asynchronously by adding a callback method to the <a href="{@docRoot}reference/com/google/android/gms/common/api/PendingResult.html"><code>PendingResult</code></a> object, which fires when the operation is completed:</p> <pre> @@ -49,12 +49,14 @@ pendingResult.setResultCallback(new ResultCallback<DataItemResult>() { }); </pre> -<h3 id="sync-waiting">Synchronously waiting</h3> +<h3 id="sync-waiting">Synchronous calls</h3> <p>If your code is running on a separate handler thread in a background service (which is the case in a <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>), it's fine for the calls to block. In this case, you can call <a href="{@docRoot}reference/com/google/android/gms/common/api/PendingResult.html#await()"><code>await()</code></a> -on the PendingResult object, which will block until the request has completed, and return a Result +on the <a href="{@docRoot}reference/com/google/android/gms/common/api/PendingResult.html"><code>PendingResult</code></a> +object, which blocks until the request completes and returns a +<a href="{@docRoot}reference/com/google/android/gms/common/api/Result.html"><code>Result</code></a> object: </p> @@ -82,14 +84,14 @@ are created, messages are received, or when the wearable and handset are connect </li> </ul> -<p>With both these options, you override any of the data event callbacks that you care about -handling in your implementation.</p> +<p>With both these options, you override the data event callback methods for the events you +are interested in handling.</p> <h3 id="listener-service">With a WearableListenerService</h3> <p> You typically create instances of this service in both your wearable and handheld apps. If you -don't care about data events in one of these apps, then you don't need to implement this +are not interested in data events in one of these apps, then you don't need to implement this service in that particular app.</p> <p>For example, you can have a handheld app that sets and gets data item objects and a wearable app @@ -107,8 +109,9 @@ triggers this callback on both sides.</li> - A message sent from one side of a connection triggers this callback on the other side of the connection.</li> <li><a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html#onMessageReceived(com.google.android.gms.wearable.MessageEvent)"><code>onPeerConnected()</code></a> and <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html#onPeerDisconnected(com.google.android.gms.wearable.Node)"><code>onPeerDisconnected()</code></a> - - Called when connection with the handheld or wearable is connected or disconnected. - Changes in connection state on one side of the connection triggers these callbacks on both sides of the connection. + Called when the connection with the handheld or wearable is connected or disconnected. + Changes in connection state on one side of the connection trigger these callbacks on both sides + of the connection. </li> </ul> @@ -118,8 +121,8 @@ triggers this callback on both sides.</li> <li>Create a class that extends <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>. </li> - <li>Listen for the events that you care about, such as - <a href="{@docRoot}/reference/com/google/android/gms/wearable/WearableListenerService.html#onDataChanged(com.google.android.gms.wearable.DataEventBuffer)"><code>onDataChanged()</code></a>. + <li>Listen for the events that you're interested in, such as + <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html#onDataChanged(com.google.android.gms.wearable.DataEventBuffer)"><code>onDataChanged()</code></a>. </li> <li>Declare an intent filter in your Android manifest to notify the system about your <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>. @@ -159,13 +162,13 @@ public class DataLayerListenerService extends WearableListenerService { } // Loop through the events and send a message - / to the node that created the data item. + // to the node that created the data item. for (DataEvent event : events) { Uri uri = event.getDataItem().getUri(); // Get the node id from the host value of the URI String nodeId = uri.getHost(); - // Set the data of the message to be the bytes of the URI. + // Set the data of the message to be the bytes of the URI byte[] payload = uri.toString().getBytes(); // Send the RPC @@ -189,7 +192,8 @@ public class DataLayerListenerService extends WearableListenerService { <h4>Permissions within Data Layer Callbacks</h4> -<p>In order to deliver callbacks to your application for data layer events, Google Play services +<p> +To deliver callbacks to your application for data layer events, Google Play services binds to your <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>, and calls your callbacks via IPC. This has the consequence that your callbacks inherit the permissions of the calling process.</p> @@ -233,7 +237,7 @@ of the following interfaces: <li>Implement the desired interfaces.</li> <li>In {@link android.app.Activity#onCreate}, create an instance of <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html"><code>GoogleApiClient</code></a> -to work with the data layer API. +to work with the Data Layer API. <li> In {@link android.app.Activity#onStart onStart()}, call <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html#connect()"><code>connect()</code></a> to connect the client to Google Play services. </li> @@ -283,7 +287,7 @@ public class MainActivity extends Activity implements } } - @Override + @Override public void onConnected(Bundle connectionHint) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "Connected to Google Api Service"); @@ -306,8 +310,8 @@ public class MainActivity extends Activity implements if (event.getType() == DataEvent.TYPE_DELETED) { Log.d(TAG, "DataItem deleted: " + event.getDataItem().getUri()); } else if (event.getType() == DataEvent.TYPE_CHANGED) { - Log.d(TAG, "DataItem changed: " + event.getDataItem().getUri()); + Log.d(TAG, "DataItem changed: " + event.getDataItem().getUri()); } } } -</pre>
\ No newline at end of file +</pre> diff --git a/docs/html/training/wearables/data-layer/index.jd b/docs/html/training/wearables/data-layer/index.jd index 39d6561..8d42ae3 100644 --- a/docs/html/training/wearables/data-layer/index.jd +++ b/docs/html/training/wearables/data-layer/index.jd @@ -8,7 +8,7 @@ page.title=Sending and Syncing Data <h2>Dependencies and prerequisites</h2> <ul> <li>Android 4.3 (API Level 18) or higher on the handset device</li> - <li>The latest version of <a href="{@docRoot}google/play">Google Play services</a></li> + <li>The latest version of <a href="{@docRoot}google/play-services/index.html">Google Play services</a></li> <li>An Android Wear device or Wear AVD</li> </ul> </div> @@ -66,7 +66,7 @@ channel. <h2>Lessons</h2> <dl> - <dt><a href="{@docRoot}training/wearables/data-layer/data-items.html">Accessing the Wearable Data Layer</a></dt> + <dt><a href="{@docRoot}training/wearables/data-layer/accessing.html">Accessing the Wearable Data Layer</a></dt> <dd>This lesson shows you how to create a client to access the Data Layer APIs.</dd> <dt><a href="{@docRoot}training/wearables/data-layer/data-items.html">Syncing Data Items</a></dt> @@ -83,5 +83,3 @@ channel. <dt><a href="{@docRoot}training/wearables/data-layer/events.html">Handling Data Layer Events</a></dt> <dd>Be notified of changes and events to the data layer.</dd> </dl> - -</div>
\ No newline at end of file diff --git a/docs/html/training/wearables/data-layer/messages.jd b/docs/html/training/wearables/data-layer/messages.jd index 71f1bb1..822e395 100644 --- a/docs/html/training/wearables/data-layer/messages.jd +++ b/docs/html/training/wearables/data-layer/messages.jd @@ -22,20 +22,16 @@ and attach the following items to the message:</p> <li>A path that uniquely identifies the message's action</li> </ul> <p> -Unlike data items, there is no syncing between the handheld and wearable apps. +Unlike with data items, there is no syncing between the handheld and wearable apps. Messages are a one-way communication mechanism that's good for remote procedure calls (RPC), -such as sending a message to the wearable -to start an activity. You can also use messages in request/response model -where one side of the connection sends a message, does some work, -sends back a response message.</p> +such as sending a message to the wearable to start an activity.</p> <h2 id="SendMessage">Send a Message</h2> <p>The following example shows how to send a message that indicates to the other -side of the connect to start an activity. -This call is made synchronously, which blocks until the message -is received or when the request times out: -</p> +side of the connection to start an activity. +This call is synchronous and blocks processing until the message is received or until the request +times out:</p> <p class="note"><b>Note:</b> Read more about asynchronous and synchronous calls to Google Play services and when to use each in @@ -61,7 +57,7 @@ send messages to:</p> <pre> private Collection<String> getNodes() { - HashSet <String>results= new HashSet<String>(); + HashSet <String>results = new HashSet<String>(); NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).await(); for (Node node : nodes.getNodes()) { @@ -71,14 +67,17 @@ private Collection<String> getNodes() { } </pre> -<h2 id="ReceiveMessage">Receiving a Message</h2> +<h2 id="ReceiveMessage">Receive a Message</h2> <p> - -To be notified of received messages, you implement a listener for message events. -This example shows how you might do this by checking the <code>START_ACTIVITY_PATH</code> -that the previous example used to send the message. If this condition is <code>true</code>, -a specific activity is started. +To be notified of received messages, you implement the +<a href="{@docRoot}reference/com/google/android/gms/wearable/MessageApi.MessageListener.html"> +<code>MessageListener</code></a> interface to provide a listener for message events. Then you register your +listener with the +<a href="{@docRoot}reference/com/google/android/gms/wearable/MessageApi.html#addListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.MessageApi.MessageListener)"> +<code>MessageApi.addListener()</code></a> method. This example shows how you might implement the listener +to check the <code>START_ACTIVITY_PATH</code> that the previous example used to send the message. +If this condition is <code>true</code>, a specific activity is started. </p> <pre> @@ -95,5 +94,6 @@ public void onMessageReceived(MessageEvent messageEvent) { <p> This is just a snippet that requires more implementation details. Learn about how to implement a full listener service or activity in -<a href="{@docRoot}training/wearables/data-layer/events.html">Listening for Data Layer Events</a>. +<a href="{@docRoot}training/wearables/data-layer/events.html#Listen">Listening for Data Layer +Events</a>. </p>
\ No newline at end of file diff --git a/docs/html/training/wearables/notifications/creating.jd b/docs/html/training/wearables/notifications/creating.jd index 84e3311..57ac36e 100644 --- a/docs/html/training/wearables/notifications/creating.jd +++ b/docs/html/training/wearables/notifications/creating.jd @@ -4,7 +4,6 @@ page.title=Creating a Notification <div id="tb-wrapper"> <div id="tb"> - <h2>This lesson teaches you to</h2> <ol> <li><a href="#Import">Import the Necessary Classes</a></li> @@ -30,7 +29,6 @@ Notifications using {@link android.widget.RemoteViews} are stripped of custom layouts and the wearable only displays the text and icons. However, you can create <a href="{@docRoot}training/wearables/apps/layouts.html#CustomNotifications">create custom notifications</a> that use custom card layouts by creating a wearable app that runs on the wearable device.</p> -</div> <h2 id="Import">Import the necessary classes</h2> @@ -255,7 +253,7 @@ NotificationCompat.WearableExtender wearableExtender = Notification notif = new NotificationCompat.Builder(mContext) .setContentTitle("New mail from " + sender) .setContentText(subject) - .setSmallIcon(R.drawable.new_mail); + .setSmallIcon(R.drawable.new_mail) .extend(wearableExtender) .build(); </pre> @@ -278,7 +276,7 @@ method, in the <code>res/drawable-hdpi</code> directory of your handheld app.</p <p>If you ever need to read wearable-specific options at a later time, use the corresponding get method for the option. This example calls the {@link android.support.v4.app.NotificationCompat.WearableExtender#getHintHideIcon()} method to -get whether or not this notification hides the icon: +get whether or not this notification hides the icon:</p> <pre> NotificationCompat.WearableExtender wearableExtender = new NotificationCompat.WearableExtender(notif); @@ -304,14 +302,3 @@ notificationManager.notify(notificationId, notif); features from {@link android.support.v4.app.NotificationCompat.WearableExtender} do not work, so make sure to use {@link android.support.v4.app.NotificationCompat}. </p> - -<pre> -NotificationCompat.WearableExtender wearableExtender = - new NotificationCompat.WearableExtender(notif); -boolean hintHideIcon = wearableExtender.getHintHideIcon(); - </pre> - -<p>The {@link android.support.v4.app.NotificationCompat.WearableExtender} APIs allow you to add -additional pages to notifications, stack notifications, and more. Continue to the following lessons -to learn about these features. -</p> diff --git a/docs/html/training/wearables/notifications/index.jd b/docs/html/training/wearables/notifications/index.jd index 17f3cb3..2833dfa 100644 --- a/docs/html/training/wearables/notifications/index.jd +++ b/docs/html/training/wearables/notifications/index.jd @@ -1,4 +1,6 @@ page.title=Adding Wearable Features to Notifications +page.tags="wear","notifications","wearables" +page.image=wear/images/01_notifications.png @jd:body <div id="tb-wrapper"> @@ -47,5 +49,3 @@ swipes to the left.</dd> <dd>Learn how to place all similar notifications from your app in a stack, allowing users to view each notification individually without adding multiple cards to the card stream.</dd> </dl> - -</div>
\ No newline at end of file diff --git a/docs/html/training/wearables/notifications/pages.jd b/docs/html/training/wearables/notifications/pages.jd index d74c8ea..6315037 100644 --- a/docs/html/training/wearables/notifications/pages.jd +++ b/docs/html/training/wearables/notifications/pages.jd @@ -57,15 +57,14 @@ Notification secondPageNotification = .setStyle(secondPageStyle) .build(); -// Add second page with wearable extender and extend the main notification -Notification twoPageNotification = - new WearableExtender() - .addPage(secondPageNotification) - .extend(notificationBuilder) - .build(); +// Extend the notification builder with the second page +Notification notification = notificationBuilder + .extend(new NotificationCompat.WearableExtender() + .addPage(secondPageNotification)) + .build(); // Issue the notification notificationManager = NotificationManagerCompat.from(this); -notificationManager.notify(notificationId, twoPageNotification); +notificationManager.notify(notificationId, notification); </pre>
\ No newline at end of file diff --git a/docs/html/training/wearables/notifications/stacks.jd b/docs/html/training/wearables/notifications/stacks.jd index e71e74c..9e70e1b 100644 --- a/docs/html/training/wearables/notifications/stacks.jd +++ b/docs/html/training/wearables/notifications/stacks.jd @@ -45,7 +45,7 @@ final static String GROUP_KEY_EMAILS = "group_key_emails"; Notification notif = new NotificationCompat.Builder(mContext) .setContentTitle("New mail from " + sender1) .setContentText(subject1) - .setSmallIcon(R.drawable.new_mail); + .setSmallIcon(R.drawable.new_mail) .setGroup(GROUP_KEY_EMAILS) .build(); @@ -65,7 +65,7 @@ instead of as a new card:</p> Notification notif2 = new NotificationCompat.Builder(mContext) .setContentTitle("New mail from " + sender2) .setContentText(subject2) - .setSmallIcon(R.drawable.new_mail); + .setSmallIcon(R.drawable.new_mail) .setGroup(GROUP_KEY_EMAILS) .build(); @@ -87,7 +87,7 @@ notification and call {@link android.support.v4.app.NotificationCompat.Builder#s on the summary notification.</p> <p>This notification does not appear in your stack of notifications on the wearable, but -appears as the only notification on the handheld device.</p> +it appears as the only notification on the handheld device.</p> <pre style="clear:right"> Bitmap largeIcon = BitmapFactory.decodeResource(getResources(), diff --git a/docs/html/training/wearables/notifications/voice-input.jd b/docs/html/training/wearables/notifications/voice-input.jd index 4a27826..5a49343 100644 --- a/docs/html/training/wearables/notifications/voice-input.jd +++ b/docs/html/training/wearables/notifications/voice-input.jd @@ -37,7 +37,7 @@ so you can type replies instead.</p> <h2 id="VoiceInput">Define the Voice Input</h2> -<p>To create an action that supports voice input, create an instance of +<p>To create an action that supports voice input, create an instance of {@link android.support.v4.app.RemoteInput.Builder} that you can add to your notification action. This class's constructor accepts a string that the system uses as the key for the voice input, which you'll later use to retrieve the text of the @@ -86,7 +86,7 @@ style="float:right;margin:0 0 20px 40px" /> {@link android.support.v4.app.RemoteInput}:</p> <pre> -public static final EXTRA_VOICE_REPLY = "extra_voice_reply"; +public static final String EXTRA_VOICE_REPLY = "extra_voice_reply"; ... String replyLabel = getResources().getString(R.string.reply_label); String[] replyChoices = getResources().getStringArray(R.array.reply_choices); @@ -116,7 +116,7 @@ PendingIntent replyPendingIntent = // Create the reply action and add the remote input NotificationCompat.Action action = new NotificationCompat.Action.Builder(R.drawable.ic_reply_icon, - getString(R.string.label, replyPendingIntent)) + getString(R.string.label), replyPendingIntent) .addRemoteInput(remoteInput) .build(); @@ -166,10 +166,9 @@ which is referenced by the <code>EXTRA_VOICE_REPLY</code> key that is used in th private CharSequence getMessageText(Intent intent) { Bundle remoteInput = RemoteInput.getResultsFromIntent(intent); - if (remoteInput != null) { - return remoteInput.getCharSequence(EXTRA_VOICE_REPLY); - } + if (remoteInput != null) { + return remoteInput.getCharSequence(EXTRA_VOICE_REPLY); } return null; } -</pre>
\ No newline at end of file +</pre> diff --git a/docs/html/training/wearables/ui/index.jd b/docs/html/training/wearables/ui/index.jd index 8ef6fe7..5d97490 100644 --- a/docs/html/training/wearables/ui/index.jd +++ b/docs/html/training/wearables/ui/index.jd @@ -1,4 +1,5 @@ page.title=Creating Custom UIs for Wear Devices +page.image=wear/images/10_uilib.png @jd:body |
