From 204e557670a299c724023cb91ad23cd5c15641a3 Mon Sep 17 00:00:00 2001 From: Joe Fernandez Date: Thu, 31 Oct 2013 09:26:43 -0700 Subject: [PATCH 1/8] docs: Code Samples landing page - listing fix Change-Id: Id63110642e37bb9232cd1397acf9f47137cd2659 (cherry picked from commit 24807d790859e6d44abe52d8c1a4bcd4f30410fb) --- docs/html/samples/index.jd | 40 ++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/docs/html/samples/index.jd b/docs/html/samples/index.jd index 5c6cb53599fb9..c1213b6bbc712 100644 --- a/docs/html/samples/index.jd +++ b/docs/html/samples/index.jd @@ -15,25 +15,31 @@ page.tags="samples","examples","code"

If you want to download a complete project, just click on any source file in the project and click the link in the upper right of the source page.

+

To import a downloaded project:

+ +

+

+ Using Android Studio

+ +
+ +
    +
  1. Unpack the downloaded project package.
  2. +
  3. In Android Studio, chose + File > Import Project and select the root folder of the unpacked project. +

    Android Studio may ask you to choose the type of project you are importing. + If this is the case, make sure to choose Import project from + external model and select the Gradle option. +

    +
  4. +
+ +
+
+

Note: At this time, the downloadable projects are designed for use with Gradle and Android Studio. Project downloads for Eclipse will be available soon!

-

To import a downloaded project into Android - Studio:

- - - - -
-
From 6af82cf924be6b1ac8875919cb23efd38c2f26ca Mon Sep 17 00:00:00 2001 From: Scott Main Date: Thu, 31 Oct 2013 09:06:59 -0700 Subject: [PATCH 2/8] add HCE dev guide Change-Id: I48c196f7f4577304b660c52ba5cd847c0cabfaff (cherry picked from commit c988ee664e9956901df61e2219c92f50bcb60bc0) --- docs/html/guide/guide_toc.cs | 1 + .../html/guide/topics/connectivity/nfc/hce.jd | 618 ++++++++++++++++++ .../guide/topics/connectivity/nfc/index.jd | 19 +- docs/html/images/nfc/dual-mode.png | Bin 0 -> 16097 bytes docs/html/images/nfc/host-based-card.png | Bin 0 -> 10073 bytes docs/html/images/nfc/protocol-stack.png | Bin 0 -> 15106 bytes docs/html/images/nfc/secure-element.png | Bin 0 -> 12656 bytes 7 files changed, 637 insertions(+), 1 deletion(-) create mode 100644 docs/html/guide/topics/connectivity/nfc/hce.jd create mode 100644 docs/html/images/nfc/dual-mode.png create mode 100644 docs/html/images/nfc/host-based-card.png create mode 100644 docs/html/images/nfc/protocol-stack.png create mode 100644 docs/html/images/nfc/secure-element.png diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs index 21d295a7ecff3..9f39c70a85f68 100644 --- a/docs/html/guide/guide_toc.cs +++ b/docs/html/guide/guide_toc.cs @@ -405,6 +405,7 @@
  • diff --git a/docs/html/guide/topics/connectivity/nfc/hce.jd b/docs/html/guide/topics/connectivity/nfc/hce.jd new file mode 100644 index 0000000000000..d9063f39ead3d --- /dev/null +++ b/docs/html/guide/topics/connectivity/nfc/hce.jd @@ -0,0 +1,618 @@ +page.title=Host-based Card Emulation +page.tags="host card emulation", "hce","HostApduService","OffHostApduService","tap and pay" + +@jd:body + + + + + + +

    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 secure element. Many SIM cards provided by +wireless carriers also contain a secure element.

    + +

    Android 4.4 introduces an additional method of card emulation that does not +involve a secure element, called host-based card emulation. 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.

    + + +

    Card Emulation with a Secure Element

    + +

    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 +from the reader directly to the secure element. Figure 1 illustrates this concept.

    + + +

    Figure 1. NFC card emulation with a secure element.

    + +

    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.

    + + +

    Host-based Card Emulation

    + +

    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.

    + + +

    Figure 2. NFC card emulation with a secure element.

    + + +

    Supported NFC Cards and Protocols

    + +
    + +

    Figure 3. Android's HCE protocol stack.

    +
    + +

    The NFC standards offer support for many different protocols, and there are +different types of cards that can be emulated.

    + +

    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 +around HCE using only Android-powered devices.

    + +

    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.

    + + + +

    HCE Services

    + +

    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 +sense.

    + + + +

    Service selection

    + +

    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 +such as Visa and MasterCard).

    + +

    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.

    + + +

    AID groups

    + +

    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).

    + +

    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:

    + +
      +
    • All AIDs in the group are routed to this HCE service
    • +
    • 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)
    • +
    + +

    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.

    + +

    AID groups and categories

    + +

    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.

    + +

    Android 4.4 supports two categories: {@link + android.nfc.cardemulation.CardEmulation#CATEGORY_PAYMENT} (covering payment +apps) and {@link android.nfc.cardemulation.CardEmulation#CATEGORY_OTHER} +(for all other HCE apps).

    + + + +

    Implementing an HCE Service

    + +

    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. + +

    Checking for HCE support

    + +

    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 +{@code <uses-feature>} 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.

    + +

    Service implementation

    + +

    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.

    + +

    The first step is therefore to extend {@link android.nfc.cardemulation.HostApduService}.

    + +
    +public class MyHostApduService extends HostApduService {
    +    @Override
    +    public byte[] processCommandApdu(byte[] apdu, Bundle extras) {
    +       ...
    +    }
    +    @Override
    +    public void onDeactivated(int reason) {
    +       ...
    +    }	
    +}
    +
    + +

    {@link android.nfc.cardemulation.HostApduService} +declares two abstract methods that need to be overridden and implemented.

    + +

    {@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 +will wait for you to send a response APDU in return.

    + +

    Note: + 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.

    + + +

    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.

    + +

    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 +in the {@link android.nfc.cardemulation.HostApduService} class to send the response when you are done.

    + +

    Android will keep forwarding new APDUs from the reader to your service, until +either:

    + +
      +
    1. The NFC reader sends another "SELECT AID" APDU, which the OS resolves to a +different service;
    2. +
    3. The NFC link between the NFC reader and your device is broken.
    4. +
    + +

    In both of these cases, your class's + {@link android.nfc.cardemulation.HostApduService#onDeactivated onDeactivated()} + implementation is +called with an argument indicating which of the two happened.

    + +

    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.

    + +

    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.

    + + + +

    Service manifest declaration and AID registration

    + +

    Your service must be declared in the manifest as usual, but some additional +pieces must be added to the service declaration as well.

    + +

    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.

    + +

    Additionally, to tell the platform which AIDs groups are requested by this +service, a {@link android.nfc.cardemulation.HostApduService#SERVICE_META_DATA} +<meta-data> tag must be included in +the declaration of the service, pointing to an XML resource with additional +information about the HCE service.

    + +

    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.

    + +

    Here's an example of a {@link android.nfc.cardemulation.HostApduService} manifest declaration:

    + +
    +<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>
    +    <meta-data android:name="android.nfc.cardemulation.host_apdu_service"
    +        android:resource="@xml/apduservice"/>
    +</service>
    +
    + +

    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:

    + +
    +<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>
    +
    + +

    The <host-apdu-service> tag is required to contain a <android:description> +attribute that contains a user-friendly description of the service that may be +shown in UI. The <requireDeviceUnlock> attribute can be used to specify that the +device must be unlocked before this service can be invoked to handle APDUs.

    + +

    The <host-apdu-service> must contain one or more <aid-group> tags. Each +<aid-group> tag is required to contain a android:description attribute that +contains a user-friendly description of the AID group that may be shown in UI. +Each <aid-group> 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 +<aid-group> must contain one or more <aid-filter> tags, each of which contains a +single AID. The AID must be specified in hexadecimal format, and contain an even +number of characters.

    + +

    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.

    + + + + +

    AID Conflict Resolution

    + +

    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.

    + +

    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()}.

    + +

    Checking if your service is the default

    + +

    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.

    + +

    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}.

    + + + +

    Payment Applications

    + +

    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.

    + +

    Required assets for payment applications

    + +

    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.

    + +

    This asset should be sized 260x96 dp, and can be specified in your meta-data XML +file by adding the android:apduServiceBanner attribute to the +<host-apdu-service> tag, which points to the drawable resource. An example is +shown below:

    + +
    +<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
    +           android:description="@string/servicedesc" 
    +           android:requireDeviceUnlock="false"
    +           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>
    +
    + + + +

    Screen Off and Lock-screen Behavior

    + +

    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.

    + +

    HCE services can function from the lock-screen however: this is controlled by +the android:requireDeviceUnlock attribute in the <host-apdu-service> tag of your +HCE service. By default, device unlock is not required, and your service will be +invoked even if the device is locked.

    + +

    If you set the <android:requireDeviceUnlock 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.

    + + +

    Coexistence with Secure Element Cards

    + +

    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.

    + +

    Note: Android does not offer APIs for directly communicating with a secure element itself.

    + +

    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.

    + +

    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.

    + +

    Note: + While ISO/IEC 7816-4 defines the concept of “partial matches” as well, this is currently not supported by Android HCE devices.

    + +

    This architecture is illustrated in figure 4.

    + + + +

    Figure 4. Android operating with both secure element +and host-card emulation.

    + + +

    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.

    + +

    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.

    + +

    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.

    + + +

    Secure element AID registration

    + +

    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:

    + +
      +
    • The action used in the intent-filter must be set to +{@link android.nfc.cardemulation.OffHostApduService#SERVICE_INTERFACE}
    • +
    • The meta-data name attribute must be set to +{@link android.nfc.cardemulation.OffHostApduService#SERVICE_META_DATA}
    • +
    • The meta-data XML file must use the <offhost-apdu-service> root tag

      + +
      +<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>
      +    <meta-data android:name="android.nfc.cardemulation.off_host_apdu_ervice"
      +         android:resource="@xml/apduservice"/>
      +</service>
      +
      +
    • +
    + +

    An example of the corresponding {@code apduservice.xml} file registering two AIDs:

    + +
    +<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>
    +
    + +

    The android:requireDeviceUnlock 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.

    + +

    The android:apduServiceBanner attribute must be used for off host services that +are payment applications as well in order to be selectable as a default payment +application.

    + +

    Off host service invocation

    + +

    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.

    + +

    HCE and Security

    + +

    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 +forwards the APDUs to the NFC controller.

    + +

    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 +transported to the NFC controller and out to the NFC reader.

    + +

    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 +Security Tips +.

    + +

    Protocol parameters and details

    + +

    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 +compatible with Android HCE devices.

    + +

    Nfc-A (ISO/IEC 14443 type A) protocol anti-collision and activation

    + +

    As part of the Nfc-A protocol activation, multiple frames are exchanged.

    + +

    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.

    + +

    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 not compare the +complete SEL_RES with a value of 0x20.

    + +

    ISO-DEP activation

    + +

    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.

    + +

    The section below provides more details on the individual bytes of the ATS +response provided by the NFC controller on a HCE device:

    + +
      +
    • TL: length of the ATS response. Must not indicate a length greater than 20 +bytes.
    • +
    • 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.
    • +
    • 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.
    • +
    • 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.
    • +
    • 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.
    • +
    • 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.
    • +
    + +

    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:

    + +
      +
    • FSCI in T0 must be between 2h and 8h.
    • +
    • 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.
    • +
    • FWI in T(B)1 must be <= 7h.
    • +
    + +

    APDU data exchange

    + +

    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.

    diff --git a/docs/html/guide/topics/connectivity/nfc/index.jd b/docs/html/guide/topics/connectivity/nfc/index.jd index 88c206f4958a2..f12facf75ecc2 100644 --- a/docs/html/guide/topics/connectivity/nfc/index.jd +++ b/docs/html/guide/topics/connectivity/nfc/index.jd @@ -14,6 +14,18 @@ page.title=Near Field Communication framework APIs are based around a NFC Forum standard called NDEF (NFC Data Exchange Format).

    +

    Android-powered devices with NFC simultaneously support three main modes of operation:

    + +
      +
    1. Reader/writer mode, allowing the NFC device to read and/or write +passive NFC tags and stickers.
    2. +
    3. P2P mode, allowing the NFC device to exchange data with other NFC +peers; this operation mode is used by Android Beam.
    4. +
    5. Card emulation mode, allowing the NFC device itself to act as an NFC +card. The emulated NFC card can then be accessed by an external NFC reader, +such as an NFC point-of-sale terminal.
    6. +
    +
    NFC Basics
    This document describes how Android handles discovered NFC tags and how it notifies @@ -29,5 +41,10 @@ NFC feature set of Android.
    bytes using your own protocol stack. In these cases, Android provides support to detect certain tag technologies and to open communication with the tag using your own protocol stack. + +
    Host-based Card Emulation
    +
    This document describes how Android devices can perform as NFC cards without using + a secure element, allowing any Android application to emulate a card and talk directly to + the NFC reader.
    -

    \ No newline at end of file +

    diff --git a/docs/html/images/nfc/dual-mode.png b/docs/html/images/nfc/dual-mode.png new file mode 100644 index 0000000000000000000000000000000000000000..8e484a8615e85b1e7beb10bbed142eaf182e6bca GIT binary patch literal 16097 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 b5>NkmWfoKYc?S5GIgaZ(#@a=iw;ujKLkQK& literal 0 HcmV?d00001 diff --git a/docs/html/images/nfc/protocol-stack.png b/docs/html/images/nfc/protocol-stack.png new file mode 100644 index 0000000000000000000000000000000000000000..71bdfe9adad55d7c96147a9cda4ae702c89f8263 GIT binary patch literal 15106 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 literal 0 HcmV?d00001 From 3b7199aed479ed4d45fff9f5ffb01718c8bc4c2c Mon Sep 17 00:00:00 2001 From: Scott Main Date: Thu, 31 Oct 2013 07:19:54 -0700 Subject: [PATCH 3/8] add static landing pages for sample topics Change-Id: I76c04e7916977d426c4d02554f2eb36309996cf4 (cherry picked from commit 152e7683355bcbc1fc697033c7472bbd508c7c0f) --- docs/html/samples/background.jd | 11 +++++++++++ docs/html/samples/connectivity.jd | 11 +++++++++++ docs/html/samples/content.jd | 11 +++++++++++ docs/html/samples/input.jd | 11 +++++++++++ docs/html/samples/media.jd | 11 +++++++++++ docs/html/samples/security.jd | 11 +++++++++++ docs/html/samples/testing.jd | 11 +++++++++++ docs/html/samples/topic.jd | 26 -------------------------- docs/html/samples/ui.jd | 11 +++++++++++ docs/html/samples/views.jd | 11 +++++++++++ 10 files changed, 99 insertions(+), 26 deletions(-) create mode 100644 docs/html/samples/background.jd create mode 100644 docs/html/samples/connectivity.jd create mode 100644 docs/html/samples/content.jd create mode 100644 docs/html/samples/input.jd create mode 100644 docs/html/samples/media.jd create mode 100644 docs/html/samples/security.jd create mode 100644 docs/html/samples/testing.jd delete mode 100644 docs/html/samples/topic.jd create mode 100644 docs/html/samples/ui.jd create mode 100644 docs/html/samples/views.jd diff --git a/docs/html/samples/background.jd b/docs/html/samples/background.jd new file mode 100644 index 0000000000000..ec87f84e65aca --- /dev/null +++ b/docs/html/samples/background.jd @@ -0,0 +1,11 @@ +page.title=Background +@jd:body + + +
    +
    + + + diff --git a/docs/html/samples/connectivity.jd b/docs/html/samples/connectivity.jd new file mode 100644 index 0000000000000..03f2f656f21fd --- /dev/null +++ b/docs/html/samples/connectivity.jd @@ -0,0 +1,11 @@ +page.title=Connectivity +@jd:body + + +
    +
    + + + diff --git a/docs/html/samples/content.jd b/docs/html/samples/content.jd new file mode 100644 index 0000000000000..628e43c1a6ed9 --- /dev/null +++ b/docs/html/samples/content.jd @@ -0,0 +1,11 @@ +page.title=Content +@jd:body + + +
    +
    + + + diff --git a/docs/html/samples/input.jd b/docs/html/samples/input.jd new file mode 100644 index 0000000000000..eab29e155d641 --- /dev/null +++ b/docs/html/samples/input.jd @@ -0,0 +1,11 @@ +page.title=Input +@jd:body + + +
    +
    + + + diff --git a/docs/html/samples/media.jd b/docs/html/samples/media.jd new file mode 100644 index 0000000000000..77a502735849e --- /dev/null +++ b/docs/html/samples/media.jd @@ -0,0 +1,11 @@ +page.title=Media +@jd:body + + +
    +
    + + + diff --git a/docs/html/samples/security.jd b/docs/html/samples/security.jd new file mode 100644 index 0000000000000..f136c0142bc7b --- /dev/null +++ b/docs/html/samples/security.jd @@ -0,0 +1,11 @@ +page.title=Security +@jd:body + + +
    +
    + + + diff --git a/docs/html/samples/testing.jd b/docs/html/samples/testing.jd new file mode 100644 index 0000000000000..dc066227454ef --- /dev/null +++ b/docs/html/samples/testing.jd @@ -0,0 +1,11 @@ +page.title=Testing +@jd:body + + +
    +
    + + + diff --git a/docs/html/samples/topic.jd b/docs/html/samples/topic.jd deleted file mode 100644 index cac9b10704f6b..0000000000000 --- a/docs/html/samples/topic.jd +++ /dev/null @@ -1,26 +0,0 @@ -page.title=Samples -@jd:body - - -
    -
    - - - - diff --git a/docs/html/samples/ui.jd b/docs/html/samples/ui.jd new file mode 100644 index 0000000000000..f558094149b67 --- /dev/null +++ b/docs/html/samples/ui.jd @@ -0,0 +1,11 @@ +page.title=UI +@jd:body + + +
    +
    + + + diff --git a/docs/html/samples/views.jd b/docs/html/samples/views.jd new file mode 100644 index 0000000000000..10e556bed0370 --- /dev/null +++ b/docs/html/samples/views.jd @@ -0,0 +1,11 @@ +page.title=Views +@jd:body + + +
    +
    + + + From dcb40061ab14c18a0fddf77b27bd3a3328facbfb Mon Sep 17 00:00:00 2001 From: Scott Main Date: Tue, 29 Oct 2013 17:56:00 -0700 Subject: [PATCH 4/8] add doc about migrating to new WebView in KLP Change-Id: Ib36c3ff58642166dfbc1b36b41f1c732c7d9a70d (cherry picked from commit dc277e1ca9f981f4685a86d0093ae76ff5656604) --- docs/html/guide/guide_toc.cs | 3 + docs/html/guide/webapps/migrating.jd | 378 +++++++++++++++++++++++++++ 2 files changed, 381 insertions(+) create mode 100644 docs/html/guide/webapps/migrating.jd diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs index 9f39c70a85f68..f9a23a33a1d9b 100644 --- a/docs/html/guide/guide_toc.cs +++ b/docs/html/guide/guide_toc.cs @@ -496,6 +496,9 @@
  • Building Web Apps in WebView
  • +
  • + Migrating to WebView in Android 4.4 +
  • Debugging Web Apps
  • diff --git a/docs/html/guide/webapps/migrating.jd b/docs/html/guide/webapps/migrating.jd new file mode 100644 index 0000000000000..314842b9c2c24 --- /dev/null +++ b/docs/html/guide/webapps/migrating.jd @@ -0,0 +1,378 @@ +page.title=Migrating to WebView in Android 4.4 +@jd:body + + + + + + + + + + + + +

    Android 4.4 (API level 19) introduces a new version of {@link android.webkit.WebView} that is +based on Chromium. This change upgrades +{@link android.webkit.WebView} performance and standards support for HTML5, CSS3, and JavaScript +to match the latest web browsers. Any apps using {@link android.webkit.WebView} will inherit these +upgrades when running on Android 4.4 and higher.

    + +

    This document describes additional changes +to {@link android.webkit.WebView} that you should be aware of if you set your +{@code +targetSdkVersion} to "19" or higher.

    + +

    Note: +If your {@code +targetSdkVersion} is set to "18" or lower, {@link android.webkit.WebView} operates in +"quirks mode" in order to avoid some of the behavior changes described below, as closely +as possible—while still providing your app the performance and web standards upgrades. +Beware, though, that single and narrow column layouts and default zoom levels are +not supported at all on Android 4.4, and there may be other behavioral differences +that have not been identified, so be sure to test your app on Android 4.4 +or higher even if you keep your {@code +targetSdkVersion} set to "18" or lower.

    + +

    To help you work through any issues you may encounter when migrating your app to +{@link android.webkit.WebView} in Android 4.4, you can enable remote debugging through +Chrome on your desktop by calling +{@link android.webkit.WebView#setWebContentsDebuggingEnabled setWebContentsDebuggingEnabled()}. +This new feature in {@link android.webkit.WebView} allows +you to inspect and analyze your web content, scripts, and network activity while running in +a {@link android.webkit.WebView}. For more information, see Remote +Debugging on Android.

    + + + + +

    User Agent Changes

    + +

    If you serve content to your {@link android.webkit.WebView} based on the user agent, you should +to be aware of the user agent string has changed slightly and now includes the Chrome version:

    + +
    +Mozilla/5.0 (Linux; Android 4.4; Nexus 4 Build/KRT16H) AppleWebKit/537.36
    +(KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36
    +
    + +

    If you need to retrieve the user agent but don't need to store it for your app or +do not want to instantiate {@link android.webkit.WebView}, you should use +the static method, {@link android.webkit.WebSettings#getDefaultUserAgent +getDefaultUserAgent()}. However, if you intend to override the user agent string in your +{@link android.webkit.WebView}, you may instead want to use +{@link android.webkit.WebSettings#getUserAgentString getUserAgentString()}.

    + + + + +

    Multi-threading and Thread Blocking

    + +

    If you call methods on {@link android.webkit.WebView} from any thread other than your app's +UI thread, it can cause unexpected results. For example, if your app uses multiple threads, +you can use the {@link android.app.Activity#runOnUiThread runOnUiThread()} method +to ensure your code executes on the UI thread:

    + +
    +runOnUiThread(new Runnable() {
    +    @Override
    +    public void run() {
    +        // Code for WebView goes here
    +    }
    +});
    +
    + +

    Also be sure that you +never block the UI thread. A situation in which some apps make this mistake is while waiting for +a JavaScript callback. For example, do not use code like this:

    + +
    +// This code is BAD and will block the UI thread
    +webView.loadUrl("javascript:fn()");
    +while(result == null) {
    +  Thread.sleep(100);
    +}
    +
    + +

    You can instead use a new method, {@link android.webkit.WebView#evaluateJavascript +evaluateJavascript()}, to run JavaScript asynchronously.

    + + + + + +

    Custom URL Handling

    + +

    The new {@link android.webkit.WebView} applies additional restrictions when requesting resources +and resolving links that use a custom URL scheme. For example, if you implement callbacks such as +{@link android.webkit.WebViewClient#shouldOverrideUrlLoading shouldOverrideUrlLoading()} or +{@link android.webkit.WebViewClient#shouldInterceptRequest shouldInterceptRequest()}, then +{@link android.webkit.WebView} invokes them only for valid URLs.

    + +

    If you are using a custom URL scheme or a base URL and +notice that your app is receiving fewer calls to these callbacks or failing +to load resources on Android 4.4, ensure that the requests specify valid URLs that conform to +RFC 3986. + +

    For example, the new {@link android.webkit.WebView} may not call your +{@link android.webkit.WebViewClient#shouldOverrideUrlLoading shouldOverrideUrlLoading()} method +for links like this:

    + +
    <a href="showProfile">Show Profile</a>
    + +

    The result of the user clicking such a link can vary: +

    + + +

    Instead of using a simple string in a link as shown above, you can use a custom scheme such +as the following:

    + +
    <a href="example-app:showProfile">Show Profile</a>
    + +

    You can then handle this URL in your +{@link android.webkit.WebViewClient#shouldOverrideUrlLoading shouldOverrideUrlLoading()} method +like this:

    + +
    +// The URL scheme should be non-hierarchical (no trailing slashes)
    +private static final String APP_SCHEME = "example-app:";
    +
    +@Override
    +public boolean shouldOverrideUrlLoading(WebView view, String url) {
    +    if (url.startsWith(APP_SCHEME)) {
    +        urlData = URLDecoder.decode(url.substring(APP_SCHEME.length()), "UTF-8");
    +        respondToData(urlData);
    +        return true;
    +    }
    +    return false;
    +}
    +
    + +

    If you can't alter the HTML then you may be able to use +{@link android.webkit.WebView#loadDataWithBaseURL loadDataWithBaseURL()} and set a base URL +consisting of a custom scheme and a valid host, such as +"example-app://<valid_host_name>/". For example:

    + +
    +webView.loadDataWithBaseURL("example-app://example.co.uk/", HTML_DATA,
    +        null, "UTF-8", null);
    +
    + +

    The valid host name should conform to +RFC 3986 +and it's important to include the trailing slash at the end, otherwise, any requests from the +loaded page may be dropped.

    + + + +

    Viewport Changes

    + + +

    Viewport target-densitydpi no longer supported

    + +

    Previously, {@link android.webkit.WebView} supported a viewport property called +target-densitydpi to help web pages specify their intended screen density. This +property is no longer supported and you should migrate to using standard solutions with +images and CSS as discussed in Pixel-Perfect UI in +the WebView.

    + + +

    Viewport zooms in when small

    + +

    Previously, if you set your viewport width to a value less than or equal to "320" +it would be set to "device-width", and if you set the viewport height to a value less than or +equal to the {@link android.webkit.WebView} height, it would be set to "device-height". However, +when running in the new {@link android.webkit.WebView}, the width or height value is adhered and +the {@link android.webkit.WebView} zooms in to fill the screen width.

    + + +

    Multiple viewport tags not supported

    + +

    Previously, if you included multiple viewport tags in a web page, {@link android.webkit.WebView} +would merge the properties from all the tags. +In the new {@link android.webkit.WebView}, only the last viewport is +used and all others are ignored.

    + + +

    Default zoom is deprecated

    + +

    The methods {@link android.webkit.WebSettings#getDefaultZoom()} and +{@link android.webkit.WebSettings#setDefaultZoom setDefaultZoom()} for getting and setting +the initial zoom level on a page have are no longer supported and you should instead define +the appropriate viewport in the web page.

    + +

    Caution: These APIs are not supported on Android 4.4 and higher +at all. Even if your {@code targetSdkVersion} is set to "18" or lower, these APIs have no effect.

    + +

    For information about how to define the viewport properties in your HTML, read +Pixel-Perfect UI in the WebView. + +

    If you cannot set the width of the viewport in the HTML, then you should call +{@link android.webkit.WebSettings#setUseWideViewPort setUseWideViewPort()} to ensure the page +is given a larger viewport. For example:

    + +
    +WebSettings settings = webView.getSettings();
    +settings.setUseWideViewPort(true);
    +settings.setLoadWithOverviewMode(true);
    +
    + + + + + +

    Styling Changes

    + +

    The background CSS shorthand overrides background-size

    + +

    Chrome and other browser have behaved this way for a while, but now +{@link android.webkit.WebView} will also override a CSS setting for {@code background-size} +if you also specify the {@code background} style. For example, the size here will be reset +to a default value:

    + +
    +.some-class {
    +  background-size: contain;
    +  background: url('images/image.png') no-repeat;
    +}
    +
    + +

    The fix is to simply switch the two properties around.

    + +
    +.some-class {
    +  background: url('images/image.png') no-repeat;
    +  background-size: contain;
    +}
    +
    + + +

    Sizes are in CSS pixels instead of screen pixels

    + +

    Previously, size parameters such as +window.outerWidth and +window.outerHeight returned a value in actual screen pixels. +In the new {@link android.webkit.WebView}, these return a value based on CSS pixels.

    + +

    It's generally bad practice to try and calculate the physical size in pixels for +sizing elements or other calculations. However, if you've disabled zooming and the initial-scale +is set to 1.0, you can use window.devicePixelRatio +to get the scale, then multiply the CSS pixel value by that. Instead, +you can also create a +JavaScript binding to query the pixel size from the {@link android.webkit.WebView} itself.

    + +

    For more information, see quirksmode.org.

    + + + +

    NARROW_COLUMNS and SINGLE_COLUMN no longer supported

    + +

    The {@link android.webkit.WebSettings.LayoutAlgorithm#NARROW_COLUMNS} value for {@link +android.webkit.WebSettings.LayoutAlgorithm} is not be supported in the new {@link +android.webkit.WebView}.

    + +

    Caution: These APIs are not supported on Android 4.4 and higher +at all. Even if your {@code targetSdkVersion} is set to "18" or lower, these APIs have no effect.

    + +

    You can handle this change in the following ways:

    + + + +

    Additionally, the {@link android.webkit.WebSettings.LayoutAlgorithm#SINGLE_COLUMN} value—which +was previously deprecated—is also not supported in the new {@link +android.webkit.WebView}.

    + + + + +

    Handling Touch Events in JavaScript

    + +

    If your web page is directly handling touch events in a {@link android.webkit.WebView}, +be sure you are also handling the touchcancel +event. There are a few scenarios where touchcancel will be called, which can +cause problems if not received:

    + + + + + From 24e5397185c41e7c35a7cd25ec00bb71878061b9 Mon Sep 17 00:00:00 2001 From: Scott Main Date: Wed, 30 Oct 2013 19:38:35 -0700 Subject: [PATCH 5/8] add API overview for Android 4.4 Change-Id: I92d3cab755a65da1ee3633a69122e5be1fafc6e9 (cherry picked from commit e2ce19d001c6499303d43f64bf12628e4ff4924c) --- docs/html/about/versions/android-4.4.jd | 579 ++++++++++++++++++++++++ 1 file changed, 579 insertions(+) create mode 100644 docs/html/about/versions/android-4.4.jd diff --git a/docs/html/about/versions/android-4.4.jd b/docs/html/about/versions/android-4.4.jd new file mode 100644 index 0000000000000..6ef0337a276dc --- /dev/null +++ b/docs/html/about/versions/android-4.4.jd @@ -0,0 +1,579 @@ +page.title=Android 4.4 APIs +excludeFromSuggestions=true +sdk.platform.version=4.4 +sdk.platform.apiLevel=19 +@jd:body + + + + + + + +

    API Level: {@sdkPlatformApiLevel}

    + +

    Android 4.4 ({@link android.os.Build.VERSION_CODES#KITKAT}) is a new release for the Android platform that offers new features for users and app developers. This document provides an introduction to the most notable new APIs.

    + +

    As an app developer, you should download the Android {@sdkPlatformVersion} system image +and SDK platform from the SDK Manager as +soon as possible. If you don't have a device running Android {@sdkPlatformVersion} on which to +test your app, use the Android {@sdkPlatformVersion} system +image to test your app on the Android emulator. +Then build your apps against the Android {@sdkPlatformVersion} platform to begin using the +latest APIs.

    + + +

    Update your target API level

    + +

    To better optimize your app for devices running Android {@sdkPlatformVersion}, + you should set your {@code targetSdkVersion} to +"{@sdkPlatformApiLevel}", install it on an Android {@sdkPlatformVersion} system image, +test it, then publish an update with this change.

    + +

    You can use APIs in Android {@sdkPlatformVersion} while also supporting older versions by adding +conditions to your code that check for the system API level before executing +APIs not supported by your {@code minSdkVersion}. +To learn more about maintaining backward compatibility, read Supporting Different +Platform Versions.

    + +

    For more information about how API levels work, read What is API +Level?

    + + + + + +

    Important Behavior Changes

    + +

    If you have previously published an app for Android, be aware that your app might +be affected by changes in Android {@sdkPlatformVersion}.

    + + +

    If your app reads from external storage...

    + +

    Your app can not read shared files on the external storage when running on Android 4.4, unless your app has the {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission. That is, files within the directory returned by {@link android.os.Environment#getExternalStoragePublicDirectory getExternalStoragePublicDirectory()} are no longer accessible without the permission. However, if you need to access only your app-specific directories, provided by {@link android.content.Context#getExternalFilesDir getExternalFilesDir()}, then you do not need the {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission.

    + + +

    If your app uses WebView...

    + +

    Your app might behave differently when running on Android 4.4, especially when you update your app's {@code targetSdkVersion} to "19" or higher.

    + +

    The code underlying the {@link android.webkit.WebView} class and related APIs has been upgraded to be based on a modern snapshot of the Chromium source code. This brings a variety of improvements for performance, support for new HTML5 features, and support for remote debugging of your {@link android.webkit.WebView} content. The scope of this upgrade means that if your app uses {@link android.webkit.WebView}, it's behavior may be impacted in some cases. Although known behavior changes are documented and mostly affect your app only when you update your app's {@code targetSdkVersion} to "19" or higher—the new {@link android.webkit.WebView} operates in "quirks mode" to provide some legacy functionality in apps that target API level 18 and lower—it's possible that your app depends on unknown behaviors from the previous version of {@link android.webkit.WebView}.

    + +

    So if your existing app uses {@link android.webkit.WebView}, it's important that you test on Android 4.4 as soon as possible and consult Migrating to WebView in Android 4.4 for information about how your app might be affected when you update your {@code targetSdkVersion} to "19" or higher.

    + + +

    If your app uses AlarmManager...

    + +

    When you set your app's {@code targetSdkVersion} to "19" or higher, alarms that you create using either {@link android.app.AlarmManager#set set()} or {@link android.app.AlarmManager#setRepeating setRepeating()} will be inexact.

    + +

    To improve power efficiency, Android now batches together alarms from all apps that occur at reasonably similar times so the system wakes the device once instead of several times to handle each alarm.

    + +

    If your alarm is not associated with an exact clock time, but it's still important that your alarm be invoked during a specific time range (such as between 2pm and 4pm), then you can use the new {@link android.app.AlarmManager#setWindow setWindow()} method, which accepts an "earliest" time for the alarm and a "window" of time following the earliest time within which the system should invoke the alarm.

    + +

    If your alarm must be pinned to an exact clock time (such as for a calendar event reminder), then you can use the new {@link android.app.AlarmManager#setExact setExact()} method.

    + +

    This inexact batching behavior applies only to updated apps. If you've set the {@code targetSdkVersion} to "18" or lower, your alarms will continue behave as they have on previous versions when running on Android 4.4.

    + + +

    If your app syncs data using ContentResolver...

    + +

    When you set your app's {@code targetSdkVersion} to "19" or higher, creating a sync with {@link android.content.ContentResolver#addPeriodicSync addPeriodicSync()} will perform your sync operations within a default flex interval of approximately 4% of the period you specify. For example, if your poll frequency is 24 hours, then your sync operation may occur within roughly a one-hour window of time each day, instead of at exactly the same time each day.

    + +

    To specify your own flex interval for sync operations, you should begin using the new {@link android.content.ContentResolver#requestSync requestSync()} method. For more details, see the section below about Sync Adapters.

    + +

    This flex interval behavior applies only to updated apps. If you've set the {@code targetSdkVersion} to "18" or lower, your existing sync requests will continue to behave as they have on previous versions when running on Android 4.4.

    + + + + + + + + + + +

    Printing Framework

    + +

    Android now includes a complete framework that allows users to print any document using a printer connected over Wi-Fi, Bluetooth, or other services. The system handles the transaction between an app that wants to print a document and the services that deliver print jobs to a printer. The {@link android.print} framework provides all the APIs necessary to specify a print document and deliver it to the system for printing. Which APIs you actually need for a given print job depends on your content.

    + +

    Printing generic content

    + +

    If you want to print content from your UI as a document, you need to first create a subclass of {@link android.print.PrintDocumentAdapter}. Within this class, you must implement a few callback methods, including {@link android.print.PrintDocumentAdapter#onLayout onLayout()} to establish your layout based on the provided printing properties, and {@link android.print.PrintDocumentAdapter#onWrite onWrite()} to serialize your printable content into a {@link android.os.ParcelFileDescriptor}.

    + +

    In order to write your content to the {@link android.os.ParcelFileDescriptor} you must pass it a PDF. The new {@link android.graphics.pdf.PdfDocument} APIs offer a convenient way to do this by providing a {@link android.graphics.Canvas} from {@link android.graphics.pdf.PdfDocument.Page#getCanvas getCanvas()}, on which you can draw your printable content. Then write the {@link android.graphics.pdf.PdfDocument} to the {@link android.os.ParcelFileDescriptor} using the {@link android.graphics.pdf.PdfDocument#writeTo writeTo()} method.

    + +

    Once you've defined your implementation for {@link android.print.PrintDocumentAdapter}, you can execute print jobs upon the user's request using the {@link android.print.PrintManager} method, {@link android.print.PrintManager#print print()}, which takes the {@link android.print.PrintDocumentAdapter} as one of its arguments.

    + +

    Printing images

    + +

    If you want to print just a photo or other bitmap, then the helper APIs in the support library do all the work for you. Simply create a new instance of {@link android.support.v4.print.PrintHelper}, set the scale mode with {@link android.support.v4.print.PrintHelper#setScaleMode setScaleMode()}, then pass your {@link android.graphics.Bitmap} to {@link android.support.v4.print.PrintHelper#printBitmap printBitmap()}. That's it. The library handles all the remaining interaction with the system to deliver the bitmap to the printer.

    + +

    Building print services

    + +

    As a printer OEM, you can use the {@link android.printservice} framework to provide interoperability with your printers from Android devices. You can build and distribute print services as APKs, which users can install on their devices . A print service app operates primarily as a headless service by subclassing the {@link android.printservice.PrintService} class, which receives print jobs from the system and communicates the jobs to its printers using the appropriate protocols.

    + +

    For more information about how to print your app content, read Printing Content.

    + + + + + + + +

    SMS Provider

    + +

    The {@link android.provider.Telephony} content provider (the "SMS Provider") allows apps to read and write SMS and MMS messages on the device. It includes tables for SMS and MMS messages received, drafted, sent, pending, and more.

    + +

    Beginning with Android 4.4, the system settings allow users to select a "default SMS app." Once selected, only the default SMS app is able to write to the SMS Provider and only the default SMS app receives the {@link android.provider.Telephony.Sms.Intents#SMS_DELIVER_ACTION} broadcast when the user receives an SMS or the {@link android.provider.Telephony.Sms.Intents#WAP_PUSH_DELIVER_ACTION} broadcast when the user receives an MMS. The default SMS app is responsible for writing details to the SMS Provider when it receives or sends a new message.

    + +

    Other apps that are not selected as the default SMS app can only read the SMS Provider, but may also be notified when a new SMS arrives by listening for the {@link android.provider.Telephony.Sms.Intents#SMS_RECEIVED_ACTION} broadcast, which is a non-abortable broadcast that may be delivered to multiple apps. This broadcast is intended for apps that---while not selected as the default SMS app---need to read special incoming messages such as to perform phone number verification.

    + +

    For more information, read the blog post, Getting Your SMS Apps Ready for KitKat.

    + + + + + + + + + +

    Wireless and Connectivity

    + +

    Host card emulation

    + +

    Android apps can now emulate ISO14443-4 (ISO-DEP) NFC cards that use APDUs for data exchange (as specified in ISO7816-4). This allows an NFC-enabled device running Android 4.4 to emulate multiple NFC cards at the same time, and allows an NFC payment terminal or other NFC reader to initiate a transaction with the appropriate NFC card based on the application identifier (AID).

    + +

    If you want to emulate an NFC card that is using these protocols in your app, create a service component based on the {@link android.nfc.cardemulation.HostApduService} class. Whereas if your app instead uses a secure element for card emulation, you need to create a service based on the {@link android.nfc.cardemulation.OffHostApduService} class, which will not directly be involved in the transactions but is necessary to register the AIDs that should be handled by the secure element.

    + +

    For more information, read the NFC Card Emulation guide.

    + + +

    NFC reader mode

    + +

    A new NFC reader mode allows an activity to restrict all NFC activity to only reading the types of tags the activity is interested in while in the foreground. You can enable reader mode for your activity with {@link android.nfc.NfcAdapter#enableReaderMode enableReaderMode()}, providing an implementation of {@link android.nfc.NfcAdapter.ReaderCallback} that receives a callback when new tags are detected.

    + +

    This new capability, in conjunction with host card emulation, allows Android to operate on both ends of a mobile payment interface: One devices operates as the payment terminal (a device running a reader mode activity) and another device operates as the payment client (a device emulating an NFC card).

    + +

    Infrared transmitters

    + +

    When running on a device that includes an infrared (IR) transmitter, you can now transmit IR signals using the {@link android.hardware.ConsumerIrManager} APIs. To get an instance of {@link android.hardware.ConsumerIrManager}, call {@link android.content.Context#getSystemService getSystemService()} with {@link android.content.Context#CONSUMER_IR_SERVICE} as the argument. You can then query the device's supported IR frequencies with {@link android.hardware.ConsumerIrManager#getCarrierFrequencies()} and transmit signals by passing your desired frequency and signal pattern with {@link android.hardware.ConsumerIrManager#transmit transmit()}.

    + +

    You should always first check whether a device includes an IR transmitter by calling {@link android.hardware.ConsumerIrManager#hasIrEmitter()}, but if your app is compatible only with devices that do have one, you should include a {@code <uses-feature>} element in your manifest for {@code "android.hardware.consumerir"} ({@link android.content.pm.PackageManager#FEATURE_CONSUMER_IR}).

    + + + + + + + + + + + + +

    Multimedia

    + +

    Adaptive playback

    + +

    Support for adaptive video playback is now available with the {@link android.media.MediaCodec} APIs, enabling seamless change in resolution during playback onto a {@link android.view.Surface}—you can feed the decoder input frames of a new resolution and the resolution of the output buffers change without a significant gap.

    + +

    You can enable adaptive playback by adding two keys to {@link android.media.MediaFormat} that specify the maximum resolution that your app requires from the codec: {@link android.media.MediaFormat#KEY_MAX_WIDTH} and {@link android.media.MediaFormat#KEY_MAX_HEIGHT}. With these added to your {@link android.media.MediaFormat}, pass the {@link android.media.MediaFormat} to your {@link android.media.MediaCodec} instance with {@link android.media.MediaCodec#configure configure()}.

    + +

    The codec will transition between resolutions that are the same as or smaller than these values in a seamless fashion. The codec may also support resolutions larger than the specified maximums (as long as it is within the limits of supported profiles), but transitions to larger resolutions may not be seamless.

    + +

    To change the resolution while decoding H.264 video, continue to queue frames using MediaCodec.queueInputBuffer(), but be certain that you provide the new Sequence Parameter Set (SPS) and Picture Parameter Set (PPS) values together with the Instantaneous Decoder Refresh (IDR) frame in a single buffer.

    + +

    However, before you attempt to configure your codec for adaptive playback, you must verify that the device supports adaptive playback by calling {@link android.media.MediaCodecInfo.CodecCapabilities#isFeatureSupported} with {@link android.media.MediaCodecInfo.CodecCapabilities#FEATURE_AdaptivePlayback}.

    + +

    Note: Support for adaptive playback is vendor specific. Some codecs may require more memory for larger resolution hints. Therefore, you should set the resolution maximums based on the source material you are decoding.

    + +

    On-demand audio timestamps

    + +

    To facilitate audio-video synchronization, the new {@link android.media.AudioTimestamp} class provides timeline details about a specific "frame" in an audio stream handled by {@link android.media.AudioTrack}. To get the most recent timestamp available, instantiate an {@link android.media.AudioTimestamp} object and pass it to {@link android.media.AudioTrack#getTimestamp getTimestamp()}. If the request for the timestamp succeeds, the {@link android.media.AudioTrack} instance is filled in with a position in frame units, together with the estimated time when that frame either was presented or is committed to be presented.

    + +

    You can use the value of {@code nanoTime} in the {@link android.media.AudioTimestamp} (which is monotonic) to find the closest associated video frame compared to {@code framePosition} so you can drop, duplicate, or interpolate video frames to match the audio. Alternatively, you can determine the delta time between the value of {@code nanoTime} and a future video frame’s expected time (with consideration for the sample rate) to predict which audio frame is expected at the same moment as a video frame.

    + +

    Surface image reader

    + +

    The new {@link android.media.ImageReader} API provides you direct access to image buffers as they are rendered into a {@link android.view.Surface}. You can acquire an {@link android.media.ImageReader} with the static method {@link android.media.ImageReader#newInstance newInstance()}. Then call {@link android.media.ImageReader#getSurface()} to create a new {@link android.view.Surface} and deliver your image data with a producer such as {@link android.media.MediaPlayer} or {@link android.media.MediaCodec}. To be notified when new images are available from the surface, implement the {@link android.media.ImageReader.OnImageAvailableListener} interface and register it with {@link android.media.ImageReader#setOnImageAvailableListener setOnImageAvailableListener()}.

    + +

    Now as you draw content to your {@link android.view.Surface}, your {@link android.media.ImageReader.OnImageAvailableListener} receives a call to {@link android.media.ImageReader.OnImageAvailableListener#onImageAvailable onImageAvailable()} as each new image frame becomes available, providing you with the corresponding {@link android.media.ImageReader}. You can use the {@link android.media.ImageReader} to acquire the frame's image data as an {@link android.media.Image} object by calling {@link android.media.ImageReader#acquireLatestImage()} or {@link android.media.ImageReader#acquireNextImage()}.

    + +

    The {@link android.media.Image} object provides direct access to the image's timestamp, format, dimensions, and pixel data in a {@link java.nio.ByteBuffer}. However, in order for the {@link android.media.Image} class to interpret your images, they must be formatted according to one of the types defined by constants in either {@link android.graphics.ImageFormat} or {@link android.graphics.PixelFormat}.

    + +

    Peak and RMS measurement

    + +

    You can now query the peak and RMS of the current audio stream from {@link android.media.audiofx.Visualizer} by creating a new instance of {@link android.media.audiofx.Visualizer.MeasurementPeakRms} and passing it to {@link android.media.audiofx.Visualizer#getMeasurementPeakRms getMeasurementPeakRms()}. When you call this method, the peak and RMS values of the given {@link android.media.audiofx.Visualizer.MeasurementPeakRms} are set to the latest measured values.

    + +

    Loudness enhancer

    + +

    The {@link android.media.audiofx.LoudnessEnhancer} is a new subclass of {@link android.media.audiofx.AudioEffect} that allows you to increase the audible volume of your {@link android.media.MediaPlayer} or {@link android.media.AudioTrack}. This can be especially useful in conjunction with the new {@link android.media.audiofx.Visualizer#getMeasurementPeakRms getMeasurementPeakRms()} method mentioned above, in order to increase the volume of spoken audio tracks while other media is currently playing.

    + +

    Remote controllers

    + +

    Android 4.0 (API level 14) introduced the {@link android.media.RemoteControlClient} APIs that allow media apps to consume media controller events from remote clients such as media controls on the lock screen. Now the new {@link android.media.RemoteController} APIs allow you to build your own remote controller, enabling the creation of innovative new apps and peripherals that can control the playback of any media app that integrates with {@link android.media.RemoteControlClient}.

    + +

    To build a remote controller, you can implement your user interface any way you want to, but to deliver the media button events to the user's media app you must create a service that extends the {@link android.service.notification.NotificationListenerService} class and implements the {@link android.media.RemoteController.OnClientUpdateListener} interface. Using the {@link android.service.notification.NotificationListenerService} as the basis is important because it provides the appropriate privacy restrictions, which require users to enable your app as a notification listener within the system security settings.

    + +

    The {@link android.service.notification.NotificationListenerService} class includes a couple abstract methods you must implement, but if you are only concerned with the media controller events for handling media playback, you can leave your implementation for those empty and instead focus on the {@link android.media.RemoteController.OnClientUpdateListener} methods.

    + +

    Ratings from remote controllers

    + +

    Android 4.4 builds upon the existing capabilities for remote control clients (apps that receive media control events with the {@link android.media.RemoteControlClient}) by adding the ability for users to rate the current track from the remote controller.

    + +

    The new {@link android.media.Rating} class encapsulates information about a user rating. A rating is defined by its rating style (either {@link android.media.Rating#RATING_HEART}, {@link android.media.Rating#RATING_THUMB_UP_DOWN}, {@link android.media.Rating#RATING_3_STARS}, {@link android.media.Rating#RATING_4_STARS}, {@link android.media.Rating#RATING_5_STARS} or {@link android.media.Rating#RATING_PERCENTAGE}) and the rating value that's appropriate for that style.

    + +

    To allow users to rate your tracks from a remote controller:

    +
      +
    • Signal that you'd like to expose the rating UI to the user (if applicable) by adding the {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_RATING} flag in {@link android.media.RemoteControlClient#setTransportControlFlags setTransportControlFlags()}.
    • +
    • Call {@link android.media.RemoteControlClient#editMetadata editMetadata()} to retrieve a {@link android.media.RemoteControlClient.MetadataEditor} and pass it {@link android.media.MediaMetadataEditor#RATING_KEY_BY_USER} with {@link android.media.MediaMetadataEditor#addEditableKey addEditableKey()}.
    • +
    • Then specify the rating style by calling {@link android.media.MediaMetadataEditor#putObject putObject()} and passing it {@link android.media.MediaMetadataEditor#RATING_KEY_BY_USER} as the key and one of the above rating styles as the value.
    • +
    + +

    To receive a callback when the user changes the rating from the remote controller, implement the new {@link android.media.RemoteControlClient.OnMetadataUpdateListener} interface and pass an instance to {@link android.media.RemoteControlClient#setMetadataUpdateListener setMetadataUpdateListener()}. When the user changes the rating, your {@link android.media.RemoteControlClient.OnMetadataUpdateListener} receives a call to {@link android.media.RemoteControlClient.OnMetadataUpdateListener#onMetadataUpdate onMetadataUpdate()}, passing {@link android.media.MediaMetadataEditor#RATING_KEY_BY_USER} as the key and a {@link android.media.Rating} object as the value.

    + +

    Closed captions

    + +

    {@link android.widget.VideoView} now supports WebVTT subtitle tracks when playing HTTP Live Stream (HLS) videos, displaying the subtitle track according to the closed caption preferences the user has defined in system settings.

    + +

    You can also provide {@link android.widget.VideoView} with your WebVTT subtitle tracks using the {@link android.widget.VideoView#addSubtitleSource addSubtitleSource()} method. This method accepts an {@link java.io.InputStream} that carries the subtitle data and a {@link android.media.MediaFormat} object that specifies the format for the subtitle data, which you can specify using {@link android.media.MediaFormat#createSubtitleFormat createSubtitleFormat()}. These subtitles also appear over the video according to the user's preferences.

    + +

    If you do not use {@link android.widget.VideoView} to display your video content, you should make your subtitle overlay match the user's closed captioning preference as closely as possible. A new {@link android.view.accessibility.CaptioningManager} API allows you to query the user’s closed captioning preferences, including styles defined by {@link android.view.accessibility.CaptioningManager.CaptionStyle}, such as typeface and color. In case the user adjusts some preferences once your video has already started, you should listen for changes to the preferences by registering an instance of {@link android.view.accessibility.CaptioningManager.CaptioningChangeListener} to receive a callback when any of the preferences change, then update your subtitles as necessary.

    + + + + + + + + + + + + + +

    Animation & Graphics

    + + +

    Scenes and transitions

    + +

    The new {@link android.transition} framework provides APIs that facilitate animations between different states of your user interface. A key feature is the ability for you to define distinct states of your UI, known as "scenes," by creating a separate layout for each one. When you want to animate from one scene to another, execute a "transition," which calculates the necessary animation to change the layout from the current scene to the next scene.

    + +

    To transition between two scenes, you generally need to perform the following:

    +
      +
    1. Specify the {@link android.view.ViewGroup} containing the UI components you want to change.
    2. +
    3. Specify the layout representing the end-result of the change (the next scene).
    4. +
    5. Specify the type of transition that should animate the layout change.
    6. +
    7. Execute the transition.
    8. +
    + +

    You can use a {@link android.transition.Scene} object to accomplish steps 1 and 2. A {@link android.transition.Scene} contains metadata describing the properties of a layout that are necessary to perform a transition, including the scene's parent view and the scene's layout. You can create a {@link android.transition.Scene} using a class constructor or the static method {@link android.transition.Scene#getSceneForLayout getSceneForLayout()}.

    + +

    You must then use the {@link android.transition.TransitionManager} to accomplish steps 3 and 4. One way is to pass your {@link android.transition.Scene} to the static method {@link android.transition.TransitionManager#go go()}. This finds the scene's parent view in the current layout and performs a transition on the child views in order to reach the layout defined by the {@link android.transition.Scene}.

    + +

    Alternatively, you don't need to create a {@link android.transition.Scene} object at all, but can instead call {@link android.transition.TransitionManager#beginDelayedTransition beginDelayedTransition()}, specifying a {@link android.view.ViewGroup} that contains the views you want to change. Then add, remove, or reconfigure the target views. After the system lays out the changes as necessary, a transition starts to animate all the affected views.

    + +

    For additional control, you can define sets of transitions that should occur between pre-defined scenes, using an XML file in your project {@code res/transition/} directory. Inside a {@code <transitionManager>} element, specify one or more {@code <transition>} tags that each specify a scene (a reference to a layout file) and the transition to apply when entering and/or exiting that scene. Then inflate this set of transitions using {@link android.transition.TransitionInflater#inflateTransitionManager inflateTransitionManager()}. Use the returned {@link android.transition.TransitionManager} to execute each transition with {@link android.transition.TransitionManager#transitionTo transitionTo()}, passing a {@link android.transition.Scene} that is represented by one of the {@code <transition>} tags. You can also define sets of transitions programmatically with the {@link android.transition.TransitionManager} APIs.

    + +

    When specifying a transition, you can use several predefined types defined by subclasses of {@link android.transition.Transition}, such as {@link android.transition.Fade} and {@link android.transition.ChangeBounds}. If you don't specify a transition type, the system uses {@link android.transition.AutoTransition} by default, which automatically fades, moves, and resizes views as necessary. Additionally, you can create custom transitions by extending any of these classes to perform the animations however you'd like. A custom transition can track any property changes you'd like, and create any animation you want to based on those changes. For example, you could provide a subclass of {@link android.transition.Transition} that listens for changes to the "rotation" property of a view then animate any changes.

    + +

    For more information, see the {@link android.transition.TransitionManager} documentation.

    + +

    Animator pausing

    + +

    The {@link android.animation.Animator} APIs now allow you to pause and resume an ongoing animation with methods {@link android.animation.Animator#pause()} and {@link android.animation.Animator#resume()}.

    + +

    To track the state of an animation, you can implement the {@link android.animation.Animator.AnimatorPauseListener} interface, which provides callbacks when an animation is paused and resumed: {@link android.animation.Animator#pause()} and {@link android.animation.Animator#resume()}. Then add the listener to an {@link android.animation.Animator} object with {@link android.animation.Animator#addPauseListener addPauseListener()}.

    + +

    Alternatively, you can subclass the {@link android.animation.AnimatorListenerAdapter} abstract class, which now includes empty implementations for the pause and resume callbacks defined by {@link android.animation.Animator.AnimatorPauseListener}.

    + + +

    Reusable bitmaps

    + +

    You can now reuse any mutable bitmap in {@link android.graphics.BitmapFactory} to decode any other bitmap—even when the new bitmap is a different size---as long as the resulting byte count of the decoded bitmap (available from {@link android.graphics.Bitmap#getByteCount()}) is less than or equal to the allocated byte count of the reused bitmap (available from {@link android.graphics.Bitmap#getAllocationByteCount()}. For more information, see {@link android.graphics.BitmapFactory.Options#inBitmap}.

    + +

    New APIs for {@link android.graphics.Bitmap} allow similar reconfiguration for reuse outside of {@link android.graphics.BitmapFactory} (for manual bitmap generation or custom decoding logic). You can now set a bitmap’s dimensions with methods {@link android.graphics.Bitmap#setHeight setHeight()} and {@link android.graphics.Bitmap#setWidth setWidth()}, and specify specify a new {@link android.graphics.Bitmap.Config} with {@link android.graphics.Bitmap#setConfig setConfig()} without affecting the underlying bitmap allocation. The {@link android.graphics.Bitmap#reconfigure reconfigure()} method also provides a convenient way to combine these changes with one call.

    + +

    However, you should not reconfigure a bitmap that's currently used by the view system, because the underlying pixel buffer will not be remapped in a predictable way.

    + + + + + + + + +

    User Content

    + +

    Storage access framework

    + +

    On previous versions of Android, if you want your app to retrieve a specific type of file from another app, it must invoke an intent with the {@link android.content.Intent#ACTION_GET_CONTENT} action. This action is still the appropriate way to request a file that you want to import into your app. However, Android 4.4 introduces the {@link android.content.Intent#ACTION_OPEN_DOCUMENT} action, which allows the user to select a file of a specific type and grant your app long-term read access to that file (possibly with write access) without importing the file to your app.

    + +

    If you're developing an app that provides storage services for files (such as a cloud save service), you can participate in this unified UI for picking files by implementing a content provider as a subclass of the new {@link android.provider.DocumentsProvider} class. Your subclass of {@link android.provider.DocumentsProvider} must include an intent filter that accepts the {@link android.provider.DocumentsContract#PROVIDER_INTERFACE} action ("android.content.action.DOCUMENTS_PROVIDER"). You must then implement the four abstract methods in the {@link android.provider.DocumentsProvider}:

    + +
    +
    {@link android.provider.DocumentsProvider#queryRoots queryRoots()}
    +
    This must return a {@link android.database.Cursor} that describes all the root directories of your document storage, using columns defined in {@link android.provider.DocumentsContract.Root}.
    +
    {@link android.provider.DocumentsProvider#queryChildDocuments queryChildDocuments()}
    +
    This must return a {@link android.database.Cursor} that describes all the files in the specified directory, using columns defined in {@link android.provider.DocumentsContract.Document}.
    +
    {@link android.provider.DocumentsProvider#queryDocument queryDocument()}
    +
    This must return a {@link android.database.Cursor} that describes the specified file, using columns defined in {@link android.provider.DocumentsContract.Document}.
    +
    {@link android.provider.DocumentsProvider#openDocument openDocument()}
    +
    This must return a {@link android.os.ParcelFileDescriptor} representing the specified file. The system calls this method once the user selects a file and the client app requests access to it by calling {@link android.content.ContentResolver#openFileDescriptor openFileDescriptor()}.
    +
    + +

    For more information, see the Storage Access Framework guide.

    + + +

    External storage access

    + +

    You can now read and write app-specific files on secondary external storage media, such as when a device provides both emulated storage and an SD card. The new method {@link android.content.Context#getExternalFilesDirs getExternalFilesDirs()} works the same as the existing {@link android.content.Context#getExternalFilesDir getExternalFilesDir()} method except it returns an array of {@link java.io.File} objects. Before reading or writing to any of the paths returned by this method, pass the {@link java.io.File} object to the new {@link android.os.Environment#getStorageState getStorageState()} method to verify the storage is currently available.

    + +

    Other methods for accessing your app-specific cache directory and OBB directory also now have corresponding versions that provide access to secondary storage devices: {@link android.content.Context#getExternalCacheDirs getExternalCacheDirs()} and {@link android.content.Context#getObbDirs getObbDirs()}, respectively.

    + +

    The first entry in the returned {@link java.io.File} array is considered the device's primary external storage, which is the same as the {@link java.io.File} returned by existing methods such as {@link android.content.Context#getExternalFilesDir getExternalFilesDir()}.

    + +

    Note: Beginning with Android 4.4, the platform no longer requires that your app acquire the {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} or {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} when you need to access only your app-specific regions of the external storage using the methods above. However, the permissions are required if you want to access the shareable regions of the external storage, provided by {@link android.os.Environment#getExternalStoragePublicDirectory getExternalStoragePublicDirectory()}.

    + +

    Sync adapters

    + +

    The new {@link android.content.ContentResolver#requestSync requestSync()} method in {@link android.content.ContentResolver} simplifies some of the procedure for defining a sync request for your {@link android.content.ContentProvider} by encapsulating requests in the new {@link android.content.SyncRequest} object, which you can create with {@link android.content.SyncRequest.Builder}. The properties in {@link android.content.SyncRequest} provide the same functionality as the existing {@link android.content.ContentProvider} sync calls, but adds the ability to specify that a sync should be dropped if the network is metered, by enabling {@link android.content.SyncRequest.Builder#setDisallowMetered setDisallowMetered()}.

    + + + + + + + + + + + +

    User Input

    + +

    New sensor types

    + +

    The new {@link android.hardware.Sensor#TYPE_GEOMAGNETIC_ROTATION_VECTOR} +sensor provides rotation vector data based on a magnetometer, which is a useful alternative to the {@link android.hardware.Sensor#TYPE_ROTATION_VECTOR} sensor when a gyroscope is not available or when used with batched sensor events to record the device's orientation while the phone is sleeping. This sensor requires less power than {@link android.hardware.Sensor#TYPE_ROTATION_VECTOR}, but may be prone to noisy event data and is most effective while the user is outdoors.

    + +

    Android also now supports built-in step sensors in hardware:

    + +
    +
    {@link android.hardware.Sensor#TYPE_STEP_DETECTOR}
    +
    This sensor triggers an event each time the user takes a step. Upon each user step, this sensor delivers an event with a value of 1.0 and a timestamp indicating when the step occurred.
    +
    {@link android.hardware.Sensor#TYPE_STEP_COUNTER}
    +
    This sensor also triggers an event upon each detected step, but instead delivers the total accumulated number of steps since this sensor was first registered by an app.
    +
    + +

    Be aware that these two step sensors don't always deliver the same results. The {@link android.hardware.Sensor#TYPE_STEP_COUNTER} events occur with a higher latency than those from {@link android.hardware.Sensor#TYPE_STEP_DETECTOR}, but that's because the {@link android.hardware.Sensor#TYPE_STEP_COUNTER} algorithm does more processing to eliminate false positives. So the {@link android.hardware.Sensor#TYPE_STEP_COUNTER} may be slower to deliver events, but its results should be more accurate.

    + +

    Both step sensors are hardware dependent (Nexus 5 is the first device to support them), so you should check for availability with {@link android.content.pm.PackageManager#hasSystemFeature hasSystemFeature()}, using the {@link android.content.pm.PackageManager#FEATURE_SENSOR_STEP_DETECTOR} and {@link android.content.pm.PackageManager#FEATURE_SENSOR_STEP_COUNTER} constants.

    + +

    Batched sensor events

    + +

    To better manage device power, the {@link android.hardware.SensorManager} APIs now allow you to specify the frequency at which you'd like the system to deliver batches of sensor events to your app. This doesn't reduce the number of actual sensor events available to your app for a given period of time, but instead reduces the frequency at which the system calls your {@link android.hardware.SensorEventListener} with sensor updates. That is, instead of delivering each event to your app the moment it occurs, the system saves up all the events that occur over a period of time, then delivers them to your app all at once.

    + +

    To provide batching, the {@link android.hardware.SensorManager} class adds two new versions of the {@link android.hardware.SensorManager#registerListener(SensorEventListener, Sensor, int, int) registerListener()} method that allow you to specify the "maximum report latency." This new parameter specifies the maximum delay that your {@link android.hardware.SensorEventListener} will tolerate for delivery of new sensor events. For example, if you specify a batch latency of one minute, the system will deliver the recent set of batched events at an interval no longer than one minute by making consecutive calls to your {@link android.hardware.SensorEventListener#onSensorChanged onSensorChanged()} method—once for each event that was batched. The sensor events will never be delayed longer than your maximum report latency value, but may arrive sooner if other apps have requested a shorter latency for the same sensor.

    + +

    However, be aware that the sensor will deliver your app the batched events based on your report latency only while the CPU is awake. Although a hardware sensor that supports batching will continue to collect sensor events while the CPU is asleep, it will not wake the CPU to deliver your app the batched events. When the sensor eventually runs out of its memory for events, it will begin dropping the oldest events in order to save the newest events. You can avoid losing events by waking the device before the sensor fills its memory then call {@link android.hardware.SensorManager#flush flush()} to capture the latest batch of events. To estimate when the memory will be full and should be flushed, call {@link android.hardware.Sensor#getFifoReservedEventCount()} to get the maximum number of sensor events it can save, and divide that number by the rate at which your app desires each event. Use that calculation to set wake alarms with {@link android.app.AlarmManager} that invoke your {@link android.app.Service} (which implements the {@link android.hardware.SensorEventListener}) to flush the sensor. It's okay that the alarm may execute even while the device is awake, because the alarm interval should be large enough that it occurs only a few times in a day.

    + + +

    Note: Not all devices support batching sensor events because it requires support by the hardware sensor. However, beginning with Android 4.4, you should always use the new {@link android.hardware.SensorManager#registerListener(SensorEventListener, Sensor, int, int) registerListener()} methods, because if the device does not support batching, then the system gracefully ignores the batch latency argument and delivers sensor events in real time.

    + +

    Controller identities

    + +

    Android now identifies each connected controller with a unique integer that you can query with {@link android.view.InputDevice#getControllerNumber()}, making it easier for you to associate each controller to a different player in a game. The number for each controller may change due to controllers being disconnected, connected, or re-configured by the user, so you should track which controller number corresponds to each input device by registering an instance of {@link android.hardware.input.InputManager.InputDeviceListener}. Then call {@link android.view.InputDevice#getControllerNumber()} for each {@link android.view.InputDevice} when a change occurs.

    + +

    Connected devices also now provide product and vendor IDs that are available from {@link android.view.InputDevice#getProductId()} and {@link android.view.InputDevice#getVendorId()}. If you need to modify your key mappings based on the available set of keys on a device, you can query the device to check whether certain keys are available with {@link android.view.InputDevice#hasKeys}.

    + + + + + + + + +

    User Interface

    + +

    Immersive full-screen mode

    + +

    To provide your app with a layout that fills the entire screen, the new {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE} flag for {@link android.view.View#setSystemUiVisibility setSystemUiVisibility()} (when combined with {@link android.view.View#SYSTEM_UI_FLAG_HIDE_NAVIGATION}) enables a new immersive full-screen mode. While immersive full-screen mode is enabled, your activity continues to receive all touch events. The user can reveal the system bars with an inward swipe along the region where the system bars normally appear. This clears the {@link android.view.View#SYSTEM_UI_FLAG_HIDE_NAVIGATION} flag (and the {@link android.view.View#SYSTEM_UI_FLAG_FULLSCREEN} flag, if applied) so the system bars remain visible. However, if you'd like the system bars to hide again after a few moments, you can instead use the {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE_STICKY} flag.

    + +

    Translucent system bars

    + +

    You can now make the system bars partially translucent with new themes, {@link android.R.style#Theme_Holo_NoActionBar_TranslucentDecor Theme.Holo.NoActionBar.TranslucentDecor} and {@link android.R.style#Theme_Holo_Light_NoActionBar_TranslucentDecor Theme.Holo.Light.NoActionBar.TranslucentDecor}. By enabling translucent system bars, your layout will fill the area behind the system bars, so you must also enable {@link android.R.attr#fitsSystemWindows} for the portion of your layout that should not be covered by the system bars.

    + +

    If you're creating a custom theme, set one of these themes as the parent theme or include the {@link android.R.attr#windowTranslucentNavigation} and {@link android.R.attr#windowTranslucentStatus} style properties in your theme.

    + +

    Enhanced notification listener

    + +

    Android 4.3 added the {@link android.service.notification.NotificationListenerService} APIs, allowing apps to receive information about new notifications as they are posted by the system. In Android 4.4, notification listeners can retrieve additional metadata for the notification and complete details about the notification's actions:

    + +

    The new {@link android.app.Notification#extras Notification.extras} field includes a {@link android.os.Bundle} to deliver your notification builder additional metadata such as {@link android.app.Notification#EXTRA_TITLE} and {@link android.app.Notification#EXTRA_PICTURE}. +The new {@link android.app.Notification.Action} class defines the characteristics of an action attached to the notification, which you can retrieve from the new {@link android.app.Notification#actions} field.

    + +

    Drawable mirroring for RTL layouts

    + +

    On previous versions of Android, if your app includes images that should reverse their horizontal orientation for right-to-left layouts, you must include the mirrored image in a drawables-ldrtl/ resource directory. Now, the system can automatically mirror images for you by enabling the {@link android.R.attr#autoMirrored} attribute on a drawable resource or by calling {@link android.graphics.drawable.Drawable#setAutoMirrored setAutoMirrored()}. When enabled, the {@link android.graphics.drawable.Drawable} is automatically mirrored when the layout direction is right-to-left.

    + +

    Accessibility

    + +

    The {@link android.view.View} class now allows you to declare "live regions" for portions of your UI that dynamically update with new text content, by adding the new {@link android.R.attr#accessibilityLiveRegion} attribute to your XML layout or calling {@link android.view.View#setAccessibilityLiveRegion setAccessibilityLiveRegion()}. For example, a login screen with a text field that displays an "incorrect password" notification should be marked as a live region, so the screen reader will recite the message when it changes.

    + +

    Apps that provide an accessibility service can now also enhance their capabilities with new APIs that provide information about view collections such as list or grid views using {@link android.view.accessibility.AccessibilityNodeInfo.CollectionInfo} and {@link android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo}.

    + + + + + + + + + +

    App Permissions

    + +

    The following are new permissions that your app must request with the {@code <uses-permission>} tag to use certain new APIs:

    + +
    +
    {@link android.Manifest.permission#INSTALL_SHORTCUT}
    +
    Allows an application to install a shortcut in Launcher
    +
    {@link android.Manifest.permission#UNINSTALL_SHORTCUT}
    +
    Allows an application to uninstall a shortcut in Launcher
    +
    {@link android.Manifest.permission#TRANSMIT_IR}
    +
    Allows an applicaiton to use the device's IR transmitter, if available
    +
    + +

    Note: Beginning with Android 4.4, the platform no longer requires that your app acquire the {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} or {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} when you want to access your app-specific regions of the external storage using methods such as {@link android.content.Context#getExternalFilesDir getExternalFilesDir()}. However, the permissions are still required if you want to access the shareable regions of the external storage, provided by {@link android.os.Environment#getExternalStoragePublicDirectory getExternalStoragePublicDirectory()}.

    + + + + + +

    Device Features

    + +

    The following are new device features that you can declare with the {@code <uses-feature>} tag to declare your app requirements and enable filtering on Google Play or check for at runtime:

    + +
    +
    {@link android.content.pm.PackageManager#FEATURE_CONSUMER_IR}
    +
    The device is capable of communicating with consumer IR devices.
    +
    {@link android.content.pm.PackageManager#FEATURE_DEVICE_ADMIN}
    +
    The device supports device policy enforcement via device admins.
    +
    {@link android.content.pm.PackageManager#FEATURE_NFC_HOST_CARD_EMULATION}
    +
    The device supports host- based NFC card emulation.
    +
    {@link android.content.pm.PackageManager#FEATURE_SENSOR_STEP_COUNTER}
    +
    The device includes a hardware step counter.
    +
    {@link android.content.pm.PackageManager#FEATURE_SENSOR_STEP_DETECTOR}
    +
    The device includes a hardware step detector.
    +
    + + + + + + + + +

    For a detailed view of all API changes in Android 4.3, see the +API Differences Report.

    + + + From 84fe617c5b3e90b961091af24ef26b9fadc8c70c Mon Sep 17 00:00:00 2001 From: Joe Fernandez Date: Tue, 29 Oct 2013 01:55:12 -0700 Subject: [PATCH 6/8] docs: Print API training for KitKat release Change-Id: Ifbe40961d4f4a6d4c0546c621174ec45c2a30911 (cherry picked from commit 0f737930b88cdc4b1ff82d7865a312e9a701a8d6) --- docs/html/training/printing/custom-docs.jd | 362 +++++++++++++++++++++ docs/html/training/printing/html-docs.jd | 175 ++++++++++ docs/html/training/printing/index.jd | 57 ++++ docs/html/training/printing/photos.jd | 84 +++++ docs/html/training/training_toc.cs | 24 ++ 5 files changed, 702 insertions(+) create mode 100644 docs/html/training/printing/custom-docs.jd create mode 100644 docs/html/training/printing/html-docs.jd create mode 100644 docs/html/training/printing/index.jd create mode 100644 docs/html/training/printing/photos.jd diff --git a/docs/html/training/printing/custom-docs.jd b/docs/html/training/printing/custom-docs.jd new file mode 100644 index 0000000000000..dd0eceb6dde1a --- /dev/null +++ b/docs/html/training/printing/custom-docs.jd @@ -0,0 +1,362 @@ +page.title=Printing Custom Documents +parent.title=Printing Content +parent.link=index.html + +trainingnavtop=true +next.title= +next.link= + +@jd:body + + + +

    For some applications, such as drawing apps, page layout apps and other apps that focus on + graphic output, creating beautiful printed pages is a key feature. In this case, it is not enough + to print an image or an HTML document. The print output for these types of applications requires + precise control of everything that goes into a page, including fonts, text flow, page breaks, + headers, footers, and graphic elements.

    + +

    Creating print output that is completely customized for your application requires more + programming investment than the previously discussed approaches. You must build components that + communicate with the print framework, adjust to printer settings, draw page elements and + manage printing on multiple pages.

    + +

    This lesson shows you how you connect with the print manager, create a print adapter and + build content for printing.

    + + + + +

    When your application manages the printing process directly, the first step after receiving a + print request from your user is to connect to the Android print framework and obtain an instance + of the {@link android.print.PrintManager} class. This class allows you to initialize a print job + and begin the printing lifecycle. The following code example shows how to get the print manager + and start the printing process.

    + +
    +private void doPrint() {
    +    // Get a PrintManager instance
    +    PrintManager printManager = (PrintManager) getActivity()
    +            .getSystemService(Context.PRINT_SERVICE);
    +
    +    // Set job name, which will be displayed in the print queue
    +    String jobName = getActivity().getString(R.string.app_name) + " Document";
    +
    +    // Start a print job, passing in a PrintDocumentAdapter implementation
    +    // to handle the generation of a print document
    +    printManager.print(jobName, new MyPrintDocumentAdapter(getActivity()),
    +            null); //
    +}
    +
    + +

    The example code above demonstrates how to name a print job and set an instance of the {@link + android.print.PrintDocumentAdapter} class which handles the steps of the printing lifecycle. The + implementation of the print adapter class is discussed in the next section.

    + +

    + Note: The last parameter in the {@link android.print.PrintManager#print print()} + method takes a {@link android.print.PrintAttributes} object. You can use this parameter to + provide hints to the printing framework and pre-set options based on the previous printing cycle, + thereby improving the user experience. You may also use this parameter to set options that are + more appropriate to the content being printed, such as setting the orientation to landscape + when printing a photo that is in that orientation. +

    + + + + +

    A print adapter interacts with the Android print framework and handles the steps of the + printing process. This process requires users to select printers and print options before creating + a document for printing. These selections can influence the final output as the user chooses + printers with different output capabilities, different page sizes, or different page orientations. + As these selections are made, the print framework asks your adapter to lay out and generate a + print document, in preparation for final output. Once a user taps the print button, the framework + takes the final print document and passes it to a print provider for output. During the printing + process, users can choose to cancel the print action, so your print adapter must also listen for + and react to a cancellation requests.

    + +

    The {@link android.print.PrintDocumentAdapter} abstract class is designed to handle the + printing lifecycle, which has four main callback methods. You must implement these methods + in your print adapter in order to interact properly with the print framework:

    + +
      +
    • {@link android.print.PrintDocumentAdapter#onStart onStart()} - Called once at the + beginning of the print process. If your application has any one-time preparation tasks to + perform, such as getting a snapshot of the data to be printed, execute them here. Implementing + this method in your adapter is not required.
    • +
    • {@link android.print.PrintDocumentAdapter#onLayout onLayout()} - Called each time a + user changes a print setting which impacts the output, such as a different page size, + or page orientation, giving your application an opportunity to compute the layout of the + pages to be printed. At the minimum, this method must return how many pages are expected + in the printed document.
    • +
    • {@link android.print.PrintDocumentAdapter#onWrite onWrite()} - Called to render printed + pages into a file to be printed. This method may be called one or more times after each + {@link android.print.PrintDocumentAdapter#onLayout onLayout()} call.
    • +
    • {@link android.print.PrintDocumentAdapter#onFinish onFinish()} - Called once at the end + of the print process. If your application has any one-time tear-down tasks to perform, + execute them here. Implementing this method in your adapter is not required.
    • +
    + +

    The following sections describe how to implement the layout and write methods, which are + critical to the functioning of a print adapter.

    + +

    + Note: These adapter methods are called on the main thread of your application. If + you expect the execution of these methods in your implementation to take a significant amount of + time, implement them to execute within a separate thread. For example, you can encapsulate the + layout or print document writing work in separate {@link android.os.AsyncTask} objects. +

    + + +

    Compute print document info

    + +

    Within an implementation of the {@link android.print.PrintDocumentAdapter} class, your + application must be able to specify the type of document it is creating and calculate the total + number of pages for print job, given information about the printed page size. + The implementation of the {@link android.print.PrintDocumentAdapter#onLayout onLayout()} method in + the adapter makes these calculations and provides information about the expected output of the + print job in a {@link android.print.PrintDocumentInfo} class, including the number of pages and + content type. The following code example shows a basic implementation of the {@link + android.print.PrintDocumentAdapter#onLayout onLayout()} method for a {@link + android.print.PrintDocumentAdapter}: + +

    +@Override
    +public void onLayout(PrintAttributes oldAttributes,
    +                     PrintAttributes newAttributes,
    +                     CancellationSignal cancellationSignal,
    +                     LayoutResultCallback callback,
    +                     Bundle metadata) {
    +    // Create a new PdfDocument with the requested page attributes
    +    mPdfDocument = new PrintedPdfDocument(getActivity(), newAttributes);
    +
    +    // Respond to cancellation request
    +    if (cancellationSignal.isCancelled() ) {
    +        callback.onLayoutCancelled();
    +        return;
    +    }
    +
    +    // Compute the expected number of printed pages
    +    int pages = computePageCount(newAttributes);
    +
    +    if (pages > 0) {
    +        // Return print information to print framework
    +        PrintDocumentInfo info = new PrintDocumentInfo
    +                .Builder("print_output.pdf")
    +                .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
    +                .setPageCount(pages);
    +                .build();
    +        // Content layout reflow is complete
    +        callback.onLayoutFinished(info, true);
    +    } else {
    +        // Otherwise report an error to the print framework
    +        callback.onLayoutFailed("Page count calculation failed.");
    +    }
    +}
    +
    + +

    The execution of {@link android.print.PrintDocumentAdapter#onLayout onLayout()} method can + have three outcomes: completion, cancellation, or failure in the case where calculation of the + layout cannot be completed. You must indicate one of these results by calling the appropriate + method of the {@link android.print.PrintDocumentAdapter.LayoutResultCallback} object.

    + +

    + Note: The boolean parameter of the + {@link android.print.PrintDocumentAdapter.LayoutResultCallback#onLayoutFinished + onLayoutFinished()} method indicates whether or not the layout content has actually changed + since the last request. Setting this parameter properly allows the print framework to avoid + unnecessarily calling the {@link android.print.PrintDocumentAdapter#onWrite onWrite()} method, + essentially caching the previously written print document and improving performance. +

    + +

    The main work of {@link android.print.PrintDocumentAdapter#onLayout onLayout()} is + calculating the number of pages that are expected as output given the attributes of the printer. + How you calculate this number is highly dependent on how your application lays out pages for + printing. The following code example shows an implementation where the number of pages is + determined by the print orientation:

    + +
    +private int computePageCount(PrintAttributes printAttributes) {
    +    int itemsPerPage = 4; // default item count for portrait mode
    +
    +    MediaSize pageSize = printAttributes.getMediaSize();
    +    if (!pageSize.isPortrait()) {
    +        // Six items per page in landscape orientation
    +        itemsPerPage = 6;
    +    }
    +
    +    // Determine number of print items
    +    int printItemCount = getPrintItemCount();
    +
    +    return (int) Math.ceil(printItemCount / itemsPerPage);
    +}
    +
    + + +

    Write a print document file

    + +

    When it is time to write print output to a file, the Android print framework calls the {@link + android.print.PrintDocumentAdapter#onWrite onWrite()} method of your application's {@link + android.print.PrintDocumentAdapter} class. The method's parameters specify which pages should be + written and the output file to be used. Your implementation of this method must then render each + requested page of content to a multi-page PDF document file. When this process is complete, you + call the {@link android.print.PrintDocumentAdapter.WriteResultCallback#onWriteFinished + onWriteFinished()} method of the callback object.

    + +

    + Note: The Android print framework may call the {@link + android.print.PrintDocumentAdapter#onWrite onWrite()} method one or more times for every + call to {@link android.print.PrintDocumentAdapter#onLayout onLayout()}. For this reason, it is + important to set the boolean parameter of + {@link android.print.PrintDocumentAdapter.LayoutResultCallback#onLayoutFinished + onLayoutFinished()} method to {@code false} when the print content layout has not changed, + to avoid unnecessary re-writes of the print document. +

    + +

    + Note: The boolean parameter of the + {@link android.print.PrintDocumentAdapter.LayoutResultCallback#onLayoutFinished + onLayoutFinished()} method indicates whether or not the layout content has actually changed + since the last request. Setting this parameter properly allows the print framework to avoid + unnecessarily calling the {@link android.print.PrintDocumentAdapter#onLayout onLayout()} method, + essentially caching the previously written print document and improving performance. +

    + + +

    The following sample demonstrates the basic mechanics of this process using the {@link + android.print.pdf.PrintedPdfDocument} class to create a PDF file:

    + +
    +@Override
    +public void onWrite(final PageRange[] pageRanges,
    +                    final ParcelFileDescriptor destination,
    +                    final CancellationSignal cancellationSignal,
    +                    final WriteResultCallback callback) {
    +    // Iterate over each page of the document,
    +    // check if it's in the output range.
    +    for (int i = 0; i < totalPages; i++) {
    +        // Check to see if this page is in the output range.
    +        if (containsPage(pageRanges, i)) {
    +            // If so, add it to writtenPagesArray. writtenPagesArray.size()
    +            // is used to compute the next output page index.
    +            writtenPagesArray.append(writtenPagesArray.size(), i);
    +            PdfDocument.Page page = mPdfDocument.startPage(i);
    +
    +            // check for cancellation
    +            if (cancellationSignal.isCancelled()) {
    +                callback.onWriteCancelled();
    +                mPdfDocument.close();
    +                mPdfDocument = null;
    +                return;
    +            }
    +
    +            // Draw page content for printing
    +            drawPage(page);
    +
    +            // Rendering is complete, so page can be finalized.
    +            mPdfDocument.finishPage(page);
    +        }
    +    }
    +
    +    // Write PDF document to file
    +    try {
    +        mPdfDocument.writeTo(new FileOutputStream(
    +                destination.getFileDescriptor()));
    +    } catch (IOException e) {
    +        callback.onWriteFailed(e.toString());
    +        return;
    +    } finally {
    +        mPdfDocument.close();
    +        mPdfDocument = null;
    +    }
    +    PageRange[] writtenPages = computeWrittenPages();
    +    // Signal the print framework the document is complete
    +    callback.onWriteFinished(writtenPages);
    +
    +    ...
    +}
    +
    + +

    This sample delegates rendering of PDF page content to drawPage() + method, which is discussed in the next section. +

    + +

    As with layout, execution of {@link android.print.PrintDocumentAdapter#onWrite onWrite()} + method can have three outcomes: completion, cancellation, or failure in the case where the + the content cannot be written. You must indicate one of these results by calling the + appropriate method of the {@link android.print.PrintDocumentAdapter.WriteResultCallback} object. +

    + + +

    + Note: Rendering a document for printing can be a resource-intensive operation. In + order to avoid blocking the main user interface thread of your application, you should consider + performing the page rendering and writing operations on a separate thread, for example + in an {@link android.os.AsyncTask}. + For more information about working with execution threads like asynchronous tasks, + see Processes + and Threads. +

    + + +

    Drawing PDF Page Content

    + +

    When your application prints, your application must generate a PDF document and pass it to + the Android print framework for printing. You can use any PDF generation library for this + purpose. This lesson shows how to use the {@link android.print.pdf.PrintedPdfDocument} class + to generate PDF pages from your content.

    + +

    The {@link android.print.pdf.PrintedPdfDocument} class uses a {@link android.graphics.Canvas} + object to draw elements on an PDF page, similar to drawing on an activity layout. You can draw + elements on the printed page using the {@link android.graphics.Canvas} draw methods. The following + example code demonstrates how to draw some simple elements on a PDF document page using these + methods:

    + +
    +private void drawPage(PdfDocument.Page page) {
    +    Canvas canvas = page.getCanvas();
    +
    +    // units are in points (1/72 of an inch)
    +    int titleBaseLine = 72;
    +    int leftMargin = 54;
    +
    +    Paint paint = new Paint();
    +    paint.setColor(Color.BLACK);
    +    paint.setTextSize(36);
    +    canvas.drawText("Test Title", leftMargin, titleBaseLine, paint);
    +
    +    paint.setTextSize(11);
    +    canvas.drawText("Test paragraph", leftMargin, titleBaseLine + 25, paint);
    +
    +    paint.setColor(Color.BLUE);
    +    canvas.drawRect(100, 100, 172, 172, paint);
    +}
    +
    + +

    When using {@link android.graphics.Canvas} to draw on a PDF page, elements are specified in + points, which is 1/72 of an inch. Make sure you use this unit of measure for specifying the size + of elements on the page. For positioning of drawn elements, the coordinate system starts at 0,0 + for the top left corner of the page.

    + +

    + Tip: While the {@link android.graphics.Canvas} object allows you to place print + elements on the edge of a PDF document, many printers are not able to print to the edge of a + physical piece of paper. Make sure that you account for the unprintable edges of the page when + you build a print document with this class. +

    diff --git a/docs/html/training/printing/html-docs.jd b/docs/html/training/printing/html-docs.jd new file mode 100644 index 0000000000000..2c7f8e3043383 --- /dev/null +++ b/docs/html/training/printing/html-docs.jd @@ -0,0 +1,175 @@ +page.title=Printing HTML Documents +parent.title=Printing Content +parent.link=index.html + +trainingnavtop=true +next.title=Printing Custom Documents +next.link=custom-docs.html + +@jd:body + +
    +
    + +

    This lesson teaches you to

    +
      +
    1. Load an HTML Document
    2. +
    3. Create a Print Job
    4. +
    + +
    +
    + +

    Printing out content beyond a simple photo on Android requires composing text and graphics in a + print document. The Android framework provides a way to use HTML to compose a document and + print it with a minimum of code.

    + +

    In Android 4.4 (API level 19), the {@link android.webkit.WebView} class has been updated to + enable printing HTML content. The class allows you to load a local HTML resource or download + a page from the web, create a print job and hand it off to Android's print services.

    + +

    This lesson shows you how to quickly build an HTML document containing text and graphics and +use {@link android.webkit.WebView} to print it.

    + + +

    Load an HTML Document

    + +

    Printing an HTML document with {@link android.webkit.WebView} involves loading an HTML + resource or building an HTML document as a string. This section describes how to build an HTML + string and load it into a {@link android.webkit.WebView} for printing.

    + +

    This view object is typically used as part of an activity layout. However, if your application + is not using a {@link android.webkit.WebView}, you can create an instance of the class + specifically for printing purposes. The main steps for creating this custom print view are:

    + +
      +
    1. Create a {@link android.webkit.WebViewClient} that starts a print job after + the HTML resource is loaded.
    2. +
    3. Load the HTML resource into the {@link android.webkit.WebView} object.
    4. +
    + +

    The following code sample demonstrates how to create a simple {@link + android.webkit.WebViewClient} and load an HTML document created on the fly:

    + +
    +private WebView mWebView;
    +
    +private void doWebViewPrint() {
    +    // Create a WebView object specifically for printing
    +    WebView webView = new WebView(getActivity());
    +    webView.setWebViewClient(new WebViewClient() {
    +
    +            public boolean shouldOverrideUrlLoading(WebView view, String url) {
    +                return false;
    +            }
    +
    +            @Override
    +            public void onPageFinished(WebView view, String url) {
    +                Log.i(TAG, "page finished loading " + url);
    +                createWebPrintJob(view);
    +                mWebView = null;
    +            }
    +    });
    +
    +    // Generate an HTML document on the fly:
    +    String htmlDocument = "<html><body><h1>Test Content</h1><p>Testing, " +
    +            "testing, testing...</p></body></html>";
    +    webView.loadDataWithBaseURL(null, htmlDocument, "text/HTML", "UTF-8", null);
    +
    +    // Keep a reference to WebView object until you pass the PrintDocumentAdapter
    +    // to the PrintManager
    +    mWebView = webView;
    +}
    +
    + +

    + Note: Make sure your call for generating a print job happens in the {@link + android.webkit.WebViewClient#onPageFinished onPageFinished()} method of the {@link + android.webkit.WebViewClient} you created in the previous section. If you don't wait until page + loading is finished, the print output may be incomplete or blank, or may fail completely. +

    + +

    + Note: The example code above holds an instance of the + {@link android.webkit.WebView} object so that is it not garbage collected before the print job + is created. Make sure you do the same in your own implementation, otherwise the print process + may fail. +

    + +

    + If you want to include graphics in the page, place the graphic files in the {@code assets/} + directory of your project and specify a base URL in the first parameter of the + {@link android.webkit.WebView#loadDataWithBaseURL loadDataWithBaseURL()} method, as shown in the + following code example: +

    + +
    +webView.loadDataWithBaseURL("file:///android_asset/images/", htmlBody,
    +        "text/HTML", "UTF-8", null);
    +
    + +

    You can also load a web page for printing by replacing the + {@link android.webkit.WebView#loadDataWithBaseURL loadDataWithBaseURL()} method with + {@link android.webkit.WebView#loadUrl loadUrl()} as shown below.

    + +
    +// Print an existing web page (remember to request INTERNET permission!):
    +webView.loadUrl("http://developer.android.com/about/index.html");
    +
    + +

    When using {@link android.webkit.WebView} for creating print documents, you should be aware of + the following limitations:

    + +
      +
    • You cannot add headers or footers, including page numbers, to the document.
    • +
    • The printing options for the HTML document do not include the ability to print page + ranges, for example: Printing page 2 to 4 of a 10 page HTML document is not supported.
    • +
    • An instance of {@link android.webkit.WebView} can only process one print job at a time.
    • +
    • An HTML document containing CSS print attributes, such as landscape properties, is not + supported.
    • +
    • You cannot use JavaScript in a HTML document to trigger printing.
    • +
    + +

    + Note: The content of a {@link android.webkit.WebView} object that is included in + a layout can also be printed once it has loaded a document. +

    + +

    If you want to create a more customized print output and have complete control of the content + draw on the printed page, jump to the next lesson: + Printing a Custom Document lesson.

    + + + + +

    After creating a {@link android.webkit.WebView} and loading your HTML content, your + application is almost done with its part of the printing process. The next steps are accessing + the {@link android.print.PrintManager}, creating a print adapter, and finally, creating a print + job. The following example illustrates how to perform these steps:

    + +
    +private void createWebPrintJob(WebView webView) {
    +
    +    // Get a PrintManager instance
    +    PrintManager printManager = (PrintManager) getActivity()
    +            .getSystemService(Context.PRINT_SERVICE);
    +
    +    // Get a print adapter instance
    +    PrintDocumentAdapter printAdapter = webView.createPrintDocumentAdapter();
    +
    +    // Create a print job with name and adapter instance
    +    String jobName = getString(R.string.app_name) + " Document";
    +    PrintJob printJob = printManager.print(jobName, printAdapter,
    +            new PrintAttributes.Builder().build());
    +
    +    // Save the job object for later status checking
    +    mPrintJobs.add(printJob);
    +}
    +
    + +

    This example saves an instance of the {@link android.print.PrintJob} object for use by the + application, which is not required. Your application may use this object to track the progress of + the print job as it's being processed. This approach is useful when you want to monitor the status + of the print job in you application for completion, failure, or user cancellation. Creating an + in-app notification is not required, because the print framework automatically creates a system + notification for the print job.

    diff --git a/docs/html/training/printing/index.jd b/docs/html/training/printing/index.jd new file mode 100644 index 0000000000000..7b67b746707b9 --- /dev/null +++ b/docs/html/training/printing/index.jd @@ -0,0 +1,57 @@ +page.title=Printing Content +page.tags="print","navigation","gesturedetector","scroller" + +trainingnavtop=true +startpage=true +@jd:body + +
    +
    + +

    Dependencies and prerequisites

    + +
      +
    • Android 4.4 (API Level 19) or higher
    • +
    + +
    +
    + +

    + Android users frequently view content solely on their devices, but there are times when + showing someone a screen is not an adequate way to share information. Being able to print + information from your Android application gives users a way to see a larger version of the + content from your app or share it with another person who is not using your application. + Printing also allows them to create a snapshot of information that does not depend on having a + device, sufficient battery power, or a wireless network connection. +

    + +

    + In Android 4.4 (API level 19) and higher, the framework provides services for printing images and + documents directly from Android applications. This training describes how to enable printing in + your application, including printing images, HTML pages and creating custom documents for + printing. +

    + + +

    Lessons

    + +
    +
    + Printing a Photo +
    +
    This lesson shows you how to print an image.
    + +
    + Printing an HTML Document +
    +
    This lesson shows you how to print an HTML document.
    + +
    + Printing a Custom Document +
    +
    This lesson shows you how you connect to the Android print manager, create a print adapter + and build content for printing.
    +
    + + diff --git a/docs/html/training/printing/photos.jd b/docs/html/training/printing/photos.jd new file mode 100644 index 0000000000000..f0289ef0d95aa --- /dev/null +++ b/docs/html/training/printing/photos.jd @@ -0,0 +1,84 @@ +page.title=Printing Photos +parent.title=Printing Content +parent.link=index.html + +trainingnavtop=true +next.title=Printing HTML Documents +next.link=html-docs.html + +@jd:body + +
    +
    + +

    This lesson teaches you to

    +
      +
    1. Print an Image
    2. +
    + +
    +
    + +

    + Taking and sharing photos is one of the most popular uses for mobile devices. If your application + takes photos, displays them, or allows users to share images, you should consider enabling printing + of those images in your application. The Android Support Library provides a convenient function for enabling image printing using a + minimal amount of code and simple set of print layout options. +

    + +

    This lesson shows you how to print an image using the v4 support library {@link + android.support.v4.print.PrintHelper} class.

    + + +

    Print an Image

    + +

    The Android Support Library {@link android.support.v4.print.PrintHelper} class provides + a simple way to print of images. The class has a single layout option, {@link + android.support.v4.print.PrintHelper#setScaleMode setScaleMode()}, which allows you to print with + one of two options:

    + +
      +
    • {@link android.support.v4.print.PrintHelper#SCALE_MODE_FIT SCALE_MODE_FIT} - This + option sizes the image so that the whole image is shown within the printable area of the page. +
    • +
    • {@link android.support.v4.print.PrintHelper#SCALE_MODE_FILL SCALE_MODE_FILL} - This + option scales the image so that it fills the entire printable area of the page. Choosing this + setting means that some portion of the top and bottom, or left and right edges of the image is + not printed. This option is the default value if you do not set a scale mode.
    • +
    + +

    Both scaling options for {@link android.support.v4.print.PrintHelper#setScaleMode + setScaleMode()} keep the existing aspect ratio of the image intact. The following code example + shows how to create an instance of the {@link android.support.v4.print.PrintHelper} class, set the + scaling option, and start the printing process:

    + +
    +private void doPhotoPrint() {
    +    PrintHelper photoPrinter = new PrintHelper(getActivity());
    +    photoPrinter.setScaleMode(PrintHelper.SCALE_MODE_FIT);
    +    Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
    +            R.drawable.droids);
    +    photoPrinter.printBitmap("droids.jpg - test print", bitmap);
    +}
    +
    + +

    + This method can be called as the action for a menu item. Note that menu items for actions that are + not always supported (such as printing) should be placed in the overflow menu. For more + information, see the Action Bar design + guide. +

    + +

    After the {@link android.support.v4.print.PrintHelper#printBitmap printBitmap()} method is + called, no further action from your application is required. The Android print user interface + appears, allowing the user to select a printer and printing options. The user can then print the + image or cancel the action. If the user chooses to print the image, a print job is created and a + printing notification appears in the system bar.

    + +

    If you want to include additional content in your printouts beyond just an image, you must + construct a print document. For information on creating documents for printing, see the + Printing an HTML Document or + Printing a Custom Document + lessons.

    + diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs index 39386bc1cc667..f176437836dc5 100644 --- a/docs/html/training/training_toc.cs +++ b/docs/html/training/training_toc.cs @@ -335,6 +335,30 @@ include the action bar on devices running Android 2.1 or higher." + + + From eb76848f8f74c77c3ad940f3264f7609cde8de3f Mon Sep 17 00:00:00 2001 From: Dirk Dougherty Date: Tue, 29 Oct 2013 22:25:12 -0700 Subject: [PATCH 7/8] Doc change: Google Play services 4.0 reference docs. Change-Id: I61c536a80a720364eadec727b9c870d5b869be1a (cherry picked from commit 28167899617b59874aeeb0f6cd822ca2f6cc9e55) --- docs/html/gms_navtree_data.js | 29 +- docs/html/google/index.jd | 4 +- docs/html/google/play-services/id.jd | 15 +- docs/html/google/play-services/wallet.jd | 15 +- .../html/images/google/gps-wallet-instant.png | Bin 0 -> 6462 bytes docs/html/images/google/gps-wallet.png | Bin 49724 -> 0 bytes .../com/google/android/gms/R.attr.html | 288 +- .../com/google/android/gms/R.color.html | 40 +- .../com/google/android/gms/R.drawable.html | 40 +- .../reference/com/google/android/gms/R.html | 54 +- .../com/google/android/gms/R.id.html | 134 +- .../com/google/android/gms/R.integer.html | 1213 ++ .../com/google/android/gms/R.string.html | 94 +- .../com/google/android/gms/R.styleable.html | 497 +- .../google/android/gms/ads/AdListener.html | 1418 ++ .../android/gms/ads/AdRequest.Builder.html | 1553 ++ .../com/google/android/gms/ads/AdRequest.html | 1780 ++ .../com/google/android/gms/ads/AdSize.html | 2001 +++ .../com/google/android/gms/ads/AdView.html | 13649 ++++++++++++++++ .../android/gms/ads/InterstitialAd.html | 1618 ++ .../identifier/AdvertisingIdClient.Info.html} | 337 +- .../ads/identifier/AdvertisingIdClient.html | 1294 ++ .../gms/ads/identifier/package-summary.html | 736 + .../gms/ads/mediation/NetworkExtras.html | 867 + .../gms/ads/mediation/admob/AdMobExtras.html | 1239 ++ .../ads/mediation/admob/package-summary.html | 736 + .../customevent/CustomEventExtras.html} | 606 +- .../customevent/package-summary.html | 736 + .../gms/ads/mediation/package-summary.html | 736 + .../android/gms/ads/package-summary.html | 756 + .../google/android/gms/appstate/AppState.html | 40 +- .../android/gms/appstate/AppStateBuffer.html | 40 +- .../gms/appstate/AppStateClient.Builder.html | 40 +- .../android/gms/appstate/AppStateClient.html | 42 +- .../appstate/OnSignOutCompleteListener.html | 40 +- .../gms/appstate/OnStateDeletedListener.html | 40 +- .../appstate/OnStateListLoadedListener.html | 40 +- .../gms/appstate/OnStateLoadedListener.html | 40 +- .../android/gms/appstate/package-summary.html | 40 +- .../android/gms/auth/GoogleAuthException.html | 40 +- .../android/gms/auth/GoogleAuthUtil.html | 88 +- ...oglePlayServicesAvailabilityException.html | 40 +- .../android/gms/auth/RecoveryDecision.html | 1700 ++ .../auth/UserRecoverableAuthException.html | 40 +- .../UserRecoverableNotifiedException.html | 40 +- .../android/gms/auth/package-summary.html | 44 +- .../android/gms/common/AccountPicker.html | 40 +- .../android/gms/common/ConnectionResult.html | 109 +- ...layServicesClient.ConnectionCallbacks.html | 40 +- ...icesClient.OnConnectionFailedListener.html | 40 +- .../gms/common/GooglePlayServicesClient.html | 48 +- ...oglePlayServicesNotAvailableException.html | 40 +- ...GooglePlayServicesRepairableException.html | 1485 ++ .../gms/common/GooglePlayServicesUtil.html | 47 +- .../com/google/android/gms/common/Scopes.html | 40 +- .../android/gms/common/SignInButton.html | 1639 +- .../gms/common/UserRecoverableException.html | 1515 ++ .../gms/common/annotation/KeepName.html | 40 +- .../android/gms/common/data/DataBuffer.html | 40 +- .../gms/common/data/DataBufferUtils.html | 40 +- .../android/gms/common/data/Freezable.html | 82 +- .../gms/common/data/package-summary.html | 40 +- .../ImageManager.OnImageLoadedListener.html | 40 +- .../gms/common/images/ImageManager.html | 66 +- .../gms/common/images/package-summary.html | 40 +- .../android/gms/common/package-summary.html | 51 +- .../com/google/android/gms/games/Game.html | 40 +- .../google/android/gms/games/GameBuffer.html | 40 +- .../google/android/gms/games/GameEntity.html | 40 +- .../gms/games/GamesActivityResultCodes.html | 40 +- .../gms/games/GamesClient.Builder.html | 40 +- .../google/android/gms/games/GamesClient.html | 521 +- .../gms/games/OnGamesLoadedListener.html | 40 +- .../gms/games/OnPlayersLoadedListener.html | 40 +- .../gms/games/OnSignOutCompleteListener.html | 40 +- .../android/gms/games/PageDirection.html | 40 +- .../com/google/android/gms/games/Player.html | 40 +- .../android/gms/games/PlayerBuffer.html | 40 +- .../android/gms/games/PlayerEntity.html | 40 +- .../gms/games/achievement/Achievement.html | 40 +- .../games/achievement/AchievementBuffer.html | 40 +- .../OnAchievementUpdatedListener.html | 40 +- .../OnAchievementsLoadedListener.html | 40 +- .../games/achievement/package-summary.html | 40 +- .../gms/games/leaderboard/Leaderboard.html | 40 +- .../games/leaderboard/LeaderboardBuffer.html | 40 +- .../games/leaderboard/LeaderboardScore.html | 176 +- .../leaderboard/LeaderboardScoreBuffer.html | 40 +- .../games/leaderboard/LeaderboardVariant.html | 98 +- .../OnLeaderboardMetadataLoadedListener.html | 40 +- .../OnLeaderboardScoresLoadedListener.html | 40 +- .../leaderboard/OnScoreSubmittedListener.html | 40 +- .../leaderboard/SubmitScoreResult.Result.html | 86 +- .../games/leaderboard/SubmitScoreResult.html | 40 +- .../games/leaderboard/package-summary.html | 40 +- .../gms/games/multiplayer/Invitation.html | 40 +- .../games/multiplayer/InvitationBuffer.html | 40 +- .../games/multiplayer/InvitationEntity.html | 40 +- .../OnInvitationReceivedListener.html | 40 +- .../OnInvitationsLoadedListener.html | 40 +- .../gms/games/multiplayer/Participant.html | 40 +- .../games/multiplayer/ParticipantBuffer.html | 40 +- .../games/multiplayer/ParticipantEntity.html | 40 +- .../games/multiplayer/ParticipantUtils.html | 40 +- .../gms/games/multiplayer/Participatable.html | 40 +- .../games/multiplayer/package-summary.html | 40 +- .../multiplayer/realtime/RealTimeMessage.html | 40 +- .../RealTimeMessageReceivedListener.html | 40 +- .../RealTimeReliableMessageSentListener.html | 40 +- .../realtime}/RealTimeSocket.html | 76 +- .../gms/games/multiplayer/realtime/Room.html | 40 +- .../realtime/RoomConfig.Builder.html | 43 +- .../multiplayer/realtime/RoomConfig.html | 40 +- .../multiplayer/realtime/RoomEntity.html | 40 +- .../realtime/RoomStatusUpdateListener.html | 40 +- .../realtime/RoomUpdateListener.html | 40 +- .../multiplayer/realtime/package-summary.html | 49 +- .../android/gms/games/package-summary.html | 45 +- .../android/gms/gcm/GoogleCloudMessaging.html | 40 +- .../android/gms/gcm/package-summary.html | 40 +- .../location/ActivityRecognitionClient.html | 45 +- .../location/ActivityRecognitionResult.html | 40 +- .../gms/location/DetectedActivity.html | 40 +- .../gms/location/Geofence.Builder.html | 177 +- .../google/android/gms/location/Geofence.html | 98 +- ...onClient.OnAddGeofencesResultListener.html | 40 +- ...lient.OnRemoveGeofencesResultListener.html | 40 +- .../android/gms/location/LocationClient.html | 40 +- .../gms/location/LocationListener.html | 40 +- .../android/gms/location/LocationRequest.html | 40 +- .../gms/location/LocationStatusCodes.html | 40 +- .../android/gms/location/package-summary.html | 40 +- .../google/android/gms/maps/CameraUpdate.html | 40 +- .../android/gms/maps/CameraUpdateFactory.html | 40 +- .../maps/GoogleMap.CancelableCallback.html | 40 +- .../gms/maps/GoogleMap.InfoWindowAdapter.html | 40 +- .../GoogleMap.OnCameraChangeListener.html | 40 +- .../GoogleMap.OnInfoWindowClickListener.html | 40 +- .../maps/GoogleMap.OnMapClickListener.html | 40 +- .../maps/GoogleMap.OnMapLoadedCallback.html | 912 ++ .../GoogleMap.OnMapLongClickListener.html | 40 +- .../maps/GoogleMap.OnMarkerClickListener.html | 40 +- .../maps/GoogleMap.OnMarkerDragListener.html | 40 +- ...leMap.OnMyLocationButtonClickListener.html | 40 +- .../GoogleMap.OnMyLocationChangeListener.html | 40 +- .../maps/GoogleMap.SnapshotReadyCallback.html | 40 +- .../google/android/gms/maps/GoogleMap.html | 267 +- .../android/gms/maps/GoogleMapOptions.html | 40 +- ...ationSource.OnLocationChangedListener.html | 40 +- .../android/gms/maps/LocationSource.html | 40 +- .../google/android/gms/maps/MapFragment.html | 118 +- .../com/google/android/gms/maps/MapView.html | 1639 +- .../android/gms/maps/MapsInitializer.html | 40 +- .../google/android/gms/maps/Projection.html | 40 +- .../android/gms/maps/SupportMapFragment.html | 40 +- .../google/android/gms/maps/UiSettings.html | 40 +- .../gms/maps/model/BitmapDescriptor.html | 40 +- .../maps/model/BitmapDescriptorFactory.html | 40 +- .../maps/model/CameraPosition.Builder.html | 40 +- .../gms/maps/model/CameraPosition.html | 40 +- .../google/android/gms/maps/model/Circle.html | 42 +- .../android/gms/maps/model/CircleOptions.html | 40 +- .../android/gms/maps/model/GroundOverlay.html | 97 +- .../gms/maps/model/GroundOverlayOptions.html | 40 +- .../google/android/gms/maps/model/LatLng.html | 40 +- .../gms/maps/model/LatLngBounds.Builder.html | 40 +- .../android/gms/maps/model/LatLngBounds.html | 40 +- .../google/android/gms/maps/model/Marker.html | 163 +- .../android/gms/maps/model/MarkerOptions.html | 151 +- .../android/gms/maps/model/Polygon.html | 40 +- .../gms/maps/model/PolygonOptions.html | 40 +- .../android/gms/maps/model/Polyline.html | 40 +- .../gms/maps/model/PolylineOptions.html | 40 +- .../maps/model/RuntimeRemoteException.html | 40 +- .../google/android/gms/maps/model/Tile.html | 40 +- .../android/gms/maps/model/TileOverlay.html | 40 +- .../gms/maps/model/TileOverlayOptions.html | 40 +- .../android/gms/maps/model/TileProvider.html | 40 +- .../gms/maps/model/UrlTileProvider.html | 40 +- .../android/gms/maps/model/VisibleRegion.html | 40 +- .../gms/maps/model/package-summary.html | 40 +- .../android/gms/maps/package-summary.html | 58 +- .../google/android/gms/package-summary.html | 46 +- ...maClient.OnPanoramaInfoLoadedListener.html | 40 +- .../android/gms/panorama/PanoramaClient.html | 40 +- .../android/gms/panorama/package-summary.html | 40 +- .../android/gms/plus/PlusClient.Builder.html | 88 +- .../PlusClient.OnAccessRevokedListener.html | 40 +- .../PlusClient.OnMomentsLoadedListener.html | 40 +- .../PlusClient.OnPeopleLoadedListener.html | 40 +- .../android/gms/plus/PlusClient.OrderBy.html | 40 +- .../google/android/gms/plus/PlusClient.html | 106 +- ...eButton.DefaultOnPlusOneClickListener.html | 40 +- .../PlusOneButton.OnPlusOneClickListener.html | 40 +- .../android/gms/plus/PlusOneButton.html | 1639 +- .../gms/plus/PlusOneButtonWithPopup.html | 1639 +- .../android/gms/plus/PlusOneDummyView.html | 1639 +- .../android/gms/plus/PlusShare.Builder.html | 109 +- .../google/android/gms/plus/PlusShare.html | 109 +- .../plus/model/moments/ItemScope.Builder.html | 40 +- .../gms/plus/model/moments/ItemScope.html | 40 +- .../plus/model/moments/Moment.Builder.html | 40 +- .../gms/plus/model/moments/Moment.html | 40 +- .../gms/plus/model/moments/MomentBuffer.html | 40 +- .../plus/model/moments/package-summary.html | 40 +- .../plus/model/people/Person.AgeRange.html | 40 +- .../model/people/Person.Cover.CoverInfo.html | 52 +- .../model/people/Person.Cover.CoverPhoto.html | 52 +- .../model/people/Person.Cover.Layout.html | 40 +- .../gms/plus/model/people/Person.Cover.html | 40 +- .../gms/plus/model/people/Person.Gender.html | 40 +- .../gms/plus/model/people/Person.Image.html | 42 +- .../gms/plus/model/people/Person.Name.html | 40 +- .../plus/model/people/Person.ObjectType.html | 40 +- .../people/Person.Organizations.Type.html | 40 +- .../model/people/Person.Organizations.html | 40 +- .../plus/model/people/Person.PlacesLived.html | 40 +- .../people/Person.RelationshipStatus.html | 40 +- .../plus/model/people/Person.Urls.Type.html | 40 +- .../gms/plus/model/people/Person.Urls.html | 40 +- .../android/gms/plus/model/people/Person.html | 230 +- .../gms/plus/model/people/PersonBuffer.html | 40 +- .../plus/model/people/package-summary.html | 79 +- .../android/gms/plus/package-summary.html | 40 +- .../google/android/gms/wallet/Address.html | 2045 +++ .../android/gms/wallet/Cart.Builder.html | 1351 ++ .../com/google/android/gms/wallet/Cart.html | 1710 ++ .../EnableWalletOptimizationReceiver.html | 1558 ++ .../google/android/gms/wallet/FullWallet.html | 1848 +++ .../gms/wallet/FullWalletRequest.Builder.html | 1306 ++ .../android/gms/wallet/FullWalletRequest.html | 1710 ++ .../android/gms/wallet/LineItem.Builder.html | 1454 ++ .../LineItem.Role.html} | 145 +- .../google/android/gms/wallet/LineItem.html | 1876 +++ .../gms/wallet/LoyaltyWalletObject.html | 1745 ++ .../android/gms/wallet/MaskedWallet.html | 1899 +++ .../wallet/MaskedWalletRequest.Builder.html | 1662 ++ .../gms/wallet/MaskedWalletRequest.html | 2062 +++ ...otifyTransactionStatusRequest.Builder.html | 1307 ++ ...TransactionStatusRequest.Status.Error.html | 1177 ++ ...otifyTransactionStatusRequest.Status.html} | 96 +- .../NotifyTransactionStatusRequest.html | 1729 ++ .../android/gms/wallet/OfferWalletObject.html | 1597 ++ .../google/android/gms/wallet/ProxyCard.html | 1692 ++ .../android/gms/wallet/WalletClient.html | 2443 +++ .../android/gms/wallet/WalletConstants.html | 2099 +++ .../android/gms/wallet/package-summary.html | 829 + docs/html/reference/gms-packages.html | 116 +- docs/html/reference/gms_lists.js | 432 +- 249 files changed, 86131 insertions(+), 5769 deletions(-) create mode 100644 docs/html/images/google/gps-wallet-instant.png delete mode 100644 docs/html/images/google/gps-wallet.png create mode 100644 docs/html/reference/com/google/android/gms/R.integer.html create mode 100644 docs/html/reference/com/google/android/gms/ads/AdListener.html create mode 100644 docs/html/reference/com/google/android/gms/ads/AdRequest.Builder.html create mode 100644 docs/html/reference/com/google/android/gms/ads/AdRequest.html create mode 100644 docs/html/reference/com/google/android/gms/ads/AdSize.html create mode 100644 docs/html/reference/com/google/android/gms/ads/AdView.html create mode 100644 docs/html/reference/com/google/android/gms/ads/InterstitialAd.html rename docs/html/reference/com/google/android/gms/{plus/model/people/Person.Emails.Type.html => ads/identifier/AdvertisingIdClient.Info.html} (89%) create mode 100644 docs/html/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient.html create mode 100644 docs/html/reference/com/google/android/gms/ads/identifier/package-summary.html create mode 100644 docs/html/reference/com/google/android/gms/ads/mediation/NetworkExtras.html create mode 100644 docs/html/reference/com/google/android/gms/ads/mediation/admob/AdMobExtras.html create mode 100644 docs/html/reference/com/google/android/gms/ads/mediation/admob/package-summary.html rename docs/html/reference/com/google/android/gms/{plus/model/people/Person.Emails.html => ads/mediation/customevent/CustomEventExtras.html} (80%) create mode 100644 docs/html/reference/com/google/android/gms/ads/mediation/customevent/package-summary.html create mode 100644 docs/html/reference/com/google/android/gms/ads/mediation/package-summary.html create mode 100644 docs/html/reference/com/google/android/gms/ads/package-summary.html create mode 100644 docs/html/reference/com/google/android/gms/auth/RecoveryDecision.html create mode 100644 docs/html/reference/com/google/android/gms/common/GooglePlayServicesRepairableException.html create mode 100644 docs/html/reference/com/google/android/gms/common/UserRecoverableException.html rename docs/html/reference/com/google/android/gms/games/{ => multiplayer/realtime}/RealTimeSocket.html (91%) create mode 100644 docs/html/reference/com/google/android/gms/maps/GoogleMap.OnMapLoadedCallback.html create mode 100644 docs/html/reference/com/google/android/gms/wallet/Address.html create mode 100644 docs/html/reference/com/google/android/gms/wallet/Cart.Builder.html create mode 100644 docs/html/reference/com/google/android/gms/wallet/Cart.html create mode 100644 docs/html/reference/com/google/android/gms/wallet/EnableWalletOptimizationReceiver.html create mode 100644 docs/html/reference/com/google/android/gms/wallet/FullWallet.html create mode 100644 docs/html/reference/com/google/android/gms/wallet/FullWalletRequest.Builder.html create mode 100644 docs/html/reference/com/google/android/gms/wallet/FullWalletRequest.html create mode 100644 docs/html/reference/com/google/android/gms/wallet/LineItem.Builder.html rename docs/html/reference/com/google/android/gms/{plus/model/people/Person.OrderBy.html => wallet/LineItem.Role.html} (89%) create mode 100644 docs/html/reference/com/google/android/gms/wallet/LineItem.html create mode 100644 docs/html/reference/com/google/android/gms/wallet/LoyaltyWalletObject.html create mode 100644 docs/html/reference/com/google/android/gms/wallet/MaskedWallet.html create mode 100644 docs/html/reference/com/google/android/gms/wallet/MaskedWalletRequest.Builder.html create mode 100644 docs/html/reference/com/google/android/gms/wallet/MaskedWalletRequest.html create mode 100644 docs/html/reference/com/google/android/gms/wallet/NotifyTransactionStatusRequest.Builder.html create mode 100644 docs/html/reference/com/google/android/gms/wallet/NotifyTransactionStatusRequest.Status.Error.html rename docs/html/reference/com/google/android/gms/{plus/model/people/Person.Collection.html => wallet/NotifyTransactionStatusRequest.Status.html} (91%) create mode 100644 docs/html/reference/com/google/android/gms/wallet/NotifyTransactionStatusRequest.html create mode 100644 docs/html/reference/com/google/android/gms/wallet/OfferWalletObject.html create mode 100644 docs/html/reference/com/google/android/gms/wallet/ProxyCard.html create mode 100644 docs/html/reference/com/google/android/gms/wallet/WalletClient.html create mode 100644 docs/html/reference/com/google/android/gms/wallet/WalletConstants.html create mode 100644 docs/html/reference/com/google/android/gms/wallet/package-summary.html diff --git a/docs/html/gms_navtree_data.js b/docs/html/gms_navtree_data.js index a4f7df306ebbd..86bfea4a638f3 100644 --- a/docs/html/gms_navtree_data.js +++ b/docs/html/gms_navtree_data.js @@ -1,15 +1,25 @@ var GMS_NAVTREE_DATA = -[ [ "com.google.android.gms", "reference/com/google/android/gms/package-summary.html", [ [ "Classes", null, [ [ "R", "reference/com/google/android/gms/R.html", null, null ], [ "R.attr", "reference/com/google/android/gms/R.attr.html", null, null ], [ "R.color", "reference/com/google/android/gms/R.color.html", null, null ], [ "R.drawable", "reference/com/google/android/gms/R.drawable.html", null, null ], [ "R.id", "reference/com/google/android/gms/R.id.html", null, null ], [ "R.string", "reference/com/google/android/gms/R.string.html", null, null ], [ "R.styleable", "reference/com/google/android/gms/R.styleable.html", null, null ] ] +[ [ "com.google.android.gms", "reference/com/google/android/gms/package-summary.html", [ [ "Classes", null, [ [ "R", "reference/com/google/android/gms/R.html", null, null ], [ "R.attr", "reference/com/google/android/gms/R.attr.html", null, null ], [ "R.color", "reference/com/google/android/gms/R.color.html", null, null ], [ "R.drawable", "reference/com/google/android/gms/R.drawable.html", null, null ], [ "R.id", "reference/com/google/android/gms/R.id.html", null, null ], [ "R.integer", "reference/com/google/android/gms/R.integer.html", null, null ], [ "R.string", "reference/com/google/android/gms/R.string.html", null, null ], [ "R.styleable", "reference/com/google/android/gms/R.styleable.html", null, null ] ] +, null ] ] +, null ], [ "com.google.android.gms.ads", "reference/com/google/android/gms/ads/package-summary.html", [ [ "Classes", null, [ [ "AdListener", "reference/com/google/android/gms/ads/AdListener.html", null, null ], [ "AdRequest", "reference/com/google/android/gms/ads/AdRequest.html", null, null ], [ "AdRequest.Builder", "reference/com/google/android/gms/ads/AdRequest.Builder.html", null, null ], [ "AdSize", "reference/com/google/android/gms/ads/AdSize.html", null, null ], [ "AdView", "reference/com/google/android/gms/ads/AdView.html", null, null ], [ "InterstitialAd", "reference/com/google/android/gms/ads/InterstitialAd.html", null, null ] ] +, null ] ] +, null ], [ "com.google.android.gms.ads.identifier", "reference/com/google/android/gms/ads/identifier/package-summary.html", [ [ "Classes", null, [ [ "AdvertisingIdClient", "reference/com/google/android/gms/ads/identifier/AdvertisingIdClient.html", null, null ], [ "AdvertisingIdClient.Info", "reference/com/google/android/gms/ads/identifier/AdvertisingIdClient.Info.html", null, null ] ] +, null ] ] +, null ], [ "com.google.android.gms.ads.mediation", "reference/com/google/android/gms/ads/mediation/package-summary.html", [ [ "Interfaces", null, [ [ "NetworkExtras", "reference/com/google/android/gms/ads/mediation/NetworkExtras.html", null, null ] ] +, null ] ] +, null ], [ "com.google.android.gms.ads.mediation.admob", "reference/com/google/android/gms/ads/mediation/admob/package-summary.html", [ [ "Classes", null, [ [ "AdMobExtras", "reference/com/google/android/gms/ads/mediation/admob/AdMobExtras.html", null, null ] ] +, null ] ] +, null ], [ "com.google.android.gms.ads.mediation.customevent", "reference/com/google/android/gms/ads/mediation/customevent/package-summary.html", [ [ "Classes", null, [ [ "CustomEventExtras", "reference/com/google/android/gms/ads/mediation/customevent/CustomEventExtras.html", null, null ] ] , null ] ] , null ], [ "com.google.android.gms.appstate", "reference/com/google/android/gms/appstate/package-summary.html", [ [ "Interfaces", null, [ [ "AppState", "reference/com/google/android/gms/appstate/AppState.html", null, null ], [ "OnSignOutCompleteListener", "reference/com/google/android/gms/appstate/OnSignOutCompleteListener.html", null, null ], [ "OnStateDeletedListener", "reference/com/google/android/gms/appstate/OnStateDeletedListener.html", null, null ], [ "OnStateListLoadedListener", "reference/com/google/android/gms/appstate/OnStateListLoadedListener.html", null, null ], [ "OnStateLoadedListener", "reference/com/google/android/gms/appstate/OnStateLoadedListener.html", null, null ] ] , null ], [ "Classes", null, [ [ "AppStateBuffer", "reference/com/google/android/gms/appstate/AppStateBuffer.html", null, null ], [ "AppStateClient", "reference/com/google/android/gms/appstate/AppStateClient.html", null, null ], [ "AppStateClient.Builder", "reference/com/google/android/gms/appstate/AppStateClient.Builder.html", null, null ] ] , null ] ] -, null ], [ "com.google.android.gms.auth", "reference/com/google/android/gms/auth/package-summary.html", [ [ "Classes", null, [ [ "GoogleAuthUtil", "reference/com/google/android/gms/auth/GoogleAuthUtil.html", null, null ] ] +, null ], [ "com.google.android.gms.auth", "reference/com/google/android/gms/auth/package-summary.html", [ [ "Classes", null, [ [ "GoogleAuthUtil", "reference/com/google/android/gms/auth/GoogleAuthUtil.html", null, null ], [ "RecoveryDecision", "reference/com/google/android/gms/auth/RecoveryDecision.html", null, null ] ] , null ], [ "Exceptions", null, [ [ "GoogleAuthException", "reference/com/google/android/gms/auth/GoogleAuthException.html", null, null ], [ "GooglePlayServicesAvailabilityException", "reference/com/google/android/gms/auth/GooglePlayServicesAvailabilityException.html", null, null ], [ "UserRecoverableAuthException", "reference/com/google/android/gms/auth/UserRecoverableAuthException.html", null, null ], [ "UserRecoverableNotifiedException", "reference/com/google/android/gms/auth/UserRecoverableNotifiedException.html", null, null ] ] , null ] ] , null ], [ "com.google.android.gms.common", "reference/com/google/android/gms/common/package-summary.html", [ [ "Interfaces", null, [ [ "GooglePlayServicesClient", "reference/com/google/android/gms/common/GooglePlayServicesClient.html", null, null ], [ "GooglePlayServicesClient.ConnectionCallbacks", "reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html", null, null ], [ "GooglePlayServicesClient.OnConnectionFailedListener", "reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html", null, null ] ] , null ], [ "Classes", null, [ [ "AccountPicker", "reference/com/google/android/gms/common/AccountPicker.html", null, null ], [ "ConnectionResult", "reference/com/google/android/gms/common/ConnectionResult.html", null, null ], [ "GooglePlayServicesUtil", "reference/com/google/android/gms/common/GooglePlayServicesUtil.html", null, null ], [ "Scopes", "reference/com/google/android/gms/common/Scopes.html", null, null ], [ "SignInButton", "reference/com/google/android/gms/common/SignInButton.html", null, null ] ] -, null ], [ "Exceptions", null, [ [ "GooglePlayServicesNotAvailableException", "reference/com/google/android/gms/common/GooglePlayServicesNotAvailableException.html", null, null ] ] +, null ], [ "Exceptions", null, [ [ "GooglePlayServicesNotAvailableException", "reference/com/google/android/gms/common/GooglePlayServicesNotAvailableException.html", null, null ], [ "GooglePlayServicesRepairableException", "reference/com/google/android/gms/common/GooglePlayServicesRepairableException.html", null, null ], [ "UserRecoverableException", "reference/com/google/android/gms/common/UserRecoverableException.html", null, null ] ] , null ] ] , null ], [ "com.google.android.gms.common.data", "reference/com/google/android/gms/common/data/package-summary.html", [ [ "Interfaces", null, [ [ "Freezable", "reference/com/google/android/gms/common/data/Freezable.html", null, null ] ] , null ], [ "Classes", null, [ [ "DataBuffer", "reference/com/google/android/gms/common/data/DataBuffer.html", null, null ], [ "DataBufferUtils", "reference/com/google/android/gms/common/data/DataBufferUtils.html", null, null ] ] @@ -17,7 +27,7 @@ var GMS_NAVTREE_DATA = , null ], [ "com.google.android.gms.common.images", "reference/com/google/android/gms/common/images/package-summary.html", [ [ "Interfaces", null, [ [ "ImageManager.OnImageLoadedListener", "reference/com/google/android/gms/common/images/ImageManager.OnImageLoadedListener.html", null, null ] ] , null ], [ "Classes", null, [ [ "ImageManager", "reference/com/google/android/gms/common/images/ImageManager.html", null, null ] ] , null ] ] -, null ], [ "com.google.android.gms.games", "reference/com/google/android/gms/games/package-summary.html", [ [ "Interfaces", null, [ [ "Game", "reference/com/google/android/gms/games/Game.html", null, null ], [ "OnGamesLoadedListener", "reference/com/google/android/gms/games/OnGamesLoadedListener.html", null, null ], [ "OnPlayersLoadedListener", "reference/com/google/android/gms/games/OnPlayersLoadedListener.html", null, null ], [ "OnSignOutCompleteListener", "reference/com/google/android/gms/games/OnSignOutCompleteListener.html", null, null ], [ "Player", "reference/com/google/android/gms/games/Player.html", null, null ], [ "RealTimeSocket", "reference/com/google/android/gms/games/RealTimeSocket.html", null, null ] ] +, null ], [ "com.google.android.gms.games", "reference/com/google/android/gms/games/package-summary.html", [ [ "Interfaces", null, [ [ "Game", "reference/com/google/android/gms/games/Game.html", null, null ], [ "OnGamesLoadedListener", "reference/com/google/android/gms/games/OnGamesLoadedListener.html", null, null ], [ "OnPlayersLoadedListener", "reference/com/google/android/gms/games/OnPlayersLoadedListener.html", null, null ], [ "OnSignOutCompleteListener", "reference/com/google/android/gms/games/OnSignOutCompleteListener.html", null, null ], [ "Player", "reference/com/google/android/gms/games/Player.html", null, null ] ] , null ], [ "Classes", null, [ [ "GameBuffer", "reference/com/google/android/gms/games/GameBuffer.html", null, null ], [ "GameEntity", "reference/com/google/android/gms/games/GameEntity.html", null, null ], [ "GamesActivityResultCodes", "reference/com/google/android/gms/games/GamesActivityResultCodes.html", null, null ], [ "GamesClient", "reference/com/google/android/gms/games/GamesClient.html", null, null ], [ "GamesClient.Builder", "reference/com/google/android/gms/games/GamesClient.Builder.html", null, null ], [ "PageDirection", "reference/com/google/android/gms/games/PageDirection.html", null, null ], [ "PlayerBuffer", "reference/com/google/android/gms/games/PlayerBuffer.html", null, null ], [ "PlayerEntity", "reference/com/google/android/gms/games/PlayerEntity.html", null, null ] ] , null ] ] , null ], [ "com.google.android.gms.games.achievement", "reference/com/google/android/gms/games/achievement/package-summary.html", [ [ "Interfaces", null, [ [ "Achievement", "reference/com/google/android/gms/games/achievement/Achievement.html", null, null ], [ "OnAchievementsLoadedListener", "reference/com/google/android/gms/games/achievement/OnAchievementsLoadedListener.html", null, null ], [ "OnAchievementUpdatedListener", "reference/com/google/android/gms/games/achievement/OnAchievementUpdatedListener.html", null, null ] ] @@ -29,7 +39,7 @@ var GMS_NAVTREE_DATA = , null ], [ "com.google.android.gms.games.multiplayer", "reference/com/google/android/gms/games/multiplayer/package-summary.html", [ [ "Interfaces", null, [ [ "Invitation", "reference/com/google/android/gms/games/multiplayer/Invitation.html", null, null ], [ "OnInvitationReceivedListener", "reference/com/google/android/gms/games/multiplayer/OnInvitationReceivedListener.html", null, null ], [ "OnInvitationsLoadedListener", "reference/com/google/android/gms/games/multiplayer/OnInvitationsLoadedListener.html", null, null ], [ "Participant", "reference/com/google/android/gms/games/multiplayer/Participant.html", null, null ], [ "Participatable", "reference/com/google/android/gms/games/multiplayer/Participatable.html", null, null ] ] , null ], [ "Classes", null, [ [ "InvitationBuffer", "reference/com/google/android/gms/games/multiplayer/InvitationBuffer.html", null, null ], [ "InvitationEntity", "reference/com/google/android/gms/games/multiplayer/InvitationEntity.html", null, null ], [ "ParticipantBuffer", "reference/com/google/android/gms/games/multiplayer/ParticipantBuffer.html", null, null ], [ "ParticipantEntity", "reference/com/google/android/gms/games/multiplayer/ParticipantEntity.html", null, null ], [ "ParticipantUtils", "reference/com/google/android/gms/games/multiplayer/ParticipantUtils.html", null, null ] ] , null ] ] -, null ], [ "com.google.android.gms.games.multiplayer.realtime", "reference/com/google/android/gms/games/multiplayer/realtime/package-summary.html", [ [ "Interfaces", null, [ [ "RealTimeMessageReceivedListener", "reference/com/google/android/gms/games/multiplayer/realtime/RealTimeMessageReceivedListener.html", null, null ], [ "RealTimeReliableMessageSentListener", "reference/com/google/android/gms/games/multiplayer/realtime/RealTimeReliableMessageSentListener.html", null, null ], [ "Room", "reference/com/google/android/gms/games/multiplayer/realtime/Room.html", null, null ], [ "RoomStatusUpdateListener", "reference/com/google/android/gms/games/multiplayer/realtime/RoomStatusUpdateListener.html", null, null ], [ "RoomUpdateListener", "reference/com/google/android/gms/games/multiplayer/realtime/RoomUpdateListener.html", null, null ] ] +, null ], [ "com.google.android.gms.games.multiplayer.realtime", "reference/com/google/android/gms/games/multiplayer/realtime/package-summary.html", [ [ "Interfaces", null, [ [ "RealTimeMessageReceivedListener", "reference/com/google/android/gms/games/multiplayer/realtime/RealTimeMessageReceivedListener.html", null, null ], [ "RealTimeReliableMessageSentListener", "reference/com/google/android/gms/games/multiplayer/realtime/RealTimeReliableMessageSentListener.html", null, null ], [ "RealTimeSocket", "reference/com/google/android/gms/games/multiplayer/realtime/RealTimeSocket.html", null, null ], [ "Room", "reference/com/google/android/gms/games/multiplayer/realtime/Room.html", null, null ], [ "RoomStatusUpdateListener", "reference/com/google/android/gms/games/multiplayer/realtime/RoomStatusUpdateListener.html", null, null ], [ "RoomUpdateListener", "reference/com/google/android/gms/games/multiplayer/realtime/RoomUpdateListener.html", null, null ] ] , null ], [ "Classes", null, [ [ "RealTimeMessage", "reference/com/google/android/gms/games/multiplayer/realtime/RealTimeMessage.html", null, null ], [ "RoomConfig", "reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.html", null, null ], [ "RoomConfig.Builder", "reference/com/google/android/gms/games/multiplayer/realtime/RoomConfig.Builder.html", null, null ], [ "RoomEntity", "reference/com/google/android/gms/games/multiplayer/realtime/RoomEntity.html", null, null ] ] , null ] ] , null ], [ "com.google.android.gms.gcm", "reference/com/google/android/gms/gcm/package-summary.html", [ [ "Classes", null, [ [ "GoogleCloudMessaging", "reference/com/google/android/gms/gcm/GoogleCloudMessaging.html", null, null ] ] @@ -37,7 +47,7 @@ var GMS_NAVTREE_DATA = , null ], [ "com.google.android.gms.location", "reference/com/google/android/gms/location/package-summary.html", [ [ "Interfaces", null, [ [ "Geofence", "reference/com/google/android/gms/location/Geofence.html", null, null ], [ "LocationClient.OnAddGeofencesResultListener", "reference/com/google/android/gms/location/LocationClient.OnAddGeofencesResultListener.html", null, null ], [ "LocationClient.OnRemoveGeofencesResultListener", "reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html", null, null ], [ "LocationListener", "reference/com/google/android/gms/location/LocationListener.html", null, null ] ] , null ], [ "Classes", null, [ [ "ActivityRecognitionClient", "reference/com/google/android/gms/location/ActivityRecognitionClient.html", null, null ], [ "ActivityRecognitionResult", "reference/com/google/android/gms/location/ActivityRecognitionResult.html", null, null ], [ "DetectedActivity", "reference/com/google/android/gms/location/DetectedActivity.html", null, null ], [ "Geofence.Builder", "reference/com/google/android/gms/location/Geofence.Builder.html", null, null ], [ "LocationClient", "reference/com/google/android/gms/location/LocationClient.html", null, null ], [ "LocationRequest", "reference/com/google/android/gms/location/LocationRequest.html", null, null ], [ "LocationStatusCodes", "reference/com/google/android/gms/location/LocationStatusCodes.html", null, null ] ] , null ] ] -, null ], [ "com.google.android.gms.maps", "reference/com/google/android/gms/maps/package-summary.html", [ [ "Interfaces", null, [ [ "GoogleMap.CancelableCallback", "reference/com/google/android/gms/maps/GoogleMap.CancelableCallback.html", null, null ], [ "GoogleMap.InfoWindowAdapter", "reference/com/google/android/gms/maps/GoogleMap.InfoWindowAdapter.html", null, null ], [ "GoogleMap.OnCameraChangeListener", "reference/com/google/android/gms/maps/GoogleMap.OnCameraChangeListener.html", null, null ], [ "GoogleMap.OnInfoWindowClickListener", "reference/com/google/android/gms/maps/GoogleMap.OnInfoWindowClickListener.html", null, null ], [ "GoogleMap.OnMapClickListener", "reference/com/google/android/gms/maps/GoogleMap.OnMapClickListener.html", null, null ], [ "GoogleMap.OnMapLongClickListener", "reference/com/google/android/gms/maps/GoogleMap.OnMapLongClickListener.html", null, null ], [ "GoogleMap.OnMarkerClickListener", "reference/com/google/android/gms/maps/GoogleMap.OnMarkerClickListener.html", null, null ], [ "GoogleMap.OnMarkerDragListener", "reference/com/google/android/gms/maps/GoogleMap.OnMarkerDragListener.html", null, null ], [ "GoogleMap.OnMyLocationButtonClickListener", "reference/com/google/android/gms/maps/GoogleMap.OnMyLocationButtonClickListener.html", null, null ], [ "GoogleMap.OnMyLocationChangeListener", "reference/com/google/android/gms/maps/GoogleMap.OnMyLocationChangeListener.html", null, null ], [ "GoogleMap.SnapshotReadyCallback", "reference/com/google/android/gms/maps/GoogleMap.SnapshotReadyCallback.html", null, null ], [ "LocationSource", "reference/com/google/android/gms/maps/LocationSource.html", null, null ], [ "LocationSource.OnLocationChangedListener", "reference/com/google/android/gms/maps/LocationSource.OnLocationChangedListener.html", null, null ] ] +, null ], [ "com.google.android.gms.maps", "reference/com/google/android/gms/maps/package-summary.html", [ [ "Interfaces", null, [ [ "GoogleMap.CancelableCallback", "reference/com/google/android/gms/maps/GoogleMap.CancelableCallback.html", null, null ], [ "GoogleMap.InfoWindowAdapter", "reference/com/google/android/gms/maps/GoogleMap.InfoWindowAdapter.html", null, null ], [ "GoogleMap.OnCameraChangeListener", "reference/com/google/android/gms/maps/GoogleMap.OnCameraChangeListener.html", null, null ], [ "GoogleMap.OnInfoWindowClickListener", "reference/com/google/android/gms/maps/GoogleMap.OnInfoWindowClickListener.html", null, null ], [ "GoogleMap.OnMapClickListener", "reference/com/google/android/gms/maps/GoogleMap.OnMapClickListener.html", null, null ], [ "GoogleMap.OnMapLoadedCallback", "reference/com/google/android/gms/maps/GoogleMap.OnMapLoadedCallback.html", null, null ], [ "GoogleMap.OnMapLongClickListener", "reference/com/google/android/gms/maps/GoogleMap.OnMapLongClickListener.html", null, null ], [ "GoogleMap.OnMarkerClickListener", "reference/com/google/android/gms/maps/GoogleMap.OnMarkerClickListener.html", null, null ], [ "GoogleMap.OnMarkerDragListener", "reference/com/google/android/gms/maps/GoogleMap.OnMarkerDragListener.html", null, null ], [ "GoogleMap.OnMyLocationButtonClickListener", "reference/com/google/android/gms/maps/GoogleMap.OnMyLocationButtonClickListener.html", null, null ], [ "GoogleMap.OnMyLocationChangeListener", "reference/com/google/android/gms/maps/GoogleMap.OnMyLocationChangeListener.html", null, null ], [ "GoogleMap.SnapshotReadyCallback", "reference/com/google/android/gms/maps/GoogleMap.SnapshotReadyCallback.html", null, null ], [ "LocationSource", "reference/com/google/android/gms/maps/LocationSource.html", null, null ], [ "LocationSource.OnLocationChangedListener", "reference/com/google/android/gms/maps/LocationSource.OnLocationChangedListener.html", null, null ] ] , null ], [ "Classes", null, [ [ "CameraUpdate", "reference/com/google/android/gms/maps/CameraUpdate.html", null, null ], [ "CameraUpdateFactory", "reference/com/google/android/gms/maps/CameraUpdateFactory.html", null, null ], [ "GoogleMap", "reference/com/google/android/gms/maps/GoogleMap.html", null, null ], [ "GoogleMapOptions", "reference/com/google/android/gms/maps/GoogleMapOptions.html", null, null ], [ "MapFragment", "reference/com/google/android/gms/maps/MapFragment.html", null, null ], [ "MapsInitializer", "reference/com/google/android/gms/maps/MapsInitializer.html", null, null ], [ "MapView", "reference/com/google/android/gms/maps/MapView.html", null, null ], [ "Projection", "reference/com/google/android/gms/maps/Projection.html", null, null ], [ "SupportMapFragment", "reference/com/google/android/gms/maps/SupportMapFragment.html", null, null ], [ "UiSettings", "reference/com/google/android/gms/maps/UiSettings.html", null, null ] ] , null ] ] , null ], [ "com.google.android.gms.maps.model", "reference/com/google/android/gms/maps/model/package-summary.html", [ [ "Interfaces", null, [ [ "TileProvider", "reference/com/google/android/gms/maps/model/TileProvider.html", null, null ] ] @@ -53,8 +63,11 @@ var GMS_NAVTREE_DATA = , null ], [ "com.google.android.gms.plus.model.moments", "reference/com/google/android/gms/plus/model/moments/package-summary.html", [ [ "Interfaces", null, [ [ "ItemScope", "reference/com/google/android/gms/plus/model/moments/ItemScope.html", null, null ], [ "Moment", "reference/com/google/android/gms/plus/model/moments/Moment.html", null, null ] ] , null ], [ "Classes", null, [ [ "ItemScope.Builder", "reference/com/google/android/gms/plus/model/moments/ItemScope.Builder.html", null, null ], [ "Moment.Builder", "reference/com/google/android/gms/plus/model/moments/Moment.Builder.html", null, null ], [ "MomentBuffer", "reference/com/google/android/gms/plus/model/moments/MomentBuffer.html", null, null ] ] , null ] ] -, null ], [ "com.google.android.gms.plus.model.people", "reference/com/google/android/gms/plus/model/people/package-summary.html", [ [ "Interfaces", null, [ [ "Person", "reference/com/google/android/gms/plus/model/people/Person.html", null, null ], [ "Person.AgeRange", "reference/com/google/android/gms/plus/model/people/Person.AgeRange.html", null, null ], [ "Person.Collection", "reference/com/google/android/gms/plus/model/people/Person.Collection.html", null, null ], [ "Person.Cover", "reference/com/google/android/gms/plus/model/people/Person.Cover.html", null, null ], [ "Person.Cover.CoverInfo", "reference/com/google/android/gms/plus/model/people/Person.Cover.CoverInfo.html", null, null ], [ "Person.Cover.CoverPhoto", "reference/com/google/android/gms/plus/model/people/Person.Cover.CoverPhoto.html", null, null ], [ "Person.Emails", "reference/com/google/android/gms/plus/model/people/Person.Emails.html", null, null ], [ "Person.Image", "reference/com/google/android/gms/plus/model/people/Person.Image.html", null, null ], [ "Person.Name", "reference/com/google/android/gms/plus/model/people/Person.Name.html", null, null ], [ "Person.OrderBy", "reference/com/google/android/gms/plus/model/people/Person.OrderBy.html", null, null ], [ "Person.Organizations", "reference/com/google/android/gms/plus/model/people/Person.Organizations.html", null, null ], [ "Person.PlacesLived", "reference/com/google/android/gms/plus/model/people/Person.PlacesLived.html", null, null ], [ "Person.Urls", "reference/com/google/android/gms/plus/model/people/Person.Urls.html", null, null ] ] -, null ], [ "Classes", null, [ [ "Person.Cover.Layout", "reference/com/google/android/gms/plus/model/people/Person.Cover.Layout.html", null, null ], [ "Person.Emails.Type", "reference/com/google/android/gms/plus/model/people/Person.Emails.Type.html", null, null ], [ "Person.Gender", "reference/com/google/android/gms/plus/model/people/Person.Gender.html", null, null ], [ "Person.ObjectType", "reference/com/google/android/gms/plus/model/people/Person.ObjectType.html", null, null ], [ "Person.Organizations.Type", "reference/com/google/android/gms/plus/model/people/Person.Organizations.Type.html", null, null ], [ "Person.RelationshipStatus", "reference/com/google/android/gms/plus/model/people/Person.RelationshipStatus.html", null, null ], [ "Person.Urls.Type", "reference/com/google/android/gms/plus/model/people/Person.Urls.Type.html", null, null ], [ "PersonBuffer", "reference/com/google/android/gms/plus/model/people/PersonBuffer.html", null, null ] ] +, null ], [ "com.google.android.gms.plus.model.people", "reference/com/google/android/gms/plus/model/people/package-summary.html", [ [ "Interfaces", null, [ [ "Person", "reference/com/google/android/gms/plus/model/people/Person.html", null, null ], [ "Person.AgeRange", "reference/com/google/android/gms/plus/model/people/Person.AgeRange.html", null, null ], [ "Person.Cover", "reference/com/google/android/gms/plus/model/people/Person.Cover.html", null, null ], [ "Person.Cover.CoverInfo", "reference/com/google/android/gms/plus/model/people/Person.Cover.CoverInfo.html", null, null ], [ "Person.Cover.CoverPhoto", "reference/com/google/android/gms/plus/model/people/Person.Cover.CoverPhoto.html", null, null ], [ "Person.Image", "reference/com/google/android/gms/plus/model/people/Person.Image.html", null, null ], [ "Person.Name", "reference/com/google/android/gms/plus/model/people/Person.Name.html", null, null ], [ "Person.Organizations", "reference/com/google/android/gms/plus/model/people/Person.Organizations.html", null, null ], [ "Person.PlacesLived", "reference/com/google/android/gms/plus/model/people/Person.PlacesLived.html", null, null ], [ "Person.Urls", "reference/com/google/android/gms/plus/model/people/Person.Urls.html", null, null ] ] +, null ], [ "Classes", null, [ [ "Person.Cover.Layout", "reference/com/google/android/gms/plus/model/people/Person.Cover.Layout.html", null, null ], [ "Person.Gender", "reference/com/google/android/gms/plus/model/people/Person.Gender.html", null, null ], [ "Person.ObjectType", "reference/com/google/android/gms/plus/model/people/Person.ObjectType.html", null, null ], [ "Person.Organizations.Type", "reference/com/google/android/gms/plus/model/people/Person.Organizations.Type.html", null, null ], [ "Person.RelationshipStatus", "reference/com/google/android/gms/plus/model/people/Person.RelationshipStatus.html", null, null ], [ "Person.Urls.Type", "reference/com/google/android/gms/plus/model/people/Person.Urls.Type.html", null, null ], [ "PersonBuffer", "reference/com/google/android/gms/plus/model/people/PersonBuffer.html", null, null ] ] +, null ] ] +, null ], [ "com.google.android.gms.wallet", "reference/com/google/android/gms/wallet/package-summary.html", [ [ "Interfaces", null, [ [ "LineItem.Role", "reference/com/google/android/gms/wallet/LineItem.Role.html", null, null ], [ "NotifyTransactionStatusRequest.Status", "reference/com/google/android/gms/wallet/NotifyTransactionStatusRequest.Status.html", null, null ], [ "NotifyTransactionStatusRequest.Status.Error", "reference/com/google/android/gms/wallet/NotifyTransactionStatusRequest.Status.Error.html", null, null ] ] +, null ], [ "Classes", null, [ [ "Address", "reference/com/google/android/gms/wallet/Address.html", null, null ], [ "Cart", "reference/com/google/android/gms/wallet/Cart.html", null, null ], [ "Cart.Builder", "reference/com/google/android/gms/wallet/Cart.Builder.html", null, null ], [ "EnableWalletOptimizationReceiver", "reference/com/google/android/gms/wallet/EnableWalletOptimizationReceiver.html", null, null ], [ "FullWallet", "reference/com/google/android/gms/wallet/FullWallet.html", null, null ], [ "FullWalletRequest", "reference/com/google/android/gms/wallet/FullWalletRequest.html", null, null ], [ "FullWalletRequest.Builder", "reference/com/google/android/gms/wallet/FullWalletRequest.Builder.html", null, null ], [ "LineItem", "reference/com/google/android/gms/wallet/LineItem.html", null, null ], [ "LineItem.Builder", "reference/com/google/android/gms/wallet/LineItem.Builder.html", null, null ], [ "LoyaltyWalletObject", "reference/com/google/android/gms/wallet/LoyaltyWalletObject.html", null, null ], [ "MaskedWallet", "reference/com/google/android/gms/wallet/MaskedWallet.html", null, null ], [ "MaskedWalletRequest", "reference/com/google/android/gms/wallet/MaskedWalletRequest.html", null, null ], [ "MaskedWalletRequest.Builder", "reference/com/google/android/gms/wallet/MaskedWalletRequest.Builder.html", null, null ], [ "NotifyTransactionStatusRequest", "reference/com/google/android/gms/wallet/NotifyTransactionStatusRequest.html", null, null ], [ "NotifyTransactionStatusRequest.Builder", "reference/com/google/android/gms/wallet/NotifyTransactionStatusRequest.Builder.html", null, null ], [ "OfferWalletObject", "reference/com/google/android/gms/wallet/OfferWalletObject.html", null, null ], [ "ProxyCard", "reference/com/google/android/gms/wallet/ProxyCard.html", null, null ], [ "WalletClient", "reference/com/google/android/gms/wallet/WalletClient.html", null, null ], [ "WalletConstants", "reference/com/google/android/gms/wallet/WalletConstants.html", null, null ] ] , null ] ] , null ] ] diff --git a/docs/html/google/index.jd b/docs/html/google/index.jd index 0e73b94922bcf..37a35fcb44522 100644 --- a/docs/html/google/index.jd +++ b/docs/html/google/index.jd @@ -112,7 +112,7 @@ cloud messaging.

    -

    Google Wallet Instant Buy

    Provide fast and easy checkout in your app when selling physical goods and services. Increase conversions by streamlining your purchase flow and reducing the amount of @@ -138,7 +138,7 @@ interaction patterns, and much more.

    -

    Google Mobile Ads

    Display ads from Google Mobile Ads offer you an alternative revenue opportunity that leverages multiple ad networks with targeted ads and several display formats. diff --git a/docs/html/google/play-services/id.jd b/docs/html/google/play-services/id.jd index 79698065c663b..664c6e6f43c7b 100644 --- a/docs/html/google/play-services/id.jd +++ b/docs/html/google/play-services/id.jd @@ -9,10 +9,12 @@ header.hide=1

    Advertising ID

    -

    The advertising ID is a user-specific, unique, resettable ID for advertising, provided by - Google Play services. Developers can use the advertising ID to deliver targeted ads to users in a consistent way. - At the same time, the advertising ID gives users control over their privacy and the ability to - op-out of interest-based ads at any time.

    +

    The advertising ID is a user-specific, unique, + resettable ID for advertising, provided by Google Play services. It gives + users better controls and provides developers with a simple, standard system + to continue to monetize your apps. It is an anonymous identifier for advertising + purposes and enables users to reset their identifier or opt out of interest-based + ads within Google Play apps.

    The advertising ID is accessible through a straightforward API that you can implement in your apps. For details, take a look at the @@ -73,8 +75,9 @@ href="{@docRoot}reference/com/google/android/gms/ads/identifier/package-summary.

    Apps making use of the advertising ID must check for and respect the user's ad tracking preference. Also please note that any use of the advertising ID - must abide by the terms of Google Play Store policies. + must abide by the terms of the Google Play + Developer Content Policies.

    Format of the Advertising ID

    diff --git a/docs/html/google/play-services/wallet.jd b/docs/html/google/play-services/wallet.jd index e83debe66237c..9a4ba67e3c4b4 100644 --- a/docs/html/google/play-services/wallet.jd +++ b/docs/html/google/play-services/wallet.jd @@ -1,16 +1,11 @@ page.title=Google Wallet Instant Buy for Android -page.tags="Wallet","payments","Google Play Services" +page.tags="Wallet","payments","Instant Buy" header.hide=1 @jd:body
    - -

    Google Wallet Instant Buy

    Add fast, secure checkout for users buying physical goods and services from your app. Transactions are monitored for fraud 24/7. Keep your existing @@ -22,10 +17,14 @@ header.hide=1 US-based merchants.

    Check out the Instant Buy API reference and visit - developers.google.com/mobile-ads-sdk + href="{@docRoot}reference/com/google/android/gms/wallet/package-summary.html">Instant + Buy API reference and visit + developers.google.com/wallet/instant-buy/ for complete information about integrating Google Wallet Instant Buy into your app.

    +
    +
    +
    diff --git a/docs/html/images/google/gps-wallet-instant.png b/docs/html/images/google/gps-wallet-instant.png new file mode 100644 index 0000000000000000000000000000000000000000..a3989a04522b6cae64b14ed743a59243d1b9004c GIT binary patch literal 6462 zcmd^E2UkA&a-e!8hshgR(I(7u7=e!95F}*CgzSp`G5d`fPetG07W^3-z@-8RaN!7hJu1D z8zGAf@8{XGRQpFd^2kw44CE*K!t z#RmYClmDL5A3zh6{|)u>`V);rS-}2^_rD4wErWbu01Frr;qM1!FPxkBcUL|jEkBqG z3gKsoKzRO9MRRuq3W0P-_=swORYcF3xIp3F-wo$~FicE92Hr@Ni#HTzpsgmx){uk4 zT|t*rloc-OUQ$$4Rni3lbre-qb(C}zG;}mo6%weAu3~VSaEl%vIM9;U)SbX%PJ1V*&oF-cPRUzsI8RuUr5-7{K?X{g0*o!^G~N z@6$gUmwoeR>%+X+{qDzZ>@S;N&aw9khqL}{r&x4=hsF?Ml2&~CgC*daN*D-E&I2%*h)HM zoi(Dbw%iHbpJS_?cJ0gfX4;#Y(b3U6dGu%1tLV%n0)Y_OSup>J(A3ma^l`1ezTP{F zKBxmSjG^vLHlLcBLT1wo8X4A!D_vb(uJOarn$xU`?IY58xkl>Tkk$I?c)}yQ*FzuEXya0t$oxR_q!gIGOVxF`q#I9BHGsx3{T#{aWZWCE@h9Z{IM4b^SY$%z1cnil z-ISc1%vfcvZ?Gyqt!n>DouqE>Ni+`1-wMUQXw%jr5{dUSKN>usjdw(zdj*-Aqv5`G zJESaUd|2bjbzEjJN5RUPq12(97JXCOiDhHI^)YEH+o)WIUF>B4)Ml=QTkjiA-;`c5 zh1T4^_7+d0lF3&CM!JRD0sAWfFrN%gHs=Z;R`crS(bj`V4J-kQsj%X$j^WLDGA*y5bdI*ZS}zh`e6{0iUsBz6;A^_h^9YH9&FW(VLm8c zDI;t%namtnK|1?w!-29e1+y3W|MTDguW?DRU%9CU+8UODgOuR|_Lg5VxfYM@5?9|l z;p}5!6zKI>?^nM4eRIzH6e4xIo~c}mI-|E+;&ZYRx3{J{`c0csJgy}dZsC!i5Lx;5 zsIsAdyi3F{`wFSK4ixlh?~6k)r-2cgH@em?U^OFzCf{sC%j81phBXjdV-*8V4R20| zecB#Vq-#v_7!p8sH7bf1S$9xyI2i0_W8;_=FOf72X`Rwf2M-7=FE2MWJ%3(qltYy3 z>?HIilV8mQeo;nl^q{8GjB?VOmMt!C9m@f#Zfe$Hhwg|+rqv>I61RDjC8#ZBbHj?) zvjMpsvYq7A=A#vpUNdomino%FU%nsLOBsH9_=w^yw>y91b@}&rH}N_eH>;i0sA(>Y{-3fkTb_0BmYazSg^E&-Vx^hVQY> z+s4I<>y4$|*?riWka5zr>{F|_jj8eA9Ss}IoHOrl;(S*U3uVCOz~Z&=V9)WQpj)c} zs-~FwjhUv1h@8Y)+srtK+v&lmfkq*9_08H0H)llsF+SjQO`B#^Cf((d4nYo$VpERs zVa)k2D@>m${uOe)-aatklvlchgW;!VC`-95X^|xGi<6QsZSI6D_DB%7GQp?637N^5 zabQ-V1o9HN=L)}UMrw{j#L2K~@>C`7(MJN&2;nP-x^U06g`drJFpC$i(BOd_esB~gx)&JneM*0j3bZZT z2M{v*<-niD111<`rr$#WB-KXhPvd`({xKDjhO|!02$~S8pslrMehU8s^Otoiv0~vP zpD7!>aP9B0{GH-`3IqNT1L^#aNdNxykN6KbU=n{v8T>DlE#^SpbOyUrRnWZu5upqU zKbj<-k?PSps>b-Sp$vXUJ)&GIoi%Hj` zq-IpSimX9XY$77mE`e2cE}5U_fnm5hsuW?&p?mFPJ0tFMQJp+O*D%#%CHrhKTvd&H zn-?PT2@6{PRz{=@+VZInq(tO0_s?Wf10i8TXEDTwMMopKqexjzp9RHvzqz%0yx4Ea zB3{$9G5+-*iy~lN z6M}R<=M&t8ZV+rk2hCd7DdRffFBm6mo`G$Ec{wA1)^|=fDFX|6XW(dVnVA@FdNXje zF{M@R>UeC0Yu!~|00+eMRtb?FHdL{EG5p0!a|G(rBVnX2EPx4$W*QZV_Yhl!jsgeW zlrk6RuZ7{iFc+9fv5re_w<03CK((L8k?{_z`M9Uka84ildjil*U2q;Ra;L!BYGj-< zWvNb1luOVYc-#&pFPCBZcv^SQw}{=cEst-xVV7_jE>$ADm&ZgtHm7j{9X*x?f-?0u zqy0h3%nTLj&w2{hkUR1H$w6|L0gQFvj#XbVZQ*EZ5c*tu& zVfhNX*R&4U)qZ5VFa)=KX)U>C3_mpu0kHSVz4i`!nLQ9gy4^hQN}d`o5MRR>Y*&+= zll$DL$@5)>eOR6Ov0Z0iC6t;vm@w{{)b-D$=eRGR3%7(dS$iSe6-KO?Md)F0>ZU7( zpB=Rs6SQ-ss8RY8dX=%#F>%oFUTyTm6F8&qzp7?|eBQ!N5IYu}b`v zanGI_FiS6<)iibql`Or9c*ySlDTw%C@Nt$)x8c^K!_x*BnVZiZH5`6*d%4wVp9YZ^ z_{;C7&trCBHTV?^iD6^G^y%hV7_j0~u6mg3hy6Vni*}MiunG-h%z%gKlYw18W!KZU zQ7RGnZE-ETfHyGio`=Cndn57>{>Xb|9rB=|dYv5oMbo&3)Z>(Ai|OA5gh3wM-0z8> z2)j@6$J4g9W-r<&cyFH(wp*G#6wxU&v))au9%D5%gf-o!yp+Kjd_7($t8b*=5xKP7 zw}V2t` zAqh4c!s<75@%`-(k4Hx;c&qB2;sv2qt!F<^N^(L+>)P%EekVVsLaj$;6Sqnl-Bkg(h z@{?-yxZk>a=F99C(;MuK@$Okx_E0s+^J*U)AAHc$kDcAV#DB4~XzbF>fXw7qF75Pf z2WZG8k^^04Z78%2Ph#`(P3%1rCyp!fsrni?Ms)?q8@%a9ieO|Ej;r>Zuk=HB?D#+p z8v{GATemOd7v4T5jQw)<>1+Lb-)MZLWna9=`QS&&t3-lP)btYx9Zz#V%$_wvXR`2R z%LqIkKMhuRkOIq%jp?mOAQ_g3qaVd3AA8o#Q)Vp|*!-=p>DwX)uL&9YQEX#3$WM9a^?Qn)oOMLXM1~7Ek$7u zSC~ra67l57VsTgZjjT%fF|nG3ueqz3@o#SPyEx}lK-eP|W@PWnXRJ>Q=lB(c0XAj( z>dcON2(Cic5H5}lIj#mpO;J(Z$4G_MJ{ZPre9;GO&}W~-HsueDnBq$sWm$-9SSisK&&b7$}0LwoQiq)5}!kH$QdQU`*bkN8;9pvd_Bhd$`j?0}1=Ym?`rJ>C~2=f3B34L?v3 z7iUxG|Ep&T&HJ_W{z*vW>+8XWcU@efbbN_B#lIL(;+2U<+90Lgi8!m$Rn4Ni79Q8awr2~We4UFtbQ{6*sF9OmQ`@P7nXgGu znn$HjOu~gbxp|1|Wc~}1cr<9O+N$rO9TknYHVDg7Y^ta{&mD5>+3;7r7KU#)sFBXkJMN*JUyea?F!E%fOC;KfwP zmCT7_`mrlv>V@y%xYyNDD6cqLOhRUlahGL&*d0X?(*C4}MJK|1p2h9nhX+FBMDkLcFDO|Ik0jO743NZIju*hUPGwmvZ`xyV6(& zVA=>spP!x48VUu|mg&u4t$EX}(T0MgF^K0r#*(16ioQhYm zuElz~U4+}Ab?Q$yBjob5d|W3>SbVj1G07Cu=m0X5*FAKRN7!z{xp_JJ^mR;3-&(Ll z|D+H(5g=5Zpr7luRu^TQFk8O1{HEfO0_HvlG+Hhh)irwW(~5RhgRDgdHsc-Wm`BrG zSue_#zZy(})VBIdWXkFL77Ih3nmKk4cQ!_;`&?o{hFW7Th>JsuZv(Ns!PajujZ#3; zJfMO|&uG1gQO~bzj~I?SCjjl_97t2PB^ZVJC%8l=}{*U6<%34}|L?gJ^1!TE--rZ!WzxDMB=1diV}0r z!cv9gi!oP>BkO${p0d9(QmPoEN?DfARdAxgsaolgE(rXL2xB?^Vyn5CT-?gOke0*^No9(w|h(IVTrf9wut1F)$-Ud9A4$ao0~GG-l7SwVLXX_ z5|S^pr0jj^p&o_9sE?3-pT{Pf6=^uq?#@H2Ip5GlIU=Lbj%l)bt6y&32fOYD648qv9(SFJ}5##YIZ29Fdwda<>2Q>qMd&Y)N z1B&GLu3C*%$?+td2R!O(nP)_?BCcP_4th#ln<2&76XrNC2ON5Aw&3Pit9U4DX{f+I z&Hj4h2F@FBEG}=A)YeCPL$Vu#ItLi0%x5mDRl!}j}v+VP_bFx27IL4!G@8j3~wJNUSuK3Ao?G7m!GE;8(#QpfS^L^Vj zK8SDieR5H#P{l}x5yk&%q(qwWcyNe0-hD`UV(`I}9)RJ-S+|gl>=B~L@x<(HueTX4 zgLBKiwmmmp7!9e-F14t6UH*!vU2>(2dfc>Z{AIi2yG7BQp-7uC3kUrTyVA!YT~l9c z`+xkRL-$1bYZ>2Q+2lM*Ex7V3GCZ{)>D7X}VaJ(VH*@uuZJl!AseWb30Qjr&#FX2$ zXL28s;}_gR*AG1Di5HpCVOb)Y#la-Ugg_uT@^Vt@;QvMl1j!s76+Eh?Nsop=Fjed%B~?{z zT|8XeZC&2d%1cVpzIAi4wsW+CK)e^SHEc9Bc8NtUm(L^=B7;9GxTq7M)2d6v1QRAO zFwtS)y@{mDpC?l5eJ(AHLNS~d`6Mnb_#=@T3wAW-9NGq5LEQVo$mr4A-+qM-GaZ*( zV-Jn9qT7|H*$oqDJ?Pjea@=aX!PsRI)X!Jn5A_fJ-e7wjf(d;K!9#Dbq;tQ2fdsh< z6c%Qt??LN=AbC$=p+kCk~Q4D!4gA|;d z#-IVoLxGsWEzH*;s;m%G#-Ob!NO1O5x*rn6;4>W&QeFatmcS}f3Suh+shrS`mWJqZ zKnSfB`UN0!tPl=)9cwvAZ8M~291p7=f{qR0P>T%v4}#(cF&%#K!W;4-9YQGcS4a4S zxf*Yq30Nw1>V{b6&W;_Yh)F4G(f7-nx9TzxuB+j@#z|#- zJmo5)kCI6IZ{X$6N6WPpmfI(yE4+|edr>661lCd`izgQfjCi^pJ!_W`$lrFC-d`~E zC&9Mwe@}Ql9*f<}=DmajTgxZ9LLkOcP&Uoc2C*S@2t+C`gsE1X;;fgHr3aO=_vvCU z)}1Ne2MK8ZHwiomOv_+OH`D(rLnUD0W3^OFrtH67Q}Ohu*@h>*#bx`Z)q*SX_SuaY zdQLB_BLo9Qd>Ea;jBX(k$vj&3MI1Uwde{|RuN(?~43u^xl2DCaA%RzpQ$1RfR!ffR zuZSD6K!l-8TY}Iqge&weyhE1rb4b0K$S>?h$<|VS@((fvSU)U1I5Xmj^D=+9eI*z9 z$d|wUqr&#tLcFNt5J%4rDH?abBL~}HpG4g&7K|hdcpZHucEuoht#;*;_Na4b?erhE17JX+*hA zsf(uAmq5MyC{(>Z#Xc3uFKT&pChHx8v{)8o4c;tt4mcIzo*}&b40U7k{_mLD)9$I- zV?@f!@&zQh-*D?RsGoke7DHQ4bG^#)P{!DXm86~qMlTZ{|F`xZMKOKcWMp>Kq@u%6_8uJ=UC730|N+N>i)okSs zMHKn%QeNH8B}ZvFUB~GW+UBGfR&Fwf!%AhKilj=2P2=_pb_@0dovPW| z<|421OS5AV(F;+x+;!1)Vg6;VWj&Mc{5{RX&2W`ImmHI@70I9%kCu=xm1%K2_0OZl{eWjN9Rc zsRr)M{6I6?GK=X8#AXbO2-67{i+dZXOFqe&%Ih_`DCxc;bt9D`wVY|gsUlFr`i7TD zw4BXec!9r-r%h~-&06pKv~ISpyrTl802@;^pR;4v%H82<#9Ha zQu0kaNa*18fevsNv23<}U@ZI8p@^fnlqr})obisUo7e9Y3tLSgFoUs0By}Px{nqz>QQl7e%itCIszwi}jMf>aF`Gqus zJ#`F*Xn)@%*;?2w+|prHGBQ3UB&PXA^Gx$blke!~Qlr`ImGk5ggts}=?Bsel^yKH0d$bq0O|z}Prm234XsXB0 zFz?Ia4$*WyWFLF6;_%^U#bynzy?86-v$1=Lv2sa`Be?MHqhIB3v?-c*R5n!X_7WL? zGh{L~GHwmb4cb(`i%!n$E&JZdB50mv@d)erygAhzv0K;;ol3I#JMl3)IXfVb?RwD^ zQPAYKZ85%L|IFpM4bS8EPwB^)ZJ`dKal^kY9)If*n*=&7IvF*BCQf@Ed%_P%Qz}F4 zS?w9st%eS*N4}kne%6<}6gm9kOJ|)vC&Z64(>VenOP!~_E|&wB=PSfZfo_cV^O8#u(_#h>i*v_|LH0dfd8d<$vX`h~?)9u( zK@5Hyr0yE==H@g$)4o0I^;-0zIxbv!rn2Er8w7i_y{1fO-U|nvUZ0I@0*>$J&(8!q?PbVg%co;4Tl)utd*Ak=pwB{GgFp3ufW~Bg z=38_^rXe?Ez&xZ!Elphh3;Ql=-9_EWf^Y1i0y;F53b|O zqTCq?#Uol1`Zn23mkpPJImf4df%l9Y@eI-QkV#uYaXeV^n-)VhO|6%iW9AtQzu%@w zci_rdcJBo-8RZ$5Lg5tK;;kTIp$PX=zERX+nrTvBDF-XtX^L2xPPSBdRe53e=Zmn6| z`P1yT&FR5)EO4J@J*xHzd%SU!>Ltfd6Nb>~m^XMRgwo=8A5Mu)&#&et4DU0C)&*R) z>uNMQdk(fs1Fe;&V8k&O3RN8v7rJxD7p`Ed68Wol#diAQv*((1x>+pAZ`Q-jpqg4r zdMU}65q+FSvnI^RZz2?@4jRRcJCi!CUOPR}!~0NLUao_J91@TEzBlteFsOOum_&s7 zS#$x2?`(0eR>PJhXAslQ%@oZD5uDl!sRaTD7fC+Yq5QBV7jTh$JMvaTXY$urVaVx< z;a~|J2P3seMxFOM4QSJZ-o^fAk0z`xnl$`LTsrYnjutvN^{uco!y&|Mg|$z)7lU8c z;fZJa(v^Rgo%`=|-)x`S?VjyZB}8ZWwkbpMEKim1$E9okc0jVVgp zh?Cp<4-$0WeskojMw)U&&hC4bmgC@N>TkFSfFuT%?;)tfluV!eCP9%wo*@Zjv-Dv|u9%3D0F@WJoC}UJ%D5yeXoLwiD|R3Fa$mVjQSvi3n;u zF3M18&Bljs5t0fCWp zZktzLM_D+IgM)+0O3KQCU{Ckiu;}8Y%a>@p!NqpJe*N;VFDlxs(bw0XkttLor=Za5 z^yLL7G%_OZ>*u$-yKCm*L8vqZDXya~FIT28%nV&1&>f@K#1e5=+A`D+$Es5#xpk_8 z7-Oa#`ptM|`-`gNtJ3C9XfP!&8}jN|m6TdP6QQ2qLAK=gyKIR17;s!(j*lCm*I}I9+?#icoC4S|2hy(lQF3*T1e(uE3w2sM`691AE z5BcW7e8buKIVZ5?&Q7V%&DriFFkt`z%m`mKvsm89$VgUJcIbU}cD8}NgTwCLp7~U< z5~ZL=q|k8(@Zgbf912@|dpDF8e^Ieml5C}E&wQsK(Yy}ARU>Q|2_m918PTyNF&Euz zkOYkaz6nk)}4=JEyj8XS~)cQ6-HY`5q+YeXsZ?qj3Fth$Mb3fMJqj2a6u)$+c1 z$DZ4h8}&ewy&&%R=h6v=Y}>YPmz6+fRn^gv1<^qr4_yBGM}%nqkmv;`aGh7aXRxHC zq%1+tJ)NO=nn%riRnqj?Z|RJAUQUQ6&FI68j7?c29w63iZ~uk=B>Swh)r<)PX2$T&H1mHipS&ucUb;v9;PQ7{PuyCyO5Pk4{^tlnXk zO;At}e*SY`VZnoM8 z*d}pggW?;1x1PkRVR%9-57+5#gC-O3M|q~?wvTH9gB;n)02u=Fb^2X`xSDVCWIpkx z1Vu3!zWLdb>-txyxRH*|rBEiH(+$W|R;OEI!k3Hg!WVNEhMv<}Aj@*4f0WE#!7$B{ zS5lh#q6$-N;2A#)&$K&8-~DWPY1fSzh8!jJjni1m4^4Z2ze4GRJG&^w;JAY_Bc(nl zI+QkA7yhMnWYY~69XhmbcD&sA@4COHrxTP*)U?jqPEJmSq6gOgbTraX$8Sex3wa$m zxVT(8EqA1Q3y;rsUGP@7?J-4=e2snSBFkZdy%=ux=}nO?$PWo}8^Sa(*XsN8fi>1s z))$;pNDh3tpC>2Pj04WKFvGr8me1}zI0bq#ymcZ$MFiFo@(t6Vs~OA&!w-Aw6}ff^ z*SBSUq>ktk#>$LrpL%y1cil|a{M}>^x-NK?Go4>nShya<%foX8LRU>I`8e>h-Q(T6 zf^w!4?>k}l6Cv?J&M63flvLz^Ii;w7nksCA6pJez8^CvO;keoTmq{adm|=27>fpj4 zb$}!A7X^ugF?StPeWRr41QJR+r>#>W zmPxw;G7+h1k>tPi z&}*b`@;@1V5&tSD^!)rBXKZZDL?B+heaYDdPgBbXpxLie>nFe&t|sFHH(Fw?8|F{7 z&;0*8GLT2lVy9TUye&a$CQsvgWnEZ#aYBNLU)y=;7*RFP!_57k{W){ySk9~sU#9dF z&rrp<=mfESg#kbxsc^bzdVp_TecdYX?=AF(qeClGseVc2yffF@rymed1xQ@2}J?co>9 znB{vCYMO-7n~TGEg)eMU?=za1Jj~5QxoyTlg^HNnFRH6Mx$JjiMw6S{#qKaZZaO+T z600sN>*c@>yoQ^ogBKORNH&UAFqzsFc5&M@WrH$D6_u5{*6)O(GX^*MN$a6z8N^`{ zIr$CuXSqAA(46olJQp|v1-~;iTNzY8#Nf~n4Tq9D$JLS;8UMz)+F>HK z+xVmXABkL>da5X?HKXIO=Eb}w#Oi8Z;nCT(zs|xVoM_3WWN5uC85&hq_8&;?zu#VU zL?-h`S9uGa{+O01rgHFUH6k~SkB_$?MFoAxnF7E`jW;*UZ&_ZJpnv)(~RN?ZAV1l zlVd3k_Dcbhn=JSyTj3FYvwE2nUuGi#G-}fJ7ppwJ+e@4Gwwa*{ML#RUQ}_{79s=TR zs+b+0_7NRt?W~a(W9E`PO74}hqPZ%ctXeBen#2vWH~vU;VYz%2+A+|h&8n(VWN;^Q zb@|j|yWVue@56_B7i%uU_R==>Nmh(Jfwc{4=i;*WTZB@MLjf+eu(!`ww&v#K=n3aF zM_ZF4?-uys;cU4Dbld&l`})E62KOvi`PWVsx;Ybkh5@G}4RJ<0X?u@sGqaA56Q1Mh zx1EHSZJ*auus&mT28rW=nqbNy*K;hZO$b11lvJoApO8}2s;aaalss0jwI`qQup#i? z7e)LnzL@eQUHvCyv+okP6+BoK3?t~lRy&c-&kFViSvELg7CK5BJJN_;^FuORIF1Gw zyy`>|r-zs31f9P`ZT5qzPcn~@jnP#}+#f+U@bL8f?bbRvBE*XK6iGS(jFPfmxrPEn zVmI5QadvTenKWW)>*#3N7mfq5Y#^&{-6D^p5|VLoVUMIwW9Vu`U^sVEi@b}QYj|e1 z@e{p1v?vv0rRZd+&joOk|Ee6z6(URd z>kPRrJf+8L6*(GTTpdXvUj9IQ6+eErTFM74_a#=Ipe>c>M9ITPnXX=ybbfbu1CtFL z6R!zfoA7SnxUY`K-(CHn!;c~zW=d-7|4c}0mLj?E58e82M81zV>Y*@ z7vHB%ykQWzRs3LVpCOBixGATZljJg9GQOop3hArw-AN9@rt*(o=@Sgez;IYZBvn zd-s{arWyUYe(2l;B}bCYoOj12FT}htAv)`rcZii3ephm>dR4W zu6!;PU58O@POzP>k0S0*#f;brAr(NrPI~E7X5(5?hCK~ zv|TQ^FgGVyL06iEKvLZIZ2$Ch(=m0%!yvIW` zat6;CfefGf(ORs6NZ3MvZd$nBAedHZ3g~@;vh<}r{0Y@XUHHgZ=cpNt917EFYZ(32 zEU{S<>t00TX9KJGy7$O@_vsMTDSfJ%Ur_KBf2qy7JS1a5kgfiLqzpbF!JhmBbCX9e z5xQQj*)NT^ot4_`PJoin0yu3)DSPS92A2H-pKy|@@Aa}% zUpbTtg?|_8>6LB$HQKJS+(F`4mbm!Fdbkw|llDGp9W z0{GVy)2~6>{AK0#eMNjXas`pJkyguyEaMB`R&mkXpG>Dt7xyC#TAA6m$X3MS*fX>; z`nBa>HtnvO9DNjeetLeNL$_uK$t$%Ymh6#-Mw*$D3l^8X(En-GJS#A0#7xM+N+6%2 zYI&ZhALQOj`BX`gu=L9_?NN;1OKcylP@9~0&^aX4YQ60P%q}d5`$A09X)9{?`8nPN zVlz`oezIc0iY7YG2o9sy`Z6C)$kK79@qzJ?NWn8iPxMV96sq=(&;z><2o9c0&5u0Z zRY%l4O@ykmqZL?YR)-UGe9q?_VD%ls9JMT8%@YR0QJvd%WvUnJ-iNmd zLgm+fRMaF+Y}+|IZgf9vK9=rerbcXnQql3)Ijg~io#Si$On=~@YwoGLc#f}rNlMu4 zetw0+%c1zra5H_=6rJRkksF>d4jGG!O`^klk)!Z!O#jD5!iW-&Z_ZKp#G!WP>DJOV zWl3=BvWl9*E^FSBn;X(x(xDeE|6!7+*yXoqN{RPZT1Mid)K$(_L+5=;o*-saD8hTk zX#8o6Yf^I`4mgX88U76ba_{9BSH8t8`aew=Wa zr9$lN*sdo(VPD5>f$5p1BkPa!SLxpkB=b5}o|+;tOE}vvapm64`r7K6o|0NVgn@ZZzuR<_W1l6${|5D2(oQHsTZYWx@Yw;}hWBH;EFKc|}Y^XDlnmHOIx zxbRIk;Xg?c95@6@%w5ZuZYRGQGO2L>xkjxS>*ew-ZFs&=5xwG6UMWQ-W;=Q-)B|3i z%5^eIuY?pvgp{6Uy{bOir~=iaPZ(RfY`H#g3HmqtefUk&HImwOhPHUMyiZ0=U0hTa zrDaqR$*7Sf$lFtMzrg#ovGL^Y)UWk?Mg`0luKosHW0^;xl$UG%6~Q{@P)+qJ)D<3V zsxt6CAnE?n)P$M}4>L>is5x4jbErAlRk;@oH=~Ut5_zOoWP0ZdI_P(N&bmV{;vYim zCOO}A*$72RB|7rKy918dqBFu-3#=gRr0j;#lYggCVdIXI+|CYds= z6bA6A_Gf6(k)Mg(xhqqOjmIAae3GCWioSR!(F?&j_cZj`#ARSOTIUzN-v9E`j@svJ zyWb)zT2H4GX2vqKajUE$N22huAOTiGDcqloXm|z4Ew%^+|3zHlOI?D>2hDb1hZ0*RqsW#i|p;{vGXoLA2I%<;q?` zFiJG`Z~zZdtSdcHS-G)MFVlRfJFCx=94^4qHwDMtmm@MkH=6A&z}D`Q;>Urq+?9WT zM(+s96$Gmgb1FXROT&J^$p~55PN^ zuD5ymA9*>i4<}f(Xp*!V3MgfD4sW~T+)^pLCVn{{o4p=_M!ojqw+^Srdq5Gh$XkVU zscxM0*zMUnTz@-$P)>hiU}ei@f53_`H)8OuyCSU9MV{iwekzz7XiXrzU38C!62h3{ zo5Jq@z*qg)=-^|vB8ohD^A|#n8fv8m%b=v0$g>k<(=!*&-nOiKtv37oyW4LC#fHix z;?>1D()xm0yD8rszXySbsR*&im2C_EJ22*B1f0y6B`5a#;1vZZ`M~}uL9A3+RoU-! zkqM1oJb0u28$!{lIynQCEx~Pu&Rs#5&#rf5owxX1?g{4&alw4wL1gIqz^QvgVSnb& zRIbPy7Gg$1?9ZOVryVlM+OhumuK{I19{cl0o;fK)lw~65@chjw^%CX-rj=!6hU7{# zP@eP(C=`EpiGVc&#};{Xb!ipO(T1gl7#C!Ds2xVAw*KiNxoGg2BBJ!&B*Jd^KD1|j zz2Pp9{dn^WkD{gi^6LL<0UQkPRvy2GPYC~*P}OIw!jQxNtXT0qFb!3-Cf=PON%&@N zV!qLV(d2$FsIaLiytCUEsaauw2Azw`H_n3rOZN*m86!(~^Cb$+-RiAfX^qY5+3xHT zN0?U*jii8@O^7Ye_qiQXug9VIog@7)#NqG7D}kF^mD8l#$M@_3Czt4`p?5pWx5Jk8 z=mn9jcwP&bgE&)P>hg0Cf&1K!h_-aupa+Gn%lGZWU${Sf6BqSDxYW7c`#$VBn0RIF zDz<-J4%LgFB}sz9Jv^(JG!CTd4WExSWwD9ter9LLf0H=;@PwV4iz~Wvcqcqc?<0?JUrFP)t@Q(RXA>neEhjMu3`-Lg!{1+A?iHkZN^bFJ={^<;$7Ww8B~bn$P* zdBd0^meDsig61bEenIERiJCJCXiowkRvu4u?v5XiEAEcA17l83+`;zIFi@XhF{M}v zuvlZrC+Z@W2Fihib+PHGJmHUXd>zNd*Gft_EBC!d9ljf+A;Hgs<9X`d75G~G}*$I&GUY^mv{X=Zv~Zr0cYpW^2#xt zn|qo;QS(*F0&L?` zo&Nft9@iPmyY7W6Dx%&*;DXqWyR&$rkqCC}AB3YuYc?4!42c zrFWL~iXX1f0cfB%O+!tD{=U40&ptm`mT4gp93!{*PSC=&?iQ+(`N6C!3oY%p|vTg#VZaw*VS#Y9$i7!4gK&^ZhPOnaz5wG zjXpc(2%*IlKfB)h>%1sdKkTU*lb|_>@O7U~>rN#@l$40`Qetu~Emi`-DZ{4fO|0G9 ztwm8Ovi^GGd3?5yQwp4I?O4B04n(^#cKJb-X ztW!MxId2xhX^_@d!?RI}ZZOmhU|!ug_oqcZMs3{~q*xIGolS~;6T)xBuWz&S-p$Wo zge2~b3tN?JnWpcM@Y_0Fsg%u^yW%zkr8s>sgX_w90_1GQ5)SSWD=oK-(P!`UFd4;v zAbWjMuloSQghl_YRvHm5$t#783T@F5N$2abup+o$;$r~z8X#MsF527MOF0kZPRFii zS%23~;$K}3i<`e)!oT55(uc?Ferb~#R(H1S+GgL>k6UFxNALLSrw+NozW!X46SWpJ%n)UBvLf@K*og+{S{gGWzd> z#PpW~(emSf{|>v{V(Pnj%#f1Fn@uOCYu^lmNvGjNl^`pR#)%zvQVk|`0Y zRx0(d@ZS2?HWIX}(Q(ab_nn$d0!bNi(6>NKaUTfgjiGi<5rp!ISuELn(`Bfiv`(TR zSy7qKRN;=1TYsuzo_?i82jm`LlPa{U02`7tu?@sI;2AI)wi(Yt%IoT)RwGm+96;Iw z+_)+mGE^P_#ZbVN*qo4sn~@}#2sb8Ly(z*Ew-bzdyOp6qK?(#&SOtQvrAl}Q>*W~3 zjw4G>CJuhR-}{r6Ogv|F`#8qkN9&JWnpW7PythT{!KgNgQ6&++sSEi2!otE|Gc!LI z7WRZK&!5`-t+~+FWg!M<2(;vQ=qOqGbSYL!nNk!jz=GJ=*g%*Dh|0nJ^YH~2K;~?p z8WAqmSH6mI`L8l*<+vn2A8CpQu%PrwBYAe@o}NJG@rEyRGn%>jE#^0baJ7{l3Nq5R zA1&Tn;u`p-1Rly=pco)J7R-$goC}iQMAjSP{!BZetkeAnm>=*rUS3{r;T*djI3Qc& z;(ks}{)YTQ_3;z~G;O~*C$JdcWTxhFT47G-SKFsPsAy<*E-twYvX%{cnp)B+n=zQb zvDgGk_62V*k8M0WJ}S>rw)rHqV> zf6O}|{s1p;VetZpi0sILp|S+r!vU2BNF4!i1t8D^P1oN3J|I935Y6#3Guq%#W#g%f zs;Xjv+5qUfGK&AvwPl)XI^8!!fc@M6hGof*U)&+02PxppIRpixfp*FqJ3y2MSQc=Tf-%eMC#HJD^NuM%+5$+wbVbzMi3s?nIUr-= z;&8!63t(&Kz5?EVXmN0GDh*pf*8%ibU3pomOvxV7YFlXbdMSF1_C){3`Oj1v!AFu9 zN30ttMSMRW9XW%Ma=4XVmWW@}x%QPhjrG=^Ex#u?hiJgJaAlU8gt|4JXW1}beW<{~ObF-hG zrknZGUl-2yD;D{xJ@qU=8}sRZbP3=o0U7l6gYIn>@Rm4AfqzOH;NKtPn1RR(s!r{Kg3=UT}=%u#+;6ai>uknTq;6G3qBIV}JQ z$QBT-94vQc@;c0zlA?las~3FX?k!9Wl{bI;7B3Yp?d8Q^0Q+YT9&%6roy?337$GL0 z2No6gJYsbK~3Oy!6JvAhUtOHUn^MXgbC|n?CIo_ml;&diU+|AgnNn z4d3)kboT%RcOcbKcy+2o12?I-oijpz{Sbg+tUL9B<;}grI4nxqvJ=wHnh5L ziy&arJ|4q&e18nAi7#mU>&jSzyr;Kx8C9+FKtfQ}|Db^y-xy zEnZ%AbsX^bTJr%+Aa4YswO*jzzyaCpV5OTTcVZj;v8MBa9I%=FfRx8Vq`biHqs2q# z;NW;Inp;v_j0z*6prWBc8x4EIs{}M^06hXB4sMMYBD9eu2CzVFBO@a&Bd7WHiO@RV zbNm0Pis57s3Spq2+uE`Q@BpZq=(ClR#;oT%e7IArT(`c1R={j1jw;S9PnQJ&N+#u(w!ag7lWu|z*UNao3T~VrHkZ#P? z&-@Koi2LeU1cijiXlQIqO@o2c;Kd98;2=f+Tsc=%iB>g^N|7N+ne|w`tRINnO3TXf z|4%3|o+A=7v0YeK=c)&Ba>%nzq5?-*p;N<<{O0$GH^>*`agGj2ic?TROgcChkYxZt zHH^^hH4GhDG&dg9SCG`4n=@b2uGW$UcIN`3yAXz%AonHlQ;A~##ld{vXfm^2tJ_Op zi1YnffM&oEZ{q(fmiO{%elM1pF%hOS#UtRhfgWy#vZYiFs+YrTb@pix_!ua@tMghP z&BGs_v40K)ipzGkjRsU&jj|lEaO2CGl#xMhgLg=@`0JO)^0<1yc-R+9quJB}7+5IK z_GO6%WB|}o3Tv2WdH?=BkR7QR7zim*s2dn4un@n-FCWb7Xi?tXz2USyAa~l` z>3Hv=)3{Qr)_SzTDNKP#HMBR+T@sw!;-bInX?1zM`9QSvN#f~dtW(UI8!6hsfSQiZ z(4RjXVG_06x$45?;Df=1{7_RsDQ% zN=k|yL(mjYf>khf|y(HBj|e*eXcHH~)~Ecisn z3MjnLsX<*{wi@*axX$)tlTy>t%6`{rAFX%anxW#+Y6!32aa_7CS~yuI{83-4p5h+5 z!1HnUKRgs91w6dUa`QNsa|U!kl{nrKn|$-jt?->O3>oH*H*q_!itY{{lg&)g%Bg5} zXxJ_*sOGLv|E))2CT@KWNQfAVnoho0*(9snUZsQmrNCXG31?|p%y zD7*Otrcmw1$HTMQFIcye3y%|w*SQw-#!@n4^Ebw$$XVBh?~v24zxdU1le0>hwkvXs z(_m5fg(oF#thuvI=xEVL(`z<0r3ZJV6<#}vHoG_Ov0B$nwNv(#qRvSib^CS@7pk{o z?~$#m))}xsRq{GMhg2IY4VX`!uvE-o0No^Crl(?clZUeqvevCyX7NaWKNx<3q*0=! zpS{~*-1*7z55Q%7nLuI%@JE7NKZa#(7|d@|N2nWdKaVxD%zE&tbgz`+*08-hJ%Of4 z-}&v^Pr59FTVt6f6XG^{Q~rq+1gR!4`)xOaIrH4q)a5XU2&jV(_qPHbJ9tl?JW>8p zEfNLl4M@%4Nh-(!?bmy3$J9xSp*Yu#;pamUecDR%39Edh2gmPBGK!J@>{ZnKZ4SC^ z_TLs-`3;nR)FA7&l2G(atHHQ$8+w_d=>gWN@!w=VJ39mT7?l6J`P_RlkP+RF%5JC+ zCz|4}6J)7>FZ&&5^Wjbh5=~ps$>Rg>y*scGdqEw~ZZFE#z)XUHpEePU843nstN)+^ zA0M#Fza@i!{wKTv_58=e!f1|&9}t4R^+%%)I8$46=06TN_WOszKoweiE7^Lt7{lHb z36%!`B**VapslS zZ2ZUU>=0NRh>$*R5album22pmo5+sIba+1{2qV`@z za&AB51IX`xQqF(kNB2G){dNFUJ6_sEy3?ES5&}a047cdIv@D5~s5KP)`m&g=(* z0Kf#AL=Y7KF{*&_q=BxfrL}z7b@?1K3?21-rE%xNZ#^d!-tLu&3|1xUKrFAy%<#hK1)K<&B#HU;p}^5erLP!lyT`!WaJ4FxFzTk4nu@S@>TzMl1b z`19=XlYw(<7%1|!W__ptOhp&`AqhGmS#*Q50uO9!Z@)e(5mPcUqN?fm3vN65C-se} zS?ToS2Ulra?`;9^0-Oz7;a_#ty_k^2W%4CwexTAcxmzO)NVyk zzyWjyEe3E*xsoZvp!@T?RWvaGTRDY=zk@Ohq8GR{wf`USuJbAv*PAmtP;x<513iFH z;IDYGhgT}1*Bd;&r)~x@&zF4dZ?l|pmlvwD`P$w^n^ zmd@&Za79MaCj5}s1_l&h)@I2i4^*iBj*JWpl$eg~rVFCa>U6(9?>Q*l1FeiOwUOM?p|>!J)*$#40s=Z4Y{9)0AhSpns#)q4tHMCqdqbaK3cw(^ zQh^;gXi9gsh~ zs?d26P0zpNK>*?cvKYW19lar z&Ia9)T${qU5Z`hRGf0FU-3)w_NZw$q#QEoFX)#(gdEK5Kq{~+c1}I0k?q>r*%{(*e6S{b-}hA9)ZhQ^6nKwV z5{aKH=pl!kroI-p{~G&v--c3WDly$Tr>9lXkZ-K`C+oi-V=uAUw0g4VhrS1rxM$CQ z7@rrN_*MR$PFyWR;lk2?H!Ovl(M5hMdfKSE zM24QcXHfKJ;fYXD>Y;$nA%=}sa(0^Dx;5KazoBVqV2v^}Uqf#CYJH7KHm;XG(L56q z@9g_TBWs4J!YPcVs&{vS=(9na;v{u?yVuvLnX?3Ii%B72if$cmDXBpFe%vqBQe z$c&J^60(z(M9GeZtg`*y&-c83f1KBOb&m4+JkNb!_jSG3UH{rFAZ_m+{nH9<%#Bap zWr&qtsy5qvFT^XSoTAlCxku67?w9NQ=K(X9zYPPN^!K@vP3r}e*rTCaS6^t)+4bmU zT&e%}8LR9sW;qM|og^h2=EZ|oKvTh_x#R)=PtUo_4DVjMHvO$0h}TR!JP|Whc+uk5 zklTYx0;t+nR;kf>ZST(*bHy+mJ!&)28l&+bccyVue~-qirlE(gjVZRS`6S&s;kyvY z`=^z>mQC<CZQx9S_8Sz4-4RikM-kV`6mv`#f0zv=OML5FxlrXkg57G1pXApLIE?0L)dz<*&kgDG=TbNx z867Z^J1Ec7`cOTJg|&tD962*5RUsE^3riFmv&s&?`wNaibbfZn_wHbkO<%kb|BFMh z&|ulEj(z^E@IwU)kICCT!Yix&weP=w=RhaZdqH!qde-Z}o4K_TFF}l;IGo1@hc`t4 zOU0Rc$NQ{i__(Ya9lP^W5FjzSl`Z(LMsdo^^xynlHnyMWQE&)|yZvOq;8nFe8iMb? z@a^6Kmw#VwodRqIL<}=M0jzxd_<&8B@K>PGnBSQ7N#1?T{Vrxy>CG|e`TVWbe4=cl zXWQJI-AV$mP=7$WJ$Z9FIZ7jAp!7P^@bWuR;`nE*{X-m5#D@d?6AM?25DGse^5tm5 z2+V?##22p;pOz?7_;m*~CFV$^k~`<*^V!L+(@9tN`j1$jyGXHiNz^E^jbBe*`{JGy zrGiYWC!pzqQ&_lN#1A|eeVbn4e0wPK7(HM3k|L?fPvDR zx%&ce2mT?3p42R#UQcfYr`(&*#aGL>HrJqtn4E|+pY*3U`vyd1?8Ec(cv@#3E%s(z zAZ#f(u5paIj|QD|U!Bf4I%9X1V?dcsH9acYVGdS?=NC>}z+{5fxX^h_0fJm5U z9=J&|5ICYG`|u$mI{dSSYL(XcryD$d+UKsjQRkde<}-|vl7ZhnTOk46jd$LPKIA4u2Lr2^w@-MzMq)0M0R)9%1Y?p!9C* zsWwKo0IOIPA3{Cf^!rPt_?^Ezg!c{zHM+x@z8nI>sjsgGxPlG@BArX9SEe^QPJ@qt z?&(7EDh;;(`%CZ?0)3J=HnluAhC>#9(Um^|(rV~4;W#QC4C4sSy;vE0#Ielx!Gm4E zO2%I4yM1Z*w>TGTgY9$s@4#hcHmaWPv$a{zAl8?mY3%mf9(I?lWlz)|LynZdTn_gt zK5HXc8aX*_*@JD|pM-eTdfvX3rBQpNv$v&JP@rqy&M$=mlm~Ad*3S!M4hjtRV^iH< z$%3lD#ZqZa6CRow*rRo=;~6u)%X&-l`rcbZ&byP>#|gyw;p!}4cbGF3=3S)zUkl*U zbo7>hprCKt#3;TJaCcyqw}!n$F=f0oDP`HS1Hg0G5x|nc(Z{ziFuk$WogunzyBiMG3beK*n06KD@HJSZN!ecw}R)_N(<=C*Nq{>IwB z1uTU}z-x={{BtCxI}~X5$@t6YD4*!R8?*F$ox&lpxjg1M7h+DJ%^GuQq9)%TIo58t zrF4DI05x}ubjS9L2Te>HT}D5pK19_-NaSRGz)$DR=FH zCl+6Ol(#zYC9vrX%T0aeZ4Oo`$n^C;<+I6})Vb}T#q%nFoh${aMK**SUOoVvb#egF5@AmQGF zpdG_(!Ob7~ERliHx608>0?Er@Aa)V@!2PqOs1$(Wu;{JuY+YSl55g%2f8x=jM}K}U z4#~?S9EWySucpGq3w8+J)v}3L6AVefoj(r_8kIU8#hN(avs{nAs|COfxIZAd*RNlH z7#Ij*Q(pZ0*QG~Yv;eOJ>i}wc_-eIy=(4i1oHI-N(w>-1=F4 z+lg`N_SDvNQqtOvUH|s&U{kuwyjMp;P9^q)QQ`i!*rS{p_C?ut)kh2(Cx*{BM@dJ0 zd0AY9tOb+2Vyny7`ngmm{K^% zP)Q0!q+t|3C6FE8F?so8uF*p8+*nio%3Nyp0(qm_8FltJnG5?Olsowk>an&kTI>3U zW>mG5T>7kT^y2vuf=xJG9`T;B4(Cw*2bpCF?KA%V>_sg%EYS}qHYq*org^Qeo&B~CT#Pm-%YeST1W zPK>=YOiAN7qsmA=cVkUntWMv9Dry#SyqUuK7!)Zkzk&nFq)Qb&cExmmPG4~6)EIE7 ziOsdyCRnuPdQ}Xss%t+o-6S=C$yUT!*us{j6!py^P)S(+Ow_yc59dvz=DelLS&mfK zF+7xux^q}XnUspc{XBz6-zAO7JwMNCI#`pbn6mX470xjXihk5Gv%LJC{zZ0saC&pQ zu7H|a*Pb)&<20v6lpe)@V~kh(>vHB|1UJpTm%53&+Hd_h%lMGHf-*QILXF*7j1k_@ z%_Z}#o4zB4oc%lVeCON>EGbUxD=>_G<8a?jEV#q5PA4r={O0znS-Tf14x8p&ZJ|)V zl=%3?(6tjZ;X(m^)xFAM4DUqG2Gn1;pZ!AX2B#Vww?41pbT$i5j7W-&4TC9P@X6{& z>g`TEk!hNzteigy7`6MiR-K?Te%atm!a7Tw3(84tji!4GUfNZ9tW3nkCnd#7L~)-s z;?L=2+G1U>my-AWqh}rE9<^BxP4m)5~5t+P~@=E;ra)*mzIMt*#sr$ktJ~9*7E`u8J<&A~u4Dc7 zif%!CSoaxjr?%9kuWHmX=3|A}%|=#*k4;!*b1`I~Lc=3_f%d$kV$EZ?1Wd9%} zez-LxP@Pm+u}7>>{B?asfrRJDhq1dTqGe>wnC9Gd^tUGXtH?HdxUHVc(@bCaoe@Yi z0e@jv9})*X721TX4>^{q-jeS+KEsz$cEvtDqcwnkl6#(}u$*U?p3DVWit)_X3Gqk5 zB5JH8M@n`*c;{DUB|hYM(mvy8$F&n8VnO{!j*lgzH#@w!wynsPIWBnYRZeEzo`G|W zyip3*oGx4niB4i{Oo>-|(r)-vzkPpOz|D7YwomrhctxpH8~$5l zqigVNf=pD-;u-(HmK5F%>+SWP_O5)<@2nq(w;Wa{>p8yDn^tH)d0q9zPtlit>Ys`{ z7iC@SH+aR;gX@id5HoEg#c4kB_b%LysX@AIGAuDHmrhx>`tn9wyT4IvoD^Z4vv;`Q zY)f-WJbHVFgXsqe=HE>xTg2GK8cAJdUN*R~pSOyMRsMp&D`}^%H!dXL#XuX{58Wn?BC}ysmItv}kb;4JK6*~NKSJa*!O`NFpE%e95mJSvXIn1y1M zo=2S5M&(T5usX#SrV#wupzEe3i3zj9Pu0>f^7leR;%`b$&Nf2YGTTBfcKD*9>d`b0 z_Pq*GhE(F7zRbo&L+`e z%{hKV++6yeLdQBRy(_OQ@oV>tc}Pp%>>lILFNPd{T|BSc6hEcYu|1y0+GX4&LW6B; zjg~eHLZ-$%mZ3&@*Q7&D2^|M#5}y4l-uWq{!}_WIyEAv3rwY@k#HmIYI(~2o8W6?kwX%}emz$+zyOj4WFi*fZ{R&r|89ZkIO+tV!8l`BU0Z}Sv?G7IWp}&d@Q}P_dGM*b8hG12ItsI`jc%+ zEiz}KWsWPJdBPr}WX0_q{VF~ve&45P<<@JqEG=yGn*X|tt#RHXwEkf`7UCCm z;e)`rf(O;D8gqsuitGWk*PqOp(%tL2zf_|?+9h^ljM{MKvw+brj$PMe4r^;meYSq0 zxu1XC+-vKZ)FPW>Ma|#y6t9_mNQs}AOO;@C~6SVBd%uz6FRt~CVJOCwk>28#VH-( zzZuP)Eo;%MD1ZKRal#Wp!*;e5!R`WvQ*(?r+{pDyY3m&rx0DWW&hqS)za$d>qSvO$ zrZ4laVdf`&)i+ENy386pF}4@D)VU(-mcCzh_E35JXZHsl1vPzYCbu|#8tqp_mphMz zDzMtv*r0P(9(F8HG?&^aST>U|YrIuT74mU>oQ=Qg&kjOHgTW`Qyga_&>`s{LnGVeS z4H)DF87MFU&Jo-W8na`!$0=1*RNOJ*K?gO2848qtB*xjVK3iVDD`%xJSV6|%@TDRK z*&iMr9?Ns#KJ7m1;aib4HB$I9_$luo`e%Eb2zW)*kXIXhq2^SVT+F?>I=-)VG%JTy7c z_NV3Jzz!uXb*`*NWy6DFHUDm)cO)qJ0&BCjm0;I}( zYqcK;4I~B~i;Kb_^bo4yvcBvL#-qLN-fnzp$T{Zmg@|N@U%yU3H6)OC z^_-GzF>F??&$q3EvY3!w57@ek;14h`gzyaWpWEzL-kT$$wJZC+eEEVW=l$m%6TvOI z%#F$y4)AnJZ%J&!LaM@44}P0~P%y0H(Rr>74!^Sy092p=YkecVIewj%v2p7G?>{>c z3!^VgQ{noLHG%b!(xsbXU1|zZb0oXe>#r0E44rDu{z#WALjHU};C;4EZlhaN&kegS zlI=#FXQ$g*lUo zMqOI`@eFT6k0&Oce_!ZuV!&tJ{-yR`^=yIHnp>_uHz>;1R+ad#>g>_&@84sPAY@$l z9_wF*H;(ext_xwXsM`2DNZ>Gl_1n^*5=H!bEkwRei#Pkc2fG$MdcJDQjBY0hXIR*yl+eJ^yrxc}m1ZFtzZyQ2W6{g(volIJ`{1eeqDbiGjB3phxR$b;xL} zUKy{(VbPLH1p|ksk1|V~4QR2GJ06fd6Y-qyhBOZyxk$pkj2=SP=6mj()G>Teh#(%t z#a%ElY0LN7xY}-e3S%fikpNowFTOxeuMzP<^=P}#+1pQ_Zqm7~Px;b>K=|lF{C!s9 zd`23AsENH4aLgkRRH`|b9ZO`yONTBy-R_hepd&@^_-mvs;gYv#E0F zxZNtl*vO)TXhw9OIEX!vj%604Z=x*~s>uuPK0QGb|I$!(sLViA%T!10A>*9Zqv@8t zw)cEhxxcUcKHQOck#1R;<07<^#GCDuSfFTZY{USqq$(&P@?h{6lCz>(tjng7?m!@1 z1!RzbkMIy`77}OwL?^Gyxd=NBl~EQAc&c)gq;Ncy_DLcTQSgM#?*@R@G49`ue~^%P zg*3iRy!Ew(U{*1xmg8TPQ}2co*<&Ft1Aas0jjnUA`As8)}KS=(ev{zX6_@T zkR_@LABNOGOINpnJHP5Jrpq?a};vU@Q37@ADE$Frkee$4g+XKc3 ze=#l_y#pmjrhw18pGeMfYQCui654$(#18wR0AcS_7PP;Zl1{BZtJOw3$yzSllIJpz_P z=+LKMZbq-IN(UkC!JMxD(%3&cn;a6-cL{U9r(^F+<553rdTD~D!0Xa#j&Po|LJ>m)^F?z zp2deg6r${E452^pa_{E5>})Rk@_e?Km>6As{nmeA;-Kb5kpVK4 z{Q1L|2?7NmKy`K;t}f-~n3y?ATN!l6;@S zjwYi=+y3N%jExjqCI>^alyxUEI2LSAC$MJRt9a5>t1rl~FLPJ@ ziIAt!VxB^8jywHpzNm8FF68SUPjaVn?>9L?2TiBTlHFQFcNxrlsd{qf)u+w49|@){ zB(XKCnkMf%1fHnbDfFb%WP5P7EkBP=ndV8YOY^KUh^`!0G%fs^J%1@HC@QW^S9|ip z!t`skOde9f8{%{t;Za;tZI>gtn){?z47kV&$5TH!hyeSTbEhyYe^c(_|7Xb3ggcmJ zg(1H;-C2@1vF{3LL@`xzZ$m|&oV9B{X@W=NBV(Gv@6Nn@vsN>d{WtUZjjR$&{ZiWR z^?7<4d<;nUTXFx8>?&(5_-xUS=a&?pN_c^8dJUaWYTJrtoHQk5DNJ*nd`4e$3VX>< z@vYt{)2{g)w*JdRxgc(a%&Z_`o$L-@<~?2|8L6O~sv5Zkd2wrzZMK~5A*AI46EiW! z+FGnjVnh8@E( zfliC-zNDPZ9b*@K+SNGAPLP%#;wjOcnQ$3_RRYb6l+G*Y=wA&u^!E2#A<@R^BJ)LOm-gxeM=eGrvIkRi#`Vb1Ti8bwZD zYf-0ETUV;$%2K{h$F176ivtUZr+NrVMR3sIFZSq` zKM({Xnadu!{(%~=vjooqP*N;W!+YzWPjaW{sBUf!FrbOrC$X zLk1x_>=})t{Rg3JsBA7R=&4irt| z&zqf$;x6}-H-27bpx6binB?Ya{?-#jp8faV5aDcso{S}=VC3|C;B!vOKx6JymtWJD z!nD%rb-E_qiSs`Xls}DFpO|gq0-XQHx!xzPi*k*R;*J(mJLg1tX7kR97 zuwyJ-`h6RJZ98Chcl1mG@oN96yue>vft2L`QD90 zyM#kuAvMxTjN%P`9GnS}kL3CLMlu@3`R}RWJ3L7gHQ!jsvrs~w|MtlBDj7IWARrTm z4%NodQDaBoS;qZ%Km-L0b_9E14~q)^3^6h`M$l0mCuzsys=Uh^4LdaC4vx;1>DtZ( zx`{DLtpBN}p`}G=4)Gepzc?aqs}NQLbZ^5e?{B$pu1wwjSk}OhGL5( zgB%I6nTyHy^v5aXvvz$eEY8ehZ_xn3wh0VpuAxH+OWsHegVv3+&2CJ^Lfd`2?)i3l{l4+I!xlspOf8kGYikF1 z2X%6?RY0OlyLxoJze>r{cHrgofVsSyQ9c_BVR&QA}x2$ zYYtxSH3)Va;`+p}LY>W=?B{QJob?^Aq~Ml$K{q#DH@A|EBReO@O&Ky3uNh3lBH5VsGsuPj$Rm`g)!;G_LU!4`NWhaaN)7noJL*rfj z7M<_kn`y7erOE&#IJgHvk$iWmJR5W#Yi75%w?k%vnnOxj8^cpvxI^{Mb0T=~e87IB zLc<}6c|n8AP53bBWRVvX_B!@sb7ikz|CiSV@nhlQDZu*UYWR2QLbeN>I&~hpt7+H6 z2_5XGJiF{%w~y-b(3za0fq&83;`k z4g>IK;LyVtLHdP)>gornh09MUKYUN1v48S_J{M&!*O9|dv5VahHUblhp-?#`g6N91Q~ zKn#Eqf|VGbm^gv|FSWGPfR4ZK<42X&G7O4ibM6qJQS94?VdNdy9H_*ELC*o7_?U0r ziO&?NL;?xu&6~x!+0>_*Mw|@w*J#J-v}Qo0dsf$irRR?1r4Dz`=z-T3LKYY?=t4-N zTiEvAm3j=RwNa1-6}7-B+#tSXkK2l@;zoY z`r9lvo-Wv;bP#>Y&dEw8qV6PgfV>T!p0)=9gg-EZDTr^EqdC7V4q@VWwh9u*5H5ZQ zE*yDz|JSedb7HV!wxMp~RR+}iwpd$!skn*P&;?frUz}B6wjMk$C=L2Kw0N|`vzK8b zg%AOccWi8|`($m*_xP=3GY&rgZ;DKBsU1n$4LX9(*h*6P;oDbK82@J7Gq`=F{2)rD zjZHca|I4hb?UURy81lFe=^^(9-$?4veY_c^37TX|tFHgo0#M7Z-x6aKW880%Buq0o zkRdm5QReye+(5V7^fJG;t5qEx3l)0`+Yz+iG#2^kh{wc-euE#*r*yI&xsoqx?H+{^ zGCDVdZq5G512j9%PIGrW7H@CNeotmuS?5`um8X&Gb)+AUzIC+W6C9#H-Og%cT!=E{ zZPDSc>yKdm6r6I9%s)-DYG_l!E3S3ooWmkn6_rY6(=N_3CQ*f~Mi0f@>vTQESKXvz zXU-2gh;VUp(=VQ&OJi2;$}r`FCvR0ND^BTb=}*#>?CkC)G{E}0UHRJa1~lz2BFxOZ zdo!8288-}nZztoNNXN$HDRVqS*-}P(VP;44o0Hr){=m(<$Yz&zQ>$A0$*28zV0@+e zo_94HnE;84vY%8d^L1ERiMU|MWQctj)_Ueeb;UAYaLB%-^ml*2Uu(?KdJL zW=`K&@kp zF5idPoGBL z3{`&Y(kO}~HmkDoUcfbI2lu|F4w6H60i#)bI}lSj78z}AN-(^qP7zxl6R{zWf>8XU zUFR5Rwf9Z`ThrD<9PxP^0*w1rEi~rL?pk_C979C_z=&QJz5zgHNFUVGqlK2ce%e*X z%nZ8b$l65Bj6z16*wqq7|NZ{55*v#>sHT#cbC@<~FYy|t*h)qrOF$%{Gut$F_SrL1-@IRB?t9yeXh5LDgW|9Pf!zrXvR(^Sp znV{Th#E++rmy2r@vmOCEMnzH4$d7;=jybA;z7l1}*47r^5++mU?;nmEiFp3`CW8|N zL@iOV1_oMymh2DMDX)#fN9g@Av9z|e;RI%saF4*F#k<3qlDxT?;d<-V1yj@Z8m~3T zN|-pen{l2mVoNsWxXDH}^46bxz0Z7u7T^Yc?8g7cnhy=NL#;1Kq+G+xse;#3yWGfc zXJ?0qeo7)sixgi2hFWA<5#Tipfk2}}5loEl9tWHddM=#RD>=2R-011w!6&!;>$*=H z6iaX@Jj2Nh1GuG7JXR!5fu!4$hX@=No@S7l|JiL1qe-?x^+n(NMJwc`&rt9dVuT^I zz%>&iPJddt^C4LJRO=&6zB?BUW~T3wlC7(aj?M)LCC2HNuaZ{Adc^V`nu~rYbNM8Z;$xXFE2=M zA)g?ds0tmXLH>UVrv>Nhn1{XBu0i92CcdWr&TMrPdKE}}z~5MjB*1FsIjw3w>a*Fo zr3_U*vFOq3*3=P`O%fVl7?xo83H$ugnjX3bCnhDldGp3KtX>n0z?-`7@xoDlac5C2yJtZBnEQRy}&K@{0zH z9t5L-i)Qem=Af9JU+mFbsNL+}BHRzU1_lfGV67!DF_V17YxwH*?;;l$*K(^t4WY|y zT3MJ{>5i+BgTsJ~>t|e-m#8`l)b+dMBJ(=DiH+yE?^1Nsf zxIJK|Xxs7Wp?R%sx_Il$iH$U37$=FOLQo{@LT*@(T zv@I&Q(#M58L#Xud#?bWNxl>7^y;VKDCP}EEFyZ1`AW*%H(9ywEiN+0V#*oj}MxpZa z)YP2;^)je|2%k@R`BL5Q)iB3Dc-`7Qq}5o99t($KRq${aF}3320jR4=N@AfAM{8(O z>WCtyZDhn*>4~lq#$R-msPlMJ7)e?MpFojvR2DmC1d?Mg3a@TVX&gFq<@$A8&LD^z z2XHJBbP4t`l*KsJ-V@(m`31-r5C+5;Kj;29A%PVmJn9U7A08nR4hS6>N*e$hkV~k# zoF=n!zbZHFPZ%#RUaGSYSdMfFg?%>wyb`QYNbW^+0vpxJ6l%<1stW8$!71xD^74(+ z@L6F~*WrZ8Cv&}Mp78X5;jxfL>qQxU07w!^YzOx=YsE20j2HxG-nBEJzB!Jq2A?z#2O6?V#m4D3>7Q#+9;G~fCbIpNAx~kJ z(QJM2a)Hwv5k~+G_QSKkBhD>)WK&D-FWaL`w(~f9mYp44*e5?Ot#9|6ECmM)vcoSR zAmXXUlq}0Y`1Xsns7PJHVTjuBlp4;9jEp?rme)US)kp0|Y2S^b!3#Qiv;ZEha{NpLrE9!XhYmP;_k^95)nk7PP!2$a>GNa}OkSJkGy}Qb zU$j;vl}whZJxH-jFkWq5qS2bh*Dt&+FLzK^du8xPeUk8lH#TB)a!?JtT zVsqmCdCgwVhdG)-KSI{!3l%hf@Rao58W{Q>nqndU;qoUE_wb~P23xw6A*NkNleZdh zMb(bw@3r*%T3Pn8Q!#rOUyHN=gN>8(_Ari}s_QH)Dc3(8e4s!=E=QyIla)%^@~Q0e z4~m89A+|JencqI2ejK}^pC>;X3G z)>C{_`+5IX|B<90)Zq9yQA3^29~Ve9#>!K;=^i3ELN~}hEZ37LL5M>n4OkNsAd$Bn+H{4+LO6M2m+w7Xt0t7>04 z9miTp1AzT%r6F%_pvt((je>c)k!ME|llYonZn0g6yR(hbkE(d*O5b(pGm8d7zc|KS zD)Bp_6Y(Q!y^TyBXFd=)+oE{fqBHm_Hp|R6?@`;t_us!K(YwV+-iF$cogOfn0~rTK z64}^3HVXj;cNjaDrMITG(D>RrI!@NE$8E9nbhA8@78Pv*W><%<8Z&apJ5KW8ixEe% zd*6NmBRm2=Z!G9!(wnilKhOjl8rz_;BMcNM@Py+YToKVhqAhVkfW~Hz&#ERmiTTNd z>n_-Ke;WC{DVJYO6)=+;W%CSd9Gvch2M|y!7&e%GfN6JTUC6L*89{rr4DW~rgvNl2 zkD`SE6Z41ga=^bB0<@t3f=|S1ak$Fp>u2TLL~^h&v(z)}A^Gpd60_FUR$?MXFpDA2 zgPv(ZIe{_Z=T9EMyYMWa!24!rWBhEMZw2Xaf`v`>Zx-^EP(_J$0UfJPy`3;|V+$fK z9NrH>-OOLJ%(Ar{zD4*PAn3RC^n8jwAJ@+8NQ#ktoX^ai{z-L4ySFKu=nnDk*Ws5z z>0ECi@JG~VL6qoZij7xrGeHA3Au2nrlp+ug^xb%3D4uu;6D$SaJZQ!rU}5dB6*{DB za6J1xsy^GMB4Q;_MTKN8n3-vyv;`Oa#LU^If2BIm*mz@y4o9_=?#Y_A(!ZqS7bAYW z=xwuqd+}!xx0iv|q-H?!sy$<>jmecRpAwoA)r{9yV%X*C^j554?-^kJTq-ve%&>dJ zF<75(?mpdY;|1f_^V2Inav6{8SgF0DME!Nhg^xQ^j@Ev^|AD(&ih_er-!!f4xQC~R z^O&PZ*(;Naawc&M(#x+*RRL2lSPtdyNtX3v7foOl=#k)3ff$XUH7VFJYsnySq(%IZ0zjz+y!DU zn=*OE*iO9%cYF{+2B;e50Yk@}V}3*M^Qc!4pQn<%`uY1ej_*RKAaLr=RxRxRAI)tc z6c6uLjPLyrdVUCipbCdW8vR`vp!n(Ezik1kqkktj*%oW#4|U!zHN6aN6$BGCPT}l8 z7n)zYc?NO_SSexN&HZ{7O$lZa^uwT>*hZrOc!8U-g&`8P6H6C)5Sfr;CIrBio@-$@f zlJ~gi!<~%vTqhjTbBr}iH|3EU8*p>GQm}|dPu{8qTyj} z%QY(6rQU-})`$TKy9TJI8-H#E)v2KoCk!tbeK4eKwX3$#|GOJiwfQ@o+h0h;UNCPp_6lk zyv2XwNZmuSB&vCEwhLp zQ{EVbL7>$&HwQKpJ#4ge;icI_g3y?>9(&AJco<0ZLUF>9#DZvTG?zGb83Z9uh*hwk_xmw%rtrtJ0!*69x@@BibUU=79p6qpKD}P!W1k0#__H z=EV6+9*PDE{5(zqP-4i?LB!7BpsJD4A%Mn&xTUaA2<;a%LU70cvLUJE_$590bn->j!2(T&{H#VM9Px;myFOZk$>mDlbG*kV65Tgm(mfO+p5Pmx8z} zTvc!cFPiY}jX)=ap8zq{jKvGs5QP^dwU$}Dbo^?$oZVI&bZ=W)h|uc)agkBA(*nGx zxAq$b%7KF+ij=X`-bKgU)H*ry6faVR^ZOo+)6D1jN>3M*Y-*?(TJ3aT@wmQZ@S|6w zE61fM>*=gA!>vLNCT-rKqWcba?8=DZoSOw_cXVf(fJXWb* zc69Yq@v%Dd2L8sY8&adij~PgrR-@@9>5{j-G<8s0D&M^!vid6jlUZ5v>aY1)^SwqT zI#ULpf|{CCF72Zqf5-i=DXgW>p@>1N!}6VT)=x)nl`&88_0n~{C7r*#&0%vd^Yw4@ zmHx8)+gMu4x^$tWXah0r*vRJon3_r42K5wb z$wCZqz@QNl1fUd7O#C7gN?kqt9fCQ;+D1Wyg^bU%>>S2kP<&L5b+iAd_mIHSbrN7H z%L|YWfPkv(nlqTWFQ?1Trn->g+bY8Kt)awW z;4PE|IDhc>pa=uhf*k{Z6Gb>3Wf8+8OiRM= zbPyg7Uc!qPwlZF?L9YXyD)01qh*JMlBSUQ*WeE)Wd1TPhg?n~gg#cBYS^z*IG%`5(_}+~;y+T-ky>Ex@DWW!`l>wy!(ffV9vLAVsY&-*? zbl}@ce7Zu)?d8Q=+<_m5QordM6_&wnK-W7Zy^X{NqRzLnwh-H$knuvn1!50>cl804ZEV zf)@@J@agn?rqDLx7Bv|3h(aqAFXp{2hNw6c*ll=YUbW^LYO|{hvQ`9jZhZ$sZI5HzW>5B{mlB1spGE z1n}NVt`9#1F!K7fuKt=h<9?h!d~xKE7{IRw`~({i;zxq$Dk>_1@&sSpfbDZ}uGmeq zW><<`vb^Ogj-Y1yiUR^oL0ZaZhZ0gj?Szh9?M2ffqN2Em2_nKxCAA{v ze#L@DFSAOwmlTbM!W2M0jx*rCTycd}v76Vf{ql1!`X*09Q7&uVz>v{nk6j$M=Sp1f zT;Zq+gd$HHR|5kL98!pDvS@&$ZSV zMk{!if1l8qUTL%ssqVj=c|A}k8w;JPYbP@9xobug-Oh1Qtn*T1DDguZ-&o)Dx4L?_rMrmv@5#Ie7@ z`~(M+p^iB?P=GUYb}mqRTPJZWF!1pk&!Y%xO3%&?MuBX(Yz76OMOd+QI-Pfi&J4HQ z*>yCNcJ}s>&&$zfYHLS2yrrerWfrO^m+zeb?1JPT?o{pI6l4MsA%h_4M@KDzN86l{ z#MW-HMo-uTdWoWs9`xI_yzOm=&Q@<$KTE6}vG&3%&X$;ajs-Olx zVRv7K#YuB!cBJwuBDKN}9%dH+>DYESVqGqsocV&L4S^Iu$WU&*Yt2`i-by9{-8vkG z$k^ry7j#g-d*g8{B}6r7oP*XMsia$5PCoD(fGPuOOz2u*>K@Nw;zEREwQ(AzDkE5hW%1vCN-;x!GR6 zJm)R}kn&KIX_lciCIRy=LqotGfPoPs9D-nQ&#F-4OZ&qb8PvcSaRF~iitNWQR1@Hu zbMB_GnHm}zI(mBkxCs>*Ghk~*oW!6vi*$rd)L(9_;&}`GarS6sOX)zaDx{X;O6^D` zp1baS^%rQzCl_-rWYPRjdm5$02BfdBu#j|#5ekaRFMN@X+r|IljKFRIT4*QS{ow<% z$pVPrv#k7`L1w)Hql*@X6;{P1l97L^i*bPe|CkdHe92iWzSR*Lf9kU1?F zUfyt@s5Q?mIq8!-Hn&V$xwW*fZ*^mdS>&x)o?P^s!k%%DEk!Lx)BW+nweHG1DrBu* zV>D+F*Qk+ULmqSN_c=owuU3=L)XY(8{WFl)>ps4%t1kVkUPy;Z1!HcbeG48a2H#7TY4D z(NL6?+n#sjSPEDwUa_TrTx&%e7n9`#Wic9bEF-Mbpi2%y@fb~9Mwo?ELCEj=N51*@ zB-4bz;V|q&VuYRF?ek|hIs?om&;bDW>axSlsZX)X3DmiqS@>`mk;5y;QU_%-Mm6FO zI6{f2QH%{l?dF`u*od)?Dq;&E697Y;;IKfKVpQub2^g6>g?z^4x*Bpx362qc)}A{b zg#KR(P)KbkJZQ{Ahd~vy1~wvO4g@{$AGyeV{2&oE`KB7wjo5Z z9$%N>kbwM0^-rNQO+#CWkI?oz)282>=j4k+A&q#qc#!A>2$Twv6<{oZh@{gpH|OVd z#z!JhE+k*qO}NnVEbeoa22D*|h6_0Ro6pwlmO6AeX`lYOOQ8Elt+Bgy&89O+66Hn3 zM;vxCv-pA3l9*28oIoJnjIET=@p_5y|1IBd`C z{N4)*!?$iz0K1|pI)1F3!6jpF(1i_2onyuDv-H; zrSjH7e5dCF09*4boj$|_k>tH<4@3r>6P4M>gZqn%iK7GqgAE9!L6XM|C%9$MgoKy} zd`}nVFXWD_L`$zw@67@tY%P|d^>DSNk_iXv|8iAvZ#maL#$)+v=d8~l{t!=EmHVa0fHPDRpo&a%~H z&(s&O#*f14EJ6dn+@^)TuiT!mtX_H=zuFw*?I15J-%z+@^|C*F{g}LDV(C}vGODRI z$$vvT+eLYS$o<3#TOsluH!@$})7U%a6*y4BKp$EYQDu>S{i!+ckaXpjnrGgMRUgl@ z1cpA_JS*uFe$3qTRc6qR6Nv0Meva+S;=Vm0HktW3nu$FxpU@Y5T%|S%t(4zV>bm!l zMrT}9zhJ3BcD0~`>AY8B(J^z0+R5{w*EXeA3+SIFkXPura$ICu+4zywYpFlMz0@c5 zJC>}og5hC9-_IhQpJl54?uPGAoB#foH~Bg5L7YwbnA7Qgckw6GUSTawU+(?L?#)iI z5K7SI_;!nCJbGd6Mw~1E9mz*eO!uGeoGLdqq9~tI8Jv`UxLA9;oHS!o0YlhyDR0bM zHU1R~-u|(Q1s~1w_G-HR{MrL6blSC_jHgeBd@VNQyt-Ae>J-K|)0Z5dV!B{;?*7BY zKnagzH956KlGIffUCHx#W&;b#154K|Wmn{OToN2M^Vz==erEpTe#?>QT9tkS=HMIs z=H?2e#`NKz*N07iRxektd(q!G*)U6fOODXTi&CsUm6e(unGmX6QLFd3e`2F}ipi?r zhjIJMGUL*?t55gLEP1-_;hy-nHj!;${+5I6s$4IIUII%(k+!k3M;loeY(mpM-f#0` z_Z16^ZF+i;yQVZGHrKX{GO&ck~Idh6CdMFz8_qf#EPj%{z5SXiOUonMO9 ztA)!@hGX=E$|&h^;pYr~KJrXqREeKQtE$ZMfByWac$(yO;hwt5)X15W!JB8RZ$6Y` zA-Pvas!k%?qtU zd3N=3(&$Nd%`*+}sJ8~zOH@CcQ3E5CL301Q!U5$Q!M>Pp0W^Zf0G_k|=ovXwZ$k8w zp^+G6t-e~qq5YlJ^n?s|!L3;{;^$C_oSd9|qpD#&;|NA7Sk)UyB?vt>V0Jw{o4zrK zV!r?UnU=56;jxvC4d0puaJ?irNJD0=m!LOrCf9f5d3g z${gYNo!&VW?K}h7Y0EG%eD8g5Lo&vs^4M*)mG<|AL#? zW2Qkt58dp)_}{JS@NW^oIv}JL%iQj69mrh(QW8P}5X}}fpLrPf7lBd#>bao4x%Ky} zgwn$w?`PM?wPSAHJo@Egn3S)hu*MD&=ZI~4bRH?m(s0hCZ`LITN9U? z$lJ3=uFg6(Y+9LIRUL_UZczH$&LeMM{F;aIJ_j|+Hea@L+ekia>k?a&>bm?TCT40= zdn0Nr}{zHhKEE{`#XPs5_CT1hgU8WDntYr z@GZjvOMe5_PG?5Tg2(h8pFe!q_68O`S?Fb=*dkl331cU*bP5V00rgST|2eY{qbJ#fus?Z5D+s&?%CI`zj>p8Xy-dkKsGVe znf#9|gP82JI2y14IpW%&Wre5}v$c9p)m5C+#NX(PzHu?`KY?3DP7Xv9Z$USpF$NX4 zt?!s9x(V@0X(*!QS2M7 z$q>T72xkMKy_#?txH_PZ#4i|^3DomgIBt*tmI(^M2`Bx-W0I{CZE=KG^6{WN0ydG# zk6*B0TtgcoAKaK?ur7Ek{Km*zQi3Z)Xc#X0CiD{U8esQG3Yb^85^+{o02nMSA=<@Y zNw5zv!VpN=tpmwQOXqXXZ4U*^2c!*42Dl$F-{W4q6WEHtC>ItRp-@VI8W;u~B%xs? z5c4=1Dtt;Tk^@z;>4fs*0dBu+67IMi|6bNXF;yG8w05;GfBByD@=o;L0hbue6f+T$ zW^Rso^|H4k?t80RzTWkNjd4E#^WsILFd-X>CS)F^~5#ee~s0Mt7y=aBa^7w`wWya#8nko_VX)M8C*uO^65Iy zp`s%sUI411+a@HOg2L#ZYv2KD#^BwXiIda|z;=unLF}4s7#W+K0s9GK?EuFlJTYey z0ogu4hF<_C8#IEqXRcPyhO`fLksO55pthFGRNNf6NTf|8XQ_H0(+VC(_vxA_--$?kZW4oh^Gtc4j%DtRk*Dnc1=u zXC|QwA@j^+uixwQ{r&TO^zGaC`uN=E^LoAB&-F5{ybg3c^8Nt{36KI{`uP~4_pnt2 z9KT5NoKW)L_DT8)Uzj0H$Fg7tivgM)meRp5d^b+Vw15tm0fC*v8{kK(X@UFj1$xPy zLesU74p8&V7BJ_u7{i4CAq6$UcNF;x5>Rc2E@LiA_QUr9eHoasBC&yZh^Ir&F<=5knBglB2 zhPcV#GYUta{?}OJn_?)qg2dvMb--5v&-mEc-aAIWS{u=J`g}TAZ2T(2;%WM@kLVb; z%6V+DT+qHe(oq+FmdV3$P33j3Pk>vq?2|i6ztUYoqpu2Eps6T$^~|16u5oW5Ix~2x zSGyIL4qt-9wa)|AffHp$Dwpq#^&Y3mRkXXatJ9IH_M1(;ikrXkN5(~A^x~}^M+V#N z{JDs`vF_hK@1!e+dS{CoMhg56un#6znNliIUhQ2`H@+3zdtgK?-uyXGH?_908c|Ds zEINp5U+(9=pb91DSncx7>?qYqXBOVz3tf}k)q=x^A@&HVr?9I6b`53OrFnISoY-uu z|4p5s(pDI@sMec0$nAjojA-b7{`?udA?LVt#VJbgYPP}FaQJvyNV80{eAI(x_vIAB z&5CpYR&N>MRD*)*r=`=t?gsT0DoOFs`^(vo*Un-Wn7P#0GB#>xRB>VzCXr>3AC6av zEYn#~$;CM|O$fqoH@;3DtGT3tbPWb_?0rzJf6+bZUcg548j6 zQ#fbTu4*R18@7gzt^+_GdAO|V0ynBhku_F%b|XG}6RV>e&=0)V`tQIpDj3F0eJ0sN zMOw{tRi6f!TfRx~&e@ax41#Gm^CP~%k&zLfq#kai>CvFO6*GGqzOWb^ku<^!Gi9l;X!cjMvd*HPW`gb#^83K|kpeskIG!k{mK#V1-d7q^VilOEq z+=Rs)fFNdeBSQ#0{zw!d@Lq_O6GlqpR0jHNFvCv@C~h73?|=!%endhVH{qQwaK&@} zzOC)ozQtjFbf!sDaCAKKF28=A6L4d3(IAuC6wOjX5~0#O`SY ze}rj)Zh*)kL0|k8&fyAem49T*^e%(hXSxB=bolJ84a_brfgQsgB153iorE?64& za-m6uMWpACO~P)%819ATA%m9!9LA zzkc$EPEI$AP!Y%xFGdJwpoFA9Ynal`ym4_yH^S zhQIzUtboE<^#V|Z7;!;})c}{?BgI52hp7?C(;boChIHaim^zW1kUTpC(}J}O@QffD zYdN{Olc|kiUUT0sK*PUTX*`7pvx28TY=fk^3EnID4a=*UNI1yZ8Rv}~9gYJ9Oie(Y z=?k(VbRU2gJkQ#^x2<8lNs2g{C;^ImF#9HI<_q z+Y7PBAm0HDm7oLi2CX!(o7Qkt05lFxh4N>&E~L>WfL>Vc)%o;J-|FXqWj6*q z9+_-NJHia51oW}r#v){}UNjxa99)CwZ$zjAq#TqQWcLgpJ{TdkrI*PXEs~9@Z6UBs z2n2J;RtG3p#xR&6dfb_+MRi8=!2&$8E2%XX@N78SWZE!P5Qwl1%7!|o@e&w?;JTnu zBR_+`aRCOl9v`aqS^@(!gjY@%T+O6Y^njL(7|4G7_}im=%;#k5iuW(lAUp&xJ-`i+ zcSdkeFo5J56u@=~ZBS~z((y|_7oFqnmV*_U0NrFD!4~n+zR1Wx7Dd5_7w#+qTL|D=#V4{ANg7mori>B4>tGOpQ0l7yKV^~S zpsJ`0ctGL>Bt9Y`CoqtLuVk>=tI&o^^|e0G$`b|h07_=?fWNn#tQE;FA`dG%$H1ofK{t^hv}HNCEB)xGr4|CtKV5urUK+ zN;W)ig}qh&MTV~miJ5`963IX|)zXB-UN|wpF|o6coSvQzWnmgD>_{jQoD3i{?g^R* zBB5`d*%^c)5XW4dqs zPzU$Wji_w4>FAT@L&WMhPbsG6n8-Qx$o+Da|8 z(c)3s=f;u&w*O~;JH}=z{x^&J4ELzO`7Apgo4TRj&dn`~Gh7UzGkXUc)uqiv`{=3D zjudo?g)%9do!5i@#rn@T%ADflyboQ%ln(Eb9d?}u-d%W9;ZAoM-Q9QJYW1uw8ksj` zA0apTu#9r-?^%EQ=R2`#)+Z{w>ppo98>Hn`6`9yBF?^fZSm;@s3m~;fJQ2ifr-+(O zA@Wn81M_loTMn(cN$&}uHI_CK0g0_5z@Zfxia{j@pfYe`(8fV_1r2u5Td!LpKV`Oj zdscPpClrt97GBt`0EZ%I)&O(BZ~_It_WjHF4AELG;#{i5)O~LBrt}9PJ?9J0-&562sHV+b_e#07 z^C6(HF=>#7eNOq@-G2TKdNul{-)1acX$r<@_blL`;jr@Nw|pjFBqVQiXxTt*!+xm=pCp{F9pD z8b8gyT^|?7*O7M*bzMFA%K(>Vdxme)aKDt?D!;RSOjew9Q;4(W5gLULHQT)R??{H< zu%~Eu$P&ZB`K^7Mq2s-la})Fp!B4H~y=u^%K^*nT9J|{7Dbw>QQ@&v;cfWWj;idyi zs5v7sALOD@*y-Uq*a$GUFfMkFf{Up1gX(!JL4VWhfIe4PWkGRIL=vZ|yLc)z%zU3X zqrRx?d0bx#J&=~Zotr%=tK)%+W@LLuPmT3aT>h2rZ}#i=1#u>G_Liq^(a%XVR3N|xroMR)tm$fJ0XAb096Ms@j`k;(LjB)h$vW)J2s3qT@b z!c0I0Q+Ci%4TXTzv*GQMzwQi#PgH0&o`23SICC_9^z``SE{dgpY4gT!_3rSw{(i57 zc_xPDFr?8=#{ZUn_Y%v{;c7|SsC1;ybNb(S<0KZFyKnRYep;RcCKsRY z){nkqOc0n~OR^tKq`Y>p#coX>=w{?BelxhZy0p%ru3}}NAC)CkQlPD>Z_KL{r990f zg|!HX(U9O}VQ9Fbz&=oX)aZ5r>a|1xXU&!S`Ya(ei&oE4HF=ngbiXF|f^q!}N9UAo8H|>NEf=|h|=moya(WjP;oD@0n z&P4|k5z73aM7mz#j`^dXxh48MXA?JX#y`1m+xUkxezz&2$-(~CP>liqsU+`pSm>*7 zGCVr?LEnt8#LpzS+lf9Y4(gC|f+gk#j{k>Lfqaqh*Eu$NzP_Uic43NxEaPpCr=l6} zU9)(2GuUfKc-%Z{z4YnDhAQ@C6_uQ>3BW9?BPCCq}SBnZvAaf*Pl0 z&+udnp8CUJbm^YGl@!~4ijBSPhdUo%;!mtEe>wN=H0#ek`k+nQ7kXLrGrF4o{ldfH zC~WPSJf4+>ZuQ+`nUC`-v_{`FYI0yoy%}HI-s(6k*lis-8!)JIoQU4;*v%cA(_{Tg z7I~P4*(Y`17%ab+8`PKwE4gfxDf+^v?xp(uq&lbW?{O#c$GxyFHu^qUT0>lZJn>f_ z{_l|Xsrcb{Mdj+*Wjfh}8)NS2RF;}YIU*d-yB{t3s8aq%OlTPOA+AA7yL{*?1E+)$bH zSH&Fz>OS0NFWG9O#x`ld#27#FT+vsm{SVJi7)GRqG;O|bS}qOcRp+X=cUvB&XE_<6ruN0nSjYI1kF9cowxiHcP7GOX zFs{j~o;AD7^oyAJ#?Nz5Zzj|jb%s==QgOavOdlxQX)szT2i_l>rx%Yb55IkF%q5=M zS)HHs#Q8d)|Y%Aezf^fq~EIVl~Pc7w3WC7dDL3`#6 zdF8f`sV;}UQ!CrrQ*-$dL`J_+lxbq6QW!bYTzf9+u@IddzJ zWxXo8E>u84!6BipqJ+UyaD)p(4Hd#Em;Wg)HqEx_m~yCZ3s?|Rn2;9NK7X>{MqufW zi|_3WTwLu4*t;dy`A-zM&E`FC?2ey<8@TyaS9PdNL`|O8Re0KfJ2{a*>cGu-I_63U zyrie^S((ZkOdTlTOKbvyF)9|TLSe5{8249;=oJG>I-VJYq8cS?2hgl16HEg4Z-?Ey ze0ZqTV6rZbBKAU5(te^r|K%*SL=4Llkpxc{{vZvaZXBG0+?&gCzxwo@F+@2bb zZ29~~S;T{YZgNhbzS#^d){5?mtZRuk_s?CWksW-kCjH zTq)zg*Onl9MZVT#Vy>cPODSgOCl+&Zq|V~+matOBFGA75qp*+XdnKJ#0aX5Kvv|bi z4arhy>G+Q~M(f9d=B_PhFej0-@|nq}4>1x;Fmh+}_EK#sWrmwhhp>wJg!HITky1hG&gANblPe*^K`CJ zs=Mh=;)}`-Fo%WD@eoB6{cZ`c<2W(M9j(1R}q7J zYqjKfSoH9OO06Oxaa6(Fidq=|U%4k#SjR<7e9P}Q+I5V*2_2d8XUE<;(#tIzi@&Z*PTu+^GHVHG%D;<9F;Csl6H1e29G1epW00 zwf{cf^VNB~n)oTTr1z-;%y;Ev=?O-|r~*!r$>%)h@2P{Jw;tf4aEY z+S`{<7pMHzon-C~pM2ny9oc!zPo%u%V;06$KUvl}lmS2QTU{J}xJd8P?}u_rS?&Gq z5mfG1Lh191RT^B59OnNc%kAzM3-2Ct@6@Tldm6 zeZwZvA^U9OD@P5))V#a-?vq%pOC0i@r-MeQB5OlM%nkT;+Rqn z$ch}^_C}GSP6IN1&Ti$SysZA+W0v=@$wXIn#gQ*-0WOArP>;j-{q_jdZ}lkDbEv4< zl9wFzCDiB-^XYyOWWJ5%`c)YlF{ee8_}Votx3%la9sO_Q&CXh<-ujdUYrw^cI>P1%Lk z#P;i8-`MNDtX9if|D=&l>kwpUs@~{&##-ob{AqkKqd_vC97Z;Wtd{Y@R4emqXU<5? zj;YHoZA-|nnNy3}fqcVHUJnb3-1{4=dpqkquTN5U>GaKw;dyy4zq)sWiQ?##>qE`S zA)ly2;+f{au?qGk2L}h!#J{J>@0YMzVv`lsLZltnT)WY#d@rvlD`lUm^PG(&?Q&~M1L16=2R9)T3MTdRY@6Lwd zCgkjbI=Pj0w=cvc?yaYSM9-mbsc(dZs{|^%Xuk(i41E9YEqwN>$fZjS>ytODwHV~} z&vsqCkr(Xyki$z66F0s_yO&X9a48Ze>6Fqt4;wo1ZVzSj6w%&>JqOAz3-RCVW_?ks zvqKpsd8Am^fkQhtFSM*=%a$>CmA?KaA>6ly8IGTz-qOor7pVqxmI@#3PP?Na+9z>D zL|8Lvz-IL|Yad2&KH8kn9g*n{zdtN4vf#I|;aqD**EoStntsuc+))pw&js-1; z`i!1wZCLq4XL?%|XBYL2Nofz+X2{UlYqbZTFq9=-`-6#Cs+GyCCra)lmOfYi=d`Pq zRW}rmvrE02_|iAkDP?Tm)W3taf5kNK3iVv>$30<8rY^qpxVs>+cpz!$n2W2KCfjfB zOKRGs3#Lzf>P&S#Jr*ek_f5xRm~0ha6keXmWwZ|J_ULWh&5k(R=wUMAOBODqt*jT_ zGN@MEVKKnBjc)jh_bv~pHQn=@E zpH6H?_BO1d)K%P*f<4xd@g$Oh#-c`p3zZ7XCBch1v;0(a&4jHaX2f#2E`}9 zjOUJ5ELL!}Dq*nzf_j5-A2=*k{pZzH=P+3Q<8=4a&O3P|uu=3&X`|HJqtziVY-s}L z#nJBMSWs(Iz#oSl@~g1s zE8eZL1JTz5avgTvT%RMCTs6YQ5u++%RtHJVZ||Z_@3=8s0AB_YJd5l^hr{|vV}%j8 zrSz~^)H}{_b5_dlkg1a+cnbudt*&6K10TIma=S_Y7@7!a-hXX^)?weE5@>fJQ*rZ} z$b!sKfQvv?t2*XFAR{`hJ9U5Azzg;nz_t3_NzqETNqWF-G;+raP(V=uLxAjpM1lhW zxbyzoCV79>yE%x)XX??AVct60h%uf$D!{SRkcl*@M{Sp!{$*ik{Og}B{8Q_RE< zOUmH-0jPlOXh4IANl3U2T;n0YO+oH10J-(s@9Hf;KL)FZ9ycy6rA&>77MfIl0oNIl z!vSo&O@>c6$iPaRN3TwyrcDlc0t^W1Dhoi8xgab8pj5`DibYOp+rC*TK)R7t=5Q0c zkJpjj*rn0h4|u$V{4KWcxdulDJX+zGBd#x>;PK#}ajX1ga{8q?C;Vx|D+u@p@;xDL zMBrb6*CP8eJZaY#O5R-mRNu*>E8hTVGS8~3IKu?X9n(S54K$*JXx5%JgFzAsSXY3! zfl8dOtVnBFegt41-c7tkw+J=3p7!B-26B0`UHb%sR)@#eE-N%0T`` zi@e!dYHy~d-(>@)e858Y^nA44wgqSuDEJp4d3H~(XOrt7+M4U=YrGI}r%#&3R4=i% zl!bBE8WaE(A;vfnumocyvXyidQ(vvH52*-ReXNehL}@}B@Bz|Z%H>vu!#FF)Vss1$ zZ3S5_Hj`lEuNpXs-qIW?s@3b5tvdP{JQE34Ly}(?rQhPLQUQAc8tl_GMf9YbY~i^c zi?H(m5nEjfcp=*{>6USJ540XXpUrt0F#$iz8P4<3)sV9QZ_at$vd+=)$7K(b4I2MX z>X8cOk9SP05Sa`B#p^XZ(K+x2|KBtk2vR)YN;p&-;XXr{B(l1;iZI&4RIYbeTpN)@ z03-^#jC*os^5P~y_}Tp+Ug3t^t96Ixr%wg|NDgs2pu3_3#(X8NKK-Q}*HM<37U0oe zYP#YieE_{F^u<$@4F3EXO|H6&Q>`>!EOXp>f1eH? ze=!c~hL?8VFP^8txhng#L3|rOEkv%9$`!>)#DUWX7L}7%ML?U?t?o8(D*xJk^0~9)hpK&rrWm+A*gS}(QFC&;>}!* z+z>0nKdW0xr1H_!=|pC_Oyw2w7v^jkOKKIXS>m0Fd?=TnHajCTVS>)#8~@82oF zY+uflT6>Thc%X)e7=D$SbB^A@vaL`hu*>b54CEFSt;_)U?IrL`{r3C24ItzK_43!^ z4haskylQPAS_}$QAQK7+!9w!#Av<hF488D#}56#~GH|0}~Sr ziRN^qau5#1WT<@9st=;cMiW8ti^K{6B@eqbB_(g6S?LeveCtzf1f!7)90Ggp=xkLN zkVlAg0mL`PB3{H-hmdB9z7TyK#heX~258YhyavjPKdU~VH`=#p5)(l;FES}HC3IRJ z48W!?Lz4kuDy%@50(2H|VqkkGO4ez4arHnwgq{Ly#O%z>eM?IabwGZSjEPY4{_T9? z(xJ6j9edJx56BSqVI5Qz)ORFy0CxTY8AoaB;9v}6z-*iz@IwU!N1DVCk_Gw~qId!B z_WO5CpuPQ^?0`qi7 zBRNlLd1F-{?5XMhzB8KS;!Zhyz;=jVgolDCV1)5|re+{^mm zVd5>n2-$;Mqu*x#DS~C8M(zkb7u|o6IFR0#OB~E|HYi@V~&w!PS~=ECPlCKe_bIea$AZKsH92BFEFj z;zjvq_01_;Eb zv9Z83g%|s4u~xPoqWpw71Na_c0$9bc=<{ISKT6zzno`p}Kom2}BN1IyUHO8> zI1?xNUTA|sHBk)`mu~{m1JmYz(F(wNie0)i$+mTYmHzBZOiNCB_q3Tb6{Rl!T5Xgb_<4|Ew%HAbIn2jNL1cVh!TSMirm!?P~_gj%$rT;If&P-ByfY$R@ zEDuZ!ve^5hpP0{75pwWzp?G{Cwy(6?Hth#QZW&>)$;~Sk0H_~_?ceEWO7G8RVG+e(|7evZrSyKWL$>3X84Ckk1yw{9uJkH8#tJobhH z;UWb&vk7_~EQrqRzJ+GLkgSo>ysCNipz#x$p-;+&v1z6VO@3;Z=KLaWs~nG4E_Y06 zR)`U2_~Krz^kGDJ_adeW&wk3TEm@t%16 zPrRUpfjlbcfdS=i*pG5COv^hsX2G;ArJXKdx+fGpstAfO1FR zE?2!vFZ$(aN+&EQq3cn%UP69D(Z`VgFJdCZOyxP|NP4Vf=1;_MfjWRxg)uyM&ZP7dM2Pdw>3y z{Kq#_Xp;7QVR*!>j82!wuq&y&aHw2?ETi*9s`DfqD75rzu7&CUaX7cPJ z1B2Rjkh|n^HQ`|u;o&`;RTaSqIQJh?oflN~3A0sKdDXw=Psk{{FR_H18^bPb*;ZHd zL0L1^8hMI=W5*y{SIdh))_#LhXH!q2UVdypR};C~WnBUa412iB@hYbZ&^)~)PF{a} z?HudT2<2RZ3n-$SqYM|p!{o9R=M5oF#`9RLb_F5*Bl_YgI_jKabcB^*9EG`h()ZKC zH1(|8SyWf{56pBG%_t1|Jcg6VRs5uKBF>8K(Bo?(9>eeL(q#LjB-8RbsU&j^>~82k zf0}3Ko2}PFslXmH3-iUKi;VGYY#GEnbwClUG+t*Ug7rW*_S5tMEehW=b^^Z!8+Iuu N)Kzs<2-ok2{14fFIJf`+ diff --git a/docs/html/reference/com/google/android/gms/R.attr.html b/docs/html/reference/com/google/android/gms/R.attr.html index 2c14e054ab0a0..1e4794f42518a 100644 --- a/docs/html/reference/com/google/android/gms/R.attr.html +++ b/docs/html/reference/com/google/android/gms/R.attr.html @@ -421,7 +421,22 @@ onkeyup="return search_changed(event, false, '/')" /> + +