diff options
Diffstat (limited to 'docs/html/training')
-rw-r--r-- | docs/html/training/location/display-address.jd | 680 | ||||
-rw-r--r-- | docs/html/training/training_toc.cs | 29 | ||||
-rw-r--r-- | docs/html/training/transitions/custom-transitions.jd | 189 | ||||
-rw-r--r-- | docs/html/training/transitions/index.jd | 80 | ||||
-rw-r--r-- | docs/html/training/transitions/overview.jd | 165 | ||||
-rw-r--r-- | docs/html/training/transitions/scenes.jd | 211 | ||||
-rw-r--r-- | docs/html/training/transitions/transitions.jd | 315 | ||||
-rw-r--r-- | docs/html/training/wearables/data-layer/data-items.jd | 128 | ||||
-rw-r--r-- | docs/html/training/wearables/data-layer/events.jd | 3 | ||||
-rw-r--r-- | docs/html/training/wearables/data-layer/messages.jd | 22 | ||||
-rw-r--r-- | docs/html/training/wearables/watch-faces/configuration.jd | 19 |
11 files changed, 1562 insertions, 279 deletions
diff --git a/docs/html/training/location/display-address.jd b/docs/html/training/location/display-address.jd index 621b082..516f14f 100644 --- a/docs/html/training/location/display-address.jd +++ b/docs/html/training/location/display-address.jd @@ -1,280 +1,468 @@ page.title=Displaying a Location Address - trainingnavtop=true - @jd:body - - <div id="tb-wrapper"> -<div id="tb"> + <div id="tb"> -<h2>This lesson teaches you to</h2> -<ol> - <li><a href="#DefineTask">Define the Address Lookup Task</a></li> - <li><a href="#DisplayResults">Define a Method to Display the Results</a></li> - <li><a href="#RunTask">Run the Lookup Task</a></li> -</ol> + <h2>This lesson teaches you how to</h2> + <ol> + <li><a href="#connect">Get a Geographic Location</a></li> + <li><a href="#fetch-address">Define an Intent Service to Fetch the + Address</a></li> + <li><a href="#start-intent">Start the Intent Service</a></li> + <li><a href="#result-receiver">Receive the Geocoding Results</a></li> + </ol> -<h2>You should also read</h2> -<ul> - <li> - <a href="{@docRoot}google/play-services/setup.html">Setup Google Play Services SDK</a> - </li> - <li> - <a href="retrieve-current.html">Retrieving the Current Location</a> - </li> - <li> - <a href="receive-location-updates.html">Receiving Location Updates</a> - </li> -</ul> -<h2>Try it out</h2> + <h2>You should also read</h2> + <ul> + <li> + <a href="{@docRoot}google/play-services/setup.html">Setting up Google + Play Services</a> + </li> + <li> + <a href="retrieve-current.html">Getting the Last Known Location</a> + </li> + <li> + <a href="receive-location-updates.html">Receiving Location Updates</a> + </li> + </ul> + <h2>Try it out</h2> -<div class="download-box"> -<a href="http://developer.android.com/shareables/training/LocationUpdates.zip" class="button">Download - the sample app</a> -<p class="filename">LocationUpdates.zip</p> + <ul> + <li> + <a href="https://github.com/googlesamples/android-play-location/tree/master/LocationAddress" class="external-link">LocationAddress</a> + </li> + </ul> + </div> </div> -</div> -</div> +<p>The lessons <a href="retrieve-current.html">Getting the Last Known + Location</a> and <a href="receive-location-updates.html">Receiving Location + Updates</a> describe how to get the user's location in the form of a + {@link android.location.Location} object that contains latitude and longitude + coordinates. Although latitude and longitude are useful for calculating + distance or displaying a map position, in many cases the address of the + location is more useful. For example, if you want to let your users know where + they are or what is close by, a street address is more meaningful than the + geographic coordinates (latitude/longitude) of the location.</p> + +<p>Using the {@link android.location.Geocoder} class in the Android framework + location APIs, you can convert an address to the corresponding geographic + coordinates. This process is called <em>geocoding</em>. Alternatively, you can + convert a geographic location to an address. The address lookup feature is + also known as <em>reverse geocoding</em>.</p> + +<p>This lesson shows you how to use the + {@link android.location.Geocoder#getFromLocation getFromLocation()} method to + convert a geographic location to an address. The method returns an estimated + street address corresponding to a given latitude and longitude.</p> + +<h2 id="connect">Get a Geographic Location</h2> + +<p>The last known location of the device is a useful starting point for the + address lookup feature. The lesson on + <a href="retrieve-current.html">Getting the Last Known Location</a> shows you + how to use the + <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#getLastLocation(com.google.android.gms.common.api.GoogleApiClient)">{@code getLastLocation()}</a> + method provided by the + <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html">fused + location provider</a> to find the latest location of the device.</p> + +<p>To access the fused location provider, you need to create an instance of the + Google Play services API client. To learn how to connect your client, see + <a href="{@docRoot}training/location/retrieve-current.html#play-services">Connect + to Google Play Services</a>.</p> + +<p>In order for the fused location provider to retrieve a precise street + address, set the location permission in your app manifest to + {@code ACCESS_FINE_LOCATION}, as shown in the following example:</p> -<p> - The lessons <a href="retrieve-current.html">Retrieving the Current Location</a> and - <a href="receive-location-updates.html">Receiving Location Updates</a> describe how to get the - user's current location in the form of a {@link android.location.Location} object that - contains latitude and longitude coordinates. Although latitude and longitude are useful for - calculating distance or displaying a map position, in many cases the address of the location is - more useful. -</p> -<p> - The Android platform API provides a feature that returns an estimated street addresses for - latitude and longitude values. This lesson shows you how to use this address lookup feature. -</p> -<p class="note"> - <strong>Note:</strong> Address lookup requires a backend service that is not included in the - core Android framework. If this backend service is not available, - {@link android.location.Geocoder#getFromLocation Geocoder.getFromLocation()} returns an empty - list. The helper method {@link android.location.Geocoder#isPresent isPresent()}, available - in API level 9 and later, checks to see if the backend service is available. -</p> -<p> - The snippets in the following sections assume that your app has already retrieved the - current location and stored it as a {@link android.location.Location} object in the global - variable {@code mLocation}. -</p> -<!-- - Define the address lookup task ---> -<h2 id="DefineTask">Define the Address Lookup Task</h2> -<p> -To get an address for a given latitude and longitude, call -{@link android.location.Geocoder#getFromLocation Geocoder.getFromLocation()}, which returns a -list of addresses. The method is synchronous, and may take a long time to do its work, so you -should call the method from the {@link android.os.AsyncTask#doInBackground -doInBackground()} method of an {@link android.os.AsyncTask}. -</p> -<p> -While your app is getting the address, display an indeterminate activity -indicator to show that your app is working in the background. Set the indicator's initial state -to {@code android:visibility="gone"}, to make it invisible and remove it from the layout -hierarchy. When you start the address lookup, you set its visibility to "visible". -</p> -<p> -The following snippet shows how to add an indeterminate {@link android.widget.ProgressBar} to -your layout file: -</p> <pre> -<ProgressBar -android:id="@+id/address_progress" -android:layout_width="wrap_content" -android:layout_height="wrap_content" -android:layout_centerHorizontal="true" -android:indeterminate="true" -android:visibility="gone" /> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.google.android.gms.location.sample.locationupdates" > + + <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> +</manifest> </pre> -<p> -To create the background task, define a subclass of {@link android.os.AsyncTask} that calls -{@link android.location.Geocoder#getFromLocation getFromLocation()} and returns an address. -Define a {@link android.widget.TextView} object {@code mAddress} to contain the returned -address, and a {@link android.widget.ProgressBar} object that allows you to control the -indeterminate activity indicator. For example: -</p> + +<h2 id="fetch-address">Define an Intent Service to Fetch the Address</h2> + +<p>The {@link android.location.Geocoder#getFromLocation getFromLocation()} + method provided by the {@link android.location.Geocoder} class accepts a + latitude and longitude, and returns a list of addresses. The method is + synchronous, and may take a long time to do its work, so you should not call + it from the main, user interface (UI) thread of your app.</p> + +<p>The {@link android.app.IntentService IntentService} class provides a + structure for running a task on a background thread. Using this class, you can + handle a long-running operation without affecting your UI's responsiveness. + Note that the {@link android.os.AsyncTask AsyncTask} class also allows you to + perform background operations, but it's designed for short operations. An + {@link android.os.AsyncTask AsyncTask} shouldn't keep a reference to the UI if + the activity is recreated, for example when the device is rotated. In + contrast, an {@link android.app.IntentService IntentService} doesn't need to + be cancelled when the activity is rebuilt.</p> + +<p>Define a {@code FetchAddressIntentService} class that extends + {@link android.app.IntentService}. This class is your address lookup service. + The intent service handles an intent asynchronously on a worker thread, and + stops itself when it runs out of work. The intent extras provide the data + needed by the service, including a {@link android.location.Location} object + for conversion to an address, and a {@link android.os.ResultReceiver} object + to handle the results of the address lookup. The service uses a {@link + android.location.Geocoder} to fetch the address for the location, and sends + the results to the {@link android.os.ResultReceiver}.</p> + +<h3>Define the Intent Service in your App Manifest</h3> + +<p>Add an entry to your app manifest defining the intent service:</p> + <pre> -public class MainActivity extends FragmentActivity { +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.google.android.gms.location.sample.locationaddress" > + <application + ... + <service + android:name=".FetchAddressIntentService" + android:exported="false"/> + </application> ... - private TextView mAddress; - private ProgressBar mActivityIndicator; +</manifest> +</pre> + +<p class="note"><strong>Note:</strong> The {@code <service>} element in + the manifest doesn't need to include an intent filter, because your main + activity creates an explicit intent by specifying the name of the class to use + for the intent.</p> + +<h3>Create a Geocoder</h3> + +<p>The process of converting a geographic location to an address is called + <em>reverse geocoding</em>. To perform the main work of the intent service, + that is, your reverse geocoding request, implement + {@link android.app.IntentService#onHandleIntent onHandleIntent()} within the + {@code FetchAddressIntentService} class. Create a + {@link android.location.Geocoder} object to handle the reverse geocoding.</p> + +<p>A locale represents a specific geographical or linguistic region. Locale + objects are used to adjust the presentation of information, such as numbers or + dates, to suit the conventions in the region represented by the locale. Pass a + <a href="{@docRoot}reference/java/util/Locale.html">{@code Locale}</a> object + to the {@link android.location.Geocoder} object, to ensure that the resulting + address is localized to the user's geographic region.</p> + +<pre> +@Override +protected void onHandleIntent(Intent intent) { + Geocoder geocoder = new Geocoder(this, Locale.getDefault()); ... - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); +} +</pre> + +<h3 id="retrieve-street-address">Retrieve the street address data</h3> + +<p>The next step is to retrieve the street address from the geocoder, handle + any errors that may occur, and send the results back to the activity that + requested the address. To report the results of the geocoding + process, you need two numeric constants that indicate success or failure. + Define a {@code Constants} class to contain the values, as shown in this code + snippet:</p> + +<pre> +public final class Constants { + public static final int SUCCESS_RESULT = 0; + public static final int FAILURE_RESULT = 1; + public static final String PACKAGE_NAME = + "com.google.android.gms.location.sample.locationaddress"; + public static final String RECEIVER = PACKAGE_NAME + ".RECEIVER"; + public static final String RESULT_DATA_KEY = PACKAGE_NAME + + ".RESULT_DATA_KEY"; + public static final String LOCATION_DATA_EXTRA = PACKAGE_NAME + + ".LOCATION_DATA_EXTRA"; +} +</pre> + +<p>To get a street address corresponding to a geographical location, call + {@link android.location.Geocoder#getFromLocation getFromLocation()}, + passing it the latitude and longitude from the location object, and the + maximum number of addresses you want returned. In this case, you want just one + address. The geocoder returns an array of addresses. If no addresses were + found to match the given location, it returns an empty list. If there is no + backend geocoding service available, the geocoder returns null.</p> + +<p>Check for the following errors as shown in the code sample below. If an error + occurs, place the corresponding error message in the {@code errorMessage} + variable, so you can send it back to the requesting activity:</p> + +<ul> + <li><strong>No location data provided</strong> - The intent extras do not + include the {@link android.location.Location} object required for reverse + geocoding.</li> + <li><strong>Invalid latitude or longitude used</strong> - The latitude + and/or longitude values provided in the {@link android.location.Location} + object are invalid.</li> + <li><strong>No geocoder available</strong> - The background geocoding service + is not available, due to a network error or IO exception.</li> + <li><strong>Sorry, no address found</strong> - The geocoder could not find an + address for the given latitude/longitude.</li> +</ul> + +<p>To get the individual lines of an address object, use the + {@link android.location.Address#getAddressLine getAddressLine()} + method provided by the {@link android.location.Address} class. Then join the + lines into a list of address fragments ready to return to the activity that + requested the address.</p> + +<p>To send the results back to the requesting activity, call the + {@code deliverResultToReceiver()} method (defined in + <a href="#return-address">Return the address to the requestor</a>). The + results consist of the previously-mentioned numeric success/failure code and + a string. In the case of a successful reverse geocoding, the string contains + the address. In the case of a failure, the string contains the error message, + as shown in the code sample below:</p> + +<pre> +@Override +protected void onHandleIntent(Intent intent) { + String errorMessage = ""; + + // Get the location passed to this service through an extra. + Location location = intent.getParcelableExtra( + Constants.LOCATION_DATA_EXTRA); + ... - mAddress = (TextView) findViewById(R.id.address); - mActivityIndicator = - (ProgressBar) findViewById(R.id.address_progress); + + List<Address> addresses = null; + + try { + addresses = geocoder.getFromLocation( + location.getLatitude(), + location.getLongitude(), + // In this sample, get just a single address. + 1); + } catch (IOException ioException) { + // Catch network or other I/O problems. + errorMessage = getString(R.string.service_not_available); + Log.e(TAG, errorMessage, ioException); + } catch (IllegalArgumentException illegalArgumentException) { + // Catch invalid latitude or longitude values. + errorMessage = getString(R.string.invalid_lat_long_used); + Log.e(TAG, errorMessage + ". " + + "Latitude = " + location.getLatitude() + + ", Longitude = " + + location.getLongitude(), illegalArgumentException); } - ... - /** - * A subclass of AsyncTask that calls getFromLocation() in the - * background. The class definition has these generic types: - * Location - A {@link android.location.Location} object containing - * the current location. - * Void - indicates that progress units are not used - * String - An address passed to onPostExecute() - */ - private class GetAddressTask extends - AsyncTask<Location, Void, String> { - Context mContext; - public GetAddressTask(Context context) { - super(); - mContext = context; + + // Handle case where no address was found. + if (addresses == null || addresses.size() == 0) { + if (errorMessage.isEmpty()) { + errorMessage = getString(R.string.no_address_found); + Log.e(TAG, errorMessage); } - ... - /** - * Get a Geocoder instance, get the latitude and longitude - * look up the address, and return it - * - * @params params One or more Location objects - * @return A string containing the address of the current - * location, or an empty string if no address can be found, - * or an error message - */ - @Override - protected String doInBackground(Location... params) { - Geocoder geocoder = - new Geocoder(mContext, Locale.getDefault()); - // Get the current location from the input parameter list - Location loc = params[0]; - // Create a list to contain the result address - List<Address> addresses = null; - try { - /* - * Return 1 address. - */ - addresses = geocoder.getFromLocation(loc.getLatitude(), - loc.getLongitude(), 1); - } catch (IOException e1) { - Log.e("LocationSampleActivity", - "IO Exception in getFromLocation()"); - e1.printStackTrace(); - return ("IO Exception trying to get address"); - } catch (IllegalArgumentException e2) { - // Error message to post in the log - String errorString = "Illegal arguments " + - Double.toString(loc.getLatitude()) + - " , " + - Double.toString(loc.getLongitude()) + - " passed to address service"; - Log.e("LocationSampleActivity", errorString); - e2.printStackTrace(); - return errorString; - } - // If the reverse geocode returned an address - if (addresses != null && addresses.size() > 0) { - // Get the first address - Address address = addresses.get(0); - /* - * Format the first line of address (if available), - * city, and country name. - */ - String addressText = String.format( - "%s, %s, %s", - // If there's a street address, add it - address.getMaxAddressLineIndex() > 0 ? - address.getAddressLine(0) : "", - // Locality is usually a city - address.getLocality(), - // The country of the address - address.getCountryName()); - // Return the text - return addressText; - } else { - return "No address found"; - } + deliverResultToReceiver(Constants.FAILURE_RESULT, errorMessage); + } else { + Address address = addresses.get(0); + ArrayList<String> addressFragments = new ArrayList<String>(); + + // Fetch the address lines using {@code getAddressLine}, + // join them, and send them to the thread. + for(int i = 0; i < address.getMaxAddressLineIndex(); i++) { + addressFragments.add(address.getAddressLine(i)); } - ... + Log.i(TAG, getString(R.string.address_found)); + deliverResultToReceiver(Constants.SUCCESS_RESULT, + TextUtils.join(System.getProperty("line.separator"), + addressFragments)); } - ... } </pre> -<p> -The next section shows you how to display the address in the user interface. -</p> -<!-- Define a method to display the address --> -<h2 id="DisplayResults">Define a Method to Display the Results</h2> -<p> - {@link android.os.AsyncTask#doInBackground doInBackground()} returns the result of the address - lookup as a {@link java.lang.String}. This value is passed to - {@link android.os.AsyncTask#onPostExecute onPostExecute()}, where you do further processing - on the results. Since {@link android.os.AsyncTask#onPostExecute onPostExecute()} - runs on the UI thread, it can update the user interface; for example, it can turn off the - activity indicator and display the results to the user: + +<h3 id="return-address">Return the address to the requestor</h3> + +<p>The final thing the intent service must do is send the address back to a + {@link android.os.ResultReceiver} in the activity that started the service. + The {@link android.os.ResultReceiver} class allows you to send a + numeric result code as well as a message containing the result data. The + numeric code is useful for reporting the success or failure of the geocoding + request. In the case of a successful reverse geocoding, the message contains + the address. In the case of a failure, the message contains some text + describing the reason for failure.</p> + +<p>You have already retrieved the address from the geocoder, trapped any errors + that may occur, and called the {@code deliverResultToReceiver()} method. Now + you need to define the {@code deliverResultToReceiver()} method that sends + a result code and message bundle to the result receiver.</p> + +<p>For the result code, use the value that you've passed to the + {@code deliverResultToReceiver()} method in the {@code resultCode} parameter. + To construct the message bundle, concatenate the {@code RESULT_DATA_KEY} + constant from your {@code Constants} class (defined in + <a href="#retrieve-street-address">Retrieve the street address data</a>) and + the value in the {@code message} parameter passed to the + {@code deliverResultToReceiver()} method, as shown in the following sample: </p> + <pre> - private class GetAddressTask extends - AsyncTask<Location, Void, String> { - ... - /** - * A method that's called once doInBackground() completes. Turn - * off the indeterminate activity indicator and set - * the text of the UI element that shows the address. If the - * lookup failed, display the error message. - */ - @Override - protected void onPostExecute(String address) { - // Set activity indicator visibility to "gone" - mActivityIndicator.setVisibility(View.GONE); - // Display the results of the lookup. - mAddress.setText(address); - } - ... +public class FetchAddressIntentService extends IntentService { + protected ResultReceiver mReceiver; + ... + private void deliverResultToReceiver(int resultCode, String message) { + Bundle bundle = new Bundle(); + bundle.putString(Constants.RESULT_DATA_KEY, message); + mReceiver.send(resultCode, bundle); } +} </pre> -<p> - The final step is to run the address lookup. -</p> -<!-- Get and display the address --> -<h2 id="RunTask">Run the Lookup Task</h2> -<p> - To get the address, call {@link android.os.AsyncTask#execute execute()}. For example, the - following snippet starts the address lookup when the user clicks the "Get Address" button: -</p> + +<h2 id="start-intent">Start the Intent Service</h2> + +<p>The intent service, as defined in the previous section, runs in the + background and is responsible for fetching the address corresponding to a + given geographic location. When you start the service, the Android framework + instantiates and starts the service if it isn't already running, and creates a + process if needed. If the service is already running then it remains running. + Because the service extends {@link android.app.IntentService IntentService}, + it shuts down automatically when all intents have been processed.</p> + +<p>Start the service from your app's main activity, + and create an {@link android.content.Intent} to pass data to the service. You + need an <em>explicit</em> intent, because you want only your service + to respond to the intent. For more information, see + <a href="{@docRoot}guide/components/intents-filters.html#Types">Intent + Types</a>.</p> + +<p>To create an explicit intent, specify the name of the + class to use for the service: {@code FetchAddressIntentService.class}. + Pass two pieces of information in the intent extras:</p> + +<ul> + <li>A {@link android.os.ResultReceiver} to handle the results of the address + lookup.</li> + <li>A {@link android.location.Location} object containing the latitude and + longitude that you want to convert to an address.</li> +</ul> + +<p>The following code sample shows you how to start the intent service:</p> + <pre> -public class MainActivity extends FragmentActivity { +public class MainActivity extends ActionBarActivity implements + ConnectionCallbacks, OnConnectionFailedListener { + + protected Location mLastLocation; + private AddressResultReceiver mResultReceiver; ... - /** - * The "Get Address" button in the UI is defined with - * android:onClick="getAddress". The method is invoked whenever the - * user clicks the button. - * - * @param v The view object associated with this method, - * in this case a Button. - */ - public void getAddress(View v) { - // Ensure that a Geocoder services is available - if (Build.VERSION.SDK_INT >= - Build.VERSION_CODES.GINGERBREAD - && - Geocoder.isPresent()) { - // Show the activity indicator - mActivityIndicator.setVisibility(View.VISIBLE); - /* - * Reverse geocoding is long-running and synchronous. - * Run it on a background thread. - * Pass the current location to the background task. - * When the task finishes, - * onPostExecute() displays the address. - */ - (new GetAddressTask(this)).execute(mLocation); + + protected void startIntentService() { + Intent intent = new Intent(this, FetchAddressIntentService.class); + intent.putExtra(Constants.RECEIVER, mResultReceiver); + intent.putExtra(Constants.LOCATION_DATA_EXTRA, mLastLocation); + startService(intent); + } +} +</pre> + +<p>Call the above {@code startIntentService()} method when the + user takes an action that requires a geocoding address lookup. For example, + the user may press a <em>Fetch address</em> button on your app's UI. Before + starting the intent service, you need to check that the connection to Google + Play services is present. The following code snippet shows the call to the + {@code startIntentService()} method in the button handler:</p> + +<pre> +public void fetchAddressButtonHandler(View view) { + // Only start the service to fetch the address if GoogleApiClient is + // connected. + if (mGoogleApiClient.isConnected() && mLastLocation != null) { + startIntentService(); + } + // If GoogleApiClient isn't connected, process the user's request by + // setting mAddressRequested to true. Later, when GoogleApiClient connects, + // launch the service to fetch the address. As far as the user is + // concerned, pressing the Fetch Address button + // immediately kicks off the process of getting the address. + mAddressRequested = true; + updateUIWidgets(); +} +</pre> + +<p>You must also start the intent service when the connection to Google Play + services is established, if the user has already clicked the button on your + app's UI. The following code snippet shows the call to the + {@code startIntentService()} method in the + <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">{@code onConnected()}</a> + callback provided by the Google API Client:</p> + +<pre> +public class MainActivity extends ActionBarActivity implements + ConnectionCallbacks, OnConnectionFailedListener { + ... + @Override + public void onConnected(Bundle connectionHint) { + // Gets the best and most recent location currently available, + // which may be null in rare cases when a location is not available. + mLastLocation = LocationServices.FusedLocationApi.getLastLocation( + mGoogleApiClient); + + if (mLastLocation != null) { + // Determine whether a Geocoder is available. + if (!Geocoder.isPresent()) { + Toast.makeText(this, R.string.no_geocoder_available, + Toast.LENGTH_LONG).show(); + return; + } + + if (mAddressRequested) { + startIntentService(); + } } - ... } +} +</pre> + +<h2 id="result-receiver">Receive the Geocoding Results</h2> + +<p>The intent service has handled the geocoding request, and uses a + {@link android.os.ResultReceiver} to return the results to the activity that + made the request. In the activity that makes the request, define an + {@code AddressResultReceiver} that extends {@link android.os.ResultReceiver} + to handle the response from {@code FetchAddressIntentService}.</p> + +<p>The result includes a numeric result code (<code>resultCode</code>) as well + as a message containing the result data (<code>resultData</code>). If the + reverse geocoding process was successful, the <code>resultData</code> contains + the address. In the case of a failure, the <code>resultData</code> contains + text describing the reason for failure. For details of the possible errors, + see <a href="#return-address">Return the address to the requestor</a>.</p> + +<p>Override the + {@link android.os.ResultReceiver#onReceiveResult onReceiveResult()} method + to handle the results delivered to the result receiver, as shown in the + following code sample:</p> + +<pre> +public class MainActivity extends ActionBarActivity implements + ConnectionCallbacks, OnConnectionFailedListener { ... + class AddressResultReceiver extends ResultReceiver { + public AddressResultReceiver(Handler handler) { + super(handler); + } + + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + + // Display the address string + // or an error message sent from the intent service. + mAddressOutput = resultData.getString(Constants.RESULT_DATA_KEY); + displayAddressOutput(); + + // Show a toast message if an address was found. + if (resultCode == Constants.SUCCESS_RESULT) { + showToast(getString(R.string.address_found)); + } + + } + } } </pre> -<p> - The next lesson, <a href="geofencing.html">Creating and Monitoring Geofences</a>, demonstrates - how to define locations of interest called <b>geofences</b> and how to use geofence monitoring - to detect the user's proximity to a location of interest. -</p> diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs index 0fcfb9c..f5999a5 100644 --- a/docs/html/training/training_toc.cs +++ b/docs/html/training/training_toc.cs @@ -437,6 +437,35 @@ include the action bar on devices running Android 2.1 or higher." </li> </ul> </li> + + <li class="nav-section"> + <div class="nav-section-header"> + <a href="<?cs var:toroot?>training/transitions/index.html" + description= + "How to animate state changes in a view hierarchy using transitions." + >Animating Views Using Scenes and Transitions</a> + </div> + <ul> + <li><a href="<?cs var:toroot ?>training/transitions/overview.html"> + The Transitions Framework + </a> + </li> + <li><a href="<?cs var:toroot ?>training/transitions/scenes.html"> + Creating a Scene + </a> + </li> + <li><a href="<?cs var:toroot ?>training/transitions/transitions.html"> + Applying a Transition + </a> + </li> + <li><a href="<?cs var:toroot ?>training/transitions/custom-transitions.html"> + Creating Custom Transitions + </a> + </li> + + </ul> + </li> + <li class="nav-section"> <div class="nav-section-header"><a href="<?cs var:toroot ?>training/animation/index.html" description= diff --git a/docs/html/training/transitions/custom-transitions.jd b/docs/html/training/transitions/custom-transitions.jd new file mode 100644 index 0000000..b64daae --- /dev/null +++ b/docs/html/training/transitions/custom-transitions.jd @@ -0,0 +1,189 @@ +page.title=Creating Custom Transitions + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> +<h2>This lesson teaches you to</h2> +<ol> + <li><a href="#Extend">Extend the Transition Class</a></li> + <li><a href="#CaptureProperties">Capture View Property Values</a></li> + <li><a href="#CreateAnimator">Create a Custom Animator</a></li> + <li><a href="#Apply">Apply a Custom Transition</a></li> +</ol> +</div> +</div> + +<p>A custom transition enables you to create an animation that is not available from any of +the built-in transition classes. For example, you can define a custom transition that turns +the foreground color of text and input fields to gray to indicate that the fields are disabled +in the new screen. This type of change helps users see the fields you disabled.</p> + +<p>A custom transition, like one of the built-in transition types, applies animations to +child views of both the starting and ending scenes. Unlike built-in transition types, +however, you have to provide the code that captures property values and generates animations. +You may also want to define a subset of target views for your animation.</p> + +<p>This lesson teaches you to capture property values and generate animations to create +custom transitions.</p> + + + +<h2 id="Extend">Extend the Transition Class</h2> + +<p>To create a custom transition, add a class to your project that extends the {@link +android.transition.Transition} class and override the methods shown in the following snippet:</p> + +<pre> +public class CustomTransition extends Transition { + + @Override + public void captureStartValues(TransitionValues values) {} + + @Override + public void captureEndValues(TransitionValues values) {} + + @Override + public Animator createAnimator(ViewGroup sceneRoot, + TransitionValues startValues, + TransitionValues endValues) {} +} +</pre> + +<p>The following sections explain how to override these methods.</p> + + + +<h2 id="CaptureProperties">Capture View Property Values</h2> + +<p>Transition animations use the property animation system described in +<a href="{@docRoot}guide/topics/graphics/prop-animation.html">Property Animation</a>. Property +animations change a view property between a starting and ending value over a specified +period of time, so the framework needs to have both the starting and ending value of +the property to construct the animation.</p> + +<p>However, a property animation usually needs only a small subset of all the view's property +values. For example, a color animation needs color property values, while a movement +animation needs position property values. Since the property values needed for an animation +are specific to a transition, the transitions framework does not provide every property value +to a transition. Instead, the framework invokes callback methods that allow a transition to +capture only the property values it needs and store them in the framework.</p> + + +<h3 id="StartingValues">Capturing Starting Values</h3> + +<p>To pass the starting view values to the framework, implement the +{@link android.transition.Transition#captureStartValues captureStartValues(transitionValues)} +method. The framework calls this method for every view in the starting scene. The method +argument is a {@link android.transition.TransitionValues} object that contains a reference +to the view and a {@link java.util.Map} instance in which you can store the view values you +want. In your implementation, retrieve these property values and pass them back to the +framework by storing them in the map.</p> + +<p>To ensure that the key for a property value does not conflict with other {@link +android.transition.TransitionValues} keys, use the following naming scheme:</p> + +<pre> +package_name:transition_name:property_name +</pre> + +<p>The following snippet shows an implementation of the {@link +android.transition.Transition#captureStartValues captureStartValues()} method:</p> + +<pre> +public class CustomTransition extends Transition { + + // Define a key for storing a property value in + // TransitionValues.values with the syntax + // package_name:transition_class:property_name to avoid collisions + private static final String PROPNAME_BACKGROUND = + "com.example.android.customtransition:CustomTransition:background"; + + @Override + public void captureStartValues(TransitionValues transitionValues) { + // Call the convenience method captureValues + captureValues(transitionValues); + } + + + // For the view in transitionValues.view, get the values you + // want and put them in transitionValues.values + private void captureValues(TransitionValues transitionValues) { + // Get a reference to the view + View view = transitionValues.view; + // Store its background property in the values map + transitionValues.values.put(PROPNAME_BACKGROUND, view.getBackground()); + } + ... +} +</pre> + + +<h3 id="EndingValues">Capture Ending Values</h3> + +<p>The framework calls the {@link android.transition.Transition#captureEndValues} method +once for every target view in the ending scene. In all other respects, {@link +android.transition.Transition#captureEndValues captureEndValues()} works the same as {@link +android.transition.Transition#captureStartValues captureStartValues()}.</p> + +<p>The following code snippet shows an implementation of the {@link +android.transition.Transition#captureEndValues captureEndValues()} method:</p> + +<pre> +@Override +public void captureEndValues(TransitionValues transitionValues) { + captureValues(transitionValues); +} +</pre> + +<p>In this example, both the {@link android.transition.Transition#captureStartValues +captureStartValues()} and {@link android.transition.Transition#captureEndValues captureEndValues()} +methods invoke <code>captureValues()</code> to retrieve and store values. The view property +that <code>captureValues()</code> retrieves is the same, but it has different values in the +starting and ending scenes. The framework maintains separate maps for the starting and ending +states of a view.</p> + + + +<h2 id="CreateAnimator">Create a Custom Animator</h2> + +<p>To animate the changes to a view between its state in the starting scene and its state in +the ending scene, you provide an animator by overriding the {@link +android.transition.Transition#createAnimator createAnimator()} method. When the +framework calls this method, it passes in the scene root view and the {@link +android.transition.TransitionValues} objects that contain the starting and ending values +you captured.</p> + +<p>The number of times the framework calls the {@link +android.transition.Transition#createAnimator createAnimator()} method depends on the changes that +occur between the starting and ending scenes. For example, consider a fade out/fade in animation +implemented as a custom transition. If the starting scene has five targets of which two are +removed from the ending scene, and the ending scene has the three targets from the starting +scene plus a new target, then the framework calls {@link +android.transition.Transition#createAnimator createAnimator()} six times: three of the calls +animate the fading out and fading in of the targets that stay in both scene objects; two more calls +animate the fading out of the targets removed from the ending scene; and one call +animates the fading in of the new target in the ending scene.</p> + +<p>For target views that exist on both the starting and ending scenes, the framework provides +a {@link android.transition.TransitionValues} object for both the <code>startValues</code> and +<code>endValues</code> arguments. For target views that only exist in the starting or the +ending scene, the framework provides a {@link android.transition.TransitionValues} object +for the corresponding argument and <code>null</code> for the other.</p> + +<p>To implement the {@link android.transition.Transition#createAnimator} method when you create +a custom transition, use the view property values you captured to create an {@link +android.animation.Animator} object and return it to the framework. For an example implementation, +see the <a +href="{@docRoot}samples/CustomTransition/src/com.example.android.customtransition/ChangeColor.html"> +<code>ChangeColor</code></a> class in the <a href="{@docRoot}samples/CustomTransition/index.html"> +CustomTransition</a> sample. For more information about property animators, see +<a href="{@docRoot}guide/topics/graphics/prop-animation.html">Property Animation</a>.</p> + + + +<h2 id="Apply">Apply a Custom Transition</h2> + +<p>Custom transitions work the same as built-in transitions. You can apply a custom transition +using a transition manager, as described in <a +href="{@docRoot}training/transitions/transitions.html#Apply">Applying a Transition</a>.</p> diff --git a/docs/html/training/transitions/index.jd b/docs/html/training/transitions/index.jd new file mode 100644 index 0000000..53faa01 --- /dev/null +++ b/docs/html/training/transitions/index.jd @@ -0,0 +1,80 @@ +page.title=Animating Views Using Scenes and Transitions + +@jd:body + +<!-- Sidebox --> +<div id="tb-wrapper"> +<div id="tb"> + <h2>Dependencies and Prerequisites</h2> + <ul> + <li>Android 4.4.2 (API level 19) or higher</li> + </ul> + <h2>You should also read</h2> + <ul> + <li><a href="{@docRoot}guide/topics/ui/how-android-draws.html"> + How Android Draws Views</a></li> + </ul> + <h2>Try it out</h2> + <ul> + <li><a href="{@docRoot}samples/BasicTransition/index.html">BasicTransition</a> sample</li> + <li><a href="{@docRoot}samples/CustomTransition/index.html">CustomTransition</a> sample</li> + </ul> +</div> +</div> + +<!-- Video box --> +<a class="notice-developers-video wide" href="http://www.youtube.com/watch?v=S3H7nJ4QaD8"> +<div> + <h3>Video</h3> + <p>DevBytes: Android 4.4 Transitions</p> +</div> +</a> + +<p>The user interface of an activity often changes in response to user input and other events. +For example, an activity that contains a form where users can type search queries can hide +the form when the user submits it and show a list of search results in its place.</p> + +<p>To provide visual continuity in these situations, you can animate changes between +different view hierarchies in your user interface. These animations give users feedback on +their actions and help them learn how your app works.</p> + +<p>Android includes the <em>transitions framework</em>, which enables you to easily +animate changes between two view hierarchies. The framework animates the views at runtime by +changing some of their property values over time. The framework includes built-in animations +for common effects and lets you create custom animations and transition lifecycle callbacks.</p> + +<p>This class teaches you to use the built-in animations in the transitions framework to +animate changes between view hierarchies. This class also covers how to create custom +animations.</p> + +<p class="note"><strong>Note:</strong> For Android versions earlier than 4.4.2 (API level 19) +but greater than or equal to Android 4.0 (API level 14), use the <code>animateLayoutChanges</code> +attribute to animate layouts. To learn more, see +<a href="{@docRoot}guide/topics/graphics/prop-animation.html">Property Animation</a> and +<a href="{@docRoot}training/animation/layout.html">Animating Layout Changes</a>.</p> + + +<h2>Lessons</h2> + +<dl> +<dt><a href="{@docRoot}training/transitions/overview.html"> +The Transitions Framework</a></dt> +<dd> + Learn the main features and components of the transitions framework. +</dd> +<dt><a href="{@docRoot}training/transitions/scenes.html"> +Creating a Scene</a></dt> +<dd> + Learn how to create a scene to store the state of a view hierarchy. +</dd> +<dt><a href="{@docRoot}training/transitions/transitions.html"> +Applying a Transition</a></dt> +<dd> + Learn how to apply a transition between two scenes of a view hierarchy. +</dd> +<dt><a href="{@docRoot}training/transitions/custom-transitions.html"> +Creating Custom Transitions</a></dt> +<dd> + Learn how to create other animation effects not included in the transitions framework. +</dd> +</dl> diff --git a/docs/html/training/transitions/overview.jd b/docs/html/training/transitions/overview.jd new file mode 100644 index 0000000..044cf16 --- /dev/null +++ b/docs/html/training/transitions/overview.jd @@ -0,0 +1,165 @@ +page.title=The Transitions Framework + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> +<h2>This lesson covers</h2> +<ol> + <li><a href="#Overview">Overview</a></li> + <li><a href="#Scenes">Scenes</a></li> + <li><a href="#Transitions">Transitions</a></li> + <li><a href="#Limitations">Limitations</a></li> +</ol> +</div> +</div> + +<p>Animating your app's user interface provides more than just visual appeal. Animations +highlight changes and provide visual cues that help users learn how your app works.</p> + +<p>To help you animate a change between one view hierarchy and another, Android provides the +transitions framework. This framework applies one or more animations to all the views in the +hierarchies as it changes between them.</p> + +<p>The framework has the following features:</p> + +<dl> +<dt><em>Group-level animations</em></dt> +<dd>Applies one or more animation effects to all of the views in a view hierarchy.</dd> +<dt><em>Transition-based animation</em></dt> +<dd>Runs animations based on the changes between starting and ending view property values.</dd> +<dt><em>Built-in animations</em></dt> +<dd>Includes predefined animations for common effects such as fade out or movement.</dd> + +<!-- Figure 1 - Transitions video --> +<div style="float:right;margin-left:30px;margin-top:10px"> +<div class="framed-nexus5-port-span-5" style="clear:left;"> +<video class="play-on-hover" height="442" autoplay="" poster=""> +<source src="{@docRoot}images/transitions/transition_sample_video.mp4" type="video/mp4"> +<source src="{@docRoot}images/transitions/transition_sample_video.ogv" type="video/ogg"> +<source src="{@docRoot}images/transitions/transition_sample_video.webm" type="video/webm"> +</video> +</div> +<p class="img-caption" style="margin-top:7px;margin-bottom:0px"> +<strong>Figure 1.</strong> Visual cues using user interface animation.</p> +<div style="margin-top:5px;margin-bottom:20px;font-size:10pt" class="video-instructions"> </div> +</div> + +<dt><em>Resource file support</em></dt> +<dd>Loads view hierarchies and built-in animations from layout resource files.</dd> +<dt><em>Lifecycle callbacks</em></dt> +<dd>Defines callbacks that provide finer control over the animation and hierarchy change +process.</dd> +</dl> + + + +<h2 id="Overview">Overview</h2> + +<p>The example in Figure 1 shows how an animation provides visual cues to help the user. As the +app changes from its search entry screen to its search results screen, it fades out views that +are no longer in use and fades in new views.</p> + +<p>This animation is an example of using the transitions framework. The framework +animates changes to all the views in two view hierarchies. A view hierarchy can be as simple +as a single view or as complex as a {@link android.view.ViewGroup} containing an elaborate +tree of views. The framework animates each view by changing one or more of its property values +over time between the initial or <em>starting</em> view hierarchy and the final or <em>ending</em> +view hierarchy.</p> + +<p>The transitions framework works in parallel with view hierarchies and animations. The +purpose of the framework is to store the state of view hierarchies, change between these +hierarchies in order to modify the appearance of the device screen, and animate the change by +storing and applying animation definitions.</p> + +<p>The diagram in Figure 2 illustrates the relationship between view hierarchies, framework +objects, and animations:</p> + +<!-- Figure 2 - diagram --> +<img src="{@docRoot}images/transitions/transitions_diagram.png" + width="506" height="234" alt="" style="margin-top:7px" /> +<p class="img-caption"><strong>Figure 2.</strong> Relationships in the transitions framework.</p> + +<p>The transitions framework provides abstractions for scenes, transitions, and transition +managers. These are described in detail in the following sections. To use the framework, you +create scenes for the view hierarchies in your app that you plan to change between. Next, you +create a transition for each animation you want to use. To start the animation between two +view hierarchies, you use a transition manager specifying the transition to use and the ending +scene. This procedure is described in detail in the remaining lessons in this class.</p> + + + +<h2 id="Scenes">Scenes</h2> + +<p>A scene stores the state of a view hierarchy, including all its views and their property +values. A view hierarchy can be a simple view or a complex tree of views and child layouts. +Storing the view hierarchy state in a scene enables you to transition into that state from +another scene. The framework provides the {@link android.transition.Scene} class to represent +a scene.</p> + +<p>The transitions framework lets you create scenes from layout resource files or from +{@link android.view.ViewGroup} objects in your code. Creating a scene in your code is useful +if you generated a view hierarchy dynamically or if you are modifying it at runtime.</p> + +<p>In most cases, you do not create a starting scene explicitly. If you have applied a +transition, the framework uses the previous ending scene as the starting scene for any +subsequent transitions. If you have not applied a transition, the framework collects information +about the views from the current state of the screen.</p> + +<p>A scene can also define its own actions that run when you make a scene change. For example, +this feature is useful for cleaning up view settings after you transition to a scene.</p> + +<p>In addition to the view hierarchy and its property values, a scene also stores a reference +to the parent of the view hierarchy. This root view is called a <strong>scene root</strong>. +Changes to the scene and animations that affect the scene occur within the scene root.</p> + +<p>To learn how to create scenes, see +<a href="{@docRoot}training/transitions/scenes.html">Creating a Scene</a>.</p> + + + +<h2 id="Transitions">Transitions</h2> + +<p>In the transitions framework, animations create a series of frames that depict a change +between the view hierarchies in the starting and ending scenes. Information about the animation +is stored in a {@link android.transition.Transition} object. To run the animation, you apply the +transition using a {@link android.transition.TransitionManager} instance. The framework can +transition between two different scenes or transition to a different state for the current +scene.</p> + +<p>The framework includes a set of built-in transitions for commonly-used animation effects, +such as fading and resizing views. You can also define your own custom transitions to create +an animation effect using the APIs in the animations framework. The transitions framework also +enables you to combine different animation effects in a transition set that contains a group +of individual built-in or custom transitions.</p> + +<p>The transition lifecycle is similar to the activity lifecycle, and it represents the +transition states that the framework monitors between the start and the completion of an +animation. At important lifecycle states, the framework invokes callback methods that you can +implement to make adjustments to your user interface at different phases of the transition.</p> + +<p>To learn more about transitions, see +<a href="{@docRoot}training/transitions/transitions.html">Applying a Transition</a> and +<a href="{@docRoot}training/transitions/custom-transitions.html">Creating Custom +Transitions</a>.</p> + + + +<h2 id="Limitations">Limitations</h2> + +<p>This section lists some known limitations of the transitions framework:</p> + +<ul> +<li>Animations applied to a {@link android.view.SurfaceView} may not appear correctly. +{@link android.view.SurfaceView} instances are updated from a non-UI thread, so the updates +may be out of sync with the animations of other views.</li> +<li>Some specific transition types may not produce the desired animation effect when applied +to a {@link android.view.TextureView}.</li> +<li>Classes that extend {@link android.widget.AdapterView}, such as +{@link android.widget.ListView}, manage their child views in ways that are incompatible with +the transitions framework. If you try to animate a view based on +{@link android.widget.AdapterView}, the device display may hang.</li> +<li>If you try to resize a {@link android.widget.TextView} with an animation, the text will +pop to a new location before the object has completely resized. To avoid this problem, do not +animate the resizing of views that contain text.</li> +</ul> diff --git a/docs/html/training/transitions/scenes.jd b/docs/html/training/transitions/scenes.jd new file mode 100644 index 0000000..4bf7d0e --- /dev/null +++ b/docs/html/training/transitions/scenes.jd @@ -0,0 +1,211 @@ +page.title=Creating a Scene + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> +<h2>This lesson teaches you to</h2> +<ol> + <li><a href="#FromLayout">Create a Scene From a Layout Resource</a></li> + <li><a href="#FromCode">Create a Scene in Your Code</a></li> + <li><a href="#Actions">Create Scene Actions</a></li> +</ol> +</div> +</div> + +<p>Scenes store the state of a view hierarchy, including all its views and their property +values. The transitions framework can run animations between a starting and an ending scene. +The starting scene is often determined automatically from the current state of the user +interface. For the ending scene, the framework enables you to create a scene from a layout +resource file or from a group of views in your code.</p> + +<p>This lesson shows you how to create scenes in your app and how to define scene actions. +The next lesson shows you how to transition between two scenes.</p> + +<p class="note"><strong>Note:</strong> The framework can animate changes in a single view +hierarchy without using scenes, as described in +<a href="{@docRoot}training/transitions/transitions.html#NoScenes">Apply a Transition Without +Scenes</a>. However, understanding this lesson is essential to work with transitions.</p> + + + +<h2 id="FromLayout">Create a Scene From a Layout Resource</h2> + +<p>You can create a {@link android.transition.Scene} instance directly from a layout resource +file. Use this technique when the view hierarchy in the file is mostly static. The resulting +scene represents the state of the view hierarchy at the time you created the +{@link android.transition.Scene} instance. If you change the view hierarchy, you have to +recreate the scene. The framework creates the scene from the entire view hierarchy in the +file; you can not create a scene from part of a layout file.</p> + +<p>To create a {@link android.transition.Scene} instance from a layout resource file, retrieve +the scene root from your layout as a {@link android.view.ViewGroup} instance and then call the +{@link android.transition.Scene#getSceneForLayout Scene.getSceneForLayout()} method with the +scene root and the resource ID of the layout file that contains the view hierarchy for the +scene.</p> + +<h3>Define Layouts for Scenes</h3> + +<p>The code snippets in the rest of this section show you how to create two different scenes +with the same scene root element. The snippets also demonstrate that you can load multiple +unrelated {@link android.transition.Scene} objects without implying that they are related to +each other.</p> + +<p>The example consists of the following layout definitions:</p> + +<ul> +<li>The main layout of an activity with a text label and a child layout.</li> +<li>A relative layout for the first scene with two text fields.</li> +<li>A relative layout for the second scene with the same two text fields in different order.</li> +</ul> + +<p>The example is designed so that all of the animation occurs within the child layout of the +main layout for the activity. The text label in the main layout remains static.</p> + +<p>The main layout for the activity is defined as follows:</p> + +<p class="code-caption">res/layout/activity_main.xml</p> + +<pre> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/master_layout"> + <TextView + android:id="@+id/title" + ... + android:text="Title"/> + <FrameLayout + android:id="@+id/scene_root"> + <include layout="@layout/a_scene" /> + </FrameLayout> +</LinearLayout> +</pre> + +<p>This layout definition contains a text field and a child layout for the scene root. The +layout for the first scene is included in the main layout file. This allows the app to display +it as part of the initial user interface and also to load it into a scene, since the framework +can load only a whole layout file into a scene.</p> + +<p>The layout for the first scene is defined as follows:</p> + +<p class="code-caption">res/layout/a_scene.xml</p> + +<pre> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/scene_container" + android:layout_width="match_parent" + android:layout_height="match_parent" > + <TextView + android:id="@+id/text_view1 + android:text="Text Line 1" /> + <TextView + android:id="@+id/text_view2 + android:text="Text Line 2" /> +</RelativeLayout> +</pre> + +<p>The layout for the second scene contains the same two text fields (with the same IDs) +placed in a different order and is defined as follows:</p> + +<p class="code-caption">res/layout/another_scene.xml</p> + +<pre> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/scene_container" + android:layout_width="match_parent" + android:layout_height="match_parent" > + <TextView + android:id="@+id/text_view2 + android:text="Text Line 2" /> + <TextView + android:id="@+id/text_view1 + android:text="Text Line 1" /> +</RelativeLayout> +</pre> + +<h3>Generate Scenes from Layouts</h3> + +<p>After you create definitions for the two relative layouts, you can obtain an scene for +each of them. This enables you to later transition between the two UI configurations. +To obtain a scene, you need a reference to the scene root and the layout resource ID.</p> + +<p>The following code snippet shows you how to get a reference to the scene root and create +two {@link android.transition.Scene} objects from the layout files:</p> + +<pre> +Scene mAScene; +Scene mAnotherScene; + +// Create the scene root for the scenes in this app +mSceneRoot = (ViewGroup) findViewById(R.id.scene_root); + +// Create the scenes +mAScene = Scene.getSceneForLayout(mSceneRoot, R.layout.a_scene, this); +mAnotherScene = + Scene.getSceneForLayout(mSceneRoot, R.layout.another_scene, this); +</pre> + +<p>In the app, there are now two {@link android.transition.Scene} objects based on view +hierarchies. Both scenes use the scene root defined by the +{@link android.widget.FrameLayout} element in <code>res/layout/activity_main.xml</code>.</p> + + + +<h2 id="FromCode">Create a Scene in Your Code</h2> + +<p>You can also create a {@link android.transition.Scene} instance in your code from a +{@link android.view.ViewGroup} object. Use this technique when you modify the view hierarchies +directly in your code or when you generate them dynamically.</p> + +<p>To create a scene from a view hierarchy in your code, use the +{@link android.transition.Scene#Scene(android.view.ViewGroup, android.view.View) Scene(sceneRoot, viewHierarchy)} +constructor. Calling this constructor is equivalent to calling the +{@link android.transition.Scene#getSceneForLayout Scene.getSceneForLayout()} method when you +have already inflated a layout file.</p> + +<p>The following code snippet demonstrates how to create a {@link android.transition.Scene} +instance from the scene root element and the view hierarchy for the scene in your code:</p> + +<pre> +Scene mScene; + +// Obtain the scene root element +mSceneRoot = (ViewGroup) mSomeLayoutElement; + +// Obtain the view hierarchy to add as a child of +// the scene root when this scene is entered +mViewHierarchy = (ViewGroup) someOtherLayoutElement; + +// Create a scene +mScene = new Scene(mSceneRoot, mViewHierarchy); +</pre> + + + +<h2 id="Actions">Create Scene Actions</h2> + +<p>The framework enables you to define custom scene actions that the system runs when entering +or exiting a scene. In many cases, defining custom scene actions is not necessary, since the +framework animates the change between scenes automatically.</p> + +<p>Scene actions are useful for handling these cases:</p> + +<ul> +<li>Animate views that are not in the same hierarchy. You can animate views for both the +starting and ending scenes using exit and entry scene actions.</li> +<li>Animate views that the transitions framework cannot animate automatically, such as +{@link android.widget.ListView} objects. For more information, see +<a href="{@docRoot}training/transitions/overview.html#Limitations">Limitations</a>.</li> +</ul> + +<p>To provide custom scene actions, define your actions as {@link java.lang.Runnable} objects +and pass them to the {@link android.transition.Scene#setExitAction Scene.setExitAction()} or +{@link android.transition.Scene#setEnterAction Scene.setEnterAction()} methods. The framework +calls the {@link android.transition.Scene#setExitAction setExitAction()} method on the starting +scene before running the transition animation and the {@link +android.transition.Scene#setEnterAction setEnterAction()} method on the ending scene after +running the transition animation.</p> + +<p class="note"><strong>Note:</strong> Do not use scene actions to pass data between views in +the starting and ending scenes. For more information, see +<a href="{@docRoot}training/transitions/transitions.html#Callbacks">Defining Transition +Lifecycle Callbacks</a>.</p> diff --git a/docs/html/training/transitions/transitions.jd b/docs/html/training/transitions/transitions.jd new file mode 100644 index 0000000..489e291 --- /dev/null +++ b/docs/html/training/transitions/transitions.jd @@ -0,0 +1,315 @@ +page.title=Applying a Transition + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> +<h2>This lesson teaches you to</h2> +<ol> + <li><a href="#Create">Create a Transition</a></li> + <li><a href="#Apply">Apply a Transition</a></li> + <li><a href="#Targets">Choose Specific Target Views</a></li> + <li><a href="#Multiple">Specify Multiple Transitions</a></li> + <li><a href="#NoScenes">Apply a Transition Without Scenes</a></li> + <li><a href="#Callbacks">Define Transition Lifecycle Callbacks</a></li> +</ol> +</div> +</div> + +<p>In the transitions framework, animations create a series of frames that depict a change +between the view hierarchies in the starting and ending scenes. The framework represents +these animations as transition objects, which contain information about an animation. To +run an animation, you provide the transition to use and the ending scene to a transition +manager.</p> + +<p>This lesson teaches you run an animation between two scenes using built-in transitions +to move, resize, and fade views. The next lesson shows you how to define custom transitions.</p> + + + +<h2 id="Create">Create a Transition</h2> + +<p>In the previous lesson, you learned how to create scenes that represent the state of +different view hierarchies. Once you have defined the starting scene and the ending scene you +want to change between, you need to create a {@link android.transition.Transition} object +that defines an animation. The framework enables you to specify a built-in transition in a +resource file and inflate it in your code or to create an instance of a built-in transition +directly in your code.</p> + +<!-- Built in transition table --> +<p class="table-caption" id="table1"><strong>Table 1.</strong> Built-in transition types.</p> +<table> +<tr> + <th scope="col">Class</th> + <th scope="col">Tag</th> + <th scope="col">Attributes</th> + <th scope="col">Effect</th> +</tr> +<tr> + <td><code><a href="/reference/android/transition/AutoTransition.html">AutoTransition</a></code></td> + <td><autoTransition/></td> + <td style="text-align=center;"> - </td> + <td>Default transition. Fade out, move and resize, and fade in views, in that order.</td> +</tr> +<tr> + <td><code><a href="/reference/android/transition/Fade.html">Fade</a></code></td> + <td><fade/></td> + <td><code>android:fadingMode="[fade_in |<br> fade_out |<br> fade_in_out]"</code></td> + <td> + <code>fade_in</code> fades in views<br> + <code>fade_out</code> fades out views<br> + <code>fade_in_out</code> (default) does a <code>fade_out</code> followed by a <code>fade_in</code>. + </td> +</tr> +<tr> + <td><code><a href="/reference/android/transition/ChangeBounds.html">ChangeBounds</a></code></td> + <td><changeBounds/></td> + <td style="text-align=center;"> - </td> + <td>Moves and resizes views.</td> +</tr> +</table> + + +<h3 id="FromFile">Create a transition instance from a resource file</h3> + +<p>This technique enables you to modify your transition definition without having to change +the code of your activity. This technique is also useful to separate complex transition +definitions from your application code, as shown in <a href="#Multiple">Specify Multiple +Transitions</a>.</p> + +<p>To specify a built-in transition in a resource file, follow these steps:</p> + +<ol> +<li>Add the <code>res/transition/</code> directory to your project.</li> +<li>Create a new XML resource file inside this directory.</li> +<li>Add an XML node for one of the built-in transitions.</li> +</ol> + +<p>For example, the following resource file specifies the {@link android.transition.Fade} +transition:</p> + +<p class="code-caption">res/transition/fade_transition.xml</p> + +<pre> +<fade xmlns:android="http://schemas.android.com/apk/res/android" /> +</pre> + +<p>The following code snippet shows how to inflate a {@link android.transition.Transition} +instance inside your activity from a resource file:</p> + +<pre> +Transition mFadeTransition = + TransitionInflater.from(this). + inflateTransition(R.transition.fade_transition); +</pre> + + +<h3 id="FromCode">Create a transition instance in your code</h3> + +<p>This technique is useful for creating transition objects dynamically if you modify the user +interface in your code, and to create simple built-in transition instances with few or +no parameters.</p> + +<p>To create an instance of a built-in transition, invoke one of the public constructors in +the subclasses of the {@link android.transition.Transition} class. For example, the following +code snippet creates an instance of the {@link android.transition.Fade} transition:</p> + +<pre> +Transition mFadeTransition = new Fade(); +</pre> + + + +<h2 id="Apply">Apply a Transition</h2> + +<p>You typically apply a transition to change between different view hierarchies in response +to an event, such as a user action. For example, consider a search app: when the user enters +a search term and clicks the search button, the app changes to the scene that represents the +results layout while applying a transition that fades out the search button and fades in the +search results.</p> + +<p>To make a scene change while applying a transition in response to some event in your +activity, call the {@link android.transition.TransitionManager#go TransitionManager.go()} +static method with the ending scene and the transition instance to use for the animation, +as shown in the following snippet:</p> + +<pre> +TransitionManager.go(mEndingScene, mFadeTransition); +</pre> + +<p>The framework changes the view hierarchy inside the scene root with the view hierarchy +from the ending scene while running the animation specified by the transition instance. The +starting scene is the ending scene from the last transition. If there was no previous +transition, the starting scene is determined automatically from the current state of the +user interface.</p> + +<p>If you do not specify a transition instance, the transition manager can apply an automatic +transition that does something reasonable for most situations. For more information, see the +API reference for the {@link android.transition.TransitionManager} class.</p> + + + +<h2 id="Targets">Choose Specific Target Views</h2> + +<p>The framework applies transitions to all views in the starting and ending scenes by +default. In some cases, you may only want to apply an animation to a subset of views in a +scene. For example, the framework does not support animating changes to +{@link android.widget.ListView} objects, so you should not try to animate them during a +transition. The framework enables you to select specific views you want to animate.</p> + +<p>Each view that the transition animates is called a <em>target</em>. You can only +select targets that are part of the view hierarchy associated with a scene.</p> + +<p>To remove one or more views from the list of targets, call the {@link +android.transition.Transition#removeTarget removeTarget()} method before starting +the transition. To add only the views you specify to the list of targets, call the +{@link android.transition.Transition#addTarget addTarget()} method. For more +information, see the API reference for the {@link android.transition.Transition} class.</p> + + + +<h2 id="Multiple">Specify Multiple Transitions</h2> + +<p>To get the most impact from an animation, you should match it to the type of changes +that occur between the scenes. For example, if you are removing some views and adding others +between scenes, a fade out/fade in animation provides a noticeable indication that some views +are no longer available. If you are moving views to different points on the screen, a better +choice would be to animate the movement so that users notice the new location of the views.</p> + +<p>You do not have to choose only one animation, since the transitions framework enables you +to combine animation effects in a transition set that contains a group of individual built-in +or custom transitions.</p> + +<p>To define a transition set from a collection of transitions in XML, create a resource file +in the <code>res/transitions/</code> directory and list the transitions under the +<code>transitionSet</code> element. For example, the following snippet shows how to specify a +transition set that has the same behaviour as the {@link android.transition.AutoTransition} +class:</p> + +<pre> +<transitionSet xmlns:android="http://schemas.android.com/apk/res/android" + android:transitionOrdering="sequential"> + <fade android:fadingMode="fade_out" /> + <changeBounds /> + <fade android:fadingMode="fade_in" /> +</transitionSet> +</pre> + +<p>To inflate the transition set into a {@link android.transition.TransitionSet} object in +your code, call the {@link android.transition.TransitionInflater#from TransitionInflater.from()} +method in your activity. The {@link android.transition.TransitionSet} class extends from the +{@link android.transition.Transition} class, so you can use it with a transition manager just +like any other {@link android.transition.Transition} instance.</p> + + + +<h2 id="NoScenes">Apply a Transition Without Scenes</h2> + +<p>Changing view hierarchies is not the only way to modify your user interface. You can also +make changes by adding, modifying, and removing child views within the current hierarchy. For +example, you can implement a search interaction with just a single layout. Start with the +layout showing a search entry field and a search icon. To change the user interface to show +the results, remove the search button when the user clicks it by calling the {@link +android.view.ViewGroup#removeView ViewGroup.removeView()} method, and add the search results by +calling {@link android.view.ViewGroup#addView ViewGroup.addView()} method.</p> + +<p>You may want to use this approach if the alternative is to have two hierarchies that are +nearly identical. Rather than having to create and maintain two separate layout files for a +minor difference in the user interface, you can have one layout file containing a view +hierarchy that you modify in code.</p> + +<p>If you make changes within the current view hierarchy in this fashion, you do not need to +create a scene. Instead, you can create and apply a transition between two states of a view +hierarchy using a <em>delayed transition</em>. This feature of the transitions framework +starts with the current view hierarchy state, records changes you make to its views, and applies +a transition that animates the changes when the system redraws the user interface.</p> + +<p>To create a delayed transition within a single view hierarchy, follow these steps:</p> + +<ol> +<li>When the event that triggers the transition occurs, call the {@link +android.transition.TransitionManager#beginDelayedTransition +TransitionManager.beginDelayedTransition()} method providing the parent view of all the views +you want to change and the transition to use. The framework stores the current state of the +child views and their property values.</li> +<li>Make changes to the child views as required by your use case. The framework records +the changes you make to the child views and their properties.</li> +<li>When the system redraws the user interface according to your changes, the framework +animates the changes between the original state and the new state.</li> +</ol> + +<p>The following example shows how to animate the addition of a text view to a view hierarchy +using a delayed transition. The first snippet shows the layout definition file:</p> + +<p class="code-caption">res/layout/activity_main.xml</p> + +<pre> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/mainLayout" + android:layout_width="match_parent" + android:layout_height="match_parent" > + <EditText + android:id="@+id/inputText" + android:layout_alignParentLeft="true" + android:layout_alignParentTop="true" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + ... +</RelativeLayout> +</pre> + +<p>The next snippet shows the code that animates the addition of the text view:</p> + +<p class="code-caption">MainActivity.java</p> + +<pre> +private TextView mLabelText; +private Fade mFade; +private ViewGroup mRootView; +... + +// Load the layout +this.setContentView(R.layout.activity_main); +... + +// Create a new TextView and set some View properties +mLabelText = new TextView(); +mLabelText.setText("Label").setId("1"); + +// Get the root view and create a transition +mRootView = (ViewGroup) findViewById(R.id.mainLayout); +mFade = new Fade(IN); + +// Start recording changes to the view hierarchy +TransitionManager.beginDelayedTransition(mRootView, mFade); + +// Add the new TextView to the view hierarchy +mRootView.addView(mLabelText); + +// When the system redraws the screen to show this update, +// the framework will animate the addition as a fade in +</pre> + + + +<h2 id="Callbacks">Define Transition Lifecycle Callbacks</h2> + +<p>The transition lifecycle is similar to the activity lifecycle. It represents the transition +states that the framework monitors during the time between a call to the {@link +android.transition.TransitionManager#go TransitionManager.go()} method and the completion of +the animation. At important lifecycle states, the framework invokes callbacks defined by +the {@link android.transition.Transition.TransitionListener TransitionListener} +interface.</p> + +<p>Transition lifecycle callbacks are useful, for example, for copying a view property value +from the starting view hierarchy to the ending view hierarchy during a scene change. You +cannot simply copy the value from its starting view to the view in the ending view hierarchy, +because the ending view hierarchy is not inflated until the transition is completed. +Instead, you need to store the value in a variable and then copy it into the ending view +hierarchy when the framework has finished the transition. To get notified when the transition +is completed, you can implement the {@link +android.transition.Transition.TransitionListener#onTransitionEnd +TransitionListener.onTransitionEnd()} method in your activity.</p> + +<p>For more information, see the API reference for the {@link +android.transition.Transition.TransitionListener TransitionListener} class.</p> diff --git a/docs/html/training/wearables/data-layer/data-items.jd b/docs/html/training/wearables/data-layer/data-items.jd index 12babbf..49a8d32 100644 --- a/docs/html/training/wearables/data-layer/data-items.jd +++ b/docs/html/training/wearables/data-layer/data-items.jd @@ -46,7 +46,7 @@ directly. Instead, you: </ol> <p> -However, instead of working with raw bytes using <a href="{@docRoot}reference/com/google/android/gms/wearable/PutDataRequest.html#setData(byte[])">setData()</a>, +However, instead of working with raw bytes using <a href="{@docRoot}reference/com/google/android/gms/wearable/PutDataRequest.html#setData(byte[])"><code>setData()</code></a>, 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> @@ -88,39 +88,121 @@ app, you should create a path scheme that matches the structure of the data. </li> </ol> -<p>The following example shows how to create a data map and put data on it:</p> +<p>The <code>increaseCounter()</code> method in the following example shows how to create a +data map and put data in it:</p> <pre> -PutDataMapRequest dataMap = PutDataMapRequest.create("/count"); -dataMap.getDataMap().putInt(COUNT_KEY, count++); -PutDataRequest request = dataMap.asPutDataRequest(); -PendingResult<DataApi.DataItemResult> pendingResult = Wearable.DataApi - .putDataItem(mGoogleApiClient, request); +public class MainActivity extends Activity implements + DataApi.DataListener, + GoogleApiClient.ConnectionCallbacks, + GoogleApiClient.OnConnectionFailedListener { + + private static final String COUNT_KEY = "com.example.key.count"; + + private GoogleApiClient mGoogleApiClient; + private int count = 0; + + ... + + // Create a data map and put data in it + private void <strong>increaseCounter</strong>() { + PutDataMapRequest putDataMapReq = PutDataMapRequest.create("/count"); + putDataMapReq.getDataMap().putInt(COUNT_KEY, count++); + PutDataRequest putDataReq = putDataMapReq.asPutDataRequest(); + PendingResult<DataApi.DataItemResult> pendingResult = + Wearable.DataApi.putDataItem(mGoogleApiClient, putDataReq); + } + + ... +} </pre> +<p>For more information about handling the +<a href="{@docRoot}reference/com/google/android/gms/common/api/PendingResult.html"> +<code>PendingResult</code></a> object, see +<a href="{@docRoot}training/wearables/data-layer/events.html#Wait">Wait for the Status of Data +Layer Calls</a>.</p> + + <h2 id="ListenEvents">Listen for Data Item Events</h2> -If one side of the data layer connection changes a data item, you probably want + +<p>If one side of the data layer connection changes a data item, you probably want 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. +You can do this by implementing a listener for data item events.</p> -<p>For example, here's what a typical callback looks like to carry out certain actions -when data changes:</p> +<p>The code snippet in the following example notifies your app when the value of the +counter defined in the previous example changes:</p> <pre> -@Override -public void onDataChanged(DataEventBuffer dataEvents) { - for (DataEvent event : dataEvents) { - 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()); +public class MainActivity extends Activity implements + DataApi.DataListener, + GoogleApiClient.ConnectionCallbacks, + GoogleApiClient.OnConnectionFailedListener { + + private static final String COUNT_KEY = "com.example.key.count"; + + private GoogleApiClient mGoogleApiClient; + private int count = 0; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + mGoogleApiClient = new GoogleApiClient.Builder(this) + .addApi(Wearable.API) + .addConnectionCallbacks(this) + .addOnConnectionFailedListener(this) + .build(); + } + + @Override + protected void onResume() { + super.onStart(); + mGoogleApiClient.connect(); + } + + @Override + public void onConnected(Bundle bundle) { + <strong>Wearable.DataApi.addListener</strong>(mGoogleApiClient, this); + } + + @Override + protected void onPause() { + super.onPause(); + <strong>Wearable.DataApi.removeListener</strong>(mGoogleApiClient, this); + mGoogleApiClient.disconnect(); + } + + @Override + public void <strong>onDataChanged</strong>(DataEventBuffer dataEvents) { + for (DataEvent event : dataEvents) { + if (event.getType() == DataEvent.TYPE_CHANGED) { + // DataItem changed + DataItem item = event.getDataItem(); + if (item.getUri().getPath().compareTo("/count") == 0) { + DataMap dataMap = DataMapItem.fromDataItem(item).getDataMap(); + updateCount(dataMap.getInt(COUNT_KEY)); + } + } else if (event.getType() == DataEvent.TYPE_DELETED) { + // DataItem deleted + } } } + + // Our method to update the count + private void updateCount(int c) { ... } + + ... } </pre> -<p> -This is just a snippet that requires more implementation details. Learn about -how to implement a full listener service or activity in + +<p>This activity implements the +<a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.DataListener.html"> +<code>DataItem.DataListener</code></a> interface. This activity adds itself as a listener +for data item events inside the <code>onConnected()</code> method and removes the listener +in the <code>onPause()</code> method.</p> + +<p>You can also implement the listener as a service. For more information, see <a href="{@docRoot}training/wearables/data-layer/events.html#Listen">Listen for Data Layer -Events</a>. -</p>
\ No newline at end of file +Events</a>.</p> diff --git a/docs/html/training/wearables/data-layer/events.jd b/docs/html/training/wearables/data-layer/events.jd index 6a3949a..c797f68 100644 --- a/docs/html/training/wearables/data-layer/events.jd +++ b/docs/html/training/wearables/data-layer/events.jd @@ -267,6 +267,8 @@ or <a href="{@docRoot}reference/com/google/android/gms/wearable/NodeApi.html#rem public class MainActivity extends Activity implements DataApi.DataListener, ConnectionCallbacks, OnConnectionFailedListener { + private GoogleApiClient mGoogleApiClient; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -314,4 +316,5 @@ public class MainActivity extends Activity implements } } } +} </pre> diff --git a/docs/html/training/wearables/data-layer/messages.jd b/docs/html/training/wearables/data-layer/messages.jd index 822e395..0ca55ba 100644 --- a/docs/html/training/wearables/data-layer/messages.jd +++ b/docs/html/training/wearables/data-layer/messages.jd @@ -39,16 +39,24 @@ to Google Play services and when to use each in </p> <pre> -Node node; // the connected device to send the message to GoogleApiClient mGoogleApiClient; -public static final START_ACTIVITY_PATH = "/start/MainActivity"; +public static final String START_ACTIVITY_PATH = "/start/MainActivity"; ... - SendMessageResult result = Wearable.MessageApi.sendMessage( - mGoogleApiClient, node, START_ACTIVITY_PATH, null).await(); - if (!result.getStatus().isSuccess()) { - Log.e(TAG, "ERROR: failed to send Message: " + result.getStatus()); - } +private void sendStartActivityMessage(String nodeId) { + Wearable.MessageApi.sendMessage( + mGoogleApiClient, nodeId, START_ACTIVITY_PATH, new byte[0]).setResultCallback( + new ResultCallback<SendMessageResult>() { + @Override + public void onResult(SendMessageResult sendMessageResult) { + if (!sendMessageResult.getStatus().isSuccess()) { + Log.e(TAG, "Failed to send message with status code: " + + sendMessageResult.getStatus().getStatusCode()); + } + } + } + ); +} </pre> <p> diff --git a/docs/html/training/wearables/watch-faces/configuration.jd b/docs/html/training/wearables/watch-faces/configuration.jd index edc7eac..5a4585d 100644 --- a/docs/html/training/wearables/watch-faces/configuration.jd +++ b/docs/html/training/wearables/watch-faces/configuration.jd @@ -92,7 +92,7 @@ and declare the following intent filter in the manifest file of the wearable app <action android:name= "com.example.android.wearable.watchface.CONFIG_DIGITAL" /> <category android:name= - "com.google.android.wearable.watchface.category.WEARABLE_CONFIGURATION" /> + <strong>"com.google.android.wearable.watchface.category.WEARABLE_CONFIGURATION"</strong> /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> @@ -119,8 +119,21 @@ a handheld device. For example, a configuration activity on a handheld device en present users with elaborate color pickers to select the background color of a watch face.</p> <p>To create a companion configuration activity, add a new activity to your handheld app module and -declare the same intent filter for this activity as the one in <a href="#WearableActivity">Create -a Wearable Configuration Activity</a>.</p> +declare the following intent filter in the manifest file of the handheld app:</p> + +<pre> +<activity + android:name=".DigitalWatchFaceCompanionConfigActivity" + android:label="@string/app_name"> + <intent-filter> + <action android:name= + "com.example.android.wearable.watchface.CONFIG_DIGITAL" /> + <category android:name= + <strong>"com.google.android.wearable.watchface.category.COMPANION_CONFIGURATION"</strong> /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> +</activity> +</pre> <p>In your configuration activity, build a UI that provides options to customize all the configurable elements of your watch face. When users make a selection, use the <a |