diff options
Diffstat (limited to 'docs/html/guide/topics')
36 files changed, 1510 insertions, 594 deletions
diff --git a/docs/html/guide/topics/connectivity/bluetooth-le.jd b/docs/html/guide/topics/connectivity/bluetooth-le.jd index 21950c2..449c892 100644 --- a/docs/html/guide/topics/connectivity/bluetooth-le.jd +++ b/docs/html/guide/topics/connectivity/bluetooth-le.jd @@ -44,6 +44,15 @@ page.tags="wireless","bluetoothadapter","bluetoothdevice","BLE","BTLE" </div> </div> +<a class="notice-developers-video" href="http://www.youtube.com/watch?v=vUbFB1Qypg8"> +<div> + <h3>Video</h3> + <p>DevBytes: Bluetooth Low Energy API</p> +</div> +</a> + + + <p> Android 4.3 (API Level 18) introduces built-in platform support for Bluetooth Low diff --git a/docs/html/guide/topics/connectivity/nfc/hce.jd b/docs/html/guide/topics/connectivity/nfc/hce.jd index 4ef6859..d6efaa7 100644 --- a/docs/html/guide/topics/connectivity/nfc/hce.jd +++ b/docs/html/guide/topics/connectivity/nfc/hce.jd @@ -33,13 +33,13 @@ page.tags="host card emulation", "hce","HostApduService","OffHostApduService","t -<p>Many Android-powered devices that offer NFC functionality already support NFC card -emulation. In most cases, the card is emulated by a separate -chip in the device, called a <em>secure element</em>. Many SIM cards provided by +<p>Many Android-powered devices that offer NFC functionality already support NFC card +emulation. In most cases, the card is emulated by a separate +chip in the device, called a <em>secure element</em>. Many SIM cards provided by wireless carriers also contain a secure element.</p> -<p>Android 4.4 introduces an additional method of card emulation that does not -involve a secure element, called <em>host-based card emulation</em>. This allows any +<p>Android 4.4 introduces an additional method of card emulation that does not +involve a secure element, called <em>host-based card emulation</em>. This allows any Android application to emulate a card and talk directly to the NFC reader. This document describes how host-based card emulation (HCE) works on Android and how you can develop an app that emulates an NFC card using this technique.</p> @@ -48,23 +48,23 @@ can develop an app that emulates an NFC card using this technique.</p> <h2 id="SecureElement">Card Emulation with a Secure Element</h2> <p>When NFC card emulation is provided using a secure element, the card to be emulated -is provisioned into the secure element on -the device through an Android application. Then, when the user holds the -device over an NFC terminal, the NFC controller in the device routes all data +is provisioned into the secure element on +the device through an Android application. Then, when the user holds the +device over an NFC terminal, the NFC controller in the device routes all data from the reader directly to the secure element. Figure 1 illustrates this concept.</p> <img src="{@docRoot}images/nfc/secure-element.png" /> <p class="img-caption"><strong>Figure 1.</strong> NFC card emulation with a secure element.</p> -<p>The secure element itself performs the communication with the NFC terminal, -and no Android application is involved in the transaction at all. After the -transaction is complete, an Android application can query the secure element +<p>The secure element itself performs the communication with the NFC terminal, +and no Android application is involved in the transaction at all. After the +transaction is complete, an Android application can query the secure element directly for the transaction status and notify the user.</p> <h2 id="HCE">Host-based Card Emulation</h2> -<p>When an NFC card is emulated using host-based card emulation, the data is routed to +<p>When an NFC card is emulated using host-based card emulation, the data is routed to the host CPU on which Android applications are running directly, instead of routing the NFC protocol frames to a secure element. Figure 2 illustrates how host-based card emulation works.</p> @@ -80,23 +80,23 @@ works.</p> <p class="img-caption"><strong>Figure 3.</strong> Android's HCE protocol stack.</p> </div> -<p>The NFC standards offer support for many different protocols, and there are +<p>The NFC standards offer support for many different protocols, and there are different types of cards that can be emulated.</p> -<p>Android 4.4 supports several protocols that are common in the -market today. Many existing contactless cards are already based on these -protocols, such as contactless payment cards. These protocols are also -supported by many NFC readers in the market today, including Android NFC +<p>Android 4.4 supports several protocols that are common in the +market today. Many existing contactless cards are already based on these +protocols, such as contactless payment cards. These protocols are also +supported by many NFC readers in the market today, including Android NFC devices functioning as readers themselves (see the {@link android.nfc.tech.IsoDep} class). -This allows you to build and deploy an end-to-end NFC solution +This allows you to build and deploy an end-to-end NFC solution around HCE using only Android-powered devices.</p> -<p>Specifically, Android 4.4 supports emulating cards that are based on the -NFC-Forum ISO-DEP specification (based on ISO/IEC 14443-4) and process -Application Protocol Data Units (APDUs) as defined in the ISO/IEC 7816-4 -specification. Android mandates emulating ISO-DEP only on top of the -Nfc-A (ISO/IEC 14443-3 Type A) technology. Support for Nfc-B (ISO/IEC 14443-4 -Type B) technology is optional. The layering of all these specifications is +<p>Specifically, Android 4.4 supports emulating cards that are based on the +NFC-Forum ISO-DEP specification (based on ISO/IEC 14443-4) and process +Application Protocol Data Units (APDUs) as defined in the ISO/IEC 7816-4 +specification. Android mandates emulating ISO-DEP only on top of the +Nfc-A (ISO/IEC 14443-3 Type A) technology. Support for Nfc-B (ISO/IEC 14443-4 +Type B) technology is optional. The layering of all these specifications is shown in the figure 3.</p> @@ -105,12 +105,12 @@ shown in the figure 3.</p> <p>The HCE architecture in Android is based around Android {@link android.app.Service} components (known as "HCE services"). -One of the key advantages of a service is that it can run in the background without -any user interface. This is a natural fit for many HCE applications like loyalty or transit cards, -with which the user shouldn't need to launch the app to use it. -Instead, tapping the device against the NFC reader starts the correct service (if not already -running) and executes the transaction in the background. Of course, you are free -to launch additional UI (such as user notifications) from your service if that makes +One of the key advantages of a service is that it can run in the background without +any user interface. This is a natural fit for many HCE applications like loyalty or transit cards, +with which the user shouldn't need to launch the app to use it. +Instead, tapping the device against the NFC reader starts the correct service (if not already +running) and executes the transaction in the background. Of course, you are free +to launch additional UI (such as user notifications) from your service if that makes sense.</p> @@ -118,72 +118,78 @@ sense.</p> <h3 id="ServiceSelection">Service selection</h3> <p>When the user taps a device to an NFC reader, the Android system needs to - know which HCE service the NFC reader actually wants to talk to. -This is where the ISO/IEC 7816-4 specification comes in: it defines a way to -select applications, centered around an Application ID (AID). An AID -consists of up to 16 bytes. If you are emulating cards for an existing NFC reader -infrastructure, the AIDs that those readers are looking for are typically -well-known and publicly registered (for example, the AIDs of payment networks +know which HCE service the NFC reader actually wants to talk to. +This is where the ISO/IEC 7816-4 specification comes in: it defines a way to +select applications, centered around an Application ID (AID). An AID +consists of up to 16 bytes. If you are emulating cards for an existing NFC reader +infrastructure, the AIDs that those readers are looking for are typically +well-known and publicly registered (for example, the AIDs of payment networks such as Visa and MasterCard).</p> -<p>If you want to deploy new reader infrastructure for your own application, you -will need to register your own AID(s). The registration procedure for AIDs is -defined in the ISO/IEC 7816-5 specification. Google recommends registering an -AID as per 7816-5 if you are deploying a HCE application for Android, as it will avoid +<p>If you want to deploy new reader infrastructure for your own application, you +will need to register your own AID(s). The registration procedure for AIDs is +defined in the ISO/IEC 7816-5 specification. Google recommends registering an +AID as per 7816-5 if you are deploying a HCE application for Android, as it will avoid collisions with other applications.</p> <h3 id="AidGroups">AID groups</h3> -<p>In some cases, an HCE service may need to register multiple AIDs to implement a -certain application, and it needs to be sure that it is the default handler for -all of these AIDs (as opposed to some AIDs in the group going to another +<p>In some cases, an HCE service may need to register multiple AIDs to implement a +certain application, and it needs to be sure that it is the default handler for +all of these AIDs (as opposed to some AIDs in the group going to another service).</p> -<p>An AID group is a list of AIDs that should be considered as belonging together -by the OS. For all AIDs in an AID group, Android guarantees one of the +<p>An AID group is a list of AIDs that should be considered as belonging together +by the OS. For all AIDs in an AID group, Android guarantees one of the following:</p> <ul> <li>All AIDs in the group are routed to this HCE service</li> -<li>No AIDs in the group are routed to this HCE service (for example, because the user -preferred another service which requested one or more AIDs in your group as +<li>No AIDs in the group are routed to this HCE service (for example, because the user +preferred another service which requested one or more AIDs in your group as well)</li> </ul> -<p>In other words, there is no in-between state, where some AIDs in the group can +<p>In other words, there is no in-between state, where some AIDs in the group can be routed to one HCE service, and some to another.</p> <h3 id="GroupsCategories">AID groups and categories</h3> -<p>Each AID group can be associated with a category. This allows Android to group -HCE services together by category, and that in turn allows the user to set -defaults at the category level instead of the AID level. In general, avoid -mentioning AIDs in any user-facing parts of your application: they do not mean +<p>Each AID group can be associated with a category. This allows Android to group +HCE services together by category, and that in turn allows the user to set +defaults at the category level instead of the AID level. In general, avoid +mentioning AIDs in any user-facing parts of your application: they do not mean anything to the average user.</p> <p>Android 4.4 supports two categories: {@link - android.nfc.cardemulation.CardEmulation#CATEGORY_PAYMENT} (covering payment +android.nfc.cardemulation.CardEmulation#CATEGORY_PAYMENT} (covering industry-standard payment apps) and {@link android.nfc.cardemulation.CardEmulation#CATEGORY_OTHER} (for all other HCE apps).</p> - +<div class="note"> + <p><strong>Note:</strong> + Only one AID group in the {@link + android.nfc.cardemulation.CardEmulation#CATEGORY_PAYMENT} category may be enabled in the system at any given time. Typically, this will be an app that understands major credit card payment protcols and which can work at any merchant.</p> + <p>For <em>closed-loop</em> payment apps that only work at one merchant (such as stored-value cards), you should use {@link + android.nfc.cardemulation.CardEmulation#CATEGORY_OTHER}. AID groups in this category can be always active, and can be given priority by NFC readers during AID selection if necessary.</p> +</div> <h2 id="ImplementingService">Implementing an HCE Service</h2> <p>To emulate an NFC card using host-based card emulation, you need to create - a {@link android.app.Service} component that handles the NFC transactions. + a {@link android.app.Service} component that handles the NFC transactions. <h3 id="CheckingforSupport">Checking for HCE support</h3> -<p>Your application can check whether a device supports HCE by checking for the -{@link android.content.pm.PackageManager#FEATURE_NFC_HOST_CARD_EMULATION} feature. You should use the -<a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code <uses-feature>}</a> tag in the manifest of your application to declare that your app +<p>Your application can check whether a device supports HCE by checking for the +{@link android.content.pm.PackageManager#FEATURE_NFC_HOST_CARD_EMULATION} feature. You should use the +<a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code <uses-feature>}</a> tag in the manifest of your application to declare that your app uses the HCE feature, and whether it is required for the app to function or not.</p> <h3 id="ServiceImplementation">Service implementation</h3> -<p>Android 4.4 comes with a convenience {@link android.app.Service} class that can be used as a +<p>Android 4.4 comes with a convenience {@link android.app.Service} class that can be used as a basis for implementing a HCE service: the {@link android.nfc.cardemulation.HostApduService} class.</p> <p>The first step is therefore to extend {@link android.nfc.cardemulation.HostApduService}.</p> @@ -197,7 +203,7 @@ public class MyHostApduService extends HostApduService { @Override public void onDeactivated(int reason) { ... - } + } } </pre> @@ -205,238 +211,237 @@ public class MyHostApduService extends HostApduService { declares two abstract methods that need to be overridden and implemented.</p> <p>{@link android.nfc.cardemulation.HostApduService#processCommandApdu processCommandApdu()} - is called whenever a NFC reader sends an Application -Protocol Data Unit (APDU) to your service. APDUs are defined in the ISO/IEC -7816-4 specification as well. APDUs are the application-level packets being -exchanged between the NFC reader and your HCE service. That application-level -protocol is half-duplex: the NFC reader will send you a command APDU, and it +is called whenever a NFC reader sends an Application +Protocol Data Unit (APDU) to your service. APDUs are defined in the ISO/IEC +7816-4 specification as well. APDUs are the application-level packets being +exchanged between the NFC reader and your HCE service. That application-level +protocol is half-duplex: the NFC reader will send you a command APDU, and it will wait for you to send a response APDU in return.</p> <p class="note"><strong>Note:</strong> - The ISO/IEC 7816-4 specification also defines the concept of multiple logical channels, - where you can have multiple parallel APDU exchanges on separate logical channels. Android’s - HCE implementation however only supports a single logical channel, so there’s only a - single-threaded exchange of APDUs.</p> - - -<p>As mentioned previously, Android uses the AID to determine which HCE service the -reader wants to talk to. Typically, the first APDU an NFC reader sends to your -device is a "SELECT AID" APDU; this APDU contains the AID that the reader wants -to talk to. Android extracts that AID from the APDU, resolves it to an HCE service, + The ISO/IEC 7816-4 specification also defines the concept of multiple logical channels, + where you can have multiple parallel APDU exchanges on separate logical channels. Android’s + HCE implementation however only supports a single logical channel, so there’s only a + single-threaded exchange of APDUs.</p> + + +<p>As mentioned previously, Android uses the AID to determine which HCE service the +reader wants to talk to. Typically, the first APDU an NFC reader sends to your +device is a "SELECT AID" APDU; this APDU contains the AID that the reader wants +to talk to. Android extracts that AID from the APDU, resolves it to an HCE service, then forwards that APDU to the resolved service.</p> -<p>You can send a response APDU by returning the bytes of the response APDU from +<p>You can send a response APDU by returning the bytes of the response APDU from {@link android.nfc.cardemulation.HostApduService#processCommandApdu processCommandApdu()}. - Note that this method will be called on the main thread of -your application, which shouldn't be blocked. So if you can't compute and return -a response APDU immediately, return null. You can then do the necessary work on -another thread, and use the {@link android.nfc.cardemulation.HostApduService#sendResponseApdu - sendResponseApdu()} method defined + Note that this method will be called on the main thread of +your application, which shouldn't be blocked. So if you can't compute and return +a response APDU immediately, return null. You can then do the necessary work on +another thread, and use the {@link android.nfc.cardemulation.HostApduService#sendResponseApdu sendResponseApdu()} method defined in the {@link android.nfc.cardemulation.HostApduService} class to send the response when you are done.</p> -<p>Android will keep forwarding new APDUs from the reader to your service, until +<p>Android will keep forwarding new APDUs from the reader to your service, until either:</p> <ol> -<li>The NFC reader sends another "SELECT AID" APDU, which the OS resolves to a +<li>The NFC reader sends another "SELECT AID" APDU, which the OS resolves to a different service;</li> <li>The NFC link between the NFC reader and your device is broken.</li> </ol> <p>In both of these cases, your class's - {@link android.nfc.cardemulation.HostApduService#onDeactivated onDeactivated()} - implementation is +{@link android.nfc.cardemulation.HostApduService#onDeactivated onDeactivated()} +implementation is called with an argument indicating which of the two happened.</p> -<p>If you are working with existing reader infrastructure, you need to -implement the existing application-level protocol that the readers expect in +<p>If you are working with existing reader infrastructure, you need to +implement the existing application-level protocol that the readers expect in your HCE service.</p> -<p>If you are deploying new reader infrastructure which you control as well, you -can define your own protocol and APDU sequence. In general try to limit the -amount of APDUs and the size of the data that needs to be exchanged: this makes -sure that your users will only have to hold their device over the NFC reader for -a short amount of time. A sane upper bound is about 1KB of data, which can +<p>If you are deploying new reader infrastructure which you control as well, you +can define your own protocol and APDU sequence. In general try to limit the +amount of APDUs and the size of the data that needs to be exchanged: this makes +sure that your users will only have to hold their device over the NFC reader for +a short amount of time. A sane upper bound is about 1KB of data, which can usually be exchanged within 300ms.</p> <h3 id="ManifestDeclaration">Service manifest declaration and AID registration</h3> -<p>Your service must be declared in the manifest as usual, but some additional +<p>Your service must be declared in the manifest as usual, but some additional pieces must be added to the service declaration as well.</p> -<p>First, to tell the platform that it is a HCE service implementing a -{@link android.nfc.cardemulation.HostApduService} interface, your service declaration must contain an +<p>First, to tell the platform that it is a HCE service implementing a +{@link android.nfc.cardemulation.HostApduService} interface, your service declaration must contain an intent filter for the {@link android.nfc.cardemulation.HostApduService#SERVICE_INTERFACE} action.</p> -<p>Additionally, to tell the platform which AIDs groups are requested by this -service, a {@link android.nfc.cardemulation.HostApduService#SERVICE_META_DATA} -<code><meta-data></code> tag must be included in -the declaration of the service, pointing to an XML resource with additional +<p>Additionally, to tell the platform which AIDs groups are requested by this +service, a {@link android.nfc.cardemulation.HostApduService#SERVICE_META_DATA} +<code><meta-data></code> tag must be included in +the declaration of the service, pointing to an XML resource with additional information about the HCE service.</p> -<p>Finally, you must set the {@code android:exported} attribute to true, and require the -{@code "android.permission.BIND_NFC_SERVICE"} permission in your service declaration. -The former ensures that the service can be bound to by external applications. -The latter then enforces that only external applications that hold the -{@code ""android.permission.BIND_NFC_SERVICE"} permission can bind to your service. Since -{@code ""android.permission.BIND_NFC_SERVICE"} is a system permission, this effectively +<p>Finally, you must set the {@code android:exported} attribute to true, and require the +{@code "android.permission.BIND_NFC_SERVICE"} permission in your service declaration. +The former ensures that the service can be bound to by external applications. +The latter then enforces that only external applications that hold the +{@code "android.permission.BIND_NFC_SERVICE"} permission can bind to your service. Since +{@code "android.permission.BIND_NFC_SERVICE"} is a system permission, this effectively enforces that only the Android OS can bind to your service. </p> <p>Here's an example of a {@link android.nfc.cardemulation.HostApduService} manifest declaration:</p> <pre> <service android:name=".MyHostApduService" android:exported="true" - android:permission="android.permission.BIND_NFC_SERVICE"> - <intent-filter> - <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/> - </intent-filter> + android:permission="android.permission.BIND_NFC_SERVICE"> + <intent-filter> + <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/> + </intent-filter> <meta-data android:name="android.nfc.cardemulation.host_apdu_service" - android:resource="@xml/apduservice"/> -</service> + android:resource="@xml/apduservice"/> +</service> </pre> -<p>This meta-data tag points to an {@code apduservice.xml} file. An example of such a file -with a single AID group declaration containing two proprietary AIDs is shown +<p>This meta-data tag points to an {@code apduservice.xml} file. An example of such a file +with a single AID group declaration containing two proprietary AIDs is shown below:</p> <pre> <host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android" - android:description="@string/servicedesc" - android:requireDeviceUnlock="false"> - <aid-group android:description="@string/aiddescription" - android:category="other"> - <aid-filter android:name="F0010203040506"/> - <aid-filter android:name="F0394148148100"/> - </aid-group> -</host-apdu-service> + android:description="@string/servicedesc" + android:requireDeviceUnlock="false"> + <aid-group android:description="@string/aiddescription" + android:category="other"> + <aid-filter android:name="F0010203040506"/> + <aid-filter android:name="F0394148148100"/> + </aid-group> +</host-apdu-service> </pre> -<p>The <code><host-apdu-service></code> tag is required to contain a <code><android:description></code> -attribute that contains a user-friendly description of the service that may be -shown in UI. The <code><requireDeviceUnlock></code> attribute can be used to specify that the +<p>The <code><host-apdu-service></code> tag is required to contain a <code><android:description></code> +attribute that contains a user-friendly description of the service that may be +shown in UI. The <code>requireDeviceUnlock</code> attribute can be used to specify that the device must be unlocked before this service can be invoked to handle APDUs.</p> -<p>The <code><host-apdu-service></code> must contain one or more <code><aid-group></code> tags. Each -<code><aid-group></code> tag is required to contain a <code>android:description</code> attribute that -contains a user-friendly description of the AID group that may be shown in UI. -Each <code><aid-group></code> tag must also have the android:category attribute set to -indicate the category the AID group belongs to, e.g. the string constants -defined by CardEmulation.CATEGORY_PAYMENT or CardEmulation.CATEGORY_OTHER. Each -<code><aid-group></code> must contain one or more <code><aid-filter></code> tags, each of which contains a -single AID. The AID must be specified in hexadecimal format, and contain an even -number of characters.</p> - -<p>As a final note, your application also needs to hold the NFC permission, - {@link android.Manifest.permission#NFC} to be able to register as a HCE service.</p> - +<p>The <code><host-apdu-service></code> must contain one or more <code><aid-group></code> tags. Each +<code><aid-group></code> tag is required to:</p> +<ul> +<li>Contain an <code>android:description</code> attribute that +contains a user-friendly description of the AID group, suitable for display in UI.</li> +<li>Have its <code>android:category</code> attribute set to +indicate the category the AID group belongs to, e.g. the string constants +defined by {@link android.nfc.cardemulation.CardEmulation#CATEGORY_PAYMENT} +or {@link android.nfc.cardemulation.CardEmulation#CATEGORY_OTHER}.</li> +<li>Each <code><aid-group></code> must contain one or more +<code><aid-filter></code> tags, each of which contains a single AID. The AID +must be specified in hexadecimal format, and contain an even number of characters.</li> +</ul> +<p>As a final note, your application also needs to hold the +{@link android.Manifest.permission#NFC} permission to be able to register as a HCE service.</p> <h2 id="AidConflicts">AID Conflict Resolution</h2> <p>Multiple {@link android.nfc.cardemulation.HostApduService} components - may be installed on a single device, and the same AID -can be registered by more than one service. The Android platform resolves AID -conflicts depending on which category an AID belongs to. Each category may have -a different conflict resolution policy. </p> - -<p>For example, for some categories (like payment) the user may be able to select a -default service in the Android settings UI. For other categories, the policy may -be to always ask the user which service is to be invoked in case of conflict. To -query the conflict resolution policy for a certain category, see +may be installed on a single device, and the same AID +can be registered by more than one service. The Android platform resolves AID +conflicts depending on which category an AID belongs to. Each category may have +a different conflict resolution policy.</p> + +<p>For example, for some categories (like payment) the user may be able to select a +default service in the Android settings UI. For other categories, the policy may +be to always ask the user which service is to be invoked in case of conflict. To +query the conflict resolution policy for a certain category, see {@link android.nfc.cardemulation.CardEmulation#getSelectionModeForCategory - getSelectionModeForCategory()}.</p> +getSelectionModeForCategory()}.</p> <h3 id="CheckingIfDefault">Checking if your service is the default</h3> -<p>Applications can check whether their HCE service is the default service for a -certain category by using the +<p>Applications can check whether their HCE service is the default service for a +certain category by using the {@link android.nfc.cardemulation.CardEmulation#isDefaultServiceForCategory} API.</p> -<p>If your service is not the default, you can request it to be made the default. +<p>If your service is not the default, you can request it to be made the default. See {@link android.nfc.cardemulation.CardEmulation#ACTION_CHANGE_DEFAULT}.</p> - - <h2 id="PaymentApps">Payment Applications</h2> -<p>Android considers HCE services that have declared an AID group with the -"payment" category as payment applications. The Android 4.4 release contains a -top-level Settings menu entry called "tap & pay", which enumerates all such -payment applications. In this settings menu, the user can select the default +<p>Android considers HCE services that have declared an AID group with the +"payment" category as payment applications. The Android 4.4 release contains a +top-level Settings menu entry called "tap & pay", which enumerates all such +payment applications. In this settings menu, the user can select the default payment application that will be invoked when a payment terminal is tapped.</p> <h3 id="RequiredAssets">Required assets for payment applications</h3> -<p>To provide a more visually attractive user experience, HCE payment applications -are required to provide an additional asset for their service: a so-called +<p>To provide a more visually attractive user experience, HCE payment applications +are required to provide an additional asset for their service: a so-called service banner.</p> -<p>This asset should be sized 260x96 dp, and can be specified in your meta-data XML -file by adding the <code>android:apduServiceBanner</code> attribute to the -<code><host-apdu-service></code> tag, which points to the drawable resource. An example is +<p>This asset should be sized 260x96 dp, and can be specified in your meta-data XML +file by adding the <code>android:apduServiceBanner</code> attribute to the +<code><host-apdu-service></code> tag, which points to the drawable resource. An example is shown below:</p> <pre> <host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android" - android:description="@string/servicedesc" + android:description="@string/servicedesc" android:requireDeviceUnlock="false" - android:apduServiceBanner="@drawable/my_banner"> + android:apduServiceBanner="@drawable/my_banner"> <aid-group android:description="@string/aiddescription" - android:category="payment"> - <aid-filter android:name="F0010203040506"/> - <aid-filter android:name="F0394148148100"/> - </aid-group> -</host-apdu-service> + android:category="payment"> + <aid-filter android:name="F0010203040506"/> + <aid-filter android:name="F0394148148100"/> + </aid-group> +</host-apdu-service> </pre> <h2 id="ScreenOffBehavior">Screen Off and Lock-screen Behavior</h2> -<p>Current Android implementations turn the NFC controller and the application -processor off completely when the screen of the device is turned off. HCE +<p>Current Android implementations turn the NFC controller and the application +processor off completely when the screen of the device is turned off. HCE services will therefore not work when the screen is off.</p> -<p>HCE services can function from the lock-screen however: this is controlled by -the <code>android:requireDeviceUnlock</code> attribute in the <code><host-apdu-service></code> tag of your -HCE service. By default, device unlock is not required, and your service will be +<p>HCE services can function from the lock-screen however: this is controlled by +the <code>android:requireDeviceUnlock</code> attribute in the <code><host-apdu-service></code> tag of your +HCE service. By default, device unlock is not required, and your service will be invoked even if the device is locked.</p> -<p>If you set the <code><android:requireDeviceUnlock</code> attribute to "true" for your HCE -service, Android will prompt the user to unlock the device when you tap an NFC -reader that selects an AID that is resolved to your service. After unlocking, -Android will show a dialog prompting the user to tap again to complete the -transaction. This is necessary because the user may have moved the device away +<p>If you set the <code>android:requireDeviceUnlock</code> attribute to "true" for your HCE +service, Android will prompt the user to unlock the device when you tap an NFC +reader that selects an AID that is resolved to your service. After unlocking, +Android will show a dialog prompting the user to tap again to complete the +transaction. This is necessary because the user may have moved the device away from the NFC reader in order to unlock it.</p> <h2 id="Coexistence">Coexistence with Secure Element Cards</h2> -<p>This section is of interest for developers that have deployed an application -that relies on a secure element for card emulation. Android's HCE implementation -is designed to work in parallel with other methods of implementing card +<p>This section is of interest for developers that have deployed an application +that relies on a secure element for card emulation. Android's HCE implementation +is designed to work in parallel with other methods of implementing card emulation, including the use of secure elements.</p> <p class="note"><strong>Note:</strong> Android does not offer APIs for directly communicating with a secure element itself.</p> -<p>This coexistence is based on a principle called "AID routing": the NFC -controller keeps a routing table that consists of a (finite) list of routing -rules. Each routing rule contains an AID and a destination. The destination can -either be the host CPU (where Android apps are running), or a connected secure +<p>This coexistence is based on a principle called "AID routing": the NFC +controller keeps a routing table that consists of a (finite) list of routing +rules. Each routing rule contains an AID and a destination. The destination can +either be the host CPU (where Android apps are running), or a connected secure element.</p> -<p>When the NFC reader sends an APDU with a "SELECT AID", the NFC controller parses -it and checks whether the AIDs matchesNo converter for: FOOTNOTE with any AID in -its routing table. If it matches, that APDU and all APDUs following it will be -sent to the destination associated with the AID, until another "SELECT AID" APDU -is received or the NFC link is broken.</p> +<p>When the NFC reader sends an APDU with a "SELECT AID", the NFC controller parses +it and checks whether the AIDs matches with any AID in its routing table. If it +matches, that APDU and all APDUs following it will be sent to the destination +associated with the AID, until another "SELECT AID" APDU is received or the NFC +link is broken.</p> <p class="note"><strong>Note:</strong> - While ISO/IEC 7816-4 defines the concept of “partial matches” as well, this is currently not supported by Android HCE devices.</p> - +While ISO/IEC 7816-4 defines the concept of “partial matches” as well, this is currently not supported by Android HCE devices.</p> + <p>This architecture is illustrated in figure 4.</p> @@ -445,46 +450,46 @@ is received or the NFC link is broken.</p> and host-card emulation.</p> -<p>The NFC controller typically also contains a default route for APDUs. When an -AID is not found in the routing table, the default route is used. Beginning with Android -4.4, the default route is required to be set to the host CPU. This -means that the routing table typically only contains entries for AIDs that need +<p>The NFC controller typically also contains a default route for APDUs. When an +AID is not found in the routing table, the default route is used. Beginning with Android +4.4, the default route is required to be set to the host CPU. This +means that the routing table typically only contains entries for AIDs that need to go to a secure element.</p> -<p>Android applications that implement a HCE service or that use a secure element -don't have to worry about configuring the routing table - that is taking care of -by Android automatically. Android merely needs to know which AIDs can be handled -by HCE services and which ones can be handled by the secure element. Based on -which services are installed and which the user has configured as preferred, the +<p>Android applications that implement a HCE service or that use a secure element +don't have to worry about configuring the routing table - that is taking care of +by Android automatically. Android merely needs to know which AIDs can be handled +by HCE services and which ones can be handled by the secure element. Based on +which services are installed and which the user has configured as preferred, the routing table is configured automatically.</p> -<p>We've already described how to declare AIDs for HCE services. The following -section explains how to declare AIDs for applications that use a secure element +<p>We've already described how to declare AIDs for HCE services. The following +section explains how to declare AIDs for applications that use a secure element for card emulation.</p> <h3 id="SecureElementReg">Secure element AID registration</h3> -<p>Applications using a secure element for card emulation can declare a so-called -"off host service" in their manifest. The declaration of such a service is +<p>Applications using a secure element for card emulation can declare a so-called +"off host service" in their manifest. The declaration of such a service is almost identical to the declaration of a HCE service. The exceptions are:</p> <ul> -<li>The action used in the intent-filter must be set to -{@link android.nfc.cardemulation.OffHostApduService#SERVICE_INTERFACE}</li> -<li>The meta-data name attribute must be set to -{@link android.nfc.cardemulation.OffHostApduService#SERVICE_META_DATA}</li> -<li><p>The meta-data XML file must use the <code><offhost-apdu-service></code> root tag</p> +<li>The action used in the intent-filter must be set to +{@link android.nfc.cardemulation.OffHostApduService#SERVICE_INTERFACE}.</li> +<li>The meta-data name attribute must be set to +{@link android.nfc.cardemulation.OffHostApduService#SERVICE_META_DATA}.</li> +<li><p>The meta-data XML file must use the <code><offhost-apdu-service></code> root tag.</p> <pre> <service android:name=".MyOffHostApduService" android:exported="true" - android:permission="android.permission.BIND_NFC_SERVICE"> - <intent-filter> - <action android:name="android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE"/> - </intent-filter> + android:permission="android.permission.BIND_NFC_SERVICE"> + <intent-filter> + <action android:name="android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE"/> + </intent-filter> <meta-data android:name="android.nfc.cardemulation.off_host_apdu_ervice" - android:resource="@xml/apduservice"/> -</service> + android:resource="@xml/apduservice"/> +</service> </pre> </li> </ul> @@ -493,126 +498,126 @@ almost identical to the declaration of a HCE service. The exceptions are:</p> <pre> <offhost-apdu-service xmlns:android="http://schemas.android.com/apk/res/android" - android:description="@string/servicedesc"> - <aid-group android:description="@string/subscription" android:category="other"> - <aid-filter android:name="F0010203040506"/> - <aid-filter android:name="F0394148148100"/> - </aid-group> -</offhost-apdu-service> + android:description="@string/servicedesc"> + <aid-group android:description="@string/subscription" android:category="other"> + <aid-filter android:name="F0010203040506"/> + <aid-filter android:name="F0394148148100"/> + </aid-group> +</offhost-apdu-service> </pre> -<p>The <code>android:requireDeviceUnlock</code> attribute does not apply to off host services, -because the host CPU is not involved in the transaction and therefore cannot -prevent the secure element from executing transactions when the device is +<p>The <code>android:requireDeviceUnlock</code> attribute does not apply to off host services, +because the host CPU is not involved in the transaction and therefore cannot +prevent the secure element from executing transactions when the device is locked.</p> -<p>The <code>android:apduServiceBanner</code> attribute must be used for off host services that -are payment applications as well in order to be selectable as a default payment +<p>The <code>android:apduServiceBanner</code> attribute must be used for off host services that +are payment applications as well in order to be selectable as a default payment application.</p> <h3 id="OffHostInvocation">Off host service invocation</h3> -<p>Android itself will never start or bind to a service that is declared as "off -host". This is because the actual transactions are executed by the secure -element and not by the Android service itself. The service declaration merely +<p>Android itself will never start or bind to a service that is declared as "off +host". This is because the actual transactions are executed by the secure +element and not by the Android service itself. The service declaration merely allows applications to register AIDs present on the secure element.</p> <h2 id="HceSecurity">HCE and Security</h2> -<p>The HCE architecture itself provides one core piece of security: because your +<p>The HCE architecture itself provides one core piece of security: because your service is protected by the {@link android.Manifest.permission#BIND_NFC_SERVICE} - system permission, only the OS can -bind to and communicate with your service. This ensures that any APDU you -receive is actually an APDU that was received by the OS from the NFC controller, -and that any APDU you send back will only go to the OS, which in turn directly + system permission, only the OS can +bind to and communicate with your service. This ensures that any APDU you +receive is actually an APDU that was received by the OS from the NFC controller, +and that any APDU you send back will only go to the OS, which in turn directly forwards the APDUs to the NFC controller.</p> -<p>The core remaining piece is where you get the data from that you're sending back -to the NFC reader. This is intentionally decoupled in the HCE design: it does -not care where the data comes from, it just makes sure that it is safely +<p>The core remaining piece is where you get your data that your app sends +to the NFC reader. This is intentionally decoupled in the HCE design: it does +not care where the data comes from, it just makes sure that it is safely transported to the NFC controller and out to the NFC reader.</p> -<p>For securely storing and retrieving the data that you want to send from your HCE -service, you can for example rely on the Android Application Sandbox, which -isolates your app's data from other apps. For more details on Android security, -read -<a href="{@docRoot}training/articles/security-tips.html">Security Tips</a> +<p>For securely storing and retrieving the data that you want to send from your HCE +service, you can, for example, rely on the Android Application Sandbox, which +isolates your app's data from other apps. For more details on Android security, +read +<a href="{@docRoot}training/articles/security-tips.html">Security Tips</a> .</p> <h2 id="ProtocolParams">Protocol parameters and details</h2> -<p>This section is of interest for developers that want to understand what protocol -parameters HCE devices use during the anti-collision and activations phases of -the NFC protocols. This allows them to build a reader infrastructure that is +<p>This section is of interest for developers that want to understand what protocol +parameters HCE devices use during the anti-collision and activation phases of +the NFC protocols. This allows building a reader infrastructure that is compatible with Android HCE devices.</p> <h3 id="AntiCollisionAct">Nfc-A (ISO/IEC 14443 type A) protocol anti-collision and activation</h3> <p>As part of the Nfc-A protocol activation, multiple frames are exchanged.</p> -<p>In the first part of the exchange the HCE device will present its UID; HCE -devices should be assumed to have a random UID. This means that on every tap, -the UID that is presented to the reader will be a randomly generated UID. -Because of this, NFC readers should not depend on the UID of HCE devices as a +<p>In the first part of the exchange the HCE device will present its UID; HCE +devices should be assumed to have a random UID. This means that on every tap, +the UID that is presented to the reader will be a randomly generated UID. +Because of this, NFC readers should not depend on the UID of HCE devices as a form of authentication or identification.</p> -<p>The NFC reader can subsequently select the HCE device by sending a SEL_REQ -command. The SEL_RES response of the HCE device will at least have the 6th bit -(0x20) set, indicating that the device supports ISO-DEP. Note that other bits in -the SEL_RES may be set as well, indicating for example support for the NFC-DEP -(p2p) protocol. Since other bits may be set, readers wanting to interact with -HCE devices should explicitly check for the 6th bit only, and <stront>not</strong> compare the +<p>The NFC reader can subsequently select the HCE device by sending a SEL_REQ +command. The SEL_RES response of the HCE device will at least have the 6th bit +(0x20) set, indicating that the device supports ISO-DEP. Note that other bits in +the SEL_RES may be set as well, indicating for example support for the NFC-DEP +(p2p) protocol. Since other bits may be set, readers wanting to interact with +HCE devices should explicitly check for the 6th bit only, and <stront>not</strong> compare the complete SEL_RES with a value of 0x20.</p> <h3 id="IsoDepAct">ISO-DEP activation</h3> -<p>After the Nfc-A protocol is activated, the ISO-DEP protocol activation is -initiated by the NFC reader. It sends a "RATS" (Request for Answer To Select) -command. The RATS response, the ATS, is completely generated by the NFC -controller and not configurable by HCE services. However, HCE implementations -are required to meet NFC Forum requirements for the ATS response, so NFC readers -can count on these parameters being set in accordance with NFC Forum +<p>After the Nfc-A protocol is activated, the ISO-DEP protocol activation is +initiated by the NFC reader. It sends a "RATS" (Request for Answer To Select) +command. The RATS response, the ATS, is completely generated by the NFC +controller and not configurable by HCE services. However, HCE implementations +are required to meet NFC Forum requirements for the ATS response, so NFC readers +can count on these parameters being set in accordance with NFC Forum requirements for any HCE device.</p> -<p>The section below provides more details on the individual bytes of the ATS +<p>The section below provides more details on the individual bytes of the ATS response provided by the NFC controller on a HCE device:</p> <ul> -<li>TL: length of the ATS response. Must not indicate a length greater than 20 +<li>TL: length of the ATS response. Must not indicate a length greater than 20 bytes.</li> -<li>T0: bits 5, 6 and 7 must be set on all HCE devices, indicating TA(1), TB(1) -and TC(1) are included in the ATS response. Bits 1 to 4 indicate the FSCI, -coding the maximum frame size. On HCE devices the value of FSCI must be +<li>T0: bits 5, 6 and 7 must be set on all HCE devices, indicating TA(1), TB(1) +and TC(1) are included in the ATS response. Bits 1 to 4 indicate the FSCI, +coding the maximum frame size. On HCE devices the value of FSCI must be between 0h and 8h.</li> -<li>T(A)1: defines bitrates between reader and emulator, and whether they can be +<li>T(A)1: defines bitrates between reader and emulator, and whether they can be asymmetric. There are no bitrate requirements or guarantees for HCE devices.</li> -<li>T(B)1: bits 1 to 4 indicate the Start-up Frame Guard time Integer (SFGI). On -HCE devices, SFGI must be <= 8h. Bits 5 to 8 indicate the Frame Waiting time -Integer (FWI) and codes the Frame Waiting Time (FWT). On HCE devices, FWI must +<li>T(B)1: bits 1 to 4 indicate the Start-up Frame Guard time Integer (SFGI). On +HCE devices, SFGI must be <= 8h. Bits 5 to 8 indicate the Frame Waiting time +Integer (FWI) and codes the Frame Waiting Time (FWT). On HCE devices, FWI must be <= 8h.</li> -<li>T(C)1: bit 5 indicates support for "Advanced Protocol features". HCE devices -may or may not support "Advanced Protocol features". Bit 2 indicates support -for DID. HCE devices may or may not support DID. Bit 1 indicates support for +<li>T(C)1: bit 5 indicates support for "Advanced Protocol features". HCE devices +may or may not support "Advanced Protocol features". Bit 2 indicates support +for DID. HCE devices may or may not support DID. Bit 1 indicates support for NAD. HCE devices must not support NAD and set bit 1 to zero.</li> -<li>Historical bytes: HCE devices may return up to 15 historical bytes. NFC -readers willing to interact with HCE services should make no assumptions about +<li>Historical bytes: HCE devices may return up to 15 historical bytes. NFC +readers willing to interact with HCE services should make no assumptions about the contents of the historical bytes or their presence.</li> </ul> -<p>Note that many HCE devices are likely made compliant with protocol requirements -that the payment networks united in EMVCo have specified in their "Contactless +<p>Note that many HCE devices are likely made compliant with protocol requirements +that the payment networks united in EMVCo have specified in their "Contactless Communication Protocol" specification. In particular:</p> <ul> <li>FSCI in T0 must be between 2h and 8h.</li> -<li>T(A)1 must be set to 0x80, indicating only the 106 kbit/s bitrate is -supported, and asymmetric bitrates between reader and emulator are not +<li>T(A)1 must be set to 0x80, indicating only the 106 kbit/s bitrate is +supported, and asymmetric bitrates between reader and emulator are not supported.</li> <li>FWI in T(B)1 must be <= 7h.</li> </ul> <h3 id="ApduExchange">APDU data exchange</h3> -<p>As noted earlier, HCE implementations only support a single logical channel. -Attempting to select applications on different logical channels will not work on +<p>As noted earlier, HCE implementations only support a single logical channel. +Attempting to select applications on different logical channels will not work on a HCE device.</p> diff --git a/docs/html/guide/topics/data/data-storage.jd b/docs/html/guide/topics/data/data-storage.jd index 385c116..4b8a647 100644 --- a/docs/html/guide/topics/data/data-storage.jd +++ b/docs/html/guide/topics/data/data-storage.jd @@ -233,138 +233,197 @@ save files. This can be a removable storage media (such as an SD card) or an int (non-removable) storage. Files saved to the external storage are world-readable and can be modified by the user when they enable USB mass storage to transfer files on a computer.</p> -<p>It's possible that a device using a partition of the -internal storage for the external storage may also offer an SD card slot. In this case, -the SD card is <em>not</em> part of the external storage and your app cannot access it (the extra -storage is intended only for user-provided media that the system scans).</p> - <p class="caution"><strong>Caution:</strong> External storage can become unavailable if the user mounts the external storage on a computer or removes the media, and there's no security enforced upon files you save to the external storage. All applications can read and write files placed on the external storage and the user can remove them.</p> +<h3 id="ExternalPermissions">Getting access to external storage</h3> + +<p>In order to read or write files on the external storage, your app must acquire the +{@link android.Manifest.permission#READ_EXTERNAL_STORAGE} +or {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} system +permissions. For example:</p> +<pre> +<manifest ...> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + ... +</manifest> +</pre> + +<p>If you need to both read and write files, then you need to request only the +{@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission, because it +implicitly requires read access as well.</p> + +<p class="note"><strong>Note:</strong> Beginning with Android 4.4, these permissions are not +required if you're reading or writing only files that are private to your app. For more +information, see the section below about +<a href="#AccessingExtFiles">saving files that are app-private</a>.</p> + + <h3 id="MediaAvail">Checking media availability</h3> <p>Before you do any work with the external storage, you should always call {@link android.os.Environment#getExternalStorageState()} to check whether the media is available. The media might be mounted to a computer, missing, read-only, or in some other state. For example, -here's how you can check the availability:</p> +here are a couple methods you can use to check the availability:</p> <pre> -boolean mExternalStorageAvailable = false; -boolean mExternalStorageWriteable = false; -String state = Environment.getExternalStorageState(); - -if (Environment.MEDIA_MOUNTED.equals(state)) { - // We can read and write the media - mExternalStorageAvailable = mExternalStorageWriteable = true; -} else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { - // We can only read the media - mExternalStorageAvailable = true; - mExternalStorageWriteable = false; -} else { - // Something else is wrong. It may be one of many other states, but all we need - // to know is we can neither read nor write - mExternalStorageAvailable = mExternalStorageWriteable = false; +/* Checks if external storage is available for read and write */ +public boolean isExternalStorageWritable() { + String state = Environment.getExternalStorageState(); + if (Environment.MEDIA_MOUNTED.equals(state)) { + return true; + } + return false; +} + +/* Checks if external storage is available to at least read */ +public boolean isExternalStorageReadable() { + String state = Environment.getExternalStorageState(); + if (Environment.MEDIA_MOUNTED.equals(state) || + Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { + return true; + } + return false; } </pre> -<p>This example checks whether the external storage is available to read and write. The -{@link android.os.Environment#getExternalStorageState()} method returns other states that you +<p>The {@link android.os.Environment#getExternalStorageState()} method returns other states that you might want to check, such as whether the media is being shared (connected to a computer), is missing entirely, has been removed badly, etc. You can use these to notify the user with more information when your application needs to access the media.</p> -<h3 id="AccessingExtFiles">Accessing files on external storage</h3> - -<p>If you're using API Level 8 or greater, use {@link -android.content.Context#getExternalFilesDir(String) getExternalFilesDir()} to open a {@link -java.io.File} that represents the external storage directory where you should save your -files. This method takes a <code>type</code> parameter that specifies the type of subdirectory you -want, such as {@link android.os.Environment#DIRECTORY_MUSIC} and -{@link android.os.Environment#DIRECTORY_RINGTONES} (pass <code>null</code> to receive -the root of your application's file directory). This method will create the -appropriate directory if necessary. By specifying the type of directory, you -ensure that the Android's media scanner will properly categorize your files in the system (for -example, ringtones are identified as ringtones and not music). If the user uninstalls your -application, this directory and all its contents will be deleted.</p> - -<p>If you're using API Level 7 or lower, use {@link -android.os.Environment#getExternalStorageDirectory()}, to open a {@link -java.io.File} representing the root of the external storage. You should then write your data in the -following directory:</p> -<pre class="no-pretty-print classic"> -/Android/data/<em><package_name></em>/files/ -</pre> -<p>The {@code <em><package_name></em>} is your Java-style package name, such as "{@code -com.example.android.app}". If the user's device is running API Level 8 or greater and they -uninstall your application, this directory and all its contents will be deleted.</p> +<h3 id="SavingSharedFiles">Saving files that can be shared with other apps</h3> - -<div class="sidebox-wrapper" style="margin-top:3em"> +<div class="sidebox-wrapper" > <div class="sidebox"> <h4>Hiding your files from the Media Scanner</h4> <p>Include an empty file named {@code .nomedia} in your external files directory (note the dot -prefix in the filename). This will prevent Android's media scanner from reading your media -files and including them in apps like Gallery or Music.</p> +prefix in the filename). This prevents media scanner from reading your media +files and providing them to other apps through the {@link android.provider.MediaStore} +content provider. However, if your files are truly private to your app, you should +<a href="#AccessingExtFiles">save them in an app-private directory</a>.</p> </div> </div> +<p>Generally, new files that the user may acquire through your app should be saved to a "public" +location on the device where other apps can access them and the user can easily copy them from the +device. When doing so, you should use to one of the shared public directories, such as {@code +Music/}, {@code Pictures/}, and {@code Ringtones/}.</p> -<h3 id="SavingSharedFiles">Saving files that should be shared</h3> - -<p>If you want to save files that are not specific to your application and that should <em>not</em> -be deleted when your application is uninstalled, save them to one of the public directories on the -external storage. These directories lay at the root of the external storage, such as {@code -Music/}, {@code Pictures/}, {@code Ringtones/}, and others.</p> - -<p>In API Level 8 or greater, use {@link +<p>To get a {@link java.io.File} representing the appropriate public directory, call {@link android.os.Environment#getExternalStoragePublicDirectory(String) -getExternalStoragePublicDirectory()}, passing it the type of public directory you want, such as +getExternalStoragePublicDirectory()}, passing it the type of directory you want, such as {@link android.os.Environment#DIRECTORY_MUSIC}, {@link android.os.Environment#DIRECTORY_PICTURES}, -{@link android.os.Environment#DIRECTORY_RINGTONES}, or others. This method will create the -appropriate directory if necessary.</p> - -<p>If you're using API Level 7 or lower, use {@link -android.os.Environment#getExternalStorageDirectory()} to open a {@link java.io.File} that represents -the root of the external storage, then save your shared files in one of the following -directories:</p> - -<ul class="nolist"></li> - <li><code>Music/</code> - Media scanner classifies all media found here as user music.</li> - <li><code>Podcasts/</code> - Media scanner classifies all media found here as a podcast.</li> - <li><code>Ringtones/ </code> - Media scanner classifies all media found here as a ringtone.</li> - <li><code>Alarms/</code> - Media scanner classifies all media found here as an alarm sound.</li> - <li><code>Notifications/</code> - Media scanner classifies all media found here as a notification -sound.</li> - <li><code>Pictures/</code> - All photos (excluding those taken with the camera).</li> - <li><code>Movies/</code> - All movies (excluding those taken with the camcorder).</li> - <li><code>Download/</code> - Miscellaneous downloads.</li> -</ul> +{@link android.os.Environment#DIRECTORY_RINGTONES}, or others. By saving your files to the +corresponding media-type directory, +the system's media scanner can properly categorize your files in the system (for +instance, ringtones appear in system settings as ringtones, not as music).</p> -<h3 id="ExternalCache">Saving cache files</h3> +<p>For example, here's a method that creates a directory for a new photo album in +the public pictures directory:</p> -<p>If you're using API Level 8 or greater, use {@link -android.content.Context#getExternalCacheDir()} to open a {@link java.io.File} that represents the -external storage directory where you should save cache files. If the user uninstalls your -application, these files will be automatically deleted. However, during the life of your -application, you should manage these cache files and remove those that aren't needed in order to -preserve file space.</p> - -<p>If you're using API Level 7 or lower, use {@link -android.os.Environment#getExternalStorageDirectory()} to open a {@link java.io.File} that represents -the root of the external storage, then write your cache data in the following directory:</p> -<pre class="no-pretty-print classic"> -/Android/data/<em><package_name></em>/cache/ +<pre> +public File getAlbumStorageDir(String albumName) { + // Get the directory for the user's public pictures directory. + File file = new File(Environment.getExternalStoragePublicDirectory( + Environment.DIRECTORY_PICTURES), albumName); + if (!file.mkdirs()) { + Log.e(LOG_TAG, "Directory not created"); + } + return file; +} +</pre> + + + +<h3 id="AccessingExtFiles">Saving files that are app-private</h3> + +<p>If you are handling files that are not intended for other apps to use +(such as graphic textures or sound effects used by only your app), you should use +a private storage directory on the external storage by calling {@link +android.content.Context#getExternalFilesDir(String) getExternalFilesDir()}. +This method also takes a <code>type</code> argument to specify the type of subdirectory +(such as {@link android.os.Environment#DIRECTORY_MOVIES}). If you don't need a specific +media directory, pass <code>null</code> to receive +the root directory of your app's private directory.</p> + +<p>Beginning with Android 4.4, reading or writing files in your app's private +directories does not require the {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} +or {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} +permissions. So you can declare the permission should be requested only on the lower versions +of Android by adding the <a +href="{@docRoot}guide/topics/manifest/uses-permission-element.html#maxSdk">{@code maxSdkVersion}</a> +attribute:</p> +<pre> +<manifest ...> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" + android:maxSdkVersion="18" /> + ... +</manifest> </pre> -<p>The {@code <em><package_name></em>} is your Java-style package name, such as "{@code -com.example.android.app}".</p> + +<p class="note"><strong>Note:</strong> +When the user uninstalls your application, this directory and all its contents are deleted. +Also, the system media scanner does not read files in these directories, so they are not accessible +from the {@link android.provider.MediaStore} content provider. As such, you <b>should not +use these directories</b> for media that ultimately belongs to the user, such as photos +captured or edited with your app, or music the user has purchased with your app—those +files should be <a href="#SavingSharedFiles">saved in the public directories</a>.</p> + +<p>Sometimes, a device that has allocated a partition of the +internal memory for use as the external storage may also offer an SD card slot. +When such a device is running Android 4.3 and lower, the {@link +android.content.Context#getExternalFilesDir(String) getExternalFilesDir()} method provides +access to only the internal partition and your app cannot read or write to the SD card. +Beginning with Android 4.4, however, you can access both locations by calling +{@link android.content.Context#getExternalFilesDirs getExternalFilesDirs()}, +which returns a {@link +java.io.File} array with entries each location. The first entry in the array is considered +the primary external storage and you should use that location unless it's full or +unavailable. If you'd like to access both possible locations while also supporting Android +4.3 and lower, use the <a href="{@docRoot}tools/support-library/index.html">support library's</a> +static method, {@link android.support.v4.content.ContextCompat#getExternalFilesDirs +ContextCompat.getExternalFilesDirs()}. This also returns a {@link +java.io.File} array, but always includes only one entry on Android 4.3 and lower.</p> + +<p class="caution"><strong>Caution</strong> Although the directories provided by {@link +android.content.Context#getExternalFilesDir(String) getExternalFilesDir()} and {@link +android.content.Context#getExternalFilesDirs getExternalFilesDirs()} are not accessible by the +{@link android.provider.MediaStore} content provider, other apps with the {@link +android.Manifest.permission#READ_EXTERNAL_STORAGE} permission can access all files on the external +storage, including these. If you need to completely restrict access for your files, you should +instead write your files to the <a href="#filesInternal">internal storage</a>.</p> + + + + + +<h3 id="ExternalCache">Saving cache files</h3> + +<p>To open a {@link java.io.File} that represents the +external storage directory where you should save cache files, call {@link +android.content.Context#getExternalCacheDir()}. If the user uninstalls your +application, these files will be automatically deleted.</p> + +<p>Similar to {@link android.support.v4.content.ContextCompat#getExternalFilesDirs +ContextCompat.getExternalFilesDirs()}, mentioned above, you can also access a cache directory on +a secondary external storage (if available) by calling +{@link android.support.v4.content.ContextCompat#getExternalCacheDirs +ContextCompat.getExternalCacheDirs()}.</p> + +<p class="note"><strong>Tip:</strong> +To preserve file space and maintain your app's performance, +it's important that you carefully manage your cache files and remove those that aren't +needed anymore throughout your app's lifecycle.</p> + diff --git a/docs/html/guide/topics/manifest/action-element.jd b/docs/html/guide/topics/manifest/action-element.jd index 037d0dc..54ee6ae 100644 --- a/docs/html/guide/topics/manifest/action-element.jd +++ b/docs/html/guide/topics/manifest/action-element.jd @@ -12,7 +12,7 @@ parent.link=manifest-intro.html <p> <dt>description:</dt> -<dd>Adds an action to an intent filter. +<dd itemprop="description">Adds an action to an intent filter. An <code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html"><intent-filter></a></code> element must contain one or more {@code <action>} elements. If it doesn't contain any, no Intent objects will get through the filter. See diff --git a/docs/html/guide/topics/manifest/activity-alias-element.jd b/docs/html/guide/topics/manifest/activity-alias-element.jd index d3df08b..343b02e 100644 --- a/docs/html/guide/topics/manifest/activity-alias-element.jd +++ b/docs/html/guide/topics/manifest/activity-alias-element.jd @@ -23,7 +23,7 @@ parent.link=manifest-intro.html <br/><code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html"><meta-data></a></code></dd> <dt>description:</dt> -<dd>An alias for an activity, named by the {@code targetActivity} +<dd itemprop="description">An alias for an activity, named by the {@code targetActivity} attribute. The target must be in the same application as the alias and it must be declared before the alias in the manifest. diff --git a/docs/html/guide/topics/manifest/activity-element.jd b/docs/html/guide/topics/manifest/activity-element.jd index 8df1fdf..bd1edc2 100644 --- a/docs/html/guide/topics/manifest/activity-element.jd +++ b/docs/html/guide/topics/manifest/activity-element.jd @@ -54,7 +54,7 @@ parent.link=manifest-intro.html <br/><code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html"><meta-data></a></code></dd> <dt>description:</dt> -<dd>Declares an activity (an {@link android.app.Activity} subclass) that +<dd itemprop="description">Declares an activity (an {@link android.app.Activity} subclass) that implements part of the application's visual user interface. All activities must be represented by {@code <activity>} elements in the manifest file. Any that are not declared there will not be seen diff --git a/docs/html/guide/topics/manifest/application-element.jd b/docs/html/guide/topics/manifest/application-element.jd index 6bfa3dc..28deed9 100644 --- a/docs/html/guide/topics/manifest/application-element.jd +++ b/docs/html/guide/topics/manifest/application-element.jd @@ -40,13 +40,14 @@ page.title=<application> <dt>can contain:</dt> <dd><code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code> <br/><code><a href="{@docRoot}guide/topics/manifest/activity-alias-element.html"><activity-alias></a></code> +<br/><code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html"><meta-data></a></code> <br/><code><a href="{@docRoot}guide/topics/manifest/service-element.html"><service></a></code> <br/><code><a href="{@docRoot}guide/topics/manifest/receiver-element.html"><receiver></a></code> <br/><code><a href="{@docRoot}guide/topics/manifest/provider-element.html"><provider></a></code> <br/><code><a href="{@docRoot}guide/topics/manifest/uses-library-element.html"><uses-library></a></code></dd> <dt>description:</dt> -<dd>The declaration of the application. This element contains subelements +<dd itemprop="description">The declaration of the application. This element contains subelements that declare each of the application's components and has attributes that can affect all the components. Many of these attributes (such as {@code icon}, {@code label}, {@code permission}, {@code process}, diff --git a/docs/html/guide/topics/manifest/category-element.jd b/docs/html/guide/topics/manifest/category-element.jd index 41a2cfd..563ed10 100644 --- a/docs/html/guide/topics/manifest/category-element.jd +++ b/docs/html/guide/topics/manifest/category-element.jd @@ -11,7 +11,7 @@ parent.link=manifest-intro.html <dd><code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html"><intent-filter></a></code></dd> <dt>description:</dt> -<dd>Adds a category name to an intent filter. See +<dd itemprop="description">Adds a category name to an intent filter. See <a href="{@docRoot}guide/components/intents-filters.html">Intents and Intent Filters</a> for details on intent filters and the role of category specifications within a filter.</dd> @@ -27,6 +27,14 @@ by prefixing "{@code android.intent.category.}" to the the string value for {@code CATEGORY_LAUNCHER} is "{@code android.intent.category.LAUNCHER}". +<p class="note"><strong>Note:</strong> In order to receive implicit intents, you must include the +{@link android.content.Intent#CATEGORY_DEFAULT} category in the intent filter. The methods +{@link android.app.Activity#startActivity startActivity()} and +{@link android.app.Activity#startActivityForResult startActivityForResult()} treat all intents +as if they declared the {@link android.content.Intent#CATEGORY_DEFAULT} category. +If you do not declare it in your intent filter, no implicit intents will resolve to +your activity.</p> + <p> Custom categories should use the package name as a prefix, to ensure that they are unique. diff --git a/docs/html/guide/topics/manifest/compatible-screens-element.jd b/docs/html/guide/topics/manifest/compatible-screens-element.jd index 00cbfe5..3606b15 100644 --- a/docs/html/guide/topics/manifest/compatible-screens-element.jd +++ b/docs/html/guide/topics/manifest/compatible-screens-element.jd @@ -20,7 +20,7 @@ parent.link=manifest-intro.html href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code></dd> <dt>description:</dt> -<dd>Specifies each screen configuration with which the application is compatible. Only one instance +<dd itemprop="description">Specifies each screen configuration with which the application is compatible. Only one instance of the {@code <compatible-screens>} element is allowed in the manifest, but it can contain multiple <code><screen></code> elements. Each <code><screen></code> element specifies a specific screen size-density combination with which the application is compatible. diff --git a/docs/html/guide/topics/manifest/data-element.jd b/docs/html/guide/topics/manifest/data-element.jd index 766d2d7..ecba508 100644 --- a/docs/html/guide/topics/manifest/data-element.jd +++ b/docs/html/guide/topics/manifest/data-element.jd @@ -5,34 +5,35 @@ parent.link=manifest-intro.html <dl class="xml"> <dt>syntax:</dt> -<dd><pre class="stx"><data android:<a href="#host">host</a>="<i>string</i>" - android:<a href="#mime">mimeType</a>="<i>string</i>" +<dd><pre class="stx"><data android:<a href="#scheme">scheme</a>="<i>string</i>" + android:<a href="#host">host</a>="<i>string</i>" + android:<a href="#port">port</a>="<i>string</i>" android:<a href="#path">path</a>="<i>string</i>" android:<a href="#path">pathPattern</a>="<i>string</i>" android:<a href="#path">pathPrefix</a>="<i>string</i>" - android:<a href="#port">port</a>="<i>string</i>" - android:<a href="#scheme">scheme</a>="<i>string</i>" /></pre></dd> + android:<a href="#mime">mimeType</a>="<i>string</i>" /></pre></dd> <dt>contained in:</dt> <dd><code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html"><intent-filter></a></code></dd> <dt>description:</dt> -<dd>Adds a data specification to an intent filter. The specification can -be just a data type (the <code><a href="{@docRoot}guide/topics/manifest/data-element.html#mime">mimeType</a></code> attribute), -just a URI, or both a data type and a URI. A URI is specified by separate +<dd itemprop="description">Adds a data specification to an intent filter. The specification can +be just a data type (the <code><a href="{@docRoot}guide/topics/manifest/data-element.html#mime">mimeType</a></code> attribute), +just a URI, or both a data type and a URI. A URI is specified by separate attributes for each of its parts: -<p style="margin-left: 2em">{@code scheme://host:port/path} <i>or</i> -{@code pathPrefix} <i>or</i> {@code pathPattern}</p> +<p style="margin-left: 2em"> +{@code <scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]}</p> <p> -These attributes are optional, but also mutually dependent: -If a <code><a href="{@docRoot}guide/topics/manifest/data-element.html#scheme">scheme</a></code> is not specified for the -intent filter, all the other URI attributes are ignored. If a -<code><a href="{@docRoot}guide/topics/manifest/data-element.html#host">host</a></code> is not specified for the filter, -the {@code port} attribute and all the path attributes are ignored. -</p> +These attributes that specify the URL format are optional, but also mutually dependent: +<ul> + <li>If a <code><a href="{@docRoot}guide/topics/manifest/data-element.html#scheme">scheme</a></code> +is not specified for the intent filter, all the other URI attributes are ignored.</li> + <li>If a <code><a href="{@docRoot}guide/topics/manifest/data-element.html#host">host</a></code> +is not specified for the filter, the {@code port} attribute and all the path attributes are ignored. +</ul> <p> All the {@code <data>} elements contained within the same @@ -54,111 +55,117 @@ the same filter. So, for example, the following filter specification, </intent-filter></pre> <p> -You can place any number of <data> elements inside an -<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html"><intent-filter></a></code> to give it multiple data -options. None of its attributes have default values. +You can place any number of {@code <data>} elements inside an +<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html"><intent-filter></a></code> to give it multiple data +options. None of its attributes have default values. </p> <p> Information on how intent filters work, including the rules for how Intent objects are matched against filters, can be found in another document, <a href="{@docRoot}guide/components/intents-filters.html">Intents and -Intent Filters</a>. See also the -<a href="{@docRoot}guide/topics/manifest/manifest-intro.html#ifs">Intent Filters</a> -section in the introduction. +Intent Filters</a>. See also the +<a href="{@docRoot}guide/topics/manifest/manifest-intro.html#ifs">Intent Filters</a> +section in the manifest file overview. </p></dd> <dt>attributes:</dt> <dd><dl class="attr"> + +<dt><a name="scheme"></a>{@code android:scheme}</dt> +<dd>The scheme part of a URI. This is the minimal essential attribute for +specifying a URI; at least one {@code scheme} attribute must be set +for the filter, or none of the other URI attributes are meaningful. + +<p> +A scheme is specified without the trailing colon (for example, +{@code http}, rather than {@code http:}). +</p> + +<p> +If the filter has a data type set (the <code><a +href="{@docRoot}guide/topics/manifest/data-element.html#mime">mimeType</a></code> +attribute) but no scheme, the {@code content:} and {@code file:} schemes are +assumed. +</p> + +<p class="note"><strong>Note</strong>: Scheme matching in the Android framework is +case-sensitive, unlike the RFC. As a result, you should always specify schemes +using lowercase letters.</p> +</dd> + <dt><a name="host"></a>{@code android:host}</dt> <dd>The host part of a URI authority. This attribute is meaningless -unless a <code><a href="{@docRoot}guide/topics/manifest/data-element.html#scheme">scheme</a></code> attribute is also +unless a <code><a href="{@docRoot}guide/topics/manifest/data-element.html#scheme">scheme</a></code> attribute is also specified for the filter. -<p class="note">Note: host name matching in the Android framework is +<p class="note"><strong>Note</strong>: host name matching in the Android framework is case-sensitive, unlike the formal RFC. As a result, you should always specify host names using lowercase letters.</p> </dd> -<dt><a name="mime"></a>{@code android:mimeType}</dt> -<dd>A MIME media type, such as {@code image/jpeg} or {@code audio/mpeg4-generic}. -The subtype can be the asterisk wildcard ({@code *}) to indicate that any -subtype matches. -<p>It's common for an intent filter to declare a {@code <data>} that includes -only the {@code android:mimeType} attribute.</p> +<dt><a name="port"></a>{@code android:port}</dt> +<dd>The port part of a URI authority. This attribute is meaningful only +if the <code><a href="#scheme">scheme</a></code> and +<code><a href="#host">host</a></code> attributes are also specified for +the filter.</dd> -<p class="note">Note: MIME type matching in the Android framework is -case-sensitive, unlike formal RFC MIME types. As a result, you should always -specify MIME types using lowercase letters.</p> -</dd> <dt><a name="path"></a>{@code android:path} <br/>{@code android:pathPrefix} <br/>{@code android:pathPattern}</dt> -<dd>The path part of a URI. The {@code path} attribute specifies a complete -path that is matched against the complete path in an Intent object. The -{@code pathPrefix} attribute specifies a partial path that is matched against -only the initial part of the path in the Intent object. The {@code pathPattern} -attribute specifies a complete path that is matched against the complete path -in the Intent object, but it can contain the following wildcards: +<dd>The path part of a URI. The {@code path} attribute specifies a complete +path that is matched against the complete path in an Intent object. The +{@code pathPrefix} attribute specifies a partial path that is matched against +only the initial part of the path in the Intent object. The {@code pathPattern} +attribute specifies a complete path that is matched against the complete path +in the Intent object, but it can contain the following wildcards: <ul> <li>An asterisk ('{@code *}') matches a sequence of 0 to many occurrences of the immediately preceding character.</li> -<li>A period followed by an asterisk ("{@code .*}") matches any sequence of +<li>A period followed by an asterisk ("{@code .*}") matches any sequence of 0 to many characters.</li> </ul> <p> -Because '{@code \}' is used as an escape character when the string is read -from XML (before it is parsed as a pattern), you will need to double-escape: -For example, a literal '{@code *}' would be written as "{@code \\*}" and a -literal '{@code \}' would be written as "{@code \\\\}". This is basically +Because '{@code \}' is used as an escape character when the string is read +from XML (before it is parsed as a pattern), you will need to double-escape: +For example, a literal '{@code *}' would be written as "{@code \\*}" and a +literal '{@code \}' would be written as "{@code \\\\}". This is basically the same as what you would need to write if constructing the string in Java code. </p> <p> -For more information on these three types of patterns, see the descriptions of +For more information on these three types of patterns, see the descriptions of {@link android.os.PatternMatcher#PATTERN_LITERAL}, {@link android.os.PatternMatcher#PATTERN_PREFIX}, and {@link android.os.PatternMatcher#PATTERN_SIMPLE_GLOB} in the {@link android.os.PatternMatcher} class. </p> -<p>These attributes are meaningful only if the -<code><a href="#scheme">scheme</a></code> and <code><a href="#host">host</a></code> +<p>These attributes are meaningful only if the +<code><a href="#scheme">scheme</a></code> and <code><a href="#host">host</a></code> attributes are also specified for the filter. </p></dd> -<dt><a name="port"></a>{@code android:port}</dt> -<dd>The port part of a URI authority. This attribute is meaningful only -if the <code><a href="#scheme">scheme</a></code> and -<code><a href="#host">host</a></code> attributes are also specified for -the filter.</dd> - -<dt><a name="scheme"></a>{@code android:scheme}</dt> -<dd>The scheme part of a URI. This is the minimal essential attribute for -specifying a URI; at least one {@code scheme} attribute must be set -for the filter, or none of the other URI attributes are meaningful. +<dt><a name="mime"></a>{@code android:mimeType}</dt> +<dd>A MIME media type, such as {@code image/jpeg} or {@code audio/mpeg4-generic}. +The subtype can be the asterisk wildcard ({@code *}) to indicate that any +subtype matches. -<p> -A scheme is specified without the trailing colon (for example, -{@code http}, rather than {@code http:}). -</p> +<p>It's common for an intent filter to declare a {@code <data>} that includes +only the {@code android:mimeType} attribute.</p> -<p> -If the filter has a data type set (the <code><a href="{@docRoot}guide/topics/manifest/data-element.html#mime">mimeType</a></code> -attribute) but no scheme, the {@code content:} and {@code file:} schemes are -assumed. -</p> -<p class="note">Note: scheme matching in the Android framework is -case-sensitive, unlike the RFC. As a result, you should always specify schemes -using lowercase letters.</p> +<p class="note"><strong>Note</strong>: MIME type matching in the Android framework is +case-sensitive, unlike formal RFC MIME types. As a result, you should always +specify MIME types using lowercase letters.</p> </dd> -</dl></dd> + +</dl></dd> <!-- ##api level indication## --> <dt>introduced in:</dt> diff --git a/docs/html/guide/topics/manifest/grant-uri-permission-element.jd b/docs/html/guide/topics/manifest/grant-uri-permission-element.jd index dc98cbb..2179359 100644 --- a/docs/html/guide/topics/manifest/grant-uri-permission-element.jd +++ b/docs/html/guide/topics/manifest/grant-uri-permission-element.jd @@ -13,7 +13,7 @@ parent.link=manifest-intro.html <dd><code><a href="{@docRoot}guide/topics/manifest/provider-element.html"><provider></a></code></dd> <dt>description:</dt> -<dd>Specifies which data subsets of the parent content provider permission +<dd itemprop="description">Specifies which data subsets of the parent content provider permission can be granted for. Data subsets are indicated by the path part of a {@code content:} URI. (The authority part of the URI identifies the content provider.) diff --git a/docs/html/guide/topics/manifest/instrumentation-element.jd b/docs/html/guide/topics/manifest/instrumentation-element.jd index 9408b84..74be559 100644 --- a/docs/html/guide/topics/manifest/instrumentation-element.jd +++ b/docs/html/guide/topics/manifest/instrumentation-element.jd @@ -16,7 +16,7 @@ parent.link=manifest-intro.html <dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code></dd> <dt>description:</dt> -<dd>Declares an {@link android.app.Instrumentation} class that enables you +<dd itemprop="description">Declares an {@link android.app.Instrumentation} class that enables you to monitor an application's interaction with the system. The Instrumentation object is instantiated before any of the application's components.</dd> diff --git a/docs/html/guide/topics/manifest/intent-filter-element.jd b/docs/html/guide/topics/manifest/intent-filter-element.jd index 68da981..14b4e03 100644 --- a/docs/html/guide/topics/manifest/intent-filter-element.jd +++ b/docs/html/guide/topics/manifest/intent-filter-element.jd @@ -25,7 +25,7 @@ parent.link=manifest-intro.html <br/><code><a href="{@docRoot}guide/topics/manifest/data-element.html"><data></a></code></dd> <dt>description:</dt> -<dd>Specifies the types of intents that an activity, service, or broadcast +<dd itemprop="description">Specifies the types of intents that an activity, service, or broadcast receiver can respond to. An intent filter declares the capabilities of its parent component — what an activity or service can do and what types of broadcasts a receiver can handle. It opens the component to receiving diff --git a/docs/html/guide/topics/manifest/manifest-element.jd b/docs/html/guide/topics/manifest/manifest-element.jd index cce951e..20dc4ea 100644 --- a/docs/html/guide/topics/manifest/manifest-element.jd +++ b/docs/html/guide/topics/manifest/manifest-element.jd @@ -25,17 +25,21 @@ parent.link=manifest-intro.html <dd><code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code></dd> <dt>can contain:</dt> -<dd><code><a href="{@docRoot}guide/topics/manifest/instrumentation-element.html"><instrumentation></a></code> +<dd><code><a href="{@docRoot}guide/topics/manifest/compatible-screens-element.html"><compatible-screens></a></code> +<br/><code><a href="{@docRoot}guide/topics/manifest/instrumentation-element.html"><instrumentation></a></code> <br/><code><a href="{@docRoot}guide/topics/manifest/permission-element.html"><permission></a></code> <br/><code><a href="{@docRoot}guide/topics/manifest/permission-group-element.html"><permission-group></a></code> <br/><code><a href="{@docRoot}guide/topics/manifest/permission-tree-element.html"><permission-tree></a></code> +<br/><code><a href="{@docRoot}guide/topics/manifest/supports-gl-texture.html"><supports-gl-texture></a></code +<br/><code><a href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><supports-screens></a></code> <br/><code><a href="{@docRoot}guide/topics/manifest/uses-configuration-element.html"><uses-configuration></a></code> <!-- ##api level 3## --> -<br/><code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html"><uses-permission></a></code></dd> +<br/><code><a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><uses-feature></a></code> +<br/><code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html"><uses-permission></a></code> <br/><code><a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html"><uses-sdk></a></code></dd> <p> <dt>description:</dt> -<dd>The root element of the AndroidManifest.xml file. It must +<dd itemprop="description">The root element of the AndroidManifest.xml file. It must contain an <code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code> element and specify {@code xmlns:android} and {@code package} attributes.</dd> @@ -189,4 +193,4 @@ more information about using this attribute (including how to maintain backward <dd> <code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code></dd> -</dl> +</dl>
\ No newline at end of file diff --git a/docs/html/guide/topics/manifest/manifest-intro.jd b/docs/html/guide/topics/manifest/manifest-intro.jd index d25a513..d2a9308 100644 --- a/docs/html/guide/topics/manifest/manifest-intro.jd +++ b/docs/html/guide/topics/manifest/manifest-intro.jd @@ -1,4 +1,4 @@ -page.title=The AndroidManifest.xml File +page.title=App Manifest @jd:body <div id="qv-wrapper"> @@ -20,11 +20,11 @@ page.title=The AndroidManifest.xml File </div> <p> -Every application must have an AndroidManifest.xml file (with precisely that -name) in its root directory. The manifest presents essential information about -the application to the Android system, information the system must have before -it can run any of the application's code. Among other things, the manifest -does the following: + Every application must have an AndroidManifest.xml file (with precisely that + name) in its root directory. <span itemprop="description">The manifest file + presents essential information about your app to the Android system, + information the system must have before it can run any of the app's + code.</span> Among other things, the manifest does the following: </p> <ul> diff --git a/docs/html/guide/topics/manifest/meta-data-element.jd b/docs/html/guide/topics/manifest/meta-data-element.jd index 56a214c..241153b 100644 --- a/docs/html/guide/topics/manifest/meta-data-element.jd +++ b/docs/html/guide/topics/manifest/meta-data-element.jd @@ -12,11 +12,13 @@ parent.link=manifest-intro.html <dt>contained in:</dt> <dd><code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code> <br/><code><a href="{@docRoot}guide/topics/manifest/activity-alias-element.html"><activity-alias></a></code> -<br/><code><a href="{@docRoot}guide/topics/manifest/service-element.html"><service></a></code> +<br/><code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code> +<br/><code><a href="{@docRoot}guide/topics/manifest/provider-element.html"><provider></a></code> <br/><code><a href="{@docRoot}guide/topics/manifest/receiver-element.html"><receiver></a></code></dd> +<br/><code><a href="{@docRoot}guide/topics/manifest/service-element.html"><service></a></code> <dt>description:</dt> -<dd>A name-value pair for an item of additional, arbitrary data that can +<dd itemprop="description">A name-value pair for an item of additional, arbitrary data that can be supplied to the parent component. A component element can contain any number of {@code <meta-data>} subelements. The values from all of them are collected in a single {@link android.os.Bundle} object and made diff --git a/docs/html/guide/topics/manifest/path-permission-element.jd b/docs/html/guide/topics/manifest/path-permission-element.jd index e644d68..cdaf82b 100644 --- a/docs/html/guide/topics/manifest/path-permission-element.jd +++ b/docs/html/guide/topics/manifest/path-permission-element.jd @@ -23,7 +23,7 @@ parent.link=manifest-intro.html --> <dt>description:</dt> -<dd>Defines the path and required permissions for a specific subset of data +<dd itemprop="description">Defines the path and required permissions for a specific subset of data within a content provider. This element can be specified multiple times to supply multiple paths. diff --git a/docs/html/guide/topics/manifest/permission-element.jd b/docs/html/guide/topics/manifest/permission-element.jd index a23fb4b..4bb5f6a 100644 --- a/docs/html/guide/topics/manifest/permission-element.jd +++ b/docs/html/guide/topics/manifest/permission-element.jd @@ -17,7 +17,7 @@ parent.link=manifest-intro.html <dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code></dd> <dt>description:</dt> -<dd>Declares a security permission that can be used to limit access +<dd itemprop="description">Declares a security permission that can be used to limit access to specific components or features of this or other applications. See the <a href="{@docRoot}guide/topics/manifest/manifest-intro.html#perms">Permissions</a> section in the introduction, diff --git a/docs/html/guide/topics/manifest/permission-group-element.jd b/docs/html/guide/topics/manifest/permission-group-element.jd index fc1de1f..3221d4b 100644 --- a/docs/html/guide/topics/manifest/permission-group-element.jd +++ b/docs/html/guide/topics/manifest/permission-group-element.jd @@ -14,7 +14,7 @@ parent.link=manifest-intro.html <dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code></dd> <dt>description:</dt> -<dd>Declares a name for a logical grouping of related permissions. Individual +<dd itemprop="description">Declares a name for a logical grouping of related permissions. Individual permission join the group through the {@code permissionGroup} attribute of the <code><a href="{@docRoot}guide/topics/manifest/permission-element.html"><permission></a></code> element. Members of a group are presented together in the user interface. diff --git a/docs/html/guide/topics/manifest/permission-tree-element.jd b/docs/html/guide/topics/manifest/permission-tree-element.jd index a9c00cd..21d7352 100644 --- a/docs/html/guide/topics/manifest/permission-tree-element.jd +++ b/docs/html/guide/topics/manifest/permission-tree-element.jd @@ -13,7 +13,7 @@ parent.link=manifest-intro.html <dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code></dd> <dt>description:</dt> -<dd>Declares the base name for a tree of permissions. The application takes +<dd itemprop="description">Declares the base name for a tree of permissions. The application takes ownership of all names within the tree. It can dynamically add new permissions to the tree by calling <code>{@link android.content.pm.PackageManager#addPermission PackageManager.addPermission()}</code>. Names within the tree are separated by periods ('{@code .}'). For example, if the base name is diff --git a/docs/html/guide/topics/manifest/provider-element.jd b/docs/html/guide/topics/manifest/provider-element.jd index 6cf6843..f3ffd58 100644 --- a/docs/html/guide/topics/manifest/provider-element.jd +++ b/docs/html/guide/topics/manifest/provider-element.jd @@ -36,7 +36,7 @@ parent.link=manifest-intro.html <br/><code><a href="{@docRoot}guide/topics/manifest/path-permission-element.html"><path-permission></a></code></dd> <dt>description:</dt> -<dd> +<dd itemprop="description"> Declares a content provider component. A content provider is a subclass of {@link android.content.ContentProvider} that supplies structured access to data managed by the application. All content providers in your application must be defined in a diff --git a/docs/html/guide/topics/manifest/receiver-element.jd b/docs/html/guide/topics/manifest/receiver-element.jd index 8416c0c..df2437e 100644 --- a/docs/html/guide/topics/manifest/receiver-element.jd +++ b/docs/html/guide/topics/manifest/receiver-element.jd @@ -23,7 +23,7 @@ parent.link=manifest-intro.html <br/><code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html"><meta-data></a></code></dd> <dt>description:</dt> -<dd>Declares a broadcast receiver (a {@link android.content.BroadcastReceiver} +<dd itemprop="description">Declares a broadcast receiver (a {@link android.content.BroadcastReceiver} subclass) as one of the application's components. Broadcast receivers enable applications to receive intents that are broadcast by the system or by other applications, even when other components of the application are not running. diff --git a/docs/html/guide/topics/manifest/service-element.jd b/docs/html/guide/topics/manifest/service-element.jd index 14eed67..2213b72 100644 --- a/docs/html/guide/topics/manifest/service-element.jd +++ b/docs/html/guide/topics/manifest/service-element.jd @@ -24,7 +24,7 @@ parent.link=manifest-intro.html <br/><code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html"><meta-data></a></code></dd> <dt>description:</dt> -<dd>Declares a service (a {@link android.app.Service} subclass) as one +<dd itemprop="description">Declares a service (a {@link android.app.Service} subclass) as one of the application's components. Unlike activities, services lack a visual user interface. They're used to implement long-running background operations or a rich communications API that can be called by other diff --git a/docs/html/guide/topics/manifest/supports-gl-texture-element.jd b/docs/html/guide/topics/manifest/supports-gl-texture-element.jd index fa39317..ab751c2 100644 --- a/docs/html/guide/topics/manifest/supports-gl-texture-element.jd +++ b/docs/html/guide/topics/manifest/supports-gl-texture-element.jd @@ -34,7 +34,7 @@ parent.link=manifest-intro.html <dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code></dd> <dt>description:</dt> -<dd>Declares a single GL texture compression format that is supported by +<dd itemprop="description">Declares a single GL texture compression format that is supported by the application. <p>An application "supports" a GL texture compression format if it is capable of diff --git a/docs/html/guide/topics/manifest/supports-screens-element.jd b/docs/html/guide/topics/manifest/supports-screens-element.jd index ae14121..bbeceb7 100644 --- a/docs/html/guide/topics/manifest/supports-screens-element.jd +++ b/docs/html/guide/topics/manifest/supports-screens-element.jd @@ -24,7 +24,7 @@ parent.link=manifest-intro.html <dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code></dd> <dt>description:</dt> -<dd>Lets you specify the screen sizes your application supports and enable <a +<dd itemprop="description">Lets you specify the screen sizes your application supports and enable <a href="{@docRoot}guide/practices/screen-compat-mode.html">screen compatibility mode</a> for screens larger than what your application supports. It's important that you always use this element in your application to specify the screen sizes your application supports. diff --git a/docs/html/guide/topics/manifest/uses-configuration-element.jd b/docs/html/guide/topics/manifest/uses-configuration-element.jd index e9a0ba4..15fd49c 100644 --- a/docs/html/guide/topics/manifest/uses-configuration-element.jd +++ b/docs/html/guide/topics/manifest/uses-configuration-element.jd @@ -27,7 +27,7 @@ easier to update the doc when the change is made... Nov 2013, this still seems u <dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code></dd> <dt>description:</dt> -<dd>Indicates what hardware and software features the application requires. +<dd itemprop="description">Indicates what hardware and software features the application requires. For example, an application might specify that it requires a physical keyboard or a particular navigation device, like a trackball. The specification is used to avoid installing the application on devices where it will not work. diff --git a/docs/html/guide/topics/manifest/uses-feature-element.jd b/docs/html/guide/topics/manifest/uses-feature-element.jd index 95f62a5..d421591 100644 --- a/docs/html/guide/topics/manifest/uses-feature-element.jd +++ b/docs/html/guide/topics/manifest/uses-feature-element.jd @@ -62,7 +62,7 @@ below.</p> href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code></dd> <dt>description:</dt> -<dd>Declares a single hardware or software feature that is used by the +<dd itemprop="description">Declares a single hardware or software feature that is used by the application. <p>The purpose of a <code><uses-feature></code> declaration is to inform @@ -136,7 +136,7 @@ device compatibility.</p> <dd>Specifies a single hardware or software feature used by the application, as a descriptor string. Valid descriptor values are listed in the <a href="#hw-features">Hardware features</a> and <a href="#sw-features">Software -features</a> tables, below. </dd> +features</a> tables, below. Descriptor string values are case-sensitive.</dd> <dt><a name="required"></a><code>android:required</code></dt> <!-- added in api level 5 --> <dd>Boolean value that indicates whether the application requires @@ -549,11 +549,15 @@ is sensitive to delays or lag in sound input or output.</td> </td> </tr> <tr> - <td>Bluetooth</td> - <td><code>android.hardware.bluetooth</td> + <td rowspan="2">Bluetooth</td> + <td><code>android.hardware.bluetooth</code></td> <td>The application uses Bluetooth radio features in the device.</td> - <td>If your app uses Bluetooth Low Energy, also declare - {@code android.software.bluetooth_le}.</td> + <td></td> + </tr> + <tr> + <td><code>android.hardware.bluetooth_le</code></td> + <td>The application uses Bluetooth Low Energy radio features in the device.</td> + <td></td> </tr> <tr> <td rowspan="5">Camera</td> @@ -586,6 +590,13 @@ not required.</td> </tr> <tr> + <td>Infrared</td> + <td><code>android.hardware.consumerir</code></td> + <td>The application uses the consumer IR capabilities on the device.</td> + <td></td> +</tr> + +<tr> <td rowspan="3">Location</td> <td><code>android.hardware.location</code></td> <td>The application uses one or more features on the device for determining @@ -613,13 +624,18 @@ from a Global Positioning System receiver on the device. </td> <td></td> </tr> <tr> - <td>NFC</td> + <td rowspan="2">NFC</td> <td><code>android.hardware.nfc</td> <td>The application uses Near Field Communications radio features in the device.</td> <td></td> </tr> <tr> - <td rowspan="6">Sensors</td> + <td><code>android.hardware.nfc.hce</code></td> + <td>The application uses the NFC card emulation feature in the device.</td> + <td></td> +</tr> +<tr> + <td rowspan="8">Sensors</td> <td><code>android.hardware.sensor.accelerometer</code></td> <td>The application uses motion readings from an accelerometer on the device.</td> @@ -651,6 +667,16 @@ the device.</td> <td>The application uses the device's proximity sensor.</td> <td></td> </tr> +<tr> + <td><code>android.hardware.sensor.stepcounter</code></td> + <td>The application uses the device's step counter.</td> + <td></td> +</tr> +<tr> + <td><code>android.hardware.sensor.stepdetector</code></td> + <td>The application uses the device's step detector.</td> + <td></td> +</tr> <tr> <td rowspan="2">Screen</td> @@ -828,11 +854,15 @@ hosts).</td> </tr> <tr> - <td>Wifi</td> + <td rowspan="2">Wi-Fi</td> <td><code>android.hardware.wifi</code></td> - <td>The application uses 802.11 networking (wifi) features on the device.</td> + <td>The application uses 802.11 networking (Wi-Fi) features on the device.</td> <td></td> </tr> +<tr> + <td><code>android.hardware.wifi.direct</code></td> + <td>The application uses the Wi-Fi Direct networking features on the device.</td> +</tr> </table> @@ -857,11 +887,9 @@ in a separate <code><uses-feature></code> element. </p> that include a Home screen or similar location where users can embed App Widgets.</td> </tr> <tr> - <td>Bluetooth Low Energy</td> - <td><code>android.software.bluetooth_le</code></td> - <td><p>The application uses Bluetooth Low Energy APIs and should be installed only on devices - that are capable of communicating with other devices via Bluetooth Low Energy. - <p>This implicitly also declares the {@code android.hardware.bluetooth} feature.</td> + <td>Device Management</td> + <td><code>android.software.device_admin</code></td> + <td>The application uses device policy enforcement via device administrators.</td> </tr> <tr> <td>Home Screen</td> @@ -1056,7 +1084,7 @@ filtering based on the <code>CAMERA</code> permission, you would add this </tr> <tr> - <td rowspan="3">Wifi</td> + <td rowspan="3">Wi-Fi</td> <td><code>ACCESS_WIFI_STATE</code></td> <td><code>android.hardware.wifi</code></td> <!-- <td></td> --> diff --git a/docs/html/guide/topics/manifest/uses-library-element.jd b/docs/html/guide/topics/manifest/uses-library-element.jd index 253807e..aa7ca82 100644 --- a/docs/html/guide/topics/manifest/uses-library-element.jd +++ b/docs/html/guide/topics/manifest/uses-library-element.jd @@ -31,7 +31,7 @@ parent.link=manifest-intro.html </code> </dd> <dt>description:</dt> -<dd> +<dd itemprop="descridption"> Specifies a shared library that the application must be linked against. This element tells the system to include the library's code in the class loader for the package. diff --git a/docs/html/guide/topics/manifest/uses-permission-element.jd b/docs/html/guide/topics/manifest/uses-permission-element.jd index bd7091e..9394114 100644 --- a/docs/html/guide/topics/manifest/uses-permission-element.jd +++ b/docs/html/guide/topics/manifest/uses-permission-element.jd @@ -42,7 +42,7 @@ href="{@docRoot}guide/topics/manifest/uses-feature-element.html#permissions-feat <dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code></dd> <dt>description:</dt> -<dd>Requests a permission that the application must be granted in +<dd itemprop="description">Requests a permission that the application must be granted in order for it to operate correctly. Permissions are granted by the user when the application is installed, not while it's running. diff --git a/docs/html/guide/topics/manifest/uses-sdk-element.jd b/docs/html/guide/topics/manifest/uses-sdk-element.jd index 9169658..b372592 100644 --- a/docs/html/guide/topics/manifest/uses-sdk-element.jd +++ b/docs/html/guide/topics/manifest/uses-sdk-element.jd @@ -48,7 +48,7 @@ page.tags="api levels","sdk version","minsdkversion","targetsdkversion","maxsdkv <dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code></dd> <dt>description:</dt> -<dd>Lets you express an application's compatibility with one or more versions of the Android platform, +<dd itemprop="description"><p> Lets you express an application's compatibility with one or more versions of the Android platform, by means of an API Level integer. The API Level expressed by an application will be compared to the API Level of a given Android system, which may vary among different Android devices. </p> @@ -273,55 +273,55 @@ Highlights</a>--></td></tr> <td>{@link android.os.Build.VERSION_CODES#HONEYCOMB_MR1}</td> <td><a href="{@docRoot}about/versions/android-3.1-highlights.html">Platform Highlights</a></td></tr> - <tr><td><a href="{@docRoot}about/versions/android-3.0.html">Android 3.0.x</td> + <tr><td><a href="{@docRoot}about/versions/android-3.0.html">Android 3.0.x</a></td> <td><a href="{@docRoot}sdk/api_diff/11/changes.html" title="Diff Report">11</a></td> <td>{@link android.os.Build.VERSION_CODES#HONEYCOMB}</td> <td><a href="{@docRoot}about/versions/android-3.0-highlights.html">Platform Highlights</a></td></tr> - <tr><td><a href="{@docRoot}about/versions/android-2.3.3.html">Android 2.3.4<br>Android 2.3.3</td> + <tr><td><a href="{@docRoot}about/versions/android-2.3.3.html">Android 2.3.4<br>Android 2.3.3</a></td> <td><a href="{@docRoot}sdk/api_diff/10/changes.html" title="Diff Report">10</a></td> <td>{@link android.os.Build.VERSION_CODES#GINGERBREAD_MR1}</td> <td rowspan="2"><a href="{@docRoot}about/versions/android-2.3-highlights.html">Platform Highlights</a></td></tr> - <tr><td><a href="{@docRoot}about/versions/android-2.3.html">Android 2.3.2<br>Android 2.3.1<br>Android -2.3</td> + <tr><td><a href="{@docRoot}about/versions/android-2.3.html">Android 2.3.2<br>Android 2.3.1<br> + Android 2.3</a></td> <td><a href="{@docRoot}sdk/api_diff/9/changes.html" title="Diff Report">9</a></td> <td>{@link android.os.Build.VERSION_CODES#GINGERBREAD}</td> </tr> - <tr><td><a href="{@docRoot}about/versions/android-2.2.html">Android 2.2.x</td> + <tr><td><a href="{@docRoot}about/versions/android-2.2.html">Android 2.2.x</a></td> <td ><a href="{@docRoot}sdk/api_diff/8/changes.html" title="Diff Report">8</a></td> <td>{@link android.os.Build.VERSION_CODES#FROYO}</td> <td><a href="{@docRoot}about/versions/android-2.2-highlights.html">Platform Highlights</a></td></tr> - <tr><td><a href="{@docRoot}about/versions/android-2.1.html">Android 2.1.x</td> + <tr><td><a href="{@docRoot}about/versions/android-2.1.html">Android 2.1.x</a></td> <td><a href="{@docRoot}sdk/api_diff/7/changes.html" title="Diff Report">7</a></td> <td>{@link android.os.Build.VERSION_CODES#ECLAIR_MR1}</td> <td rowspan="3" ><a href="{@docRoot}about/versions/android-2.0-highlights.html">Platform Highlights</a></td></tr> - <tr><td><a href="{@docRoot}about/versions/android-2.0.1.html">Android 2.0.1</td> + <tr><td><a href="{@docRoot}about/versions/android-2.0.1.html">Android 2.0.1</a></td> <td><a href="{@docRoot}sdk/api_diff/6/changes.html" title="Diff Report">6</a></td> <td>{@link android.os.Build.VERSION_CODES#ECLAIR_0_1}</td> </tr> - <tr><td><a href="{@docRoot}about/versions/android-2.0.html">Android 2.0</td> + <tr><td><a href="{@docRoot}about/versions/android-2.0.html">Android 2.0</a></td> <td><a href="{@docRoot}sdk/api_diff/5/changes.html" title="Diff Report">5</a></td> <td>{@link android.os.Build.VERSION_CODES#ECLAIR}</td> </tr> - <tr><td><a href="{@docRoot}about/versions/android-1.6.html">Android 1.6</td> + <tr><td><a href="{@docRoot}about/versions/android-1.6.html">Android 1.6</a></td> <td><a href="{@docRoot}sdk/api_diff/4/changes.html" title="Diff Report">4</a></td> <td>{@link android.os.Build.VERSION_CODES#DONUT}</td> <td><a href="{@docRoot}about/versions/android-1.6-highlights.html">Platform Highlights</a></td></tr> - <tr><td><a href="{@docRoot}about/versions/android-1.5.html">Android 1.5</td> + <tr><td><a href="{@docRoot}about/versions/android-1.5.html">Android 1.5</a></td> <td><a href="{@docRoot}sdk/api_diff/3/changes.html" title="Diff Report">3</a></td> <td>{@link android.os.Build.VERSION_CODES#CUPCAKE}</td> <td><a href="{@docRoot}about/versions/android-1.5-highlights.html">Platform Highlights</a></td></tr> - <tr><td><a href="{@docRoot}about/versions/android-1.1.html">Android 1.1</td> + <tr><td><a href="{@docRoot}about/versions/android-1.1.html">Android 1.1</a></td> <td>2</td> <td>{@link android.os.Build.VERSION_CODES#BASE_1_1}</td><td></td></tr> diff --git a/docs/html/guide/topics/media/mediaplayer.jd b/docs/html/guide/topics/media/mediaplayer.jd index fb272d2..dc789d2 100644 --- a/docs/html/guide/topics/media/mediaplayer.jd +++ b/docs/html/guide/topics/media/mediaplayer.jd @@ -119,7 +119,7 @@ mediaPlayer.start(); // no need to call prepare(); create() does that for you <p>In this case, a "raw" resource is a file that the system does not try to parse in any particular way. However, the content of this resource should not -be raw audio. It should be a properly encoded and formatted media file in one +be raw audio. It should be a properly encoded and formatted media file in one of the supported formats.</p> <p>And here is how you might play from a URI available locally in the system @@ -207,7 +207,7 @@ call {@link android.media.MediaPlayer#stop stop()}, however, notice that you cannot call {@link android.media.MediaPlayer#start start()} again until you prepare the {@link android.media.MediaPlayer} again.</p> -<p>Always keep <a href='{@docRoot}images/mediaplayer_state_diagram.gif'>the state diagram</a> +<p>Always keep <a href='{@docRoot}images/mediaplayer_state_diagram.gif'>the state diagram</a> in mind when writing code that interacts with a {@link android.media.MediaPlayer} object, because calling its methods from the wrong state is a common cause of bugs.</p> @@ -238,7 +238,7 @@ mediaPlayer = null; <p>As an example, consider the problems that could happen if you forgot to release the {@link android.media.MediaPlayer} when your activity is stopped, but create a new one when the activity starts again. As you may know, when the user changes the -screen orientation (or changes the device configuration in another way), +screen orientation (or changes the device configuration in another way), the system handles that by restarting the activity (by default), so you might quickly consume all of the system resources as the user rotates the device back and forth between portrait and landscape, because at each @@ -287,7 +287,7 @@ For example:</p> <pre> public class MyService extends Service implements MediaPlayer.OnPreparedListener { - private static final ACTION_PLAY = "com.example.action.PLAY"; + private static final String ACTION_PLAY = "com.example.action.PLAY"; MediaPlayer mMediaPlayer = null; public int onStartCommand(Intent intent, int flags, int startId) { @@ -346,7 +346,7 @@ and you must reset it before you can use it again. <p>When designing applications that play media in the background, the device may go to sleep while your service is running. Because the Android system tries to conserve -battery while the device is sleeping, the system tries to shut off any +battery while the device is sleeping, the system tries to shut off any of the phone's features that are not necessary, including the CPU and the WiFi hardware. However, if your service is playing or streaming music, you want to prevent @@ -473,7 +473,7 @@ the user might not hear the notification tone due to the loud music. Starting wi Android 2.2, the platform offers a way for applications to negotiate their use of the device's audio output. This mechanism is called Audio Focus.</p> -<p>When your application needs to output audio such as music or a notification, +<p>When your application needs to output audio such as music or a notification, you should always request audio focus. Once it has focus, it can use the sound output freely, but it should always listen for focus changes. If it is notified that it has lost the audio @@ -691,7 +691,7 @@ adding the following to your manifest:</p> intent. You should then implement this class:</p> <pre> -public class MusicIntentReceiver implements android.content.BroadcastReceiver { +public class MusicIntentReceiver extends android.content.BroadcastReceiver { @Override public void onReceive(Context ctx, Intent intent) { if (intent.getAction().equals( diff --git a/docs/html/guide/topics/media/mediarouter.jd b/docs/html/guide/topics/media/mediarouter.jd new file mode 100644 index 0000000..1b10265 --- /dev/null +++ b/docs/html/guide/topics/media/mediarouter.jd @@ -0,0 +1,670 @@ +page.title=MediaRouter +page.tags="cast","chromecast","wireless display","miracast" +@jd:body + +<div id="qv-wrapper"> + <div id="qv"> + <h2>In this document</h2> + <ol> + <li><a href="#overview">Overview</a> + <ol> + <li><a href="#mr-packages">Media router packages</a></li> + </ol> + </li> + <li><a href="#cast-ui">Cast User Interface</a> + <ol> + <li><a href="#cast-button">Cast button</a></li> + <li><a href="#selector">Media route selector</a></li> + </ol> + </li> + <li><a href="#media-routes">Connecting to Media Routes</a> + <ol> + <li><a href="#create-mr-callback">Creating a MediaRouter callback</a></li> + <li><a href="#attach-mr-callback">Attaching a callback to MediaRouter</a></li> + </ol> + <li><a href="#remote-playback">Remote Playback</a></li> + <li><a href="#secondary-output">Secondary Output</a> + <ol> + <li><a href="#pres-obj">Creating a Presentation object</a></li> + <li><a href="#pres-cntrlr">Creating a Presentation controller</a></li> + </ol> + </li> + </ol> + <h2>Key Classes</h2> + <ol> + <li>{@link android.support.v7.media.MediaRouter}</li> + <li>{@link android.support.v7.media.MediaRouter.Callback}</li> + <li>{@link android.support.v7.media.MediaRouteProvider}</li> + </ol> + </div> +</div> + +<p>As users connect their televisions, home theater systems and music players with wireless + technologies, they want to be able to play content from Android apps on these larger, + louder devices. Enabling this kind of playback can turn your one-device, one-user app + into a shared experience that delights and inspires multiple users.</p> + +<p>The Android media router APIs are designed to enable media display and playback on these + secondary devices. There are two main approaches you can use to play content using these + APIs:</p> + +<ul> + <li><strong>Remote Playback</strong> — This approach uses the receiving device to handle + the content data retrieval, decoding, and playback, while an Android device in the user's hand + is used as a remote control. This approach is used by Android apps that support + <a href="https://developers.google.com/cast/">Google Cast</a>.</li> + <li><strong>Secondary Output</strong> — With this approach, your app retrieves, renders + and streams video or music directly to the receiving device. This approach is used to support + Wireless Display output + on Android.</li> +</ul> + +<p>This guide explains how your app can deliver media to secondary playback devices using either + of these approaches.</p> + + +<h2 id="overview">Overview</h2> + +<p>The media router APIs enable a broad range of media output to playback equipment connected to + Android devices through wireless and wired means. To enable these connections, + the media router framework abstracts the logical paths for audio and video output for an Android + device. This architecture allows your app to quickly channel media content to + connected playback devices such as home theaters and sound systems that provide Android media + route support.</p> + +<p>In order to use this framework within your app, you must get an instance + of the {@link android.support.v7.media.MediaRouter} framework object and attach a {@link + android.support.v7.media.MediaRouter.Callback} object to listen for events in + available media routes. Content channelled through a media route passes through the route's + associated {@link android.support.v7.media.MediaRouteProvider} (except in a few special cases, + such as a Bluetooth output device). The following diagram provides a high-level view of the + classes your app can use to play content with the media router framework. +</p> + +<img src="{@docRoot}images/mediarouter/mediarouter-framework.png" alt="" id="figure1"/> +<p class="img-caption"> + <strong>Figure 1.</strong> Overview of key media router classes used by apps. +</p> + +<p>Manufacturers of media playback hardware that is not supported by the media router framework + can add support for their devices by implementing a + {@link android.support.v7.media.MediaRouteProvider} and distributing it as an application. + For more information on implementing a media route provider, see the {@link + android.support.v7.media.MediaRouteProvider} reference documentation and the v7-mediarouter + support library sample {@code <sdk>/extras/android/compatibility/v7/mediarouter}. +</p> + + +<h3 id="mr-packages">Media router packages</h3> + +<p>The media router APIs are provided as part of the Android Support Library version 18 and + higher, in the + <a href="{@docRoot}tools/support-library/features.html#v7-mediarouter">v7-mediarouter support + library</a>. Specifically, you should use the classes in the {@link android.support.v7.media} + package for media router functions. These APIs are compatible with devices running Android 2.1 + (API level 7) and higher. +</p> + +<p class="note"> + <strong>Note:</strong> There is another set of media router APIs provided in the + {@link android.media} that have been superseded by the v7-mediarouter support library. + You <em>should not</em> use the {@link android.media} classes for media router functions. +</p> + +<p>In order to use the {@link android.support.v7.media} media router classes, you must add + the <a href="{@docRoot}tools/support-library/features.html#v7-mediarouter">v7-mediarouter + support library package</a> to your app development project. +</p> + + +<h2 id="cast-ui">Cast User Interface</h2> + +<p> + Android apps that implement the media router API should include a Cast button + as part of their user interface, to allow users to select a media route to play media on + a secondary output device. The media router framework provides a standard interface for + the button, which you should use to help users recognize and use the feature in your app. + Figure 2 illustrates how the Cast button should appear in an app. +</p> + +<img src="{@docRoot}images/mediarouter/mediarouter-actionbar.png" alt="" width="428" id="figure2"/> +<p class="img-caption"> + <strong>Figure 2.</strong> A Cast button shown on the right side of the action bar. +</p> + +<p class="caution"> + <strong>Caution:</strong> When implementing an activity that provides a media router interface + you <em>must</em> extend either {@link android.support.v7.app.ActionBarActivity} + or {@link android.support.v4.app.FragmentActivity} from the Android Support Library, even if + your {@code android:minSdkVersion} is API 11 or higher. +</p> + + +<h3 id="cast-button">Cast button</h3> + +<p>The recommended way to implement the Cast button user interface is to extend your activity + from {@link android.support.v7.app.ActionBarActivity} and use the {@link + android.app.Activity#onCreateOptionsMenu onCreateOptionsMenu()} method to add an options menu. + The Cast button must use the {@link android.support.v7.app.MediaRouteActionProvider} class + as its action:</p> + +<pre> +<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + > + + <item android:id="@+id/media_route_menu_item" + android:title="@string/media_route_menu_title" + <strong>app:actionProviderClass="android.support.v7.app.MediaRouteActionProvider"</strong> + app:showAsAction="always" + /> +</menu> +</pre> + +<p>For more information about implementing the action bar in your app, + see the <a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> + developer guide. +</p> + +<p>Once you have added the Cast button to your user interface, you must attach a media + route selector object. Building a selector is discussed in the next section. +</p> + +<p>If you do not want a menu in your action bar, you can also add a Cast button to your app using + {@link android.support.v7.app.MediaRouteButton}. If you choose this approach, you should add + this button to your app's action bar according to the + <a href="https://developers.google.com/cast/docs/design_checklist">Google Cast Design + Checklist</a>. You must also attach a media route selector to the button using the + {@link android.support.v7.app.MediaRouteButton#setRouteSelector setRouteSelector()} method. +</p> + +<p>For guidelines on incorporating the Cast button into your application, review the + <a href="https://developers.google.com/cast/docs/design_checklist">Google Cast Design + Checklist</a>.</p> + + +<h3 id="selector">Media route selector</h3> + +<p>When a user presses the Cast button, the media router framework looks for available media + routes and presents a list of choices to the user, as shown in figure 3.</p> + +<img src="{@docRoot}images/mediarouter/mediarouter-selector-ui.png" alt="" width="500" id="figure3"/> +<p class="img-caption"> + <strong>Figure 3.</strong> A list of available media routes, shown after pressing the Cast button. +</p> + + +<p>The <em>types</em> of media routes that appear on this list—Remote Playback, Secondary + Output or others—are defined by your app.You define these type by creating a {@link + android.support.v7.media.MediaRouteSelector}, which accepts {@link + android.support.v7.media.MediaControlIntent} objects provided by the framework and other media + route providers created by you or other developers. The framework-provided route categories are as + follows: +</p> + +<ul> + <li>{@link android.support.v7.media.MediaControlIntent#CATEGORY_LIVE_AUDIO + CATEGORY_LIVE_AUDIO} — Output of audio to a secondary output device, such as a + wireless-enabled music system.</li> + <li>{@link android.support.v7.media.MediaControlIntent#CATEGORY_LIVE_VIDEO + CATEGORY_LIVE_VIDEO} — Output of video to a secondary output device, such as Wireless + Display devices.</li> + <li>{@link android.support.v7.media.MediaControlIntent#CATEGORY_REMOTE_PLAYBACK + CATEGORY_REMOTE_PLAYBACK} — Play video or audio on a separate device that supports the + <a href="https://developers.google.com/cast/">Google Cast</a> remote control protocol, such + as <a href="https://www.google.com/url?q=http://www.google.com/chromecast">Chromecast</a>. + </li> +</ul> + +<p>When creating a {@link android.support.v7.media.MediaRouteSelector} object, use the + {@link android.support.v7.media.MediaRouteSelector.Builder} class to create the object and set + the media playback categories (control categories), as shown + in the following code sample:</p> + +<pre> +public class MediaRouterPlaybackActivity extends ActionBarActivity { + private MediaRouteSelector mSelector; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + // Create a route selector for the type of routes your app supports. + <strong>mSelector = new MediaRouteSelector.Builder() + // These are the framework-supported intents + .addControlCategory(MediaControlIntent.CATEGORY_LIVE_AUDIO) + .addControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO) + .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)</strong> + .build(); + } +} +</pre> + +<p>The media router framework uses this selector object to provide an interface for selecting + media routes that your app supports, as shown in figure 3. Once you have defined this selector, + you attach it to the {@link android.support.v7.app.MediaRouteActionProvider} object associated + with the Cast menu item, as shown in the following code sample:</p> + +<pre> +@Override +public boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + + // Inflate the menu and configure the media router action provider. + getMenuInflater().inflate(R.menu.sample_media_router_menu, menu); + + // Attach the MediaRouteSelector to the menu item + MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item); + MediaRouteActionProvider mediaRouteActionProvider = + (MediaRouteActionProvider)MenuItemCompat.getActionProvider( + mediaRouteMenuItem); + <strong>mediaRouteActionProvider.setRouteSelector(mSelector);</strong> + + // Return true to show the menu. + return true; +} +</pre> + +<p>Once you have made these changes to your app, you might expect the Cast button to appear in your + activity. Alas, it does not (unless your device is already paired with a Wireless Display). In + most cases, you must also connect with the media route framework, which is discussed in the next + section. +</p> + + +<h2 id="media-routes">Connecting to Media Routes</h2> + +<p>In order to connect to a media route selected by the user, your app must obtain the {@link + android.support.v7.media.MediaRouter} framework object and then attach a {@link + android.support.v7.media.MediaRouter.Callback} object. The callback object receives messages + from the media router framework when a route selected, changed or disconnected by the user.</p> + +<p>To obtain an instance of the {@link android.support.v7.media.MediaRouter} framework object, + call {@link android.support.v7.media.MediaRouter#getInstance MediaRouter.getInstance()} + from the {@link android.app.Activity#onCreate onCreate()} method of an activity that supports + the media router API.</p> + +<p class="note"> + <strong>Note:</strong> The {@link android.support.v7.media.MediaRouter} object is a singleton + that is maintained by the framework. However, once your application obtains an instance of the + object you must retain that instance until your application terminates to prevent it from being + garbage collected. +</p> + + +<h3 id="create-mr-callback">Creating a MediaRouter callback</h3> + +<p>The media router framework communicates with an app through a callback object that + you attach to the {@link android.support.v7.media.MediaRouter} framework object. An app + that uses the media router framework must extend the {@link + android.support.v7.media.MediaRouter.Callback} object to receive messages when a media route is + connected and provide content to the connected device through that route.</p> + +<p>There are several methods in the callback that can be overwritten to receive messages about + media router events. At the minimum, your implementation of the {@link + android.support.v7.media.MediaRouter.Callback} class should override the following + methods:</p> + +<ul> + <li>{@link android.support.v7.media.MediaRouter.Callback#onRouteSelected onRouteSelected()} + — Called when the user connects to a media router output device.</li> + <li>{@link android.support.v7.media.MediaRouter.Callback#onRouteUnselected + onRouteUnselected()} — Called when the user disconnects from a media router output device.</li> + <li>{@link android.support.v7.media.MediaRouter.Callback#onRoutePresentationDisplayChanged + onRoutePresentationDisplayChanged()} — Called when the presentation display changes its + display metrics, such as changing from 720 pixel to 1080 pixel resolution.</li> +</ul> + +<p>The methods of your {@link android.support.v7.media.MediaRouter.Callback} + implementation are the first opportunity to determine if the connected route is a remote playback + device, such as Chromecast, or a secondary output device, such as a Wireless Display device. + If your app supports both device types, then your implementation should branch here, as + shown in this sample code:</p> + +<pre> +private final MediaRouter.Callback mMediaRouterCallback = + new MediaRouter.Callback() { + + @Override + public void onRouteSelected(MediaRouter router, RouteInfo route) { + Log.d(TAG, "onRouteSelected: route=" + route); + + if (route.supportsControlCategory( + MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)){ + // remote playback device + updateRemotePlayer(route); + } else { + // secondary output device + updatePresentation(route); + } + } + + @Override + public void onRouteUnselected(MediaRouter router, RouteInfo route) { + Log.d(TAG, "onRouteUnselected: route=" + route); + + if (route.supportsControlCategory( + MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)){ + // remote playback device + updateRemotePlayer(route); + } else { + // secondary output device + updatePresentation(route); + } + } + + @Override + public void onRoutePresentationDisplayChanged( + MediaRouter router, RouteInfo route) { + Log.d(TAG, "onRoutePresentationDisplayChanged: route=" + route); + + if (route.supportsControlCategory( + MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)){ + // remote playback device + updateRemotePlayer(route); + } else { + // secondary output device + updatePresentation(route); + } + } +} +</pre> + +<p>After defining your callback object for the media router, you still need to attach it to + the main media router framework object. The next section discusses the appropriate way to attach + your callbacks for media routes.</p> + + +<h3 id="attach-mr-callback">Attaching a callback to MediaRouter</h3> + +<p>Since media routes are a shared interface, your app must attach and detach your + {@link android.support.v7.media.MediaRouter.Callback} object as your app starts up and shuts + down. To accomplish this, you must add and remove your app's + callback object from the media router framework as part of your app's activity lifecycle. This + approach allows other apps to make use of media route outputs while your app + is in the background or not running.</p> + +<p class="note"> + <strong>Note:</strong> If you are writing a music playback app and want to allow music to play + while your app is in the background, you must build a {@link android.app.Service} for playback + and connect that service and it's lifecycle to the media router framework. +</p> + +<p>The following code sample demonstrates how to use the lifecycle methods to appropriately + add and remove your app's media router callback object:</p> + +<pre> +public class MediaRouterPlaybackActivity extends ActionBarActivity { + private MediaRouter mMediaRouter; + private MediaRouteSelector mSelector; + private Callback mMediaRouterCallback; + + // your app works with so the framework can discover them. + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + // Get the media router service. + mMediaRouter = MediaRouter.getInstance(this); + ... + } + + // Add the callback on start to tell the media router what kinds of routes + // your app works with so the framework can discover them. + @Override + public void onStart() { + mMediaRouter.addCallback(mSelector, mMediaRouterCallback, + MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY); + super.onStart(); + } + + // Remove the selector on stop to tell the media router that it no longer + // needs to discover routes for your app. + @Override + public void onStop() { + mMediaRouter.removeCallback(mMediaRouterCallback); + super.onStop(); + } + ... +} +</pre> + +<p>You should add and remove the media router callback only in the {@link + android.app.Activity#onStart onStart()} and {@link android.app.Activity#onStop onStop()} + lifecycle methods. Do not include these calls in the {@link android.app.Activity#onResume + onResume()} or {@link android.app.Activity#onPause onPause()} methods. +</p> + +<p class="note"> + <strong>Note:</strong> The media route framework also provides a + {@link android.support.v7.app.MediaRouteDiscoveryFragment} class which takes care of adding and + removing the call back for an activity. +</p> + +<p>Now when you run your application, you should see a Cast button appear in your activity. + When you press the button the media router framework, a route selection dialog appears as shown + in figure 3, allowing your user to select an available media route. Make sure you have a + supported device available on your local network when testing this interface.</p> + +<p class="note"> + <strong>Note:</strong> In order for Wireless Display routes to show up in the media route + selection dialog, users must enable this option in the Settings app. The option is under + the <em>Display</em> category and is called <em>Cast screen</em> on Android 4.4 (KitKat) and higher + devices and <em>Wireless Display</em> on Android 4.2.x (Jelly Bean) devices. For more information + on enabling this feature see this + <a href="https://support.google.com/nexus/answer/2865484">Wireless display</a> support page. +</p> + + +<h2 id="remote-playback">Remote Playback</h2> + +<p>The remote playback approach sends control commands to a secondary device to initiate playback + and to control playback that is in progress (pause, rewind, fast-forward, volume up and down). + Using this approach, the receiving device (such as a Chromecast) is responsible for retrieving + and rendering content.</p> + +<p>When your app supports this type of media route, you must create a {@link + android.support.v7.media.RemotePlaybackClient} object using a remote playback {@link + android.support.v7.media.MediaRouter.RouteInfo} object received through your app's + {@link android.support.v7.media.MediaRouter.Callback} object. The following sample + code demonstrates a controller method that creates a new remote playback client and sends it a + video for playback:</p> + +<pre> +private void updateRemotePlayer(RouteInfo route) { + // Changed route: tear down previous client + if (mRoute != null && mRemotePlaybackClient != null) { + mRemotePlaybackClient.release(); + mRemotePlaybackClient = null; + } + + // Save new route + mRoute = route; + + // Attach new playback client + mRemotePlaybackClient = new RemotePlaybackClient(this, mRoute); + + // Send file for playback + mRemotePlaybackClient.play(Uri.parse( + "http://archive.org/download/Sintel/sintel-2048-stereo_512kb.mp4"), + "video/mp4", null, 0, null, new ItemActionCallback() { + + @Override + public void onResult(Bundle data, String sessionId, + MediaSessionStatus sessionStatus, + String itemId, MediaItemStatus itemStatus) { + logStatus("play: succeeded for item " + itemId); + } + + @Override + public void onError(String error, int code, Bundle data) { + logStatus("play: failed - error:"+ code +" - "+ error); + } + }); + } +} +</pre> + +<p>The {@link android.support.v7.media.RemotePlaybackClient} class provides additional methods + for managing content playback. Here are a few of the key playback methods from the {@link + android.support.v7.media.RemotePlaybackClient} class:</p> + +<ul> + <li>{@link android.support.v7.media.RemotePlaybackClient#play play()} — Play a specific + media file, specified by a {@link android.net.Uri}.</li> + <li>{@link android.support.v7.media.RemotePlaybackClient#pause pause()} — Pause the + currently playing media track.</li> + <li>{@link android.support.v7.media.RemotePlaybackClient#resume resume()} — Continue + playing the current track after a pause command.</li> + <li>{@link android.support.v7.media.RemotePlaybackClient#seek seek()} — Move to a specific + position in the current track.</li> + <li>{@link android.support.v7.media.RemotePlaybackClient#release release()} — Tear down the + connection from your app to the remote playback device.</li> +</ul> + +<p>You can use these methods to attach actions to playback controls you provide in your + app. Most of these methods also allow you to include a callback object so you can monitor + the progress of the playback task or control request.</p> + +<p> + The {@link android.support.v7.media.RemotePlaybackClient} class also supports queueing of + multiple media items for playback and management of the media queue. For a comprehensive sample + implementation of these features, see {@code SampleMediaRouterActivity} and its associated + classes in the v7 mediarouter support library sample + {@code <sdk>/extras/android/compatibility/v7/mediarouter}. +</p> + +<p> + For additional information on using the Google Cast API for Chromecast devices, see the + <a href="http://developers.google.com/cast/">Google Cast</a> developer documentation. +</p> + + +<h2 id="secondary-output">Secondary Output</h2> + +<p>The secondary output approach sends prepared media content to a connected secondary device + for playback. Secondary devices can include televisions or wireless sound systems and can be + attached through wireless protocols or wires, such as an HDMI cable. With this approach, your + app is responsible for processing media content for playback (downloading, decoding, + synchronization of audio and video tracks), while the secondary device only outputs the content + in its final form.</p> + +<p class="note"> + <strong>Note:</strong> Using the secondary output display routes with the media router framework + requires classes that are available only in Android 4.2 (API level 17) and higher, specifically the + {@link android.app.Presentation} class. If you are building an app that supports both + remote playback and secondary output devices, you must include checks that disable this code + below the supported Android version level. +</p> + + +<h3 id="pres-obj">Creating a Presentation object</h3> + +<p>When using a secondary output display with the media router framework, you create a {@link + android.app.Presentation} object that contains the content you want to show on that display. The + {@link android.app.Presentation} is extended from the {@link android.app.Dialog} class, so can + add layouts and views to a {@link android.app.Presentation}.</p> + +<p>You should be aware that the {@link android.app.Presentation} object has its own + {@link android.content.Context} and + {@link android.content.res.Resources}, + separate from the app activity that created the object. Having a secondary + context is required, because the content of the {@link android.app.Presentation} is drawn on a + display that is separate from your app's display on the local Android device. + Specifically, the secondary display needs a separate context because it may need to load + resources based on its specific screen metrics.</p> + +<p>The following code sample shows a minimal implementation of a + {@link android.app.Presentation} object, including a {@link android.opengl.GLSurfaceView} + object.</p> + +<pre> +public class SamplePresentation extends Presentation { + public SamplePresentation(Context outerContext, Display display) { + super(outerContext, display); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // Notice that we get resources from the context of the Presentation + Resources resources = getContext().getResources(); + + // Inflate a layout. + setContentView(R.layout.presentation_with_media_router_content); + + // Add presentation content here: + // Set up a surface view for visual interest + mSurfaceView = (GLSurfaceView)findViewById(R.id.surface_view); + mSurfaceView.setRenderer(new CubeRenderer(false)); + } +} +</pre> + + +<h3 id="pres-cntrlr">Creating a Presentation controller</h3> + +<p>In order to display a {@link android.app.Presentation} object, you should write a + controller layer that handles responses to the messages received by the {@link + android.support.v7.media.MediaRouter.Callback} object and manages the creation and + removal of the {@link android.app.Presentation} object. The controller layer should also handle + attaching presentations to a selected {@link android.view.Display} object, which represents the + separate physical display device chosen by the user. The controller layer can simply be a method + in the activity that supports a secondary display.</p> + +<p>The following code sample shows a controller layer for a {@link android.app.Presentation} + implemented as a single method. This method handles dismissing invalid presentations when a + {@link android.view.Display} is unselected or disconnected, and creates the {@link + android.app.Presentation} object when a display device is connected.</p> + +<pre> +private void updatePresentation(RouteInfo route) { + // Get its Display if a valid route has been selected + Display selectedDisplay = null; + if (route != null) { + selectedDisplay = route.getPresentationDisplay(); + } + + // Dismiss the current presentation if the display has changed or no new + // route has been selected + if (mPresentation != null && mPresentation.getDisplay() != selectedDisplay) { + mPresentation.dismiss(); + mPresentation = null; + } + + // Show a new presentation if the previous one has been dismissed and a + // route has been selected. + if (mPresentation == null && selectedDisplay != null) { + // Initialize a new Presentation for the Display + mPresentation = new SamplePresentation(this, selectedDisplay); + mPresentation.setOnDismissListener( + new DialogInterface.OnDismissListener() { + // Listen for presentation dismissal and then remove it + @Override + public void onDismiss(DialogInterface dialog) { + if (dialog == mPresentation) { + mPresentation = null; + } + } + }); + + // Try to show the presentation, this might fail if the display has + // gone away in the meantime + try { + mPresentation.show(); + } catch (WindowManager.InvalidDisplayException ex) { + // Couldn't show presentation - display was already removed + mPresentation = null; + } + } +} +</pre> + +<p class="note"> + <strong>Note:</strong> When the a user connects to a Wireless Display, the media router + framework automatically provides a notification that it is displaying screen content on a + connected device. +</p> diff --git a/docs/html/guide/topics/providers/document-provider.jd b/docs/html/guide/topics/providers/document-provider.jd index 9af8d5a..8ea08bd 100644 --- a/docs/html/guide/topics/providers/document-provider.jd +++ b/docs/html/guide/topics/providers/document-provider.jd @@ -3,8 +3,11 @@ page.title=Storage Access Framework <div id="qv-wrapper"> <div id="qv"> -<h2>In this document</h2> -<ol> +<h2>In this document + <a href="#" onclick="hideNestedItems('#toc44',this);return false;" class="header-toggle"> + <span class="more">show more</span> + <span class="less" style="display:none">show less</span></a></h2> +<ol id="toc44" class="hide-nested"> <li> <a href="#overview">Overview</a> </li> @@ -38,8 +41,25 @@ page.title=Storage Access Framework <ol> <li>{@link android.provider.DocumentsProvider}</li> <li>{@link android.provider.DocumentsContract}</li> - <li>{@link android.provider.DocumentsContract.Document}</li> - <li>{@link android.provider.DocumentsContract.Root}</li> +</ol> + +<h2>Videos</h2> + +<ol> + <li><a href="http://www.youtube.com/watch?v=zxHVeXbK1P4"> +DevBytes: Android 4.4 Storage Access Framework: Provider</a></li> + <li><a href="http://www.youtube.com/watch?v=UFj9AEz0DHQ"> +DevBytes: Android 4.4 Storage Access Framework: Client</a></li> +</ol> + + +<h2>Code Samples</h2> + +<ol> + <li><a href="{@docRoot}samples/StorageProvider/index.html"> +Storage Provider</a></li> + <li><a href="{@docRoot}samples/StorageClient/index.html"> +StorageClient</a></li> </ol> <h2>See Also</h2> @@ -50,18 +70,28 @@ page.title=Storage Access Framework </a> </li> </ol> + </div> </div> -<p>Android 4.4 (API level 19) introduces the Storage Access Framework. The -Storage Access Framework encapsulates capabilities in the Android platform that -allow apps to request files from file storage services. The Storage Access -Framework includes the following:</p> + + +<p>Android 4.4 (API level 19) introduces the Storage Access Framework (SAF). The SAF + makes it simple for users to browse and open documents, images, and other files +across all of their their preferred document storage providers. A standard, easy-to-use UI +lets users browse files and access recents in a consistent way across apps and providers.</p> + +<p>Cloud or local storage services can participate in this ecosystem by implementing a +{@link android.provider.DocumentsProvider} that encapsulates their services. Client +apps that need access to a provider's documents can integrate with the SAF with just a few +lines of code.</p> + +<p>The SAF includes the following:</p> <ul> <li><strong>Document provider</strong>—A content provider that allows a -storage service (such as Google Drive) to reveal the files it manages. This is +storage service (such as Google Drive) to reveal the files it manages. A document provider is implemented as a subclass of the {@link android.provider.DocumentsProvider} class. -The document provider schema is based on a traditional file hierarchy, +The document-provider schema is based on a traditional file hierarchy, though how your document provider physically stores data is up to you. The Android platform includes several built-in document providers, such as Downloads, Images, and Videos.</li> @@ -75,7 +105,7 @@ files returned by document providers.</li> document providers that satisfy the client app's search criteria.</li> </ul> -<p>Some of the features offered by the Storage Access Framework are as follows:</p> +<p>Some of the features offered by the SAF are as follows:</p> <ul> <li>Lets users browse content from all document providers, not just a single app.</li> <li>Makes it possible for your app to have long term, persistent access to @@ -87,7 +117,7 @@ providers, which only appear if the drive is plugged in. </li> <h2 id ="overview">Overview</h2> -<p>The Storage Access Framework centers around a content provider that is a +<p>The SAF centers around a content provider that is a subclass of the {@link android.provider.DocumentsProvider} class. Within a <em>document provider</em>, data is structured as a traditional file hierarchy:</p> <p><img src="{@docRoot}images/providers/storage_datamodel.png" alt="data model" /></p> @@ -134,7 +164,7 @@ file hierarchy. However, you can physically store your data however you like, as long as it can be accessed through the {@link android.provider.DocumentsProvider} API. For example, you could use tag-based cloud storage for your data.</p> -<p>Figure 2 shows an example of how a photo app might use the Storage Access Framework +<p>Figure 2 shows an example of how a photo app might use the SAF to access stored data:</p> <p><img src="{@docRoot}images/providers/storage_dataflow.png" alt="app" /></p> @@ -143,7 +173,7 @@ to access stored data:</p> <p>Note the following:</p> <ul> -<li>In the Storage Access Framework, providers and clients don't interact +<li>In the SAF, providers and clients don't interact directly. A client requests permission to interact with files (that is, to read, edit, create, or delete files).</li> @@ -430,7 +460,7 @@ DocumentsContract.deleteDocument(getContentResolver(), uri); <h3 id="edit">Edit a document</h3> -<p>You can use the Storage Access Framework to edit a text document in place. +<p>You can use the SAF to edit a text document in place. This snippet fires the {@link android.content.Intent#ACTION_OPEN_DOCUMENT} intent and uses the category {@link android.content.Intent#CATEGORY_OPENABLE} to to display only @@ -513,8 +543,8 @@ freshest data.</p> <p> If you're developing an app that provides storage services for files (such as -a cloud save service), you can make your files available through the Storage -Access Framework by writing a custom document provider. This section describes +a cloud save service), you can make your files available through the +SAF by writing a custom document provider. This section describes how to do this.</p> @@ -540,13 +570,25 @@ For example: <code>com.example.android.storageprovider.MyCloudProvider</code>.</ You must export your provider so that other apps can see it.</li> <li>The attribute <code>android:grantUriPermissions</code> set to -<code>"true"</code>. This allows the system to grant other apps access +<code>"true"</code>. This setting allows the system to grant other apps access to content in your provider. For a discussion of how to persist a grant for a particular document, see <a href="#permissions">Persist permissions</a>.</li> <li>The {@code MANAGE_DOCUMENTS} permission. By default a provider is available -to everyone. Adding this permission restricts your provider to the system, -which is important for security. </li> +to everyone. Adding this permission restricts your provider to the system. +This restriction is important for security.</li> + +<li>The {@code android:enabled} attribute set to a boolean value defined in a resource +file. The purpose of this attribute is to disable the provider on devices running Android 4.3 or lower. +For example, {@code android:enabled="@bool/atLeastKitKat"}. In +addition to including this attribute in the manifest, you need to do the following: +<ul> +<li>In your {@code bool.xml} resources file under {@code res/values/}, add +this line: <pre><bool name="atLeastKitKat">false</bool></pre></li> + +<li>In your {@code bool.xml} resources file under {@code res/values-v19/}, add +this line: <pre><bool name="atLeastKitKat">true</bool></pre></li> +</ul></li> <li>An intent filter that includes the {@code android.content.action.DOCUMENTS_PROVIDER} action, so that your provider @@ -566,7 +608,8 @@ appears in the picker when the system searches for providers.</li> android:authorities="com.example.android.storageprovider.documents" android:grantUriPermissions="true" android:exported="true" - android:permission="android.permission.MANAGE_DOCUMENTS"> + android:permission="android.permission.MANAGE_DOCUMENTS" + android:enabled="@bool/atLeastKitKat"> <intent-filter> <action android:name="android.content.action.DOCUMENTS_PROVIDER" /> </intent-filter> @@ -575,7 +618,7 @@ appears in the picker when the system searches for providers.</li> </manifest></pre> -<h4>Supporting devices running Android 4.3 and lower</h4> +<h4 id="43">Supporting devices running Android 4.3 and lower</h4> <p>The {@link android.content.Intent#ACTION_OPEN_DOCUMENT} intent is only available @@ -583,7 +626,7 @@ on devices running Android 4.4 and higher. If you want your application to support {@link android.content.Intent#ACTION_GET_CONTENT} to accommodate devices that are running Android 4.3 and lower, you should disable the {@link android.content.Intent#ACTION_GET_CONTENT} intent filter in -your manifest if a device is running Android 4.4 or higher. A +your manifest for devices running Android 4.4 or higher. A document provider and {@link android.content.Intent#ACTION_GET_CONTENT} should be considered mutually exclusive. If you support both of them simultaneously, your app will appear twice in the system picker UI, offering two different ways of accessing @@ -630,7 +673,7 @@ implementing contract classes, as described in the <a href="{@docRoot}guide/topics/providers/content-provider-creating.html#ContractClass"> Content Providers</a> developers guide. A contract class is a {@code public final} class that contains constant definitions for the URIs, column names, MIME types, and -other metadata that pertain to the provider. The Storage Access Framework +other metadata that pertain to the provider. The SAF provides these contract classes for you, so you don't need to write your own:</p> @@ -872,4 +915,4 @@ available if the user is logged into the provider.</p> getContentResolver().notifyChange(DocumentsContract .buildRootsUri(AUTHORITY), null); } -</pre> +</pre>
\ No newline at end of file diff --git a/docs/html/guide/topics/resources/runtime-changes.jd b/docs/html/guide/topics/resources/runtime-changes.jd index 45a548a..d074873 100644 --- a/docs/html/guide/topics/resources/runtime-changes.jd +++ b/docs/html/guide/topics/resources/runtime-changes.jd @@ -53,7 +53,7 @@ situation, you have two other options:</p> <ol type="a"> <li><a href="#RetainingAnObject">Retain an object during a configuration change</a> <p>Allow your activity to restart when a configuration changes, but carry a stateful -{@link java.lang.Object} to the new instance of your activity.</p> +object to the new instance of your activity.</p> </li> <li><a href="#HandlingTheChange">Handle the configuration change yourself</a> @@ -73,40 +73,53 @@ activity state with the {@link android.os.Bundle} that the system saves for you android.app.Activity#onSaveInstanceState(Bundle) onSaveInstanceState()} callback—it is not designed to carry large objects (such as bitmaps) and the data within it must be serialized then deserialized, which can consume a lot of memory and make the configuration change slow. In such a -situation, you can alleviate the burden of reinitializing your activity by retaining a stateful -{@link java.lang.Object} when your activity is restarted due to a configuration change.</p> +situation, you can alleviate the burden of reinitializing your activity by retaining a {@link +android.app.Fragment} when your activity is restarted due to a configuration change. This fragment +can contain references to stateful objects that you want to retain.</p> + +<p>When the Android system shuts down your activity due to a configuration change, the fragments +of your activity that you have marked to retain are not destroyed. You can add such fragments to +your activity to preserve stateful objects.</p> + +<p>To retain stateful objects in a fragment during a runtime configuration change:</p> -<p>To retain an object during a runtime configuration change:</p> <ol> - <li>Override the {@link android.app.Activity#onRetainNonConfigurationInstance()} method to return -the object you would like to retain.</li> - <li>When your activity is created again, call {@link -android.app.Activity#getLastNonConfigurationInstance()} to recover your object.</li> + <li>Extend the {@link android.app.Fragment} class and declare references to your stateful + objects.</li> + <li>Call {@link android.app.Fragment#setRetainInstance(boolean)} when the fragment is created. + </li> + <li>Add the fragment to your activity.</li> + <li>Use {@link android.app.FragmentManager} to retrieve the fragment when the activity is + restarted.</li> </ol> -<p>When the Android system shuts down your activity due to a configuration change, it calls {@link -android.app.Activity#onRetainNonConfigurationInstance()} between the {@link -android.app.Activity#onStop()} and {@link android.app.Activity#onDestroy()} callbacks. In your -implementation of {@link android.app.Activity#onRetainNonConfigurationInstance()}, you can return -any {@link java.lang.Object} that you need in order to efficiently restore your state after the -configuration change.</p> - -<p>A scenario in which this can be valuable is if your application loads a lot of data from the -web. If the user changes the orientation of the device and the activity restarts, your application -must re-fetch the data, which could be slow. What you can do instead is implement -{@link android.app.Activity#onRetainNonConfigurationInstance()} to return an object carrying your -data and then retrieve the data when your activity starts again with {@link -android.app.Activity#getLastNonConfigurationInstance()}. For example:</p> +<p>For example, define your fragment as follows:</p> <pre> -@Override -public Object onRetainNonConfigurationInstance() { - final MyDataObject data = collectMyLoadedData(); - return data; +public class RetainedFragment extends Fragment { + + // data object we want to retain + private MyDataObject data; + + // this method is only called once for this fragment + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // retain this fragment + setRetainInstance(true); + } + + public void setData(MyDataObject data) { + this.data = data; + } + + public MyDataObject getData() { + return data; + } } </pre> -<p class="caution"><strong>Caution:</strong> While you can return any object, you +<p class="caution"><strong>Caution:</strong> While you can store any object, you should never pass an object that is tied to the {@link android.app.Activity}, such as a {@link android.graphics.drawable.Drawable}, an {@link android.widget.Adapter}, a {@link android.view.View} or any other object that's associated with a {@link android.content.Context}. If you do, it will @@ -114,26 +127,51 @@ leak all the views and resources of the original activity instance. (Leaking res means that your application maintains a hold on them and they cannot be garbage-collected, so lots of memory can be lost.)</p> -<p>Then retrieve the data when your activity starts again:</p> +<p>Then use {@link android.app.FragmentManager} to add the fragment to the activity. +You can obtain the data object from the fragment when the activity starts again during runtime +configuration changes. For example, define your activity as follows:</p> <pre> -@Override -public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.main); +public class MyActivity extends Activity { + + private RetainedFragment dataFragment; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + + // find the retained fragment on activity restarts + FragmentManager fm = getFragmentManager(); + dataFragment = (DataFragment) fm.findFragmentByTag(“data”); + + // create the fragment and data the first time + if (dataFragment == null) { + // add the fragment + dataFragment = new DataFragment(); + fm.beginTransaction().add(dataFragment, “data”).commit(); + // load the data from the web + dataFragment.setData(loadMyData()); + } + + // the data is available in dataFragment.getData() + ... + } - final MyDataObject data = (MyDataObject) getLastNonConfigurationInstance(); - if (data == null) { - data = loadMyData(); + @Override + public void onDestroy() { + super.onDestroy(); + // store the data in the fragment + dataFragment.setData(collectMyLoadedData()); } - ... } </pre> -<p>In this case, {@link android.app.Activity#getLastNonConfigurationInstance()} returns the data -saved by {@link android.app.Activity#onRetainNonConfigurationInstance()}. If {@code data} is null -(which happens when the activity starts due to any reason other than a configuration change) then -this code loads the data object from the original source.</p> +<p>In this example, {@link android.app.Activity#onCreate(Bundle) onCreate()} adds a fragment +or restores a reference to it. {@link android.app.Activity#onCreate(Bundle) onCreate()} also +stores the stateful object inside the fragment instance. +{@link android.app.Activity#onDestroy() onDestroy()} updates the stateful object inside the +retained fragment instance.</p> diff --git a/docs/html/guide/topics/security/permissions.jd b/docs/html/guide/topics/security/permissions.jd index 4ad9b7c..6f919da 100644 --- a/docs/html/guide/topics/security/permissions.jd +++ b/docs/html/guide/topics/security/permissions.jd @@ -1,4 +1,4 @@ -page.title=Permissions +page.title=System Permissions @jd:body <div id="qv-wrapper"> @@ -20,10 +20,6 @@ page.title=Permissions </ol> </div> </div> -<p>This document describes how application developers can use the -security features provided by Android. A more general <a -href="http://source.android.com/tech/security/index.html"> Android Security -Overview</a> is provided in the Android Open Source Project.</p> <p>Android is a privilege-separated operating system, in which each application runs with a distinct system identity (Linux user ID and group @@ -33,7 +29,13 @@ Linux thereby isolates applications from each other and from the system.</p> <p>Additional finer-grained security features are provided through a "permission" mechanism that enforces restrictions on the specific operations that a particular process can perform, and per-URI permissions for granting -ad-hoc access to specific pieces of data.</p> +ad hoc access to specific pieces of data.</p> + +<p>This document describes how application developers can use the +security features provided by Android. A more general <a +href="http://source.android.com/tech/security/index.html"> Android Security +Overview</a> is provided in the Android Open Source Project.</p> + <a name="arch"></a> <h2>Security Architecture</h2> @@ -42,10 +44,10 @@ ad-hoc access to specific pieces of data.</p> application, by default, has permission to perform any operations that would adversely impact other applications, the operating system, or the user. This includes reading or writing the user's private data (such as contacts or -e-mails), reading or writing another application's files, performing -network access, keeping the device awake, etc.</p> +emails), reading or writing another application's files, performing +network access, keeping the device awake, and so on.</p> -<p>Because Android sandboxes applications from each other, applications +<p>Because each Android application operates in a process sandbox, applications must explicitly share resources and data. They do this by declaring the <em>permissions</em> they need for additional capabilities not provided by the basic sandbox. Applications statically declare the permissions they @@ -65,10 +67,10 @@ other.</p> <a name="signing"></a> <h2>Application Signing</h2> -<p>All Android applications (.apk files) must be signed with a certificate +<p>All APKs ({@code .apk} files) must be signed with a certificate whose private key is held by their developer. This certificate identifies the author of the application. The certificate does <em>not</em> need to be -signed by a certificate authority: it is perfectly allowable, and typical, +signed by a certificate authority; it is perfectly allowable, and typical, for Android applications to use self-signed certificates. The purpose of certificates in Android is to distinguish application authors. This allows the system to grant or deny applications access to <a @@ -86,7 +88,7 @@ device. On a different device, the same package may have a different UID; what matters is that each package has a distinct UID on a given device.</p> <p>Because security enforcement happens at the -process level, the code of any two packages can not normally +process level, the code of any two packages cannot normally run in the same process, since they need to run as different Linux users. You can use the {@link android.R.attr#sharedUserId} attribute in the <code>AndroidManifest.xml</code>'s @@ -114,7 +116,7 @@ been set appropriately so any other application can see it.</p> <h2>Using Permissions</h2> <p>A basic Android application has no permissions associated with it by default, -meaning it can not do anything that would adversely impact the user experience +meaning it cannot do anything that would adversely impact the user experience or any data on the device. To make use of protected features of the device, you must include in your <code>AndroidManifest.xml</code> one or more <code>{@link android.R.styleable#AndroidManifestUsesPermission <uses-permission>}</code> @@ -133,9 +135,9 @@ specify:</p> granted to it by the package installer, based on checks against the signatures of the applications declaring those permissions and/or interaction with the user. <em>No</em> checks with the user -are done while an application is running: it either was granted a particular +are done while an application is running; the app is either granted a particular permission when installed, and can use that feature as desired, or the -permission was not granted and any attempt to use the feature will fail +permission is not granted and any attempt to use the feature fails without prompting the user.</p> <p>Often times a permission failure will result in a {@link @@ -146,6 +148,12 @@ being delivered to each receiver, after the method call has returned, so you will not receive an exception if there are permission failures. In almost all cases, however, a permission failure will be printed to the system log.</p> +<p>However, in a normal user situation (such as when the app is installed +from Google Play Store), an app cannot be installed if the user does not grant the app +each of the requested permissions. So you generally don't need to worry about runtime failures +caused by missing permissions because the mere fact that the app is installed at all +means that your app has been granted its desired permissions.</p> + <p>The permissions provided by the Android system can be found at {@link android.Manifest.permission}. Any application may also define and enforce its own permissions, so this is not a comprehensive list of all possible @@ -433,3 +441,37 @@ android:grantUriPermissions} attribute or {@link android.content.Context#checkUriPermission Context.checkUriPermission()} methods.</p> + + + + +<div class="next-docs"> +<div class="col-6"> + <h2 class="norule">Continue reading about:</h2> + <dl> + <dt><a href="{@docRoot}guide/topics/manifest/uses-feature-element.html#permissions" + >Permissions that Imply Feature Requirements</a></dt> + <dd>Information about how requesting some permissions will implicitly restrict your app + to devices that include the corresponding hardware or software feature.</dd> + <dt><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">{@code + <uses-permission>}</a></dt> + <dd>API reference for the manifest tag that declare's your app's required system permissions. + </dd> + <dt>{@link android.Manifest.permission}</dt> + <dd>API reference for all system permissions.</dd> + </dl> +</div> +<div class="col-6"> + <h2 class="norule">You might also be interested in:</h2> + <dl> + <dt><a href="{@docRoot}guide/practices/compatibility.html" + >Device Compatibility</a></dt> + <dd>Information about Android works on different types of devices and an introduction + to how you can optimize your app for each device or restrict your app's availability + to different devices.</dd> + <dt><a href="{@docRoot}http://source.android.com/devices/tech/security/index.html" + class="external-link">Android Security Overview</a></dt> + <dd>A detailed discussion about the Android platform's security model.</dd> + </dl> +</div> +</div> diff --git a/docs/html/guide/topics/ui/dialogs.jd b/docs/html/guide/topics/ui/dialogs.jd index d934c4b..043879c 100644 --- a/docs/html/guide/topics/ui/dialogs.jd +++ b/docs/html/guide/topics/ui/dialogs.jd @@ -281,7 +281,7 @@ use the {@link android.app.AlertDialog.Builder#setItems setItems()} method:</p> @Override public Dialog onCreateDialog(Bundle savedInstanceState) { AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - builder.setTitle(R.string.pick_color); + builder.setTitle(R.string.pick_color) .setItems(R.array.colors_array, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // The 'which' argument contains the index position |
