Merge "Polish animations for fingerprint icon" into mnc-dev
diff --git a/api/current.txt b/api/current.txt
index 41acac5..15c4a9b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -28383,7 +28383,6 @@
   }
 
   public final deprecated class KeyStoreParameter implements java.security.KeyStore.ProtectionParameter {
-    method public android.content.Context getContext();
     method public boolean isEncryptionRequired();
   }
 
diff --git a/api/system-current.txt b/api/system-current.txt
index 0f6bd2a..e7032c3 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -30409,7 +30409,6 @@
   }
 
   public final deprecated class KeyStoreParameter implements java.security.KeyStore.ProtectionParameter {
-    method public android.content.Context getContext();
     method public boolean isEncryptionRequired();
   }
 
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 43678cc..62a1617 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1560,6 +1560,42 @@
     public static final String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
 
     /**
+     * Broadcast action that requests current permission granted information.  It will respond
+     * to the request by sending a broadcast with action defined by
+     * {@link #EXTRA_GET_PERMISSIONS_RESPONSE_INTENT}. The response will contain
+     * {@link #EXTRA_GET_PERMISSIONS_COUNT_RESULT} with contents described below or a null upon
+     * failure.
+     *
+     * <p>If {@link #EXTRA_PACKAGE_NAME} is included then the number of permissions granted and the
+     * number of permissions requested by that package will be calculated and included as the first
+     * and second elements respectively of an int[] in the response as
+     * {@link #EXTRA_GET_PERMISSIONS_COUNT_RESULT}.
+     *
+     * <p>If {@link #EXTRA_PACKAGE_NAME} is not included then the number of apps granted any runtime
+     * permissions and the total number of apps requesting runtime permissions will be the first
+     * and second elements respectively of an int[] in the response as
+     * {@link #EXTRA_GET_PERMISSIONS_COUNT_RESULT}.
+     *
+     * @hide
+     */
+    public static final String ACTION_GET_PERMISSIONS_COUNT
+            = "android.intent.action.GET_PERMISSIONS_COUNT";
+
+    /**
+     * Extra included in response to {@link #ACTION_GET_PERMISSIONS_COUNT}.
+     * @hide
+     */
+    public static final String EXTRA_GET_PERMISSIONS_COUNT_RESULT
+            = "android.intent.extra.GET_PERMISSIONS_COUNT_RESULT";
+
+    /**
+     * Required extra to be sent with {@link #ACTION_GET_PERMISSIONS_COUNT} broadcast.
+     * @hide
+     */
+    public static final String EXTRA_GET_PERMISSIONS_RESPONSE_INTENT
+            = "android.intent.extra.GET_PERMISSIONS_RESONSE_INTENT";
+
+    /**
      * Activity action: Launch UI to manage which apps have a given permission.
      * <p>
      * Input: {@link #EXTRA_PERMISSION_NAME} specifies the permission access
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index acc27c3..596c0e4 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2047,8 +2047,9 @@
             String tagName = parser.getName();
             if (tagName.equals("key-set")) {
                 if (currentKeySet != null) {
-                    Slog.w(TAG, "Improperly nested 'key-set' tag at "
-                            + parser.getPositionDescription());
+                    outError[0] = "Improperly nested 'key-set' tag at "
+                            + parser.getPositionDescription();
+                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                     return false;
                 }
                 final TypedArray sa = res.obtainAttributes(attrs,
@@ -2061,8 +2062,9 @@
                 sa.recycle();
             } else if (tagName.equals("public-key")) {
                 if (currentKeySet == null) {
-                    Slog.w(TAG, "Improperly nested 'public-key' tag at "
-                            + parser.getPositionDescription());
+                    outError[0] = "Improperly nested 'key-set' tag at "
+                            + parser.getPositionDescription();
+                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                     return false;
                 }
                 final TypedArray sa = res.obtainAttributes(attrs,
@@ -2072,8 +2074,9 @@
                 final String encodedKey = sa.getNonResourceString(
                             com.android.internal.R.styleable.AndroidManifestPublicKey_value);
                 if (encodedKey == null && publicKeys.get(publicKeyName) == null) {
-                    Slog.w(TAG, "'public-key' " + publicKeyName + " must define a public-key value"
-                            + " on first use at " + parser.getPositionDescription());
+                    outError[0] = "'public-key' " + publicKeyName + " must define a public-key value"
+                            + " on first use at " + parser.getPositionDescription();
+                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                     sa.recycle();
                     return false;
                 } else if (encodedKey != null) {
@@ -2093,9 +2096,10 @@
                         /* public-key first definition, or matches old definition */
                         publicKeys.put(publicKeyName, currentKey);
                     } else {
-                        Slog.w(TAG, "Value of 'public-key' " + publicKeyName
+                        outError[0] = "Value of 'public-key' " + publicKeyName
                                + " conflicts with previously defined value at "
-                               + parser.getPositionDescription());
+                               + parser.getPositionDescription();
+                        mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                         sa.recycle();
                         return false;
                     }
@@ -2112,9 +2116,10 @@
                 sa.recycle();
                 XmlUtils.skipCurrentTag(parser);
             } else if (RIGID_PARSER) {
-                Slog.w(TAG, "Bad element under <key-sets>: " + parser.getName()
+                outError[0] = "Bad element under <key-sets>: " + parser.getName()
                         + " at " + mArchiveSourcePath + " "
-                        + parser.getPositionDescription());
+                        + parser.getPositionDescription();
+                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                 return false;
             } else {
                 Slog.w(TAG, "Unknown element under <key-sets>: " + parser.getName()
@@ -2126,8 +2131,9 @@
         }
         Set<String> publicKeyNames = publicKeys.keySet();
         if (publicKeyNames.removeAll(definedKeySets.keySet())) {
-            Slog.w(TAG, "Package" + owner.packageName + " AndroidManifext.xml "
-                   + "'key-set' and 'public-key' names must be distinct.");
+            outError[0] = "Package" + owner.packageName + " AndroidManifext.xml "
+                    + "'key-set' and 'public-key' names must be distinct.";
+            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
             return false;
         }
         owner.mKeySetMapping = new ArrayMap<String, ArraySet<PublicKey>>();
@@ -2152,8 +2158,9 @@
         if (owner.mKeySetMapping.keySet().containsAll(upgradeKeySets)) {
             owner.mUpgradeKeySets = upgradeKeySets;
         } else {
-            Slog.w(TAG, "Package" + owner.packageName + " AndroidManifext.xml "
-                   + "does not define all 'upgrade-key-set's .");
+            outError[0] ="Package" + owner.packageName + " AndroidManifext.xml "
+                   + "does not define all 'upgrade-key-set's .";
+            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
             return false;
         }
         return true;
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index e175e9a..3a3c47d 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -611,11 +611,11 @@
 
     /**
      * Retrieves the current preferred network type.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      *
      * @return an integer representing the preferred network type
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * @deprecated Functionality has been removed as it no longer makes sense,
      *             with many more than two networks - we'd need an array to express
      *             preference.  Instead we use dynamic network properties of
@@ -631,12 +631,11 @@
      * You should always check {@link NetworkInfo#isConnected()} before initiating
      * network traffic. This may return {@code null} when there is no default
      * network.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      *
      * @return a {@link NetworkInfo} object for the current default network
      *        or {@code null} if no default network is currently active
-     *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      */
     public NetworkInfo getActiveNetworkInfo() {
         try {
@@ -652,12 +651,11 @@
      * network disconnects, the returned {@code Network} object will no longer
      * be usable.  This will return {@code null} when there is no default
      * network.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      *
      * @return a {@link Network} object for the current default network or
      *        {@code null} if no default network is currently active
-     *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      */
     public Network getActiveNetwork() {
         try {
@@ -671,13 +669,13 @@
      * Returns details about the currently active default data network
      * for a given uid.  This is for internal use only to avoid spying
      * other apps.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}
      *
      * @return a {@link NetworkInfo} object for the current default network
      *        for the given uid or {@code null} if no default network is
      *        available for the specified uid.
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}
      * {@hide}
      */
     public NetworkInfo getActiveNetworkInfoForUid(int uid) {
@@ -691,6 +689,8 @@
     /**
      * Returns connection status information about a particular
      * network type.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      *
      * @param networkType integer specifying which networkType in
      *        which you're interested.
@@ -698,9 +698,6 @@
      *        network type or {@code null} if the type is not
      *        supported by the device.
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
-     *
      * @deprecated This method does not support multiple connected networks
      *             of the same type. Use {@link #getAllNetworks} and
      *             {@link #getNetworkInfo(android.net.Network)} instead.
@@ -716,15 +713,14 @@
     /**
      * Returns connection status information about a particular
      * Network.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      *
      * @param network {@link Network} specifying which network
      *        in which you're interested.
      * @return a {@link NetworkInfo} object for the requested
      *        network or {@code null} if the {@code Network}
      *        is not valid.
-     *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      */
     public NetworkInfo getNetworkInfo(Network network) {
         try {
@@ -737,13 +733,12 @@
     /**
      * Returns connection status information about all network
      * types supported by the device.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      *
      * @return an array of {@link NetworkInfo} objects.  Check each
      * {@link NetworkInfo#getType} for which type each applies.
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
-     *
      * @deprecated This method does not support multiple connected networks
      *             of the same type. Use {@link #getAllNetworks} and
      *             {@link #getNetworkInfo(android.net.Network)} instead.
@@ -779,11 +774,10 @@
     /**
      * Returns an array of all {@link Network} currently tracked by the
      * framework.
-     *
-     * @return an array of {@link Network} objects.
-     *
      * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+     *
+     * @return an array of {@link Network} objects.
      */
     public Network[] getAllNetworks() {
         try {
@@ -812,13 +806,12 @@
      * You should always check {@link NetworkInfo#isConnected()} before initiating
      * network traffic. This may return {@code null} when there is no default
      * network.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      *
      * @return a {@link NetworkInfo} object for the current default network
      *        or {@code null} if no default network is currently active
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
-     *
      * {@hide}
      */
     public NetworkInfo getProvisioningOrActiveNetworkInfo() {
@@ -831,13 +824,13 @@
 
     /**
      * Returns the IP information for the current default network.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      *
      * @return a {@link LinkProperties} object describing the IP info
      *        for the current default network, or {@code null} if there
      *        is no current default network.
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
     public LinkProperties getActiveLinkProperties() {
@@ -850,14 +843,14 @@
 
     /**
      * Returns the IP information for a given network type.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      *
      * @param networkType the network type of interest.
      * @return a {@link LinkProperties} object describing the IP info
      *        for the given networkType, or {@code null} if there is
      *        no current default network.
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      * @deprecated This method does not support multiple connected networks
      *             of the same type. Use {@link #getAllNetworks},
@@ -875,10 +868,12 @@
     /**
      * Get the {@link LinkProperties} for the given {@link Network}.  This
      * will return {@code null} if the network is unknown.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      *
      * @param network The {@link Network} object identifying the network in question.
      * @return The {@link LinkProperties} for the network, or {@code null}.
-     **/
+     */
     public LinkProperties getLinkProperties(Network network) {
         try {
             return mService.getLinkProperties(network);
@@ -890,6 +885,8 @@
     /**
      * Get the {@link android.net.NetworkCapabilities} for the given {@link Network}.  This
      * will return {@code null} if the network is unknown.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      *
      * @param network The {@link Network} object identifying the network in question.
      * @return The {@link android.net.NetworkCapabilities} for the network, or {@code null}.
@@ -1493,11 +1490,11 @@
     /**
      * Get the set of tetherable, available interfaces.  This list is limited by
      * device configuration and current interface existence.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      *
      * @return an array of 0 or more Strings of tetherable interface names.
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
     public String[] getTetherableIfaces() {
@@ -1510,11 +1507,11 @@
 
     /**
      * Get the set of tethered interfaces.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      *
      * @return an array of 0 or more String of currently tethered interface names.
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
     public String[] getTetheredIfaces() {
@@ -1532,12 +1529,12 @@
      * may cause them to reset to the available state.
      * {@link ConnectivityManager#getLastTetherError} can be used to get more
      * information on the cause of the errors.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      *
      * @return an array of 0 or more String indicating the interface names
      *        which failed to tether.
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
     public String[] getTetheringErroredIfaces() {
@@ -1570,12 +1567,12 @@
      * allowed between the tethered devices and this device, though upstream net
      * access will of course fail until an upstream network interface becomes
      * active.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
      *
      * @param iface the interface name to tether.
      * @return error a {@code TETHER_ERROR} value indicating success or failure type
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
      * {@hide}
      */
     public int tether(String iface) {
@@ -1588,12 +1585,12 @@
 
     /**
      * Stop tethering the named interface.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
      *
      * @param iface the interface name to untether.
      * @return error a {@code TETHER_ERROR} value indicating success or failure type
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
      * {@hide}
      */
     public int untether(String iface) {
@@ -1608,11 +1605,11 @@
      * Check if the device allows for tethering.  It may be disabled via
      * {@code ro.tether.denied} system property, Settings.TETHER_SUPPORTED or
      * due to device configuration.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      *
      * @return a boolean - {@code true} indicating Tethering is supported.
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
     public boolean isTetheringSupported() {
@@ -1627,12 +1624,12 @@
      * Get the list of regular expressions that define any tetherable
      * USB network interfaces.  If USB tethering is not supported by the
      * device, this list should be empty.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      *
      * @return an array of 0 or more regular expression Strings defining
      *        what interfaces are considered tetherable usb interfaces.
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
     public String[] getTetherableUsbRegexs() {
@@ -1647,12 +1644,12 @@
      * Get the list of regular expressions that define any tetherable
      * Wifi network interfaces.  If Wifi tethering is not supported by the
      * device, this list should be empty.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      *
      * @return an array of 0 or more regular expression Strings defining
      *        what interfaces are considered tetherable wifi interfaces.
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
     public String[] getTetherableWifiRegexs() {
@@ -1667,12 +1664,12 @@
      * Get the list of regular expressions that define any tetherable
      * Bluetooth network interfaces.  If Bluetooth tethering is not supported by the
      * device, this list should be empty.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      *
      * @return an array of 0 or more regular expression Strings defining
      *        what interfaces are considered tetherable bluetooth interfaces.
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
     public String[] getTetherableBluetoothRegexs() {
@@ -1689,12 +1686,12 @@
      * attempt to switch to Rndis and subsequently tether the resulting
      * interface on {@code true} or turn off tethering and switch off
      * Rndis on {@code false}.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
      *
      * @param enable a boolean - {@code true} to enable tethering
      * @return error a {@code TETHER_ERROR} value indicating success or failure type
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
      * {@hide}
      */
     public int setUsbTethering(boolean enable) {
@@ -1731,13 +1728,13 @@
     /**
      * Get a more detailed error code after a Tethering or Untethering
      * request asynchronously failed.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      *
      * @param iface The name of the interface of interest
      * @return error The error code of the last error tethering or untethering the named
      *               interface
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
     public int getLastTetherError(String iface) {
@@ -1751,12 +1748,11 @@
     /**
      * Report network connectivity status.  This is currently used only
      * to alter status bar UI.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#STATUS_BAR}.
      *
      * @param networkType The type of network you want to report on
      * @param percentage The quality of the connection 0 is bad, 100 is good
-     *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#STATUS_BAR}.
      * {@hide}
      */
     public void reportInetCondition(int networkType, int percentage) {
@@ -1886,12 +1882,11 @@
      * for typical HTTP proxies - they are general network dependent.  However if you're
      * doing something unusual like general internal filtering this may be useful.  On
      * a private network where the proxy is not accessible, you may break HTTP using this.
-     *
-     * @param p The a {@link ProxyInfo} object defining the new global
-     *        HTTP proxy.  A {@code null} value will clear the global HTTP proxy.
-     *
      * <p>This method requires the caller to hold the permission
      * android.Manifest.permission#CONNECTIVITY_INTERNAL.
+     *
+     * @param p A {@link ProxyInfo} object defining the new global
+     *        HTTP proxy.  A {@code null} value will clear the global HTTP proxy.
      * @hide
      */
     public void setGlobalProxy(ProxyInfo p) {
@@ -1958,12 +1953,12 @@
      * hardware supports it.  For example a GSM phone without a SIM
      * should still return {@code true} for mobile data, but a wifi only
      * tablet would return {@code false}.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      *
      * @param networkType The network type we'd like to check
      * @return {@code true} if supported, else {@code false}
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * @hide
      */
     public boolean isNetworkSupported(int networkType) {
@@ -1980,12 +1975,11 @@
      * battery/performance issues. You should check this before doing large
      * data transfers, and warn the user or delay the operation until another
      * network is available.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      *
      * @return {@code true} if large transfers should be avoided, otherwise
      *        {@code false}.
-     *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      */
     public boolean isActiveNetworkMetered() {
         try {
@@ -2015,13 +2009,12 @@
     /**
      * Signal that the captive portal check on the indicated network
      * is complete and whether its a captive portal or not.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}.
      *
      * @param info the {@link NetworkInfo} object for the networkType
      *        in question.
      * @param isCaptivePortal true/false.
-     *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}.
      * {@hide}
      */
     public void captivePortalCheckCompleted(NetworkInfo info, boolean isCaptivePortal) {
@@ -2093,11 +2086,11 @@
 
     /**
      * Set the value for enabling/disabling airplane mode
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}.
      *
      * @param enable whether to enable airplane mode or not
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}.
      * @hide
      */
     public void setAirplaneMode(boolean enable) {
@@ -2438,6 +2431,8 @@
      * Status of the request can be followed by listening to the various
      * callbacks described in {@link NetworkCallback}.  The {@link Network}
      * can be used to direct traffic to the network.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
      *
      * @param request {@link NetworkRequest} describing this request.
      * @param networkCallback The {@link NetworkCallback} to be utilized for this
@@ -2457,6 +2452,8 @@
      * network is not found within the given time (in milliseconds) the
      * {@link NetworkCallback#unavailable} callback is called.  The request must
      * still be released normally by calling {@link releaseNetworkRequest}.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
      * @param request {@link NetworkRequest} describing this request.
      * @param networkCallback The callbacks to be utilized for this request.  Note
      *                        the callbacks must not be shared - they uniquely specify
@@ -2522,7 +2519,8 @@
      * <p>
      * The request may be released normally by calling
      * {@link #releaseNetworkRequest(android.app.PendingIntent)}.
-     *
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
      * @param request {@link NetworkRequest} describing this request.
      * @param operation Action to perform when the network is available (corresponds
      *                  to the {@link NetworkCallback#onAvailable} call.  Typically
@@ -2563,6 +2561,8 @@
      * Registers to receive notifications about all networks which satisfy the given
      * {@link NetworkRequest}.  The callbacks will continue to be called until
      * either the application exits or {@link #unregisterNetworkCallback} is called
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      *
      * @param request {@link NetworkRequest} describing this request.
      * @param networkCallback The {@link NetworkCallback} that the system will call as suitable
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 11043b3..a81b83f 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -177,7 +177,8 @@
     /**
      * Specifies if a user is disallowed from configuring VPN.
      * The default value is <code>false</code>.
-     * This restriction has no effect in a managed profile.
+     * This restriction has an effect in a managed profile only from
+     * {@link android.os.Build.VERSION_CODES#MNC}
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
diff --git a/core/java/android/preference/RingtonePreference.java b/core/java/android/preference/RingtonePreference.java
index 488a0c4..a76bb09 100644
--- a/core/java/android/preference/RingtonePreference.java
+++ b/core/java/android/preference/RingtonePreference.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.TypedArray;
+import android.media.AudioAttributes;
 import android.media.RingtoneManager;
 import android.net.Uri;
 import android.provider.Settings.System;
@@ -169,6 +170,8 @@
         ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, mShowSilent);
         ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, mRingtoneType);
         ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE, getTitle());
+        ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_AUDIO_ATTRIBUTES_FLAGS,
+                AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY);
     }
     
     /**
diff --git a/core/java/android/service/chooser/ChooserTargetService.java b/core/java/android/service/chooser/ChooserTargetService.java
index 0d1834a..a3bfece 100644
--- a/core/java/android/service/chooser/ChooserTargetService.java
+++ b/core/java/android/service/chooser/ChooserTargetService.java
@@ -44,7 +44,7 @@
  * the {@link android.Manifest.permission#BIND_CHOOSER_TARGET_SERVICE} permission
  * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
  * <pre>
- *     &lt;service android:name=".ChooserTargetService"
+ *     &lt;service android:name=".MyChooserTargetService"
  *             android:label="&#64;string/service_name"
  *             android:permission="android.permission.BIND_CHOOSER_TARGET_SERVICE">
  *         &lt;intent-filter>
@@ -69,7 +69,7 @@
  *             &lt;action android:name="android.intent.action.SEND" />
  *         &lt;/intent-filter>
  *         &lt;meta-data android:name="android.service.chooser.chooser_target_service"
- *                 android:value=".ChooserTargetService" />
+ *                 android:value=".MyChooserTargetService" />
  *     &lt;/activity>
  * </pre>
  */
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 1e42913..dd3cedc 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -16,6 +16,7 @@
 
 package android.service.notification;
 
+import android.app.ActivityManager;
 import android.app.NotificationManager.Policy;
 import android.content.ComponentName;
 import android.content.Context;
@@ -23,6 +24,7 @@
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.UserHandle;
 import android.provider.Settings.Global;
 import android.text.TextUtils;
 import android.text.format.DateFormat;
@@ -728,6 +730,7 @@
         return new Uri.Builder().scheme(Condition.SCHEME)
                 .authority(SYSTEM_AUTHORITY)
                 .appendPath(EVENT_PATH)
+                .appendQueryParameter("userId", Long.toString(event.userId))
                 .appendQueryParameter("calendar", Long.toString(event.calendar))
                 .appendQueryParameter("reply", Integer.toString(event.reply))
                 .build();
@@ -745,6 +748,7 @@
                 && conditionId.getPathSegments().get(0).equals(EVENT_PATH);
         if (!isEvent) return null;
         final EventInfo rt = new EventInfo();
+        rt.userId = tryParseInt(conditionId.getQueryParameter("userId"), UserHandle.USER_NULL);
         rt.calendar = tryParseLong(conditionId.getQueryParameter("calendar"),
                 EventInfo.ANY_CALENDAR);
         rt.reply = tryParseInt(conditionId.getQueryParameter("reply"), 0);
@@ -758,6 +762,7 @@
         public static final int REPLY_YES_OR_MAYBE = 1;
         public static final int REPLY_YES = 2;
 
+        public int userId = UserHandle.USER_NULL;  // USER_NULL = unspecified - use current user
         public long calendar = ANY_CALENDAR;  // CalendarContract.Calendars._ID, or ANY_CALENDAR
         public int reply;
 
@@ -770,16 +775,23 @@
         public boolean equals(Object o) {
             if (!(o instanceof EventInfo)) return false;
             final EventInfo other = (EventInfo) o;
-            return calendar == other.calendar
+            return userId == other.userId
+                    && calendar == other.calendar
                     && reply == other.reply;
         }
 
         public EventInfo copy() {
             final EventInfo rt = new EventInfo();
+            rt.userId = userId;
             rt.calendar = calendar;
             rt.reply = reply;
             return rt;
         }
+
+        public static int resolveUserId(int userId) {
+            return userId == UserHandle.USER_NULL ? ActivityManager.getCurrentUser() : userId;
+
+        }
     }
 
     // ==== End built-in system conditions ====
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 41f906a..e59560f 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -66,6 +66,7 @@
 import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
 import android.view.accessibility.AccessibilityManager.HighTextContrastChangeListener;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 import android.view.accessibility.AccessibilityNodeProvider;
 import android.view.accessibility.IAccessibilityInteractionConnection;
 import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
@@ -6354,16 +6355,18 @@
      *              {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED}
      */
     private void handleWindowContentChangedEvent(AccessibilityEvent event) {
-        // No virtual view focused, nothing to do here.
-        if (mAccessibilityFocusedHost == null || mAccessibilityFocusedVirtualView == null) {
+        final View focusedHost = mAccessibilityFocusedHost;
+        if (focusedHost == null || mAccessibilityFocusedVirtualView == null) {
+            // No virtual view focused, nothing to do here.
             return;
         }
 
-        // If we have a node but no provider, abort.
-        final AccessibilityNodeProvider provider =
-                mAccessibilityFocusedHost.getAccessibilityNodeProvider();
+        final AccessibilityNodeProvider provider = focusedHost.getAccessibilityNodeProvider();
         if (provider == null) {
-            // TODO: Should we clear the focused virtual view?
+            // Error state: virtual view with no provider. Clear focus.
+            mAccessibilityFocusedHost = null;
+            mAccessibilityFocusedVirtualView = null;
+            focusedHost.clearAccessibilityFocusNoCallbacks();
             return;
         }
 
@@ -6410,10 +6413,23 @@
         final Rect oldBounds = mTempRect;
         mAccessibilityFocusedVirtualView.getBoundsInScreen(oldBounds);
         mAccessibilityFocusedVirtualView = provider.createAccessibilityNodeInfo(focusedChildId);
-        final Rect newBounds = mAccessibilityFocusedVirtualView.getBoundsInScreen();
-        if (!oldBounds.equals(newBounds)) {
-            oldBounds.union(newBounds);
+        if (mAccessibilityFocusedVirtualView == null) {
+            // Error state: The node no longer exists. Clear focus.
+            mAccessibilityFocusedHost = null;
+            focusedHost.clearAccessibilityFocusNoCallbacks();
+
+            // This will probably fail, but try to keep the provider's internal
+            // state consistent by clearing focus.
+            provider.performAction(focusedChildId,
+                    AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS.getId(), null);
             invalidateRectOnScreen(oldBounds);
+        } else {
+            // The node was refreshed, invalidate bounds if necessary.
+            final Rect newBounds = mAccessibilityFocusedVirtualView.getBoundsInScreen();
+            if (!oldBounds.equals(newBounds)) {
+                oldBounds.union(newBounds);
+                invalidateRectOnScreen(oldBounds);
+            }
         }
     }
 
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 1b759a3..eebcd84 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -274,11 +274,18 @@
          * Get the layer at which this window's surface will be Z-ordered.
          */
         public int getSurfaceLayer();
-        
+
         /**
-         * Return the token for the application (actually activity) that owns 
-         * this window.  May return null for system windows. 
-         * 
+         * Retrieve the type of the top-level window.
+         *
+         * @return the base type of the parent window if attached or its own type otherwise
+         */
+        public int getBaseType();
+
+        /**
+         * Return the token for the application (actually activity) that owns
+         * this window.  May return null for system windows.
+         *
          * @return An IApplicationToken identifying the owning activity.
          */
         public IApplicationToken getAppToken();
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index b7a53b0..3cff59a 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -26,6 +26,7 @@
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.graphics.drawable.ColorDrawable;
+import android.text.TextUtils;
 import android.util.Size;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -44,6 +45,7 @@
 import android.widget.ArrayAdapter;
 import android.widget.Button;
 import android.widget.ImageButton;
+import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.ListView;
 import android.widget.PopupWindow;
@@ -902,7 +904,7 @@
             boolean isFirstItem = true;
             while (!remainingMenuItems.isEmpty()) {
                 final MenuItem menuItem = remainingMenuItems.peek();
-                Button menuItemButton = createMenuItemButton(mContext, menuItem);
+                View menuItemButton = createMenuItemButton(mContext, menuItem);
 
                 // Adding additional start padding for the first button to even out button spacing.
                 if (isFirstItem) {
@@ -926,8 +928,7 @@
                 menuItemButton.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
                 int menuItemButtonWidth = Math.min(menuItemButton.getMeasuredWidth(), toolbarWidth);
                 if (menuItemButtonWidth <= availableWidth) {
-                    menuItemButton.setTag(menuItem);
-                    menuItemButton.setOnClickListener(mMenuItemButtonOnClickListener);
+                    setButtonTagAndClickListener(menuItemButton, menuItem);
                     mContentView.addView(menuItemButton);
                     ViewGroup.LayoutParams params = menuItemButton.getLayoutParams();
                     params.width = menuItemButtonWidth;
@@ -936,7 +937,7 @@
                     remainingMenuItems.pop();
                 } else {
                     if (mOpenOverflowButton == null) {
-                        mOpenOverflowButton = (ImageButton) LayoutInflater.from(mContext)
+                        mOpenOverflowButton = LayoutInflater.from(mContext)
                                 .inflate(R.layout.floating_popup_open_overflow_button, null);
                         mOpenOverflowButton.setOnClickListener(new View.OnClickListener() {
                             @Override
@@ -980,6 +981,15 @@
             mContentView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
             return new Size(mContentView.getMeasuredWidth(), mContentView.getMeasuredHeight());
         }
+
+        private void setButtonTagAndClickListener(View menuItemButton, MenuItem menuItem) {
+            View button = menuItemButton;
+            if (isIconOnlyMenuItem(menuItem)) {
+                button = menuItemButton.findViewById(R.id.floating_toolbar_menu_item_image_button);
+            }
+            button.setTag(menuItem);
+            button.setOnClickListener(mMenuItemButtonOnClickListener);
+        }
     }
 
 
@@ -1141,10 +1151,34 @@
                     ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
             overflowListView.setDivider(null);
             overflowListView.setDividerHeight(0);
+
+            final int viewTypeCount = 2;
+            final int stringLabelViewType = 0;
+            final int iconOnlyViewType = 1;
             final ArrayAdapter overflowListViewAdapter =
                     new ArrayAdapter<MenuItem>(context, 0) {
                         @Override
+                        public int getViewTypeCount() {
+                            return viewTypeCount;
+                        }
+
+                        @Override
+                        public int getItemViewType(int position) {
+                            if (isIconOnlyMenuItem(getItem(position))) {
+                                return iconOnlyViewType;
+                            }
+                            return stringLabelViewType;
+                        }
+
+                        @Override
                         public View getView(int position, View convertView, ViewGroup parent) {
+                            if (getItemViewType(position) == iconOnlyViewType) {
+                                return getIconOnlyView(position, convertView);
+                            }
+                            return getStringTitleView(position, convertView);
+                        }
+
+                        private View getStringTitleView(int position, View convertView) {
                             TextView menuButton;
                             if (convertView != null) {
                                 menuButton = (TextView) convertView;
@@ -1157,6 +1191,22 @@
                             menuButton.setMinimumWidth(mOverflowWidth);
                             return menuButton;
                         }
+
+                        private View getIconOnlyView(int position, View convertView) {
+                            View menuButton;
+                            if (convertView != null) {
+                                menuButton = convertView;
+                            } else {
+                                menuButton = LayoutInflater.from(context).inflate(
+                                        R.layout.floating_popup_overflow_image_list_item, null);
+                            }
+                            MenuItem menuItem = getItem(position);
+                            ((ImageView) menuButton
+                                    .findViewById(R.id.floating_toolbar_menu_item_image_button))
+                                    .setImageDrawable(menuItem.getIcon());
+                            menuButton.setMinimumWidth(mOverflowWidth);
+                            return menuButton;
+                        }
                     };
             overflowListView.setAdapter(overflowListViewAdapter);
             return overflowListView;
@@ -1208,11 +1258,30 @@
         }
     }
 
+    /**
+     * @return {@code true} if the menu item does not not have a string title but has an icon.
+     *   {@code false} otherwise.
+     */
+    private static boolean isIconOnlyMenuItem(MenuItem menuItem) {
+        if (TextUtils.isEmpty(menuItem.getTitle()) && menuItem.getIcon() != null) {
+            return true;
+        }
+        return false;
+    }
 
     /**
      * Creates and returns a menu button for the specified menu item.
      */
-    private static Button createMenuItemButton(Context context, MenuItem menuItem) {
+    private static View createMenuItemButton(Context context, MenuItem menuItem) {
+        if (isIconOnlyMenuItem(menuItem)) {
+            View imageMenuItemButton = LayoutInflater.from(context)
+                    .inflate(R.layout.floating_popup_menu_image_button, null);
+            ((ImageButton) imageMenuItemButton
+                    .findViewById(R.id.floating_toolbar_menu_item_image_button))
+                    .setImageDrawable(menuItem.getIcon());
+            return imageMenuItemButton;
+        }
+
         Button menuItemButton = (Button) LayoutInflater.from(context)
                 .inflate(R.layout.floating_popup_menu_button, null);
         menuItemButton.setText(menuItem.getTitle());
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 2692ad8..e8acd97 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -580,8 +580,8 @@
             break;
         }
 
-        if (!strstr(line, "ioremap")) {
-            // Ignore ioremap regions, since they don't actually consume memory
+        if (!strstr(line, "ioremap") && !strstr(line, "map_lowmem")) {
+            // Ignore ioremap and map_lowmem regions, since they don't actually consume memory
             if (sscanf(line, "%*x-%*x %ld", &size) == 1) {
                 vmalloc_allocated_size += size;
             }
diff --git a/core/res/res/drawable-hdpi/perm_group_calendar.png b/core/res/res/drawable-hdpi/perm_group_calendar.png
deleted file mode 100644
index 1ef032f..0000000
--- a/core/res/res/drawable-hdpi/perm_group_calendar.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_camera.png b/core/res/res/drawable-hdpi/perm_group_camera.png
deleted file mode 100644
index fb5a2f5..0000000
--- a/core/res/res/drawable-hdpi/perm_group_camera.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_location.png b/core/res/res/drawable-hdpi/perm_group_location.png
deleted file mode 100644
index 6989b16..0000000
--- a/core/res/res/drawable-hdpi/perm_group_location.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_messages.png b/core/res/res/drawable-hdpi/perm_group_messages.png
deleted file mode 100644
index 21929b6..0000000
--- a/core/res/res/drawable-hdpi/perm_group_messages.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_microphone.png b/core/res/res/drawable-hdpi/perm_group_microphone.png
deleted file mode 100644
index 9f8a681..0000000
--- a/core/res/res/drawable-hdpi/perm_group_microphone.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_phone_calls.png b/core/res/res/drawable-hdpi/perm_group_phone_calls.png
deleted file mode 100644
index 8fa802e..0000000
--- a/core/res/res/drawable-hdpi/perm_group_phone_calls.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_social_info.png b/core/res/res/drawable-hdpi/perm_group_social_info.png
deleted file mode 100644
index dcf67e4..0000000
--- a/core/res/res/drawable-hdpi/perm_group_social_info.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_calendar.png b/core/res/res/drawable-mdpi/perm_group_calendar.png
deleted file mode 100644
index d2ad9d6..0000000
--- a/core/res/res/drawable-mdpi/perm_group_calendar.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_camera.png b/core/res/res/drawable-mdpi/perm_group_camera.png
deleted file mode 100644
index 1727cf1..0000000
--- a/core/res/res/drawable-mdpi/perm_group_camera.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_location.png b/core/res/res/drawable-mdpi/perm_group_location.png
deleted file mode 100644
index 7ad1e02..0000000
--- a/core/res/res/drawable-mdpi/perm_group_location.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_messages.png b/core/res/res/drawable-mdpi/perm_group_messages.png
deleted file mode 100644
index 12c5d88..0000000
--- a/core/res/res/drawable-mdpi/perm_group_messages.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_microphone.png b/core/res/res/drawable-mdpi/perm_group_microphone.png
deleted file mode 100644
index f6015b5..0000000
--- a/core/res/res/drawable-mdpi/perm_group_microphone.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_phone_calls.png b/core/res/res/drawable-mdpi/perm_group_phone_calls.png
deleted file mode 100644
index e373c2c..0000000
--- a/core/res/res/drawable-mdpi/perm_group_phone_calls.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_social_info.png b/core/res/res/drawable-mdpi/perm_group_social_info.png
deleted file mode 100644
index 4ca0767..0000000
--- a/core/res/res/drawable-mdpi/perm_group_social_info.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_calendar.png b/core/res/res/drawable-xhdpi/perm_group_calendar.png
deleted file mode 100644
index 9821c27..0000000
--- a/core/res/res/drawable-xhdpi/perm_group_calendar.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_camera.png b/core/res/res/drawable-xhdpi/perm_group_camera.png
deleted file mode 100644
index 23b7167..0000000
--- a/core/res/res/drawable-xhdpi/perm_group_camera.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_location.png b/core/res/res/drawable-xhdpi/perm_group_location.png
deleted file mode 100644
index d949cdb..0000000
--- a/core/res/res/drawable-xhdpi/perm_group_location.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_messages.png b/core/res/res/drawable-xhdpi/perm_group_messages.png
deleted file mode 100644
index dbb9aba..0000000
--- a/core/res/res/drawable-xhdpi/perm_group_messages.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_microphone.png b/core/res/res/drawable-xhdpi/perm_group_microphone.png
deleted file mode 100644
index 8887a41..0000000
--- a/core/res/res/drawable-xhdpi/perm_group_microphone.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_phone_calls.png b/core/res/res/drawable-xhdpi/perm_group_phone_calls.png
deleted file mode 100644
index 9e1d2ca..0000000
--- a/core/res/res/drawable-xhdpi/perm_group_phone_calls.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_social_info.png b/core/res/res/drawable-xhdpi/perm_group_social_info.png
deleted file mode 100644
index 842662c..0000000
--- a/core/res/res/drawable-xhdpi/perm_group_social_info.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_calendar.png b/core/res/res/drawable-xxhdpi/perm_group_calendar.png
deleted file mode 100644
index 08f0474..0000000
--- a/core/res/res/drawable-xxhdpi/perm_group_calendar.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_camera.png b/core/res/res/drawable-xxhdpi/perm_group_camera.png
deleted file mode 100644
index 88a3d0e..0000000
--- a/core/res/res/drawable-xxhdpi/perm_group_camera.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_location.png b/core/res/res/drawable-xxhdpi/perm_group_location.png
deleted file mode 100644
index 3a83d8b..0000000
--- a/core/res/res/drawable-xxhdpi/perm_group_location.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_messages.png b/core/res/res/drawable-xxhdpi/perm_group_messages.png
deleted file mode 100644
index 9e2ef73..0000000
--- a/core/res/res/drawable-xxhdpi/perm_group_messages.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_microphone.png b/core/res/res/drawable-xxhdpi/perm_group_microphone.png
deleted file mode 100644
index 65a6bf2..0000000
--- a/core/res/res/drawable-xxhdpi/perm_group_microphone.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_phone_calls.png b/core/res/res/drawable-xxhdpi/perm_group_phone_calls.png
deleted file mode 100644
index e4daafb..0000000
--- a/core/res/res/drawable-xxhdpi/perm_group_phone_calls.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_social_info.png b/core/res/res/drawable-xxhdpi/perm_group_social_info.png
deleted file mode 100644
index 076fd19..0000000
--- a/core/res/res/drawable-xxhdpi/perm_group_social_info.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_calendar.png b/core/res/res/drawable-xxxhdpi/perm_group_calendar.png
deleted file mode 100644
index d6243b1..0000000
--- a/core/res/res/drawable-xxxhdpi/perm_group_calendar.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_camera.png b/core/res/res/drawable-xxxhdpi/perm_group_camera.png
deleted file mode 100644
index fdc4b44..0000000
--- a/core/res/res/drawable-xxxhdpi/perm_group_camera.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_location.png b/core/res/res/drawable-xxxhdpi/perm_group_location.png
deleted file mode 100644
index a1019b2..0000000
--- a/core/res/res/drawable-xxxhdpi/perm_group_location.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_messages.png b/core/res/res/drawable-xxxhdpi/perm_group_messages.png
deleted file mode 100644
index f7165fe..0000000
--- a/core/res/res/drawable-xxxhdpi/perm_group_messages.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_microphone.png b/core/res/res/drawable-xxxhdpi/perm_group_microphone.png
deleted file mode 100644
index a85e4cd..0000000
--- a/core/res/res/drawable-xxxhdpi/perm_group_microphone.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_phone_calls.png b/core/res/res/drawable-xxxhdpi/perm_group_phone_calls.png
deleted file mode 100644
index f4e6b9f..0000000
--- a/core/res/res/drawable-xxxhdpi/perm_group_phone_calls.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_social_info.png b/core/res/res/drawable-xxxhdpi/perm_group_social_info.png
deleted file mode 100644
index 3b17e39..0000000
--- a/core/res/res/drawable-xxxhdpi/perm_group_social_info.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/perm_group_calendar.xml b/core/res/res/drawable/perm_group_calendar.xml
new file mode 100644
index 0000000..a0f9dd2
--- /dev/null
+++ b/core/res/res/drawable/perm_group_calendar.xml
@@ -0,0 +1,24 @@
+<!--
+    Copyright (C) 2015 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M34.0,24.0L24.0,24.0l0.0,10.0l10.0,0.0L34.0,24.0zM32.0,2.0l0.0,4.0L16.0,6.0L16.0,2.0l-4.0,0.0l0.0,4.0l-2.0,0.0c-2.21,0.0 -3.98,1.79 -3.98,4.0L6.0,38.0c0.0,2.21 1.79,4.0 4.0,4.0l28.0,0.0c2.21,0.0 4.0,-1.79 4.0,-4.0L42.0,10.0c0.0,-2.21 -1.79,-4.0 -4.0,-4.0l-2.0,0.0L36.0,2.0l-4.0,0.0zm6.0,36.0L10.0,38.0L10.0,16.0l28.0,0.0l0.0,22.0z"/>
+</vector>
diff --git a/core/res/res/drawable/perm_group_camera.xml b/core/res/res/drawable/perm_group_camera.xml
new file mode 100644
index 0000000..30d31ce
--- /dev/null
+++ b/core/res/res/drawable/perm_group_camera.xml
@@ -0,0 +1,24 @@
+<!--
+    Copyright (C) 2015 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M18.8,21.0l9.53,-16.51C26.94,4.18 25.49,4.0 24.0,4.0c-4.8,0.0 -9.19,1.69 -12.64,4.51l7.33,12.6 0.11,-0.2zm24.28,-3.0c-1.84,-5.85 -6.3,-10.52 -11.99,-12.68L23.77,18.0l19.31,0.0zm0.52,2.0L28.62,20.0l0.58,1.0 9.53,16.5C41.99,33.94 44.0,29.21 44.0,24.0c0.0,-1.37 -0.14,-2.71 -0.4,-4.0zm-26.53,4.0l-7.8,-13.5C6.01,14.06 4.0,18.79 4.0,24.0c0.0,1.3 0.14,2.7 0.4,4.0l14.98,0.0l-2.31,-4.0zM4.92,30.0c1.84,5.85 6.3,10.52 11.99,12.68L24.23,30.0L4.92,30.0zm22.54,0.0l-7.8,13.51c1.0,0.31 2.8,0.49 4.3,0.49 4.8,0.0 9.19,-1.69 12.64,-4.51L29.31,26.8 27.46,30.0z"/>
+</vector>
diff --git a/core/res/res/drawable/perm_group_location.xml b/core/res/res/drawable/perm_group_location.xml
new file mode 100644
index 0000000..4184cf9
--- /dev/null
+++ b/core/res/res/drawable/perm_group_location.xml
@@ -0,0 +1,24 @@
+<!--
+    Copyright (C) 2015 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M24.0,16.0c-4.42,0.0 -8.0,3.58 -8.0,8.0s3.58,8.0 8.0,8.0 8.0,-3.58 8.0,-8.0 -3.58,-8.0 -8.0,-8.0zm17.88,6.0C40.96,13.66 34.34,7.04 26.0,6.12L26.0,2.0l-4.0,0.0l0.0,4.12C13.66,7.04 7.04,13.66 6.12,22.0L2.0,22.0l0.0,4.0l4.12,0.0c0.92,8.34 7.54,14.96 15.88,15.88L22.0,46.0l4.0,0.0l0.0,-4.12c8.34,-0.92 14.96,-7.54 15.88,-15.88L46.0,26.0l0.0,-4.0l-4.12,0.0zM24.0,38.0c-7.73,0.0 -14.0,-6.27 -14.0,-14.0s6.27,-14.0 14.0,-14.0 14.0,6.27 14.0,14.0 -6.27,14.0 -14.0,14.0z"/>
+</vector>
diff --git a/core/res/res/drawable/perm_group_messages.xml b/core/res/res/drawable/perm_group_messages.xml
new file mode 100644
index 0000000..4140e6c
--- /dev/null
+++ b/core/res/res/drawable/perm_group_messages.xml
@@ -0,0 +1,24 @@
+<!--
+    Copyright (C) 2015 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M40.0,4.0L8.0,4.0C5.79,4.0 4.02,5.79 4.02,8.0L4.0,44.0l8.0,-8.0l28.0,0.0c2.21,0.0 4.0,-1.79 4.0,-4.0L44.0,8.0c0.0,-2.21 -1.79,-4.0 -4.0,-4.0zm-4.0,24.0L12.0,28.0l0.0,-4.0l16.0,0.0l0.0,4.0zm0.0,-6.0L12.0,22.0l0.0,-4.0l24.0,0.0l0.0,4.0zm0.0,-6.0L12.0,16.0l0.0,-4.0l24.0,0.0l0.0,4.0z"/>
+</vector>
diff --git a/core/res/res/drawable/perm_group_microphone.xml b/core/res/res/drawable/perm_group_microphone.xml
new file mode 100644
index 0000000..670ef98
--- /dev/null
+++ b/core/res/res/drawable/perm_group_microphone.xml
@@ -0,0 +1,24 @@
+<!--
+    Copyright (C) 2015 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M24.0,28.0c3.31,0.0 5.98,-2.69 5.98,-6.0L30.0,10.0c0.0,-3.32 -2.68,-6.0 -6.0,-6.0 -3.31,0.0 -6.0,2.68 -6.0,6.0l0.0,12.0c0.0,3.31 2.69,6.0 6.0,6.0zm10.6,-6.0c0.0,6.0 -5.07,10.2 -10.6,10.2 -5.52,0.0 -10.6,-4.2 -10.6,-10.2L10.0,22c0.0,6.83 5.44,12.47 12.0,13.44L22.0,42.0l4.0,0.0l0.0,-6.56c6.56,-0.97 12.0,-6.61 12.0,-13.44l-3.4,0.0z"/>
+</vector>
diff --git a/core/res/res/drawable/perm_group_phone_calls.xml b/core/res/res/drawable/perm_group_phone_calls.xml
new file mode 100644
index 0000000..04ac6b9
--- /dev/null
+++ b/core/res/res/drawable/perm_group_phone_calls.xml
@@ -0,0 +1,24 @@
+<!--
+    Copyright (C) 2015 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M13.25,21.59c2.88,5.66 7.51,10.29 13.18,13.17l4.4,-4.41c0.55,-0.55 1.34,-0.71 2.03,-0.49C35.1,30.6 37.51,31.0 40.0,31.0c1.11,0.0 2.0,0.89 2.0,2.0l0.0,7.0c0.0,1.11 -0.89,2.0 -2.0,2.0C21.22,42.0 6.0,26.78 6.0,8.0c0.0,-1.1 0.9,-2.0 2.0,-2.0l7.0,0.0c1.11,0.0 2.0,0.89 2.0,2.0 0.0,2.4 0.4,4.9 1.14,7.1 0.2,0.6 0.06,1.48 -0.49,2.03l-4.4,4.42z"/>
+</vector>
diff --git a/core/res/res/drawable/perm_group_social_info.xml b/core/res/res/drawable/perm_group_social_info.xml
new file mode 100644
index 0000000..f0f7a90
--- /dev/null
+++ b/core/res/res/drawable/perm_group_social_info.xml
@@ -0,0 +1,24 @@
+<!--
+    Copyright (C) 2015 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M32.0,22.0c3.31,0.0 5.98,-2.69 5.98,-6.0s-2.67,-6.0 -5.98,-6.0c-3.31,0.0 -6.0,2.69 -6.0,6.0s2.69,6.0 6.0,6.0zm-16.0,0.0c3.31,0.0 5.98,-2.69 5.98,-6.0s-2.67,-6.0 -5.98,-6.0c-3.31,0.0 -6.0,2.69 -6.0,6.0s2.69,6.0 6.0,6.0zm0.0,4.0c-4.67,0.0 -14.0,2.34 -14.0,7.0l0.0,5.0l28.0,0.0l0.0,-5.0c0.0,-4.66 -9.33,-7.0 -14.0,-7.0zm16.0,0.0c-0.58,0.0 -1.2,0.04 -1.9,0.11C32.39,27.78 34.0,30.03 34.0,33.0l0.0,5.0l12.0,0.0l0.0,-5.0c0.0,-4.66 -9.33,-7.0 -14.0,-7.0z"/>
+</vector>
diff --git a/core/res/res/layout/floating_popup_menu_image_button.xml b/core/res/res/layout/floating_popup_menu_image_button.xml
new file mode 100644
index 0000000..5934136
--- /dev/null
+++ b/core/res/res/layout/floating_popup_menu_image_button.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="@dimen/floating_toolbar_menu_button_minimum_width"
+    android:layout_height="@dimen/floating_toolbar_height"
+    android:minWidth="@dimen/floating_toolbar_menu_button_minimum_width"
+    android:minHeight="@dimen/floating_toolbar_height"
+    android:focusable="false"
+    android:focusableInTouchMode="false"
+    android:importantForAccessibility="no">
+    <ImageButton
+        android:id="@+id/floating_toolbar_menu_item_image_button"
+        android:layout_width="@dimen/floating_toolbar_menu_button_minimum_width"
+        android:layout_height="@dimen/floating_toolbar_height"
+        android:scaleType="centerInside"
+        android:background="?attr/selectableItemBackground" />
+</LinearLayout>
diff --git a/core/res/res/layout/floating_popup_overflow_image_list_item.xml b/core/res/res/layout/floating_popup_overflow_image_list_item.xml
new file mode 100644
index 0000000..9988ad5
--- /dev/null
+++ b/core/res/res/layout/floating_popup_overflow_image_list_item.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="@dimen/floating_toolbar_menu_button_minimum_width"
+    android:layout_height="@dimen/floating_toolbar_height"
+    android:minWidth="@dimen/floating_toolbar_menu_button_minimum_width"
+    android:minHeight="@dimen/floating_toolbar_height"
+    android:focusable="false"
+    android:focusableInTouchMode="false"
+    android:importantForAccessibility="no">
+    <ImageView
+        android:id="@+id/floating_toolbar_menu_item_image_button"
+        android:layout_width="@dimen/floating_toolbar_menu_button_minimum_width"
+        android:layout_height="@dimen/floating_toolbar_height"
+        android:layout_marginStart="18dp"
+        android:scaleType="centerInside"/>
+</LinearLayout>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index 842c72e..fca1285 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -94,6 +94,7 @@
   <item type="id" name="redo" />
   <item type="id" name="replaceText" />
   <item type="id" name="shareText" />
+  <item type="id" name="floating_toolbar_menu_item_image_button" />
 
   <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_SHOW_ON_SCREEN}. -->
   <item type="id" name="accessibilityActionShowOnScreen" />
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 4b57a47..e3033e7 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2243,11 +2243,14 @@
   <java-symbol type="drawable" name="ic_usb_48dp" />
 
   <!-- Floating toolbar -->
+  <java-symbol type="id" name="floating_toolbar_menu_item_image_button" />
   <java-symbol type="layout" name="floating_popup_container" />
   <java-symbol type="layout" name="floating_popup_menu_button" />
   <java-symbol type="layout" name="floating_popup_open_overflow_button" />
   <java-symbol type="layout" name="floating_popup_close_overflow_button" />
+  <java-symbol type="layout" name="floating_popup_menu_image_button" />
   <java-symbol type="layout" name="floating_popup_overflow_list_item" />
+  <java-symbol type="layout" name="floating_popup_overflow_image_list_item" />
   <java-symbol type="dimen" name="floating_toolbar_height" />
   <java-symbol type="dimen" name="floating_toolbar_menu_button_side_padding" />
   <java-symbol type="dimen" name="floating_toolbar_overflow_side_padding" />
diff --git a/docs/html/images/media/mediacodec_async_states.png b/docs/html/images/media/mediacodec_async_states.png
new file mode 100644
index 0000000..c21f5c0
--- /dev/null
+++ b/docs/html/images/media/mediacodec_async_states.png
Binary files differ
diff --git a/docs/html/images/media/mediacodec_async_states.svg b/docs/html/images/media/mediacodec_async_states.svg
new file mode 100644
index 0000000..7349511
--- /dev/null
+++ b/docs/html/images/media/mediacodec_async_states.svg
@@ -0,0 +1,151 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="649 397 519 356" width="519pt" height="356pt" xmlns:dc="http://purl.org/dc/elements/1.1/">
+    <defs>
+        <marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="FilledArrow_Marker" viewBox="-1 -3 7 6" markerWidth="7" markerHeight="6" color="#ea8008">
+            <g>
+                <path d="M 4.8 0 L 0 -1.8 L 0 1.8 Z" fill="currentColor" stroke="currentColor" stroke-width="1"/>
+            </g>
+        </marker>
+        <marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="FilledArrow_Marker_2" viewBox="-1 -3 7 6" markerWidth="7" markerHeight="6" color="#274ecc">
+            <g>
+                <path d="M 4.8 0 L 0 -1.8 L 0 1.8 Z" fill="currentColor" stroke="currentColor" stroke-width="1"/>
+            </g>
+        </marker>
+        <marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="FilledArrow_Marker_3" viewBox="-1 -3 7 6" markerWidth="7" markerHeight="6" color="#d02e2a">
+            <g>
+                <path d="M 4.8 0 L 0 -1.8 L 0 1.8 Z" fill="currentColor" stroke="currentColor" stroke-width="1"/>
+            </g>
+        </marker>
+        <marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="FilledArrow_Marker_4" viewBox="-1 -3 7 6" markerWidth="7" markerHeight="6" color="#262626">
+            <g>
+                <path d="M 4.8 0 L 0 -1.8 L 0 1.8 Z" fill="currentColor" stroke="currentColor" stroke-width="1"/>
+            </g>
+        </marker>
+        <font-face font-family="Roboto" font-size="20" panose-1="2 0 0 0 0 0 0 0 0 0" units-per-em="1000" underline-position="-73.242188" underline-thickness="48.828125" slope="0" x-height="538.08594" cap-height="720.70312" ascent="927.7344" descent="-244.14062" font-weight="500">
+            <font-face-src>
+                <font-face-name name="Roboto-Regular"/>
+            </font-face-src>
+        </font-face>
+        <font-face font-family="Roboto Condensed" font-size="16" panose-1="0 0 4 6 0 0 0 0 0 0" units-per-em="1000" underline-position="-73.242188" underline-thickness="48.828125" slope="0" x-height="538.08594" cap-height="720.70312" ascent="927.7344" descent="-244.14062" font-weight="300" font-stretch="condensed">
+            <font-face-src>
+                <font-face-name name="RobotoCondensed-Light"/>
+            </font-face-src>
+        </font-face>
+        <marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="FilledArrow_Marker_5" viewBox="-1 -3 7 6" markerWidth="7" markerHeight="6" color="#126f33">
+            <g>
+                <path d="M 4.8 0 L 0 -1.8 L 0 1.8 Z" fill="currentColor" stroke="currentColor" stroke-width="1"/>
+            </g>
+        </marker>
+    </defs>
+    <g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1">
+        <title>MediaCodec state diagram for asynchronous operation</title>
+        <g>
+            <line x1="740" y1="508.5" x2="740" y2="471.4" marker-end="url(#FilledArrow_Marker)" stroke="#ea8008" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <line x1="740" y1="598.5" x2="740" y2="561.4" marker-end="url(#FilledArrow_Marker_2)" stroke="#274ecc" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <line x1="763.33333" y1="458.5" x2="763.33333" y2="495.6" marker-end="url(#FilledArrow_Marker_2)" stroke="#274ecc" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <line x1="920" y1="542" x2="822.9" y2="541.85288" marker-end="url(#FilledArrow_Marker_2)" stroke="#274ecc" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <line x1="920" y1="617.5" x2="822.89947" y2="618.38273" marker-end="url(#FilledArrow_Marker_3)" stroke="#d02e2a" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <line x1="919.5" y1="528.5" x2="822.9" y2="528.5" marker-end="url(#FilledArrow_Marker)" stroke="#ea8008" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <line x1="827.11573" y1="674.83365" x2="843.6129" y2="701.97642" marker-end="url(#FilledArrow_Marker_4)" stroke="#262626" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <line x1="922.88427" y1="674.83365" x2="904.22416" y2="702.32635" marker-end="url(#FilledArrow_Marker_4)" stroke="#262626" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <path d="M 927.5 400 L 1092.5 400 C 1095.8137 400 1098.5 402.6863 1098.5 406 L 1098.5 671 C 1098.5 674.3137 1095.8137 677 1092.5 677 L 927.5 677 C 924.1863 677 921.5 674.3137 921.5 671 L 921.5 406 C 921.5 402.6863 924.1863 400 927.5 400 Z" fill="#178f46"/>
+            <path d="M 927.5 400 L 1092.5 400 C 1095.8137 400 1098.5 402.6863 1098.5 406 L 1098.5 671 C 1098.5 674.3137 1095.8137 677 1092.5 677 L 927.5 677 C 924.1863 677 921.5 674.3137 921.5 671 L 921.5 406 C 921.5 402.6863 924.1863 400 927.5 400 Z" stroke="#178f46" stroke-linecap="round" stroke-linejoin="round" stroke-width="3"/>
+            <text transform="translate(926.5 648.5)" fill="#aadbc2">
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#aadbc2" x="40.091797" y="19" textLength="21.279297">Ex</tspan>
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#aadbc2" x="61.17578" y="19" textLength="65.73242">ecuting</tspan>
+            </text>
+            <path d="M 657.5 400 L 822.5 400 C 825.8137 400 828.5 402.6863 828.5 406 L 828.5 671 C 828.5 674.3137 825.8137 677 822.5 677 L 657.5 677 C 654.1863 677 651.5 674.3137 651.5 671 L 651.5 406 C 651.5 402.6863 654.1863 400 657.5 400 Z" stroke="#d02e2a" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <text transform="translate(656.5 648.5)" fill="#d02e2a">
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#d02e2a" x="46.53711" y="19" textLength="18.398438">St</tspan>
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#d02e2a" x="64.740234" y="19" textLength="55.722656">opped</tspan>
+            </text>
+            <text transform="translate(1130.1743 479.5)" fill="#262626">
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#262626" x=".64453125" y="15" textLength="30.710938">flush</tspan>
+            </text>
+            <text transform="translate(968 467)" fill="#262626">
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#262626" x="4.4101562" y="15" textLength="24.148438">star</tspan>
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#262626" x="28.949219" y="15" textLength="4.640625">t</tspan>
+            </text>
+            <text transform="translate(844.054 419.2185)" fill="#136f34">
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#136f34" x="14.255245" y="15" textLength="24.148438">star</tspan>
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#136f34" x="38.794307" y="15" textLength="4.640625">t</tspan>
+            </text>
+            <text transform="translate(848.3963 505)" fill="#ea8008">
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#ea8008" x="11.621094" y="15" textLength="11.78125">st</tspan>
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#ea8008" x="23.246094" y="15" textLength="15.6328125">op</tspan>
+            </text>
+            <text transform="translate(858.68587 621.3852)" fill="#b6251f">
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#b6251f" x=".21875" y="15" textLength="16.992188">err</tspan>
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#b6251f" x="17.054688" y="15" textLength="12.6875">or</tspan>
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#b6251f" x="28.78125" y="15" textLength="9">…</tspan>
+            </text>
+            <text transform="translate(857.8257 546.43005)" fill="#274ecc">
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#274ecc" x=".4453125" y="15" textLength="4.8359375">r</tspan>
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#274ecc" x="5.1328125" y="15" textLength="26.421875">eset</tspan>
+            </text>
+            <text transform="translate(768.33333 466.62302)" fill="#274ecc">
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#274ecc" x=".4453125" y="15" textLength="4.8359375">r</tspan>
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#274ecc" x="5.1328125" y="15" textLength="26.421875">eset</tspan>
+            </text>
+            <text transform="translate(744 571.12)" fill="#274ecc">
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#274ecc" x=".4453125" y="15" textLength="4.8359375">r</tspan>
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#274ecc" x="5.1328125" y="15" textLength="26.421875">eset</tspan>
+            </text>
+            <text transform="translate(675 479.5)" fill="#ea8008">
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#ea8008" x="2.8125" y="15" textLength="30.382812">confi</tspan>
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#ea8008" x="33.195312" y="15" textLength="20.320312">gur</tspan>
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#ea8008" x="53.367187" y="15" textLength="7.3203125">e</tspan>
+            </text>
+            <path d="M 676 418.5 L 804 418.5 C 807.3137 418.5 810 421.1863 810 424.5 L 810 452.5 C 810 455.8137 807.3137 458.5 804 458.5 L 676 458.5 C 672.6863 458.5 670 455.8137 670 452.5 L 670 424.5 C 670 421.1863 672.6863 418.5 676 418.5 Z" fill="#f0a608"/>
+            <text transform="translate(675 426.5)" fill="#fbe4a3">
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#fbe4a3" x="16.381836" y="19" textLength="46.533203">Confi</tspan>
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#fbe4a3" x="62.91504" y="19" textLength="29.013672">gur</tspan>
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#fbe4a3" x="91.743164" y="19" textLength="21.875">ed</tspan>
+            </text>
+            <path d="M 946 508.5 L 1074 508.5 C 1077.3137 508.5 1080 511.1863 1080 514.5 L 1080 542.5 C 1080 545.8137 1077.3137 548.5 1074 548.5 L 946 548.5 C 942.6863 548.5 940 545.8137 940 542.5 L 940 514.5 C 940 511.1863 942.6863 508.5 946 508.5 Z" fill="#f8f8f8"/>
+            <path d="M 946 508.5 L 1074 508.5 C 1077.3137 508.5 1080 511.1863 1080 514.5 L 1080 542.5 C 1080 545.8137 1077.3137 548.5 1074 548.5 L 946 548.5 C 942.6863 548.5 940 545.8137 940 542.5 L 940 514.5 C 940 511.1863 942.6863 508.5 946 508.5 Z" stroke="#49b077" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <text transform="translate(945 516.5)" fill="#178f46">
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#178f46" x="28.740234" y="19" textLength="72.51953">Running</tspan>
+            </text>
+            <path d="M 676 508.5 L 804 508.5 C 807.3137 508.5 810 511.1863 810 514.5 L 810 542.5 C 810 545.8137 807.3137 548.5 804 548.5 L 676 548.5 C 672.6863 548.5 670 545.8137 670 542.5 L 670 514.5 C 670 511.1863 672.6863 508.5 676 508.5 Z" fill="#346df1"/>
+            <text transform="translate(675 516.5)" fill="#bad0fb">
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#bad0fb" x="10.825195" y="19" textLength="86.63086">Uninitializ</tspan>
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#bad0fb" x="97.299805" y="19" textLength="21.875">ed</tspan>
+            </text>
+            <path d="M 676 598.5 L 804 598.5 C 807.3137 598.5 810 601.1863 810 604.5 L 810 632.5 C 810 635.8137 807.3137 638.5 804 638.5 L 676 638.5 C 672.6863 638.5 670 635.8137 670 632.5 L 670 604.5 C 670 601.1863 672.6863 598.5 676 598.5 Z" fill="#d02e2a"/>
+            <text transform="translate(675 606.5)" fill="white">
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="white" x="43.55957" y="19" textLength="24.902344">Err</tspan>
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="white" x="68.2666" y="19" textLength="18.173828">or</tspan>
+            </text>
+            <path d="M 946 418.5 L 1074 418.5 C 1077.3137 418.5 1080 421.1863 1080 424.5 L 1080 452.5 C 1080 455.8137 1077.3137 458.5 1074 458.5 L 946 458.5 C 942.6863 458.5 940 455.8137 940 452.5 L 940 424.5 C 940 421.1863 942.6863 418.5 946 418.5 Z" fill="#f8f8f8"/>
+            <path d="M 946 418.5 L 1074 418.5 C 1077.3137 418.5 1080 421.1863 1080 424.5 L 1080 452.5 C 1080 455.8137 1077.3137 458.5 1074 458.5 L 946 458.5 C 942.6863 458.5 940 455.8137 940 452.5 L 940 424.5 C 940 421.1863 942.6863 418.5 946 418.5 Z" stroke="#de6560" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <text transform="translate(945 426.5)" fill="#178f46">
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#178f46" x="29.93164" y="19" textLength="70.13672">Flushed</tspan>
+            </text>
+            <path d="M 946 598.5 L 1074 598.5 C 1077.3137 598.5 1080 601.1863 1080 604.5 L 1080 632.5 C 1080 635.8137 1077.3137 638.5 1074 638.5 L 946 638.5 C 942.6863 638.5 940 635.8137 940 632.5 L 940 604.5 C 940 601.1863 942.6863 598.5 946 598.5 Z" fill="#f8f8f8"/>
+            <path d="M 946 598.5 L 1074 598.5 C 1077.3137 598.5 1080 601.1863 1080 604.5 L 1080 632.5 C 1080 635.8137 1077.3137 638.5 1074 638.5 L 946 638.5 C 942.6863 638.5 940 635.8137 940 632.5 L 940 604.5 C 940 601.1863 942.6863 598.5 946 598.5 Z" stroke="#f4c23d" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <text transform="translate(945 606.5)" fill="#178f46">
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#178f46" x="2.0410156" y="19" textLength="87.09961">End of Str</tspan>
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#178f46" x="88.95508" y="19" textLength="39.003906">eam</tspan>
+            </text>
+            <path d="M 810 438.5 C 810 438.5 878.0599 435.16865 921.5 455 C 947.861 467.03438 957.6335 484.16434 961.2431 495.77385" marker-end="url(#FilledArrow_Marker_5)" stroke="#126f33" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <line x1="963.33333" y1="458.5" x2="963.33333" y2="495.6" marker-end="url(#FilledArrow_Marker_4)" stroke="#262626" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <line x1="963.33333" y1="548.5" x2="963.33333" y2="585.6" marker-end="url(#FilledArrow_Marker_4)" stroke="#262626" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <path d="M 1080 521.83333 C 1080 521.83333 1106 504.33135 1106 484.5 C 1106 473.46106 1097.9439 464.58984 1090.80046 458.89346" marker-end="url(#FilledArrow_Marker_4)" stroke="#262626" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <path d="M 1056.66667 598.5 C 1056.66667 598.5 1110.38955 548.8288 1117 503.5 C 1121.4143 473.23063 1103.434 454.40253 1090.9997 445.23311" marker-end="url(#FilledArrow_Marker_4)" stroke="#262626" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <text transform="translate(968.25 550.5)" fill="#262626">
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#262626" x="2.171875" y="15" textLength="111.25">queueInputBuffer</tspan>
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#262626" x="38.46875" y="34" textLength="35.0625">(EOS)</tspan>
+            </text>
+            <path d="M 809.6463 713 L 937.6463 713 C 940.96 713 943.6463 715.6863 943.6463 719 L 943.6463 747 C 943.6463 750.3137 940.96 753 937.6463 753 L 809.6463 753 C 806.3326 753 803.6463 750.3137 803.6463 747 L 803.6463 719 C 803.6463 715.6863 806.3326 713 809.6463 713 Z" fill="#535353"/>
+            <text transform="translate(808.6463 721)" fill="#d5d5d5">
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#d5d5d5" x="24.28711" y="19" textLength="81.42578">Released</tspan>
+            </text>
+            <text transform="translate(852.18587 683)" fill="#262626">
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#262626" x=".15625" y="15" textLength="4.8359375">r</tspan>
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#262626" x="4.84375" y="15" textLength="40">elease</tspan>
+            </text>
+        </g>
+    </g>
+</svg>
diff --git a/docs/html/images/media/mediacodec_buffers.png b/docs/html/images/media/mediacodec_buffers.png
new file mode 100644
index 0000000..f17f4ac
--- /dev/null
+++ b/docs/html/images/media/mediacodec_buffers.png
Binary files differ
diff --git a/docs/html/images/media/mediacodec_buffers.svg b/docs/html/images/media/mediacodec_buffers.svg
new file mode 100644
index 0000000..fa121ee
--- /dev/null
+++ b/docs/html/images/media/mediacodec_buffers.svg
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="20 17 540 208" width="45pc" height="208pt" xmlns:dc="http://purl.org/dc/elements/1.1/">
+    <defs>
+        <font-face font-family="Roboto" font-size="20" panose-1="2 0 0 0 0 0 0 0 0 0" units-per-em="1000" underline-position="-73.242188" underline-thickness="48.828125" slope="0" x-height="538.08594" cap-height="720.70312" ascent="927.7344" descent="-244.14062" font-weight="500">
+            <font-face-src>
+                <font-face-name name="Roboto-Regular"/>
+            </font-face-src>
+        </font-face>
+        <font-face font-family="Roboto" font-size="12" panose-1="2 0 0 0 0 0 0 0 0 0" units-per-em="1000" underline-position="-73.242188" underline-thickness="48.828125" slope="0" x-height="538.08594" cap-height="720.70312" ascent="927.7344" descent="-244.14062" font-weight="300">
+            <font-face-src>
+                <font-face-name name="Roboto-Light"/>
+            </font-face-src>
+        </font-face>
+        <marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="FilledArrow_Marker" viewBox="-4 -2 5 4" markerWidth="5" markerHeight="4" color="#262626">
+            <g>
+                <path d="M -2.16 0 L 0 .81 L 0 -.81 Z" fill="currentColor" stroke="currentColor" stroke-width="1"/>
+            </g>
+        </marker>
+    </defs>
+    <g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1">
+        <title>MediaCodec buffer flow diagram</title>
+        <g>
+            <line x1="291" y1="20" x2="290" y2="220" stroke="#535353" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" stroke-dasharray="4,4"/>
+            <path d="M 560 71 L 560 179 L 560 185 L 554 185 L 510 185 L 466 185 C 462.6863 185 460 182.31371 460 179 L 460 71 C 460 67.68629 462.6863 65 466 65 L 510 65 L 554 65 L 560 65 Z M 554 65 C 554 65 554 65 554 65 Z" fill="#178f46"/>
+            <text transform="translate(465 113)" fill="#aadcc2">
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#aadcc2" x="19.555664" y="19" textLength="50.888672">Client</tspan>
+            </text>
+            <path d="M 246 75 L 334 75 C 337.3137 75 340 77.68629 340 81 L 340 169 C 340 172.31371 337.3137 175 334 175 L 246 175 C 242.68629 175 240 172.31371 240 169 L 240 81 C 240 77.68629 242.68629 75 246 75 Z" fill="#346df1"/>
+            <text transform="translate(245 113)" fill="#bad0fb">
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#bad0fb" x="16.616211" y="19" textLength="56.767578">Codec</tspan>
+            </text>
+            <path d="M 132 140 L 148 140 C 149.10457 140 150 140.89543 150 142 L 150 158 C 150 159.10457 149.10457 160 148 160 L 132 160 C 130.89543 160 130 159.10457 130 158 L 130 142 C 130 140.89543 130.89543 140 132 140 Z" fill="#de6560"/>
+            <path d="M 132 140 L 148 140 C 149.10457 140 150 140.89543 150 142 L 150 158 C 150 159.10457 149.10457 160 148 160 L 132 160 C 130.89543 160 130 159.10457 130 158 L 130 142 C 130 140.89543 130.89543 140 132 140 Z" stroke="#b6251f" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <path d="M 172 140 L 188 140 C 189.10457 140 190 140.89543 190 142 L 190 158 C 190 159.10457 189.10457 160 188 160 L 172 160 C 170.89543 160 170 159.10457 170 158 L 170 142 C 170 140.89543 170.89543 140 172 140 Z" fill="#de6560"/>
+            <path d="M 172 140 L 188 140 C 189.10457 140 190 140.89543 190 142 L 190 158 C 190 159.10457 189.10457 160 188 160 L 172 160 C 170.89543 160 170 159.10457 170 158 L 170 142 C 170 140.89543 170.89543 140 172 140 Z" stroke="#b6251f" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <path d="M 212 140 L 228 140 C 229.10457 140 230 140.89543 230 142 L 230 158 C 230 159.10457 229.10457 160 228 160 L 212 160 C 210.89543 160 210 159.10457 210 158 L 210 142 C 210 140.89543 210.89543 140 212 140 Z" fill="#de6560"/>
+            <path d="M 212 140 L 228 140 C 229.10457 140 230 140.89543 230 142 L 230 158 C 230 159.10457 229.10457 160 228 160 L 212 160 C 210.89543 160 210 159.10457 210 158 L 210 142 C 210 140.89543 210.89543 140 212 140 Z" stroke="#b6251f" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <path d="M 212 90 L 228 90 C 229.10457 90 230 90.89543 230 92 L 230 108 C 230 109.10457 229.10457 110 228 110 L 212 110 C 210.89543 110 210 109.10457 210 108 L 210 92 C 210 90.89543 210.89543 90 212 90 Z" stroke="#b6251f" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <path d="M 172 90 L 188 90 C 189.10457 90 190 90.89543 190 92 L 190 108 C 190 109.10457 189.10457 110 188 110 L 172 110 C 170.89543 110 170 109.10457 170 108 L 170 92 C 170 90.89543 170.89543 90 172 90 Z" stroke="#b6251f" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <path d="M 132 90 L 148 90 C 149.10457 90 150 90.89543 150 92 L 150 108 C 150 109.10457 149.10457 110 148 110 L 132 110 C 130.89543 110 130 109.10457 130 108 L 130 92 C 130 90.89543 130.89543 90 132 90 Z" stroke="#b6251f" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <text transform="translate(128.5 70.5)" fill="#262626">
+                <tspan font-family="Roboto" font-size="12" font-weight="300" fill="#262626" x=".19238281" y="11" textLength="86.44336">empty input buff</tspan>
+                <tspan font-family="Roboto" font-size="12" font-weight="300" fill="#262626" x="86.495117" y="11" textLength="16.3125">ers</tspan>
+            </text>
+            <path d="M 20 71 L 20 179 L 20 185 L 26 185 L 70 185 L 114 185 C 117.31371 185 120 182.31371 120 179 L 120 71 C 120 67.68629 117.31371 65 114 65 L 70 65 L 26 65 L 20 65 Z M 26 65 C 26 65 26 65 26 65 Z" fill="#178f46"/>
+            <text transform="translate(25 113)" fill="#aadcc2">
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#aadcc2" x="19.555664" y="19" textLength="50.888672">Client</tspan>
+            </text>
+            <path d="M 352 110 L 368 110 C 369.10457 110 370 109.10457 370 108 L 370 92 C 370 90.89543 369.10457 90 368 90 L 352 90 C 350.89543 90 350 90.89543 350 92 L 350 108 C 350 109.10457 350.89543 110 352 110 Z" fill="#f4c23d"/>
+            <path d="M 352 110 L 368 110 C 369.10457 110 370 109.10457 370 108 L 370 92 C 370 90.89543 369.10457 90 368 90 L 352 90 C 350.89543 90 350 90.89543 350 92 L 350 108 C 350 109.10457 350.89543 110 352 110 Z" stroke="#eb8007" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <path d="M 392 110 L 408 110 C 409.10457 110 410 109.10457 410 108 L 410 92 C 410 90.89543 409.10457 90 408 90 L 392 90 C 390.89543 90 390 90.89543 390 92 L 390 108 C 390 109.10457 390.89543 110 392 110 Z" fill="#f4c23d"/>
+            <path d="M 392 110 L 408 110 C 409.10457 110 410 109.10457 410 108 L 410 92 C 410 90.89543 409.10457 90 408 90 L 392 90 C 390.89543 90 390 90.89543 390 92 L 390 108 C 390 109.10457 390.89543 110 392 110 Z" stroke="#eb8007" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <path d="M 432 110 L 448 110 C 449.10457 110 450 109.10457 450 108 L 450 92 C 450 90.89543 449.10457 90 448 90 L 432 90 C 430.89543 90 430 90.89543 430 92 L 430 108 C 430 109.10457 430.89543 110 432 110 Z" fill="#f4c23d"/>
+            <path d="M 432 110 L 448 110 C 449.10457 110 450 109.10457 450 108 L 450 92 C 450 90.89543 449.10457 90 448 90 L 432 90 C 430.89543 90 430 90.89543 430 92 L 430 108 C 430 109.10457 430.89543 110 432 110 Z" stroke="#eb8007" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <path d="M 432 160 L 448 160 C 449.10457 160 450 159.10457 450 158 L 450 142 C 450 140.89543 449.10457 140 448 140 L 432 140 C 430.89543 140 430 140.89543 430 142 L 430 158 C 430 159.10457 430.89543 160 432 160 Z" fill="#f4c23d"/>
+            <path d="M 432 160 L 448 160 C 449.10457 160 450 159.10457 450 158 L 450 142 C 450 140.89543 449.10457 140 448 140 L 432 140 C 430.89543 140 430 140.89543 430 142 L 430 158 C 430 159.10457 430.89543 160 432 160 Z" stroke="#eb8007" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <path d="M 392 160 L 408 160 C 409.10457 160 410 159.10457 410 158 L 410 142 C 410 140.89543 409.10457 140 408 140 L 392 140 C 390.89543 140 390 140.89543 390 142 L 390 158 C 390 159.10457 390.89543 160 392 160 Z" fill="#f4c23d"/>
+            <path d="M 392 160 L 408 160 C 409.10457 160 410 159.10457 410 158 L 410 142 C 410 140.89543 409.10457 140 408 140 L 392 140 C 390.89543 140 390 140.89543 390 142 L 390 158 C 390 159.10457 390.89543 160 392 160 Z" stroke="#eb8007" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <path d="M 352 160 L 368 160 C 369.10457 160 370 159.10457 370 158 L 370 142 C 370 140.89543 369.10457 140 368 140 L 352 140 C 350.89543 140 350 140.89543 350 142 L 350 158 C 350 159.10457 350.89543 160 352 160 Z" fill="#f4c23d"/>
+            <path d="M 352 160 L 368 160 C 369.10457 160 370 159.10457 370 158 L 370 142 C 370 140.89543 369.10457 140 368 140 L 352 140 C 350.89543 140 350 140.89543 350 142 L 350 158 C 350 159.10457 350.89543 160 352 160 Z" stroke="#eb8007" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <line x1="230" y1="120.03223" x2="110" y2="120" stroke="#262626" stroke-linecap="square" stroke-linejoin="round" stroke-width="2" stroke-dasharray="8,5"/>
+            <line x1="232.38" y1="130.03034" x2="110" y2="130" marker-start="url(#FilledArrow_Marker)" stroke="#262626" stroke-linecap="square" stroke-linejoin="round" stroke-width="2" stroke-dasharray="8,5"/>
+            <path d="M 110 130 C 107.238576 130 105 127.76142 105 125 C 105 122.238576 107.238576 120 110 120" stroke="#262626" stroke-linecap="square" stroke-linejoin="round" stroke-width="2" stroke-dasharray="8,5"/>
+            <line x1="350" y1="120.53223" x2="470" y2="120.5" stroke="#262626" stroke-linecap="square" stroke-linejoin="round" stroke-width="2" stroke-dasharray="8,5"/>
+            <line x1="347.62" y1="130.53034" x2="470" y2="130.5" marker-start="url(#FilledArrow_Marker)" stroke="#262626" stroke-linecap="square" stroke-linejoin="round" stroke-width="2" stroke-dasharray="8,5"/>
+            <path d="M 470 130.5 C 472.76142 130.5 475 128.26142 475 125.5 C 475 122.738576 472.76142 120.5 470 120.5" stroke="#262626" stroke-linecap="square" stroke-linejoin="round" stroke-width="2" stroke-dasharray="8,5"/>
+            <text transform="translate(132.5 166.5)" fill="#262626">
+                <tspan font-family="Roboto" font-size="12" font-weight="300" fill="#262626" x=".3671875" y="11" textLength="6.4453125">fi</tspan>
+                <tspan font-family="Roboto" font-size="12" font-weight="300" fill="#262626" x="6.8125" y="11" textLength="71.648438">lled input buff</tspan>
+                <tspan font-family="Roboto" font-size="12" font-weight="300" fill="#262626" x="78.320312" y="11" textLength="16.3125">ers</tspan>
+            </text>
+            <text transform="translate(348.5 70.5)" fill="#262626">
+                <tspan font-family="Roboto" font-size="12" font-weight="300" fill="#262626" x=".42382812" y="11" textLength="6.4453125">fi</tspan>
+                <tspan font-family="Roboto" font-size="12" font-weight="300" fill="#262626" x="6.8691406" y="11" textLength="79.535156">lled output buff</tspan>
+                <tspan font-family="Roboto" font-size="12" font-weight="300" fill="#262626" x="86.26367" y="11" textLength="16.3125">ers</tspan>
+            </text>
+            <text transform="translate(366.5 165)" fill="#262626">
+                <tspan font-family="Roboto" font-size="12" font-weight="300" fill="#262626" x="11.748047" y="11" textLength="32.080078">discar</tspan>
+                <tspan font-family="Roboto" font-size="12" font-weight="300" fill="#262626" x="43.716797" y="11" textLength="19.535156">ded</tspan>
+                <tspan font-family="Roboto" font-size="12" font-weight="300" fill="#262626" x=".22851562" y="25" textLength="58.371094">output buff</tspan>
+                <tspan font-family="Roboto" font-size="12" font-weight="300" fill="#262626" x="58.458984" y="25" textLength="16.3125">ers</tspan>
+            </text>
+            <text transform="translate(35.5 192)" fill="#262626">
+                <tspan font-family="Roboto" font-size="12" font-weight="300" fill="#262626" x=".13378906" y="11" textLength="41.8125">client pr</tspan>
+                <tspan font-family="Roboto" font-size="12" font-weight="300" fill="#262626" x="41.829102" y="11" textLength="6.720703">o</tspan>
+                <tspan font-family="Roboto" font-size="12" font-weight="300" fill="#262626" x="48.461914" y="11" textLength="27.404297">vides</tspan>
+                <tspan font-family="Roboto" font-size="12" font-weight="300" fill="#262626" x="11.6621094" y="25" textLength="52.67578">input data</tspan>
+            </text>
+            <text transform="translate(466.5 192)" fill="#262626">
+                <tspan font-family="Roboto" font-size="12" font-weight="300" fill="#262626" x=".40136719" y="11" textLength="86.197266">client consumes</tspan>
+                <tspan font-family="Roboto" font-size="12" font-weight="300" fill="#262626" x="13.21875" y="25" textLength="60.5625">output data</tspan>
+            </text>
+            <text transform="translate(157.5 30)" fill="#d02d2a">
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#d02d2a" x=".166015625" y="19" textLength="44.66797">input</tspan>
+            </text>
+            <text transform="translate(371 30)" fill="#f0a608">
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#f0a608" x=".12792969" y="19" textLength="57.74414">output</tspan>
+            </text>
+        </g>
+    </g>
+</svg>
diff --git a/docs/html/images/media/mediacodec_states.png b/docs/html/images/media/mediacodec_states.png
new file mode 100644
index 0000000..a34b613
--- /dev/null
+++ b/docs/html/images/media/mediacodec_states.png
Binary files differ
diff --git a/docs/html/images/media/mediacodec_states.svg b/docs/html/images/media/mediacodec_states.svg
new file mode 100644
index 0000000..81646fd
--- /dev/null
+++ b/docs/html/images/media/mediacodec_states.svg
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="649 8 519 357" width="519pt" height="357pt" xmlns:dc="http://purl.org/dc/elements/1.1/">
+    <defs>
+        <marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="FilledArrow_Marker" viewBox="-1 -3 7 6" markerWidth="7" markerHeight="6" color="#ea8008">
+            <g>
+                <path d="M 4.8 0 L 0 -1.8 L 0 1.8 Z" fill="currentColor" stroke="currentColor" stroke-width="1"/>
+            </g>
+        </marker>
+        <marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="FilledArrow_Marker_2" viewBox="-1 -3 7 6" markerWidth="7" markerHeight="6" color="#274ecc">
+            <g>
+                <path d="M 4.8 0 L 0 -1.8 L 0 1.8 Z" fill="currentColor" stroke="currentColor" stroke-width="1"/>
+            </g>
+        </marker>
+        <marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="FilledArrow_Marker_3" viewBox="-1 -3 7 6" markerWidth="7" markerHeight="6" color="#d02e2a">
+            <g>
+                <path d="M 4.8 0 L 0 -1.8 L 0 1.8 Z" fill="currentColor" stroke="currentColor" stroke-width="1"/>
+            </g>
+        </marker>
+        <marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="FilledArrow_Marker_4" viewBox="-1 -3 7 6" markerWidth="7" markerHeight="6" color="#262626">
+            <g>
+                <path d="M 4.8 0 L 0 -1.8 L 0 1.8 Z" fill="currentColor" stroke="currentColor" stroke-width="1"/>
+            </g>
+        </marker>
+        <font-face font-family="Roboto" font-size="20" panose-1="2 0 0 0 0 0 0 0 0 0" units-per-em="1000" underline-position="-73.242188" underline-thickness="48.828125" slope="0" x-height="538.08594" cap-height="720.70312" ascent="927.7344" descent="-244.14062" font-weight="500">
+            <font-face-src>
+                <font-face-name name="Roboto-Regular"/>
+            </font-face-src>
+        </font-face>
+        <font-face font-family="Roboto Condensed" font-size="16" panose-1="0 0 4 6 0 0 0 0 0 0" units-per-em="1000" underline-position="-73.242188" underline-thickness="48.828125" slope="0" x-height="538.08594" cap-height="720.70312" ascent="927.7344" descent="-244.14062" font-weight="300" font-stretch="condensed">
+            <font-face-src>
+                <font-face-name name="RobotoCondensed-Light"/>
+            </font-face-src>
+        </font-face>
+        <marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="FilledArrow_Marker_5" viewBox="-1 -3 7 6" markerWidth="7" markerHeight="6" color="#126f33">
+            <g>
+                <path d="M 4.8 0 L 0 -1.8 L 0 1.8 Z" fill="currentColor" stroke="currentColor" stroke-width="1"/>
+            </g>
+        </marker>
+    </defs>
+    <g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1">
+        <title>MediaCodec state diagram</title>
+        <g>
+            <line x1="740" y1="120" x2="740" y2="82.9" marker-end="url(#FilledArrow_Marker)" stroke="#ea8008" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <line x1="740" y1="210" x2="740" y2="172.9" marker-end="url(#FilledArrow_Marker_2)" stroke="#274ecc" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <line x1="763.33333" y1="70" x2="763.33333" y2="107.1" marker-end="url(#FilledArrow_Marker_2)" stroke="#274ecc" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <line x1="920" y1="153.5" x2="822.9" y2="153.35288" marker-end="url(#FilledArrow_Marker_2)" stroke="#274ecc" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <line x1="920" y1="229" x2="822.89947" y2="229.88273" marker-end="url(#FilledArrow_Marker_3)" stroke="#d02e2a" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <line x1="919.5" y1="140" x2="822.9" y2="140" marker-end="url(#FilledArrow_Marker)" stroke="#ea8008" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <line x1="827.11573" y1="286.33365" x2="843.6129" y2="313.47642" marker-end="url(#FilledArrow_Marker_4)" stroke="#262626" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <line x1="922.88427" y1="286.33365" x2="904.22416" y2="313.82635" marker-end="url(#FilledArrow_Marker_4)" stroke="#262626" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <path d="M 927.5 11.5 L 1092.5 11.5 C 1095.8137 11.5 1098.5 14.1862915 1098.5 17.5 L 1098.5 282.5 C 1098.5 285.8137 1095.8137 288.5 1092.5 288.5 L 927.5 288.5 C 924.1863 288.5 921.5 285.8137 921.5 282.5 L 921.5 17.5 C 921.5 14.1862915 924.1863 11.5 927.5 11.5 Z" fill="#178f46"/>
+            <path d="M 927.5 11.5 L 1092.5 11.5 C 1095.8137 11.5 1098.5 14.1862915 1098.5 17.5 L 1098.5 282.5 C 1098.5 285.8137 1095.8137 288.5 1092.5 288.5 L 927.5 288.5 C 924.1863 288.5 921.5 285.8137 921.5 282.5 L 921.5 17.5 C 921.5 14.1862915 924.1863 11.5 927.5 11.5 Z" stroke="#178f46" stroke-linecap="round" stroke-linejoin="round" stroke-width="3"/>
+            <text transform="translate(926.5 260)" fill="#aadbc2">
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#aadbc2" x="40.091797" y="19" textLength="21.279297">Ex</tspan>
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#aadbc2" x="61.17578" y="19" textLength="65.73242">ecuting</tspan>
+            </text>
+            <path d="M 657.5 11.5 L 822.5 11.5 C 825.8137 11.5 828.5 14.1862915 828.5 17.5 L 828.5 282.5 C 828.5 285.8137 825.8137 288.5 822.5 288.5 L 657.5 288.5 C 654.1863 288.5 651.5 285.8137 651.5 282.5 L 651.5 17.5 C 651.5 14.1862915 654.1863 11.5 657.5 11.5 Z" stroke="#d02e2a" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <text transform="translate(656.5 260)" fill="#d02e2a">
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#d02e2a" x="46.53711" y="19" textLength="18.398438">St</tspan>
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#d02e2a" x="64.740234" y="19" textLength="55.722656">opped</tspan>
+            </text>
+            <text transform="translate(1130.1743 91)" fill="#262626">
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#262626" x=".64453125" y="15" textLength="30.710938">flush</tspan>
+            </text>
+            <text transform="translate(968 78.5)" fill="#262626">
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#262626" x=".859375" y="15" textLength="122.78125">dequeueInputBuffer</tspan>
+            </text>
+            <text transform="translate(846.272 20.5)" fill="#126f33">
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#126f33" x="14.255245" y="15" textLength="24.148438">star</tspan>
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#126f33" x="38.794307" y="15" textLength="4.640625">t</tspan>
+            </text>
+            <text transform="translate(848.3963 116.5)" fill="#eb8007">
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#eb8007" x="11.621094" y="15" textLength="11.78125">st</tspan>
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#eb8007" x="23.246094" y="15" textLength="15.6328125">op</tspan>
+            </text>
+            <text transform="translate(858.68587 232.88521)" fill="#b6251f">
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#b6251f" x=".21875" y="15" textLength="16.992188">err</tspan>
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#b6251f" x="17.054688" y="15" textLength="12.6875">or</tspan>
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#b6251f" x="28.78125" y="15" textLength="9">…</tspan>
+            </text>
+            <text transform="translate(857.8257 157.930055)" fill="#274ecd">
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#274ecd" x=".4453125" y="15" textLength="4.8359375">r</tspan>
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#274ecd" x="5.1328125" y="15" textLength="26.421875">eset</tspan>
+            </text>
+            <text transform="translate(768.33333 78.12302)" fill="#274ecd">
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#274ecd" x=".4453125" y="15" textLength="4.8359375">r</tspan>
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#274ecd" x="5.1328125" y="15" textLength="26.421875">eset</tspan>
+            </text>
+            <text transform="translate(744 182.62)" fill="#274ecd">
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#274ecd" x=".4453125" y="15" textLength="4.8359375">r</tspan>
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#274ecd" x="5.1328125" y="15" textLength="26.421875">eset</tspan>
+            </text>
+            <text transform="translate(675 91)" fill="#eb8007">
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#eb8007" x="2.8125" y="15" textLength="30.382812">confi</tspan>
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#eb8007" x="33.195312" y="15" textLength="20.320312">gur</tspan>
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#eb8007" x="53.367187" y="15" textLength="7.3203125">e</tspan>
+            </text>
+            <path d="M 676 30 L 804 30 C 807.3137 30 810 32.686292 810 36 L 810 64 C 810 67.31371 807.3137 70 804 70 L 676 70 C 672.6863 70 670 67.31371 670 64 L 670 36 C 670 32.686292 672.6863 30 676 30 Z" fill="#f0a608"/>
+            <text transform="translate(675 38)" fill="#fbe4a3">
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#fbe4a3" x="16.381836" y="19" textLength="46.533203">Confi</tspan>
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#fbe4a3" x="62.91504" y="19" textLength="29.013672">gur</tspan>
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#fbe4a3" x="91.743164" y="19" textLength="21.875">ed</tspan>
+            </text>
+            <path d="M 946 120 L 1074 120 C 1077.3137 120 1080 122.68629 1080 126 L 1080 154 C 1080 157.31371 1077.3137 160 1074 160 L 946 160 C 942.6863 160 940 157.31371 940 154 L 940 126 C 940 122.68629 942.6863 120 946 120 Z" fill="#f8f8f8"/>
+            <path d="M 946 120 L 1074 120 C 1077.3137 120 1080 122.68629 1080 126 L 1080 154 C 1080 157.31371 1077.3137 160 1074 160 L 946 160 C 942.6863 160 940 157.31371 940 154 L 940 126 C 940 122.68629 942.6863 120 946 120 Z" stroke="#49b077" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <text transform="translate(945 128)" fill="#178f46">
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#178f46" x="28.740234" y="19" textLength="72.51953">Running</tspan>
+            </text>
+            <path d="M 676 120 L 804 120 C 807.3137 120 810 122.68629 810 126 L 810 154 C 810 157.31371 807.3137 160 804 160 L 676 160 C 672.6863 160 670 157.31371 670 154 L 670 126 C 670 122.68629 672.6863 120 676 120 Z" fill="#346df1"/>
+            <text transform="translate(675 128)" fill="#bad0fb">
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#bad0fb" x="10.825195" y="19" textLength="86.63086">Uninitializ</tspan>
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#bad0fb" x="97.299805" y="19" textLength="21.875">ed</tspan>
+            </text>
+            <path d="M 676 210 L 804 210 C 807.3137 210 810 212.68629 810 216 L 810 244 C 810 247.31371 807.3137 250 804 250 L 676 250 C 672.6863 250 670 247.31371 670 244 L 670 216 C 670 212.68629 672.6863 210 676 210 Z" fill="#d02e2a"/>
+            <text transform="translate(675 218)" fill="white">
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="white" x="43.55957" y="19" textLength="24.902344">Err</tspan>
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="white" x="68.2666" y="19" textLength="18.173828">or</tspan>
+            </text>
+            <path d="M 946 30 L 1074 30 C 1077.3137 30 1080 32.686292 1080 36 L 1080 64 C 1080 67.31371 1077.3137 70 1074 70 L 946 70 C 942.6863 70 940 67.31371 940 64 L 940 36 C 940 32.686292 942.6863 30 946 30 Z" fill="#f8f8f8"/>
+            <path d="M 946 30 L 1074 30 C 1077.3137 30 1080 32.686292 1080 36 L 1080 64 C 1080 67.31371 1077.3137 70 1074 70 L 946 70 C 942.6863 70 940 67.31371 940 64 L 940 36 C 940 32.686292 942.6863 30 946 30 Z" stroke="#de6560" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <text transform="translate(945 38)" fill="#178f46">
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#178f46" x="29.93164" y="19" textLength="70.13672">Flushed</tspan>
+            </text>
+            <path d="M 946 210 L 1074 210 C 1077.3137 210 1080 212.68629 1080 216 L 1080 244 C 1080 247.31371 1077.3137 250 1074 250 L 946 250 C 942.6863 250 940 247.31371 940 244 L 940 216 C 940 212.68629 942.6863 210 946 210 Z" fill="#f8f8f8"/>
+            <path d="M 946 210 L 1074 210 C 1077.3137 210 1080 212.68629 1080 216 L 1080 244 C 1080 247.31371 1077.3137 250 1074 250 L 946 250 C 942.6863 250 940 247.31371 940 244 L 940 216 C 940 212.68629 942.6863 210 946 210 Z" stroke="#f4c23d" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <text transform="translate(945 218)" fill="#178f46">
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#178f46" x="2.0410156" y="19" textLength="87.09961">End of Str</tspan>
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#178f46" x="88.95508" y="19" textLength="39.003906">eam</tspan>
+            </text>
+            <line x1="810" y1="50" x2="927.1" y2="50" marker-end="url(#FilledArrow_Marker_5)" stroke="#126f33" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <line x1="963.33333" y1="70" x2="963.33333" y2="107.1" marker-end="url(#FilledArrow_Marker_4)" stroke="#262626" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <line x1="963.33333" y1="160" x2="963.33333" y2="197.1" marker-end="url(#FilledArrow_Marker_4)" stroke="#262626" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <path d="M 1080 133.33333 C 1080 133.33333 1106 115.83135 1106 96 C 1106 84.961065 1097.9439 76.089842 1090.80046 70.39346" marker-end="url(#FilledArrow_Marker_4)" stroke="#262626" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <path d="M 1056.66667 210 C 1056.66667 210 1110.38955 160.3288 1117 115 C 1121.4143 84.73063 1103.434 65.902535 1090.9997 56.733113" marker-end="url(#FilledArrow_Marker_4)" stroke="#262626" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+            <text transform="translate(968.25 162)" fill="#262626">
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#262626" x="2.171875" y="15" textLength="111.25">queueInputBuffer</tspan>
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#262626" x="38.46875" y="34" textLength="35.0625">(EOS)</tspan>
+            </text>
+            <path d="M 809.6463 324.5 L 937.6463 324.5 C 940.96 324.5 943.6463 327.1863 943.6463 330.5 L 943.6463 358.5 C 943.6463 361.8137 940.96 364.5 937.6463 364.5 L 809.6463 364.5 C 806.3326 364.5 803.6463 361.8137 803.6463 358.5 L 803.6463 330.5 C 803.6463 327.1863 806.3326 324.5 809.6463 324.5 Z" fill="#535353"/>
+            <text transform="translate(808.6463 332.5)" fill="#d5d5d5">
+                <tspan font-family="Roboto" font-size="20" font-weight="500" fill="#d5d5d5" x="24.28711" y="19" textLength="81.42578">Released</tspan>
+            </text>
+            <text transform="translate(852.18587 294.5)" fill="#262626">
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#262626" x=".15625" y="15" textLength="4.8359375">r</tspan>
+                <tspan font-family="Roboto Condensed" font-size="16" font-weight="300" font-stretch="condensed" fill="#262626" x="4.84375" y="15" textLength="40">elease</tspan>
+            </text>
+        </g>
+    </g>
+</svg>
diff --git a/docs/html/preview/api-overview.jd b/docs/html/preview/api-overview.jd
index 5ab4b89..d1639aa 100644
--- a/docs/html/preview/api-overview.jd
+++ b/docs/html/preview/api-overview.jd
@@ -14,8 +14,7 @@
         <span class="less" style="display:none">show less</span></a></h2>
 
 <ol id="toc44" class="hide-nested">
-  <li><a href="#backup">Auto Backup for Apps</a></li>
-  <li><a href="#notifications">Notifications</a></li>
+  <li><a href="#backup">Automatic App Data Backup</a></li>
   <li><a href="#authentication">Authentication</a>
     <ul>
       <li><a href="#fingerprint-authentication">Fingerprint Authentication</a></li>
@@ -24,14 +23,27 @@
   </li>
   <li><a href="#direct-share">Direct Share</a></li>
   <li><a href="#voice-interactions">Voice Interactions</a></li>
+  <li><a href="#assist">Assist API</a></li>
+  <li><a href="#notifications">Notifications</a></li>
   <li><a href="#bluetooth-stylus">Bluetooth Stylus Support</a></li>
-  <li><a href="#audio">New Audio Features</a></li>
-  <li><a href="#afw">New Android for Work Features</a></li>
+  <li><a href="#ble-scanning">Improved Bluetooth Low Energy Scanning</a></li>
+  <li><a href="#hotspot">Hotspot 2.0 Release 1 Support</a></li>
+  <li><a href="#4K-display">4K Display Mode</a></li>
+  <li><a href="#behavior-themeable-colorstatelists">Themeable ColorStateLists</a></li>
+  <li><a href="#audio">Audio Features</a></li>
+  <li><a href="#video">Video Features</a></li>
+  <li><a href="#camera">Camera Features</a>
+    <ul>
+      <li><a href="#flashlight">Flashlight API</a></li>
+      <li><a href="#reprocessing">Camera Reprocessing</a></li>
+    </ul>
+  </li>
+  <li><a href="#afw">Android for Work Features</a></li>
 </ol>
 
 <h2>API Differences</h2>
 <ol>
-<li><a href="">API level 22 to M &raquo;</a> </li>
+<li><a href="{@docRoot}preview/download.html">API level 22 to M Preview &raquo;</a> </li>
 </ol>
 
 </div>
@@ -55,40 +67,24 @@
 href="{@docRoot}">developer.android.com</a>. These API elements are
 formatted in {@code code style} in this document (without hyperlinks). For the
 preliminary API documentation for these elements, download the <a
-href="http://storage.googleapis.com/androiddevelopers/preview/m-developer-preview-reference.zip">
-preview reference</a>.</p>
+href="{@docRoot}preview/download.html#docs"> preview reference</a>.</p>
 
 <h3>Important behavior changes</h3>
 
 <p>If you have previously published an app for Android, be aware that your app might be affected
-by changes in M.</p>
+by changes in the platform.</p>
 
-<p>Please see <a href="api-changes.html">Behavior Changes</a> for complete information.</p>
+<p>Please see <a href="behavior-changes.html">Behavior Changes</a> for complete information.</p>
 
-<h2 id="backup">Auto Backup for Apps</h2>
+<h2 id="backup">Automatic App Data Backup</h2>
 <p>The system now performs automatic full data backup and restore for apps. This behavior is
-enabled by default for apps targeting M; you do not need to add any additional code. If users
-delete their Google account, their backup data is deleted as well.</p>
-<p>To learn how this feature works and how to configure what to back up on the file system,
-see the <a href="">App Backup for Apps guide</a>.</p>
-
-<h2 id="notifications">Notifications</h2>
-<p>M adds the following API changes for notifications:</p>
-<ul>
-  <li>New {@code NotificationListenerService.INTERRUPTION_FILTER_ALARMS} filter level that
-    corresponds to the new <em>Alarms only</em> do not disturb mode.</li>
-  <li>New {@code Notification.CATEGORY_REMINDER} category value that is used to distinguish
-  user-scheduled reminders from other events
-  ({@link android.app.Notification#CATEGORY_EVENT}) and alarms
-  ({@link android.app.Notification#CATEGORY_ALARM}).</li>
-  <li>New {@code android.graphics.drawable.Icon} class which can be attached to your notifications
-    via the Notification.Builder.setIcon() and Notification.Builder.setLargeIcon() methods.</li>
-  <li>New {@code NotificationManager.getActiveNotifications()} method that allows your apps to
-    find out which of their notifications are currently alive.</li>
-</ul>
+enabled by default for apps targeting M Preview; you do not need to add any additional code. If
+users delete their Google accounts, their backup data is deleted as well. To learn how this feature
+works and how to configure what to back up on the file system, see
+<a href="{@docRoot}preview/backup/index.html">Automatic App Data Backup</a>.</p>
 
 <h2 id="authentication">Authentication</h2>
-<p>The M release offers new APIs to let you authenticate users by using their fingerprint scans on
+<p>This preview offers new APIs to let you authenticate users by using their fingerprint scans on
 supported devices, and check how recently the user was last authenticated using a device unlocking
 mechanism (such as a lockscreen password). Use these APIs in conjunction with
 the <a href="{@docRoot}training/articles/keystore.html">Android Keystore system</a>.</p>
@@ -97,17 +93,15 @@
 
 <p>To authenticate users via fingerprint scan, get an instance of the new
 {@code android.hardware.fingerprint.FingerprintManager} class and call the
-{@code FingerprintManager.authenticate()} method. Your app must be running on a device with a
-fingerprint sensor. You must implement the user interface for the fingerprint
-authentication flow on your app, and use the standard fingerprint Android icon in your UI.
-If you are developing multiple apps that use fingerprint authentication, note that each app must
-authenticate the user’s fingerprint independently.
+{@code FingerprintManager.authenticate()} method. Your app must be running on a compatible
+device with a fingerprint sensor. You must implement the user interface for the fingerprint
+authentication flow on your app, and use the standard Android fingerprint icon in your UI.
+The Android fingerprint icon ({@code c_fp_40px.png}) is included in the
+<a href="https://github.com/googlesamples/android-FingerprintDialog"
+class="external-link">sample app</a>. If you are developing multiple apps that use fingerprint
+authentication, note that each app must authenticate the user’s fingerprint independently.
 </p>
 
-<img src="{@docRoot}preview/images/fingerprint-screen_2x.png"
-srcset="{@docRoot}preview/images/fingerprint-screen.png 1x, preview/images/fingerprint-screen_2x.png 2x"
-style="margin:0 0 10px 20px" width="282" height="476" />
-
 <p>To use this feature in your app, first add the {@code USE_FINGERPRINT} permission in your
 manifest.</p>
 
@@ -116,34 +110,34 @@
         android:name="android.permission.USE_FINGERPRINT" /&gt;
 </pre>
 
-<p>The following snippet shows how you might listen for fingerprint events in your
-{@code FingerprintManager.AuthenticationCallback} implementation.</p>
+<img src="{@docRoot}preview/images/fingerprint-screen.png"
+srcset="{@docRoot}preview/images/fingerprint-screen.png 1x, {@docRoot}preview/images/fingerprint-screen_2x.png 2x"
+style="float:right; margin:0 0 10px 20px" width="282" height="476" />
 
-<pre>
-// Call this to start listening for fingerprint events
-public void startListening(FingerprintManager.CryptoObject cryptoObject) {
-    if (!isFingerprintAuthAvailable()) {
-        return;
-    }
-    mCancellationSignal = new CancellationSignal();
-    mSelfCancelled = false;
-    mFingerprintManager.authenticate(cryptoObject,
-            mCancellationSignal, this, 0 /* flags */);
-    // Icon to display when prompting users to start a fingerprint scan
-    mIcon.setImageResource(R.drawable.ic_fp_40px);
-}
+<p>To see an app implementation of fingerprint authentication, refer to the
+<a href="https://github.com/googlesamples/android-FingerprintDialog" class="external-link">
+  Fingerprint Dialog sample</a>.</p>
 
-// Helper method to check if the device supports fingerprint
-// scanning and if the user has enrolled at least one fingerprint.
-public boolean isFingerprintAuthAvailable() {
-    return mFingerprintManager.isHardwareDetected()
-        &amp;&amp; mFingerprintManager.hasEnrolledFingerprints();
-}
+<p>If you are testing this feature, follow these steps:</p>
+<ol>
+<li>Enroll a new fingerprint in the emulator by going to
+<strong>Settings > Security > Fingerprint</strong>, then follow the enrollment instructions.</li>
+<li>Install Android SDK Tools Revision 24.3, if you have not done so.</li>
+<li>Use an emulator to emulate fingerprint touch events with the
+following command. Use the same command to emulate fingerprint touch events on the lockscreen or
+in your app.
+<pre class="no-prettyprint">
+adb -e emu finger touch &lt;finger_id&gt;
 </pre>
+<p>On Windows, you may have to run {@code telnet 127.0.0.1 &lt;emulator-id&gt;} followed by
+  {@code finger touch &lt;finger_id&gt;}.
+</p>
+</li>
+</ol>
 
 <h3 id="confirm-credentials">Confirm Credentials</h3>
 <p>Your app can authenticate users based on how recently they last unlocked their device. You can
-use the same public or secret key to authenticate users into multiple apps. This feature frees
+use the same public or secret key to authenticate users. This feature frees
 users from having to remember additional app-specific passwords, and avoids the need for you to
 implement your own authentication user interface.</p>
 
@@ -152,46 +146,14 @@
 {@code android.security.KeyPairGeneratorSpec.Builder} and
 {@code android.security.KeyGeneratorSpec.Builder} classes for public key pairs and secret keys
 respectively. If you are importing keys, use the {@link android.security.KeyStoreParameter.Builder}
-class to set your constraints.</p>
+class to set your constraints. You can use the
+{@link android.app.KeyguardManager#createConfirmDeviceCredentialIntent(java.lang.CharSequence, java.lang.CharSequence) createConfirmDeviceCredentialIntent()}
+method to re-authenticate the user within your app if the timeout expired.
+</p>
 
-<p>The following example shows how you might create a symmetric key in the Keystore which can only be
-used if the user has successfully unlocked the device within the last 5 minutes.</p>
-
-<pre>
-private void createKey() {
-    // Generate a key to decrypt payment credentials, tokens, etc.
-    // This will most likely be a registration step for the user when
-    // they are setting up your app.
-    try {
-        KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
-        ks.load(null);
-        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES",
-                "AndroidKeyStore");
-        keyGenerator.init(new KeyGeneratorSpec.Builder(this)
-                // Alias of the entry in Android KeyStore where the key will appear
-                .setAlias(KEY_NAME)
-                // Key use constraints
-                .setPurposes(KeyStoreKeyProperties.Purpose.ENCRYPT
-                    | KeyStoreKeyProperties.Purpose.DECRYPT)
-                .setBlockModes("CBC")
-                .setUserAuthenticationRequired(true)
-                // Require that the user has unlocked in the last 5 minutes
-                .setUserAuthenticationValidityDurationSeconds(5 * 60)
-                .setEncryptionPaddings("PKCS7Padding")
-                .build());
-        keyGenerator.generateKey();
-    } catch (NoSuchAlgorithmException | NoSuchProviderException
-            | InvalidAlgorithmParameterException | KeyStoreException
-            | CertificateException | IOException e) {
-          throw new RuntimeException(e);
-    }
-}
-</pre>
-
-<p>To determine the last time users logged into their account, call the
-{@code android.accounts.AccountManager.confirmCredentials()} method. If the call is successful, the
-method returns an bundle that includes a {@code KEY_LAST_AUTHENTICATED_TIME} value which indicates
-the last time, in milliseconds, that the credential for that account was validated or created.</p>
+<p>To see an app implementation of this feature, refer to the
+<a href="https://github.com/googlesamples/android-ConfirmDeviceCredentials" class="external-link">
+  Confirm Device Credentials sample</a>.</p>
 
 <h2 id="direct-share">Direct Share</h2>
 
@@ -199,7 +161,7 @@
 srcset="{@docRoot}preview/images/direct-share-screen.png 1x, preview/images/direct-share-screen_2x.png 2x"
 style="float:right; margin:0 0 20px 30px" width="312" height="385" />
 
-<p>This release provides you with APIs to makes sharing intuitive and quick for users. You can now
+<p>This preview provides you with APIs to makes sharing intuitive and quick for users. You can now
 define <em>deep links</em> that target a specific activity in your app. These deep links are
 exposed to users via the <em>Share</em> menu. This feature allows users to share content to
 targets, such as contacts, within other apps. For example, the deep link might launch an
@@ -214,9 +176,6 @@
 {@code SERVICE_INTERFACE} action.</p>
 <p>The following example shows how you might declare the {@code ChooserTargetService} in your
 manifest.</p>
-<br>
-<br>
-<br>
 <pre>
 &lt;service android:name=".ChooserTargetService"
         android:label="&#64;string/service_name"
@@ -243,37 +202,142 @@
         android:value=".ChooserTargetService" /&gt;
 &lt;/activity>
 </pre>
+<p>To see an app implementation of this feature, refer to the
+<a href="https://github.com/googlesamples/android-DeepLinkSharing" class="external-link">
+  Deep Link Sharing sample</a>.</p>
+
 
 <h2 id="voice-interactions">Voice Interactions</h2>
 <p>
-This release provides a new voice interaction API which, together with
+This preview provides a new voice interaction API which, together with
 <a href="https://developers.google.com/voice-actions/" class="external-link">Voice Actions</a>,
 allows you to build conversational voice experiences into your apps. Call the
 {@code android.app.Activity.isVoiceInteraction()} method to determine if your activity was
 started in response to a voice action. If so, your app can use the
 {@code android.app.VoiceInteractor} class to request a voice confirmation from the user, select
-from a list of options, and more.</p>
-<p>To learn more about implementing voice actions, see the voice interaction API
+from a list of options, and more. To learn more about implementing voice actions, see the
 <a href="https://developers.google.com/voice-actions/interaction/"
-class="external-link">guide</a>.
+class="external-link">Voice Actions developer site</a>.
 </p>
 
+<h2 id="assist">Assist API</h2>
+<p>
+This preview offers a new way for users to engage with your apps through an assistant. To use this
+feature, the user must enable the assistant to use the current context. Once enabled, the user
+can summon the assistant within any app, by long-pressing on the <strong>Home</strong> button.</p>
+<p>The platform passes the current context to the assistant. In addition to the standard set of
+information that the platform passes to the assistant, your app can share additional information
+by using the new {@code android.app.Activity.AssistContent} class.</p>
+
+<p>To provide the assistant with additional context from your app, follow these steps:</p>
+
+<ol>
+<li>Implement the {@link android.app.Application.OnProvideAssistDataListener} interface.</li>
+<li>Register this listener by using
+{@link android.app.Application#registerOnProvideAssistDataListener(android.app.Application.OnProvideAssistDataListener) registerOnProvideAssistDataListener()}.</li>
+<li>In order to provide activity-specific contextual information, override the
+{@link android.app.Activity#onProvideAssistData(android.os.Bundle) onProvideAssistData()}
+callback and, optionally, the new {@code Activity.onProvideAssistContent()} callback.
+</ol>
+
+<h2 id="notifications">Notifications</h2>
+<p>This preview adds the following API changes for notifications:</p>
+<ul>
+  <li>New {@code NotificationListenerService.INTERRUPTION_FILTER_ALARMS} filter level that
+    corresponds to the new <em>Alarms only</em> do not disturb mode.</li>
+  <li>New {@code Notification.CATEGORY_REMINDER} category value that is used to distinguish
+  user-scheduled reminders from other events
+  ({@link android.app.Notification#CATEGORY_EVENT}) and alarms
+  ({@link android.app.Notification#CATEGORY_ALARM}).</li>
+  <li>New {@code android.graphics.drawable.Icon} class which can be attached to your notifications
+    via the {@code Notification.Builder.setSmallIcon(Icon)} and
+    {@code Notification.Builder.setLargeIcon(Icon)} methods.</li>
+  <li>New {@code NotificationManager.getActiveNotifications()} method that allows your apps to
+    find out which of their notifications are currently alive. To see an app implementation that
+    uses this feature, see the <a href="https://github.com/googlesamples/android-ActiveNotifications"
+    class="external-link">Active Notifications sample</a>.</li>
+</ul>
+
 <h2 id="bluetooth-stylus">Bluetooth Stylus Support</h2>
-<p>The M release provides improved support for user input using a Bluetooth stylus. If the user
-touches a stylus with a button on the screen of your app, the
-{@link android.view.MotionEvent#getToolType(int) getTooltype()} method now returns
-{@code TOOL_TYPE_STYLUS}. The {@link android.view.MotionEvent#getButtonState() getButtonState()}
-method returns {@link android.view.MotionEvent#BUTTON_SECONDARY} when the user
+<p>This preview provides improved support for user input using a Bluetooth stylus. Users can pair
+and connect a compatible Bluetooth stylus with their phone or tablet.  While connected, position
+information from the touch screen is fused with pressure and button information from the stylus to
+provide a greater range of expression than with the touch screen alone. Your app can listen for
+stylus button presses and perform secondary actions, by registering the new
+{@code View.onStylusButtonPressListener} and {@code GestureDetector.OnStylusButtonPressListener}
+callbacks in your activity.</p>
+
+<p>Use the {@link android.view.MotionEvent} methods and constants to detect stylus button
+interactions:</p>
+<ul>
+<li>If the user touches a stylus with a button on the screen of your app, the
+{@link android.view.MotionEvent#getToolType(int) getTooltype()} method returns
+{@link android.view.MotionEvent#TOOL_TYPE_STYLUS}.</li>
+<li>For apps targeting M Preview, the
+{@link android.view.MotionEvent#getButtonState() getButtonState()}
+method returns {@code MotionEvent.STYLUS_BUTTON_PRIMARY} when the user
 presses the primary stylus button. If the stylus has a second button, the same method returns
-{@link android.view.MotionEvent#BUTTON_TERTIARY} when the user presses it. If the user presses
-both buttons simultaneously, the method returns both these values. In addition, the system reports
-the user button-press action to the new {@code View.onStylusButtonPressListener} and
-{@code GestureDetector.OnStylusButtonPressListener} callbacks in your activity, if you have
-registered these listeners in your app.</p>
+{@code MotionEvent.STYLUS_BUTTON_SECONDARY} when the user presses it. If the user presses
+both buttons simultaneously, the method returns both values OR'ed together
+({@code STYLUS_BUTTON_PRIMARY|STYLUS_BUTTON_SECONDARY}).</li>
+<li>
+For apps targeting a lower platform version, the
+{@link android.view.MotionEvent#getButtonState() getButtonState()} method returns
+{@link android.view.MotionEvent#BUTTON_SECONDARY} (for primary stylus button press),
+{@link android.view.MotionEvent#BUTTON_TERTIARY} (for secondary stylus button press), or both.
+</li>
+</ul>
 
-<h2 id="audio">New Audio Features</h2>
+<h2 id="ble-scanning">Improved Bluetooth Low Energy Scanning</h2>
+<p>
+If your app performs performs Bluetooth Low Energy scans, you can use the new
+{@code android.bluetooth.le.ScanSettings.Builder.setCallbackType()} method to specify that
+you want callbacks to only be notified when an advertisement packet matching the set
+{@link android.bluetooth.le.ScanFilter} is first found, and when it is not seen for a period of
+time. This approach to scanning is more power-efficient than what’s provided in the previous
+platform version.
+</p>
 
-<p>This release adds enhancements to audio processing on Android, including: </p>
+<h2 id="hotspot">Hotspot 2.0 Release 1 Support</h2>
+<p>
+This preview adds support for the Hotspot 2.0 Release 1 spec on Nexus 6 and Nexus 9 devices. To
+provision Hotspot 2.0 credentials in your app, use the new methods of the
+{@link android.net.wifi.WifiEnterpriseConfig} class, such as {@code setPlmn()} and
+{@code setRealm()}. In the {@link android.net.wifi.WifiConfiguration} object, you can set the
+{@link android.net.wifi.WifiConfiguration#FQDN} and the {@code providerFriendlyName} fields.
+The new {@code ScanResult.PasspointNetwork} property indicates if a detected
+network represents a Hotspot 2.0 access point.
+</p>
+
+<h2 id="4K-display">4K Display Mode</h2>
+<p>The platform now allows apps to request that the display resolution be upgraded to 4K rendering
+on compatible hardware. To query the current physical resolution, use the new
+{@code android.view.Display.Mode} APIs. If the UI is drawn at a lower logical resolution and is
+upscaled to a larger physical resolution, be aware that the physical resolution the
+{@code Display.Mode.getPhysicalWidth()} method returns may differ from the logical
+resolution reported by {@link android.view.Display#getSize(android.graphics.Point) getSize()}.</p>
+
+<p>You can request the system to change the physical resolution in your app as it runs, by setting
+the {@code WindowManager.LayoutParams.preferredDisplayModeId} property of your app’s window.  This
+feature is useful if you want to switch to 4K display resolution. While in 4K display mode, the
+UI continues to be rendered at the original resolution (such as 1080p) and is upscaled to 4K, but
+{@link android.view.SurfaceView} objects may show content at the native resolution.</p>
+
+<p>To test the new 4K display mode, simulate a secondary display of a larger resolution using the
+<strong>Developer Options</strong> settings.</p>
+
+<h2 id="behavior-themeable-colorstatelists">Themeable ColorStateLists</h2>
+<p>Theme attributes are now supported in
+{@link android.content.res.ColorStateList} for devices running the M Preview. The
+{@link android.content.res.Resources#getColorStateList(int) getColorStateList()} and
+{@link android.content.res.Resources#getColor(int) getColor()} methods have been deprecated. If
+you are calling these APIs, call the new {@code Context.getColorStateList()} or
+{@code Context.getColor()} methods instead. These methods are also available in the
+v4 appcompat library via {@link android.support.v4.content.ContextCompat}.</p>
+
+<h2 id="audio">Audio Features</h2>
+
+<p>This preview adds enhancements to audio processing on Android, including: </p>
 <ul>
   <li>Support for the <a href="http://en.wikipedia.org/wiki/MIDI" class="external-link">MIDI</a>
 protocol, with the new {@code android.media.midi} APIs. Use these APIs to send and receive MIDI
@@ -293,8 +357,78 @@
 when an audio device is connected or disconnected.</li>
 </ul>
 
-<h2 id="afw">New Android for Work Features</h2>
-<p>This release includes the following new APIs for Android for Work:</p>
+<h2 id="video">Video Features</h2>
+<p>This preview adds new capabilities to the video processing APIs, including:</p>
+<ul>
+<li>New {@code android.media.MediaSync} class which helps applications to synchronously render
+audio and video streams. The audio buffers are submitted in non-blocking fashion and are
+returned via a callback. It also supports dynamic playback rate.
+</li>
+<li>New {@code MediaDrm.EVENT_SESSION_RECLAIMED} event, which indicates that a session opened by
+the app has been reclaimed by the resource manager. If your app uses DRM sessions, you should
+handle this event and make sure not to use a reclaimed session.
+</li>
+<li>New {@code MediaCodec.CodecException.ERROR_RECLAIMED} error code, which indicates that the
+resource manager reclaimed the media resource used by the codec. With this exception, the codec
+must be released, as it has moved to terminal state.
+</li>
+<li>New {@code MediaCodecInfo.CodecCapabilities.getMaxSupportedInstances()} interface to get a
+hint for the max number of the supported concurrent codec instances.
+</li>
+<li>New {@code MediaPlayer.setPlaybackParams()} method to set the media playback rate for fast or
+slow motion playback. It also stretches or speeds up the audio playback automatically in
+conjunction with the video.</li>
+</ul>
+
+<h2 id="camera">Camera Features</h2>
+<p>This preview includes the following new APIs for accessing the camera’s flashlight and for
+camera reprocessing of images:</p>
+
+<h3 id="flashlight">Flashlight API</h3>
+<p>If a camera device has a flash unit, you can call the {@code CameraManager.setTorchMode()}
+method to switch the flash unit’s torch mode on or off without opening the camera device. The app
+does not have exclusive ownership of the flash unit or the camera device. The torch mode is turned
+off and becomes unavailable whenever the camera device becomes unavailable, or when other camera
+resources keeping the torch on become unavailable. Other apps can also call {@code setTorchMode()}
+to turn off the torch mode. When the last app that turned on the torch mode is closed, the torch
+mode is turned off.</p>
+
+<p>You can register a callback to be notified about torch mode status by calling the
+{@code CameraManager.registerTorchCallback()} method. The first time the callback is registered,
+it is immediately called with the torch mode status of all currently known camera devices with a
+flash unit. If the torch mode is turned on or off successfully, the
+{@code CameraManager.TorchCallback.onTorchModeChanged()} method is invoked.</p>
+
+<h3 id="reprocessing">Reprocessing API</h3>
+<p>The {@link android.hardware.camera2 Camera2} API is extended to support YUV and private
+opaque format image reprocessing. Your app determine if the reprocessing capabilities are available
+via {@code CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES}. If a device supports reprocessing,
+you can create a reprocessable camera capture session by calling
+{@code CameraDevice.createReprocessableCaptureSession()}, and create requests for input
+buffer reprocessing.</p>
+
+<p>Use the {@code ImageWriter} class to connect the input buffer flow to the camera reprocessing
+input. To get an empty buffer, follow this programming model:</p>
+
+<ol>
+<li>Call the {@code ImageWriter.dequeueInputImage()} method.</li>
+<li>Fill the data into the input buffer.</li>
+<li>Send the buffer to the  camera by calling the {@code ImageWriter.queueInputImage()} method.</li>
+</ol>
+
+<p>If you are using a {@code ImageWriter} object together with an
+{@code android.graphics.ImageFormat.PRIVATE} image, your app cannot access the image
+data directly. Instead, pass the {@code ImageFormat.PRIVATE} image directly to the
+{@code ImageWriter} by calling the {@code ImageWriter.queueInputImage()} method without any
+buffer copy.</p>
+
+<p>The {@code ImageReader} class now supports {@code android.graphics.ImageFormat.PRIVATE} format
+image streams. This support allows your app to maintain a circular image queue of
+{@code ImageReader} output images, select one or more images, and send them to the
+{@code ImageWriter} for camera reprocessing.</p>
+
+<h2 id="afw">Android for Work Features</h2>
+<p>This preview includes the following new APIs for Android for Work:</p>
 <ul>
   <li><strong>Enhanced controls for Corporate-Owned, Single-Use devices:</strong> The Device Owner
 can now control the following settings to improve management of
@@ -325,13 +459,13 @@
 <li><strong>Auto-acceptance of system updates.</strong> By setting a system update policy with
 {@code DevicePolicyManager.setSystemUpdatePolicy()}, a Device Owner can now auto-accept a system
 update, for instance in the case of a kiosk device, or postpone the update and prevent it being
-taken by the user for up to 30 days. Furthermore, an administrator can set a time window in which an
-update must be taken, for example during the hours when a kiosk device is not in use. When a
-system update is available, the system checks if the Work Policy Controller app has set a system
+taken by the user for up to 30 days. Furthermore, an administrator can set a daily time window in
+which an update must be taken, for example during the hours when a kiosk device is not in use. When
+a system update is available, the system checks if the Work Policy Controller app has set a system
 update policy, and behaves accordingly.
 </li>
 <li>
-<strong>Delegated certificate installation.</strong> A Profile or Device Owner can now grant a
+<strong>Delegated certificate installation:</strong> A Profile or Device Owner can now grant a
 third-party app the ability to call these {@link android.app.admin.DevicePolicyManager} certificate
 management APIs:
 <ul>
@@ -349,21 +483,49 @@
 installKeyPair()}</li>
 </ul>
 </li>
-<li><strong>Enterprise factory reset protection.</strong> When provisioning a Device Owner, you can
-now configure parameters for bypassing Factory Reset Protection (FRP), by setting the
+<li><strong>Enterprise factory reset protection:</strong> When provisioning a Device Owner, you can
+now configure parameters to unlock Factory Reset Protection (FRP) by setting the
 {@code DeviceManagerPolicy.EXTRA_PROVISIONING_RESET_PROTECTION_PARAMETERS} bundle. An NFC Programmer
-app can provide these parameters after a device has been reset to bypass FRP and provision the device,
+app can provide these parameters after a device has been reset to unlock FRP and provision the device,
 without requiring the previously configured Google account. If you don't modify these parameters,
 FRP remains in-place and prevents the device from being activated without the previously activated
-Google credentials.</li>
-<li><strong>Data usage tracking.</strong> A Profile or Device Owner can now query for the data
-usage statistics visible in <em>Settings > Data</em> usage by using the new
+Google credentials.
+<p>Additionally, by setting app restrictions on Google Play services, Device Owners can specify
+alternative Google accounts for unlocking FRP to replace the ones activated on the device.</p>
+</li>
+<li><strong>Data usage tracking.</strong> A Profile or Device Owner can now query for the
+data usage statistics visible in <strong>Settings > Data</strong> usage by using the new
 {@code android.app.usage.NetworkStatsManager} methods. Profile Owners are automatically granted
 permission to query data on the profile they manage, while Device Owners get access to usage data
 of the managed primary user.</li>
+<li><strong>Runtime permission management:</strong> With the new runtime permissions model, a
+Profile or Device Owner can now silently grant or revoke an app’s permissions by calling
+{@code DevicePolicyManager.setPermissionGranted()}. Granting or revoking a single permission applies
+that setting to all permissions within that runtime permission group; the user is not prompted
+at runtime when any permission from that runtime permission group is required. Furthermore, the
+user cannot modify the selection made by the Profile or Device Owner within the app’s permissions
+screen in <strong>Settings</strong>.
+<img src="{@docRoot}preview/images/work-profile-screen_2x.png"
+srcset="{@docRoot}preview/images/work-profile-screen.png 1x, preview/images/work-profile-screen_2x.png 2x"
+style="float:right; margin:0 0 10px 20px" width="282" height="476" />
+<p>A Profile or Device Owner can also set a permission policy
+for all runtime requests of all applications using
+{@code DevicePolicyManager.setPermissionPolicy()}, to either prompt the user to grant the
+permission as normal or automatically grant or deny the permission silently. If the latter policy
+is set, the user cannot modify the selection made by the Profile or Device Owner within the
+app’s permissions screen in <strong>Settings</strong>.</p></li>
+<li><strong>VPN in Settings:</strong> VPN apps are now visible in
+    <strong>Settings > More > VPN</strong>.
+Additionally, the notifications that accompany VPN usage are now specific to whether that VPN is
+configured for a managed profile or the entire device.</li>
+<li><strong>Work status notification:</strong> A status bar briefcase icon now appears whenever
+an app from the managed profile has an activity in the foreground. Furthermore, if the device is
+unlocked directly to the activity of an app in the managed profile, a toast is displayed notifying
+the user that they are within the work profile.
+</li>
 </ul>
 
 <p class="note">
   For a detailed view of all API changes in the M Developer Preview, see the <a href=
-  "{@docRoot}preview/reference.html">API Differences Report</a>.
+  "{@docRoot}preview/download.html">API Differences Report</a>.
 </p>
\ No newline at end of file
diff --git a/docs/html/preview/behavior-changes.jd b/docs/html/preview/behavior-changes.jd
new file mode 100644
index 0000000..0dd549b
--- /dev/null
+++ b/docs/html/preview/behavior-changes.jd
@@ -0,0 +1,407 @@
+page.title=Behavior Changes
+page.keywords=preview,sdk,compatibility
+sdk.platform.apiLevel=23
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document</h2>
+
+<ol id="toc44" class="hide-nested">
+    <li><a href="#behavior-runtime-permissions">Runtime Permissions</a></li>
+    <li><a href="#behavior-project-volta">Project Volta</a>
+        <ol>
+            <li><a href="#behavior-doze">Doze mode</a></li>
+            <li><a href="#behavior-app-standby">App Standby</a></li>
+        </ol>
+    </li>
+    <li><a href="#behavior-adoptable-storage">Adoptable Storage Devices</a></li>
+    <li><a href="#behavior-apache-http-client">Apache HTTP Client Removal</a></li>
+    <li><a href="#behavior-audiomanager-Changes">AudioManager Changes</a></li>
+    <li><a href="#behavior-test-selection">Text Selection</a></li>
+    <li><a href="#behavior-keystore">Android Keystore Changes</a></li>
+    <li><a href="#night-mode">Night Mode</a></li>
+    <li><a href="#behavior-network">Wi-Fi and Networking Changes</a></li>
+    <li><a href="#behavior-camera">Camera Service Changes</a></li>
+    <li><a href="#behavior-art-runtime">ART Runtime</a></li>
+    <li><a href="#behavior-apk-validation">APK Validation</a></li>
+    <li><a href="#behavior-afw">Android for Work Changes</a></li>
+</ol>
+
+<h2>API Differences</h2>
+<ol>
+<li><a href="{@docRoot}preview/download.html">API level 22 to M Preview &raquo;</a> </li>
+</ol>
+
+
+<h2>See Also</h2>
+<ol>
+<li><a href="{@docRoot}preview/api-overview.html">M Developer Preview API Overview</a> </li>
+</ol>
+
+</div>
+</div>
+
+<p>API Level: M</p>
+<p>Along with new features and capabilities, the M Developer Preview includes a variety of
+system changes and API behavior changes. This document highlights
+some of the key changes that you should be understand and account for in your apps.</p>
+
+<p>If you have previously published an app for Android, be aware that your app
+  might be affected by these changes in the platform.</p>
+
+<h2 id="behavior-runtime-permissions">Runtime Permissions</h1>
+<p>This preview introduces a new runtime permissions model, where users can now directly manage
+their app permissions at runtime. This model gives users improved visibility and control over
+permissions, while streamlining the installation and auto-update processes for app developers.
+Users can set permissions on or off for all apps running on the M Preview. However, apps that
+don’t target the M Preview cannot request permissions at runtime.</p>
+
+<p>On your apps that target the M Preview, make sure to check and request for permissions at
+runtime. To determine if your app has been granted a permission, call the
+new {@code Context.checkSelfPermission()} method. To request for a permission, call the new
+{@code Activity.requestPermission()} method.</p>
+
+<p>For more information on supporting the new permissions model in your app, see
+<a href="{@docRoot}preview/features/runtime-permissions.html">
+Android M Preview Runtime Permissions</a>.</p>
+
+<h2 id="behavior-project-volta">Project Volta</h2>
+<p>This preview introduces new power-saving optimizations for idle devices and apps.</p>
+
+<h3 id="behavior-doze">Doze mode</h3>
+<p>If a device is unplugged and left stationary with the screen off for a period of time, it
+goes into <em>Doze</em> mode where it attempts to keep the system in a sleep state. In this mode,
+devices periodically resume normal operations for brief periods of time so that app syncing can
+occur and the system can perform any pending operations.</p>
+
+<p>The following restrictions apply to your apps while in Doze mode:</p>
+<ul>
+<li>Network access is disabled, unless your app receives a high priority Google Cloud Messaging
+tickle.</li>
+<li><a href="{@docRoot}reference/android/os/PowerManager.WakeLock.html">Wake locks</a> are ignored.</li>
+<li>Alarms scheduled with the {@link android.app.AlarmManager} class are disabled, except for
+alarms that you've set with the {@link android.app.AlarmManager#setAlarmClock setAlarmClock()}
+method and {@code AlarmManager.setAndAllowWhileIdle()}.</li>
+<li>WiFi scans are not performed.</li>
+<li>Syncs and jobs for your sync adapters and {@link android.app.job.JobScheduler} are not
+permitted to run.</li>
+</ul>
+</p>
+<p>When the device exists doze mode, it executes any jobs and syncs that are pending.</p>
+<p>You can test this feature by connecting a device running the M Preview to your development
+machine and calling the following commands:
+</p>
+<pre class="no-prettyprint">
+$ adb shell dumpsys battery unplug
+$ adb shell dumpsys deviceidle step
+$ adb shell dumpsys deviceidle -h
+</pre>
+<p class="note"><strong>Note</strong>: The upcmoning
+<a href="{@docRoot}google/gcm/index.html">Google Cloud Messaging</a> release lets you designate
+high-priority messages. If your app receives high-priority GCM messages, it’s granted
+brief network access even when the device is in doze mode.
+</p>
+
+<h3 id="behavior-app-standby">App standby</h3>
+<p>With this preview, the system may determine that apps are idle when they are not in active
+use. Your app is considered idle after a period of time, unless the system detects
+any of these signals:</p>
+
+<ul>
+<li>The app has a process currently in the foreground (either as an activity or foreground service,
+or in use by another activity or foreground service).</li>
+<li>The app generates a notification that users see on the lock screen or in the
+notification tray.</li>
+<li>The user explicitly asks for the app to be exempt from optimizations,
+via <strong>Settings</strong>.</li>
+</ul>
+
+<p>If the device is unplugged, apps deemed idle will have their network access disabled
+and their syncs and jobs suspended. When the device is plugged into a power supply, these apps are
+allowed network access and can execute any jobs and syncs that are pending. If the
+device is idle for long periods of time, idle apps are allowed network access around once a day.</p>
+
+<p>You can test this feature by connecting a device running the M Preview to your development
+machine and calling the following commands:
+</p>
+<pre class="no-prettyprint">
+$ adb shell am broadcast -a android.os.action.DISCHARGING
+$ adb shell am set-idle &lt;packageName&gt; true
+$ adb shell am set-idle &lt;packageName&gt; false
+$ adb shell am get-idle &lt;packageName&gt;
+</pre>
+
+<p class="note"><strong>Note</strong>: The upcoming
+<a href="{@docRoot}google/gcm/index.html">Google Cloud Messaging</a> (GCM) release lets you
+designate high-priority messages. If your app receives high-priority GCM messages, it’s granted
+brief network access even when the app is idle.
+</p>
+
+<h2 id="behavior-adoptable-storage">Adoptable Storage Devices</h2>
+<p>
+With this preview, users can <em>adopt</em> external storage devices such as SD cards. Adopting an
+external storage device encrypts and formats the device to behave like internal storage. This
+feature allows users to move both apps and private data of those apps between storage devices. When
+moving apps, the system respects the
+<a href="{@docRoot}guide/topics/manifest/manifest-element.html#install">{@code android:installLocation}</a>
+preference in the manifest.</p>
+
+<p>If your app accesses the following APIs or fields, be aware that the file paths they return
+will dynamically change when the app is moved between internal and external storage devices.
+When building file paths, it is strongly recommended that you always call these APIs dynamically.
+Don’t use hardcoded file paths or persist fully-qualified file paths that were built previously.</p>
+
+<ul>
+<li>{@link android.content.Context} methods:
+    <ul>
+        <li>{@link android.content.Context#getFilesDir() getFilesDir()}</li>
+        <li>{@link android.content.Context#getCacheDir() getCacheDir()}</li>
+        <li>{@link android.content.Context#getCodeCacheDir() getCodeCacheDir()}</li>
+        <li>{@link android.content.Context#getDatabasePath(java.lang.String) getDatabasePath()}</li>
+        <li>{@link android.content.Context#getDir(java.lang.String,int) getDir()}</li>
+        <li>{@link android.content.Context#getNoBackupFilesDir() getNoBackupFilesDir()}</li>
+        <li>{@link android.content.Context#getFileStreamPath(java.lang.String) getFileStreamPath()}</li>
+        <li>{@link android.content.Context#getPackageCodePath() getPackageCodePath()}</li>
+        <li>{@link android.content.Context#getPackageResourcePath() getPackageResourcePath()}</li>
+    </ul>
+</li>
+<li>{@link android.content.pm.ApplicationInfo} fields:
+    <ul>
+        <li>{@link android.content.pm.ApplicationInfo#dataDir dataDir}</li>
+        <li>{@link android.content.pm.ApplicationInfo#sourceDir sourceDir}</li>
+        <li>{@link android.content.pm.ApplicationInfo#nativeLibraryDir nativeLibraryDir}</li>
+        <li>{@link android.content.pm.ApplicationInfo#publicSourceDir publicSourceDir}</li>
+        <li>{@link android.content.pm.ApplicationInfo#splitSourceDirs splitSourceDirs}</li>
+        <li>{@link android.content.pm.ApplicationInfo#splitPublicSourceDirs splitPublicSourceDirs}</li>
+    </ul>
+</li>
+</ul>
+
+<p>To debug this feature in the developer preview, you can enable adoption of a USB drive that is
+connected to an Android device through a USB On-The-Go (OTG) cable, by running this command:</p>
+
+<pre class="no-prettyprint">
+$ adb shell sm set-force-adoptable true
+</pre>
+
+<h2 id="behavior-apache-http-client">Apache HTTP Client Removal</h2>
+<p>This preview removes support for the Apache HTTP client. If your app is using this client and
+targets Android 2.3 (API level 9) or higher, use the {@link java.net.HttpURLConnection} class
+instead. This API is more efficient because it reduces network use through transparent compression
+and response caching, and minimizes power consumption. To continue using the Apache HTTP APIs, you
+must first declare the following compile-time dependency in your {@code build.gradle} file:
+</p>
+<pre>
+android {
+    useLibrary 'org.apache.http.legacy'
+}
+</pre>
+<p>Android is moving away from OpenSSL to the
+<a href="https://boringssl.googlesource.com/boringssl/" class="external-link">BoringSSL</a>
+library. If you’re using the Android NDK in your app, don't link against cryptographic libraries
+that are not a part of the NDK API, such as {@code libcrypto.so} and {@code libssl.so}. These
+libraries are not public APIs, and may change or break without notice across releases and devices.
+In addition, you may expose yourself to security vulnerabilities. Instead, modify your
+native code to call the Java cryptography APIs via JNI or to statically link against a
+cryptography library of your choice.</p>
+
+<h2 id="behavior-audiomanager-Changes">AudioManager Changes</h2>
+<p>Setting the volume directly or muting specific streams via the {@link android.media.AudioManager}
+class is no longer supported. The {@link android.media.AudioManager#setStreamSolo(int,boolean)
+setStreamSolo()} method is deprecated, and you should call the
+{@code AudioManager.requestAudioFocus()} method instead. Similarly, the
+{@link android.media.AudioManager#setStreamMute(int,boolean) setStreamMute()} method is
+deprecated; instead, call the {@code AudioManager.adjustStreamVolume()} method
+and pass in the direction value {@code ADJUST_MUTE} or {@code ADJUST_UNMUTE}.</p>
+
+<h2 id="behavior-test-selection">Text Selection</h2>
+
+<img src="{@docRoot}preview/images/text-selection.gif"
+style="float:right; margin:0 0 20px 30px" width="360" height="640" />
+
+<p>When users select text in your app, you can now display text selection actions such as
+<em>Cut</em>, <em>Copy</em>, and <em>Paste</em> in a
+<a href="http://www.google.com/design/spec/patterns/selection.html#selection-text-selection"
+class="external-link">floating toolbar</a>. The user interaction implementation is similar to that
+for the contextual action bar, as described in
+<a href="{@docRoot}guide/topics/ui/menus.html#CABforViews">
+Enabling the contextual action mode for individual views</a>.</p>
+
+<p>To implement a floating toolbar for text selection, make the following changes in your existing
+apps:</p>
+<ol>
+<li>In your {@link android.view.View} or {@link android.app.Activity} object, change your
+{@link android.view.ActionMode} calls from
+{@code startActionMode(Callback)} to {@code startActionMode(Callback, ActionMode.TYPE_FLOATING)}.</li>
+<li>Take your existing implementation of {@code ActionMode.Callback} and make it extend
+{@code ActionMode.Callback2} instead.</li>
+<li>Override the {@code Callback2.onGetContentRect()} method to provide the coordinates of the
+content {@link android.graphics.Rect} object (such as a text selection rectangle) in the view.</li>
+<li>If the rectangle positioning is no longer valid, and this is the only element to be invalidated,
+call the {@code ActionMode.invalidateContentRect()} method.</li>
+</ol>
+
+<p>If you are using <a href="{@docRoot}tools/support-library/index.html">
+Android Support Library</a> revision 22.2, be aware that floating toolbars are not
+backward-compatible and appcompat takes control over {@link android.view.ActionMode} objects by
+default. This prevents floating toolbars from being displayed. To enable
+{@link android.view.ActionMode} support in an
+{@link android.support.v7.app.AppCompatActivity}, call
+{@code android.support.v7.app.AppCompatActivity.getDelegate()}, then call
+{@code android.support.v7.app.AppCompatDelegate.setHandleNativeActionModesEnabled()} on the returned
+{@link android.support.v7.app.AppCompatDelegate} object and set the input
+parameter to {@code false}. This call returns control of {@link android.view.ActionMode} objects to
+the framework. In devices running the M Preview, that allows the framework to support
+{@link android.support.v7.app.ActionBar} or floating toolbar modes, while on pre-M Preview devices,
+only the {@link android.support.v7.app.ActionBar} modes are supported.</p>
+
+<h2 id="behavior-keystore">Android Keystore Changes</h2>
+<p>With this preview, the
+<a href="{@docRoot}training/articles/keystore.html">Android Keystore provider</a> no longer supports
+DSA. ECDSA is still supported.</p>
+
+<p>Keys which do not require encryption at rest will no longer be deleted when secure lock screen
+is disabled or reset (for example, by the user or a Device Administrator). Keys which require
+encryption at rest will be deleted during these events.</p>
+
+<h2 id="night-mode">Night Mode (User-configurable Dark Theme)</h2>
+<p>
+Support for the {@code -night} resource qualifier has been updated. Previously, night mode was
+only available when a device was docked and in car mode. With this preview, night mode is
+available on
+all devices and is user-configurable via <strong>Settings > Display > Theme</strong>. You can adjust
+this setting globally using {@link android.app.UiModeManager#setNightMode(int) setNightMode()}. The
+Dark theme corresponds to {@link android.app.UiModeManager#MODE_NIGHT_YES}. When the device is in
+night mode, the resource framework prefers resources that have the {@code -night} qualifier. To
+take advantage of user-configurable Dark mode in your app, extend from the
+{@code Theme.Material.DayNight} set of themes rather than {@code Theme.Material} or
+{@code Theme.Material.Light}.
+</p>
+
+<h2 id="behavior-network">Wi-Fi and Networking Changes</h2>
+
+<p>This preview introduces the following behavior changes to the Wi-Fi and networking APIs.</p>
+<ul>
+<li>Your apps can now change the state of {@link android.net.wifi.WifiConfiguration} objects only
+if you created these objects. You are not permitted to modify or delete
+{@link android.net.wifi.WifiConfiguration} objects created by the user or by other apps.
+</li>
+<li>
+Previously, if an app forced the device to connect to a specific Wi-Fi network by using
+{@link android.net.wifi.WifiManager#enableNetwork(int,boolean) enableNetwork()} with the
+{@code disableAllOthers=true} setting, the device disconnected from other networks such as
+cellular data. In this preview, the device no longer disconnects from such other networks. If
+your app’s {@code targetSdkVersion} is {@code “20”} or lower, it is pinned to the selected
+Wi-Fi network. If your app’s {@code targetSdkVersion} is {@code “21”} or higher, use the
+multinetwork APIs (such as
+{@link android.net.Network#openConnection(java.net.URL) openConnection()},
+{@link android.net.Network#bindSocket(java.net.Socket) bindSocket()}, and the new
+{@code ConnectivityManager.bindProcessToNetwork()} method) to ensure that its network traffic is
+sent on the selected network.</li>
+</ul>
+
+<h2 id="behavior-camera">Camera Service Changes</h2>
+<p>In this preview, the model for accessing shared resources in the camera service has been changed
+from the previous “first come, first serve” access model to an access model where high-priority
+processes are favored.  Changes to the service behavior include:</p>
+<ul>
+<li>Access to camera subsystem resources, including opening and configuring a camera device, is
+awarded based on the “priority” of the client application process. Application processes with
+user-visible or foreground activities are generally given a higher-priority, making camera resource
+acquisition and use more dependable.</li>
+<li>Active camera clients for lower priority apps may be “evicted” when a higher priority
+application attempts to use the camera.  In the deprecated {@link android.hardware.Camera} API,
+this results in
+{@link android.hardware.Camera.ErrorCallback#onError(int,android.hardware.Camera) onError()} being
+called for the evicted client. In the {@link android.hardware.camera2 Camera2} API, it results in
+{@link android.hardware.camera2.CameraDevice.StateCallback#onDisconnected(android.hardware.camera2.CameraDevice) onDisconnected()}
+being called for the evicted client.</li>
+<li>On devices with appropriate camera hardware, separate application processes are able to
+independently open and use separate camera devices simultaneously. However, multi-process use
+cases, where simultaneous access causes significant degradation of performance or capabilities of
+any of the open camera devices, are now detected and disallowed by the camera service. This change
+may result in “evictions” for lower priority clients even when no other app is directly
+attempting to access the same camera device.
+</li>
+<li>
+Changing the current user causes active camera clients in apps owned by the previous user account
+to be evicted.  Access to the camera is limited to user profiles owned by the current device user.
+In practice, this means that a “Guest” account, for example, will not be able to leave running
+processes that use the camera subsystem when the user has switched to a different account.
+</li>
+</ul>
+
+<h2 id="behavior-art-runtime">ART Runtime</h2>
+<p>The ART runtime now properly implements access rules for the
+{@link java.lang.reflect.Constructor#newInstance(java.lang.Object...) newInstance()} method. This
+change fixes a problem where Dalvik was checking access rules incorrectly in previous versions.
+If your app uses the
+{@link java.lang.reflect.Constructor#newInstance(java.lang.Object...) newInstance()} method and you
+want to override access checks, call the
+{@link java.lang.reflect.Constructor#setAccessible(boolean) setAccessible()} method with the input
+parameter set to {@code true}. If your app uses the
+<a href="{@docRoot}tools/support-library/features.html#v7-appcompat">v7 appcompat library</a> or the
+<a href="{@docRoot}tools/support-library/features.html#v7-recyclerview">v7 recyclerview library</a>,
+you must update your app to use to the latest versions of these libraries. Otherwise, make sure that
+any custom classes referenced from XML are updated so that their class constructors are accessible.</p>
+
+<p>This preview updates the behavior of the dynamic linker. The dynamic linker now understands the
+difference between a library’s {@code soname} and its path
+(<a href="https://code.google.com/p/android/issues/detail?id=6670" class="external-link">
+public bug 6670</a>), and search by {@code soname} is now
+implemented. Apps which previously worked that have bad {@code DT_NEEDED} entries
+(usually absolute paths on the build machine’s file system) may fail when loaded.</p>
+
+<p>The {@code dlopen(3) RTLD_LOCAL} flag is now correctly implemented. Note that
+{@code RTLD_LOCAL} is the default, so calls to {@code dlopen(3)} that didn’t explicitly use
+{@code RTLD_LOCAL} will be affected (unless your app explicitly used {@code RTLD_GLOBAL}). With
+{@code RTLD_LOCAL}, symbols will not be made available to libraries loaded by later calls to
+{@code dlopen(3)} (as opposed to being referenced by {@code DT_NEEDED} entries).</p>
+</p>
+
+<h2 id="behavior-apk-validation">APK Validation</h2>
+<p>The platform now performs stricter validation of APKs. An APK is considered corrupt if a file is
+declared in the manifest but not present in the APK itself. An APK must be re-signed if any of the
+contents are removed.</p>
+
+<h2 id="behavior-afw">Android for Work Changes</h2>
+<p>This preview includes the following behavior changes for Android for Work:</p>
+<ul>
+<li><strong>Work contacts in personal contexts.</strong> The Google Dialer
+Call Log now displays work contacts when the user views past calls. Both
+work and personal contacts are now available to devices over Bluetooth, but you can hide work
+profile contacts through a device policy by calling the new
+{@code DevicePolicyManager.setBluetoothContactSharingDisabled()} method. Initiating a call still
+shows personal contacts, as consistent with the experience in Android 5.0.
+</li>
+<li><strong>WiFi configuration removal:</strong> WiFi configurations added by a Profile Owner
+(for example, through calls to the
+{@link android.net.wifi.WifiManager#addNetwork(android.net.wifi.WifiConfiguration)
+addNetwork()} method) are now removed if that work profile is deleted.</li>
+<li><strong>WiFi configuration lockdown:</strong> Any WiFi configuration created by an active Device
+Owner can no longer be modified or deleted by the user. The user can still create and
+modify their own WiFi configurations, so long as the {@link android.os.UserManager} constant
+{@link android.os.UserManager#DISALLOW_CONFIG_WIFI} has not been set for that user.</li>
+<li><strong>Download Work Policy Controller via Google account addition:</strong> When a Google
+account that requires management via a Work Policy Controller (WPC) app is added to a device
+outside of a managed context, the add account flow now prompts the user to install the
+appropriate WPC. This behavior also applies to accounts added via
+<strong>Settings > Accounts</strong> in the initial device setup wizard.</li>
+<li><strong>Changes to specific DevicePolicyManager API behaviors:</strong>
+Calling the {@link android.app.admin.DevicePolicyManager#setCameraDisabled(android.content.ComponentName,boolean) setCameraDisabled()}
+method affects the camera for the calling user only; calling it from the managed profile doesn’t
+affect camera apps running on the primary user. In addition, the
+{@link android.app.admin.DevicePolicyManager#setKeyguardDisabledFeatures(android.content.ComponentName,int) setKeyguardDisabledFeatures()}
+method is now available for Profile Owners, in addition to Device Owners. A Profile Owner can set
+these keyguard restrictions:
+<ul>
+<li>{@link android.app.admin.DevicePolicyManager#KEYGUARD_DISABLE_TRUST_AGENTS} and
+    {@link android.app.admin.DevicePolicyManager#KEYGUARD_DISABLE_FINGERPRINT}, which affect the
+    keyguard settings for the profile’s parent user.</li>
+<li>{@link android.app.admin.DevicePolicyManager#KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS}, which
+    only affects notifications generated by applications in the managed profile.</li>
+</ul>
+</li>
+</ul>
diff --git a/docs/html/preview/images/perf-test-frame-latency.png b/docs/html/preview/images/perf-test-frame-latency.png
new file mode 100644
index 0000000..87d1cfc
--- /dev/null
+++ b/docs/html/preview/images/perf-test-frame-latency.png
Binary files differ
diff --git a/docs/html/preview/images/perf-test-framestats.png b/docs/html/preview/images/perf-test-framestats.png
new file mode 100644
index 0000000..589a923
--- /dev/null
+++ b/docs/html/preview/images/perf-test-framestats.png
Binary files differ
diff --git a/docs/html/preview/images/work-profile-screen.png b/docs/html/preview/images/work-profile-screen.png
new file mode 100644
index 0000000..c3e4e44
--- /dev/null
+++ b/docs/html/preview/images/work-profile-screen.png
Binary files differ
diff --git a/docs/html/preview/images/work-profile-screen_2x.png b/docs/html/preview/images/work-profile-screen_2x.png
new file mode 100644
index 0000000..5dcf610
--- /dev/null
+++ b/docs/html/preview/images/work-profile-screen_2x.png
Binary files differ
diff --git a/docs/html/preview/preview_toc.cs b/docs/html/preview/preview_toc.cs
index 7e9f292..0371932 100644
--- a/docs/html/preview/preview_toc.cs
+++ b/docs/html/preview/preview_toc.cs
@@ -38,10 +38,9 @@
   </li>
 
   <li class="nav-section">
-    <div class="nav-section-header empty"><a href="<?cs var:toroot ?>preview/api-changes.html">
+    <div class="nav-section-header empty"><a href="<?cs var:toroot ?>preview/behavior-changes.html">
       Behavior Changes</a></div>
   </li>
-
   <li class="nav-section">
     <div class="nav-section-header empty"><a href="<?cs var:toroot ?>preview/samples.html">
       Samples</a></div>
diff --git a/docs/html/preview/testing/guide.jd b/docs/html/preview/testing/guide.jd
new file mode 100644
index 0000000..1879268
--- /dev/null
+++ b/docs/html/preview/testing/guide.jd
@@ -0,0 +1,176 @@
+page.title=Testing Guide
+page.image=images/cards/card-set-up_16-9_2x.png
+
+@jd:body
+
+<div id="qv-wrapper">
+  <div id="qv">
+    <h2>In this document</h2>
+      <ol>
+        <li><a href="#runtime-permissions">Testing Runtime Permissions</a></li>
+        <li><a href="#doze-standby">Testing Doze and App Standby</a></li>
+      </ol>
+  </div>
+</div>
+
+<p>
+  The Android M Developer Preview gives you an opportunity to ensure your apps work with the next
+  version of the platform. This preview includes a number of APIs and behavior changes that can
+  impact your app, as described in the <a href="{@docRoot}preview/api-overview.html">API
+  Overview</a> and <a href="{@docRoot}preview/api-changes.html">Behavior Changes</a>. In testing
+  your app with the preview, there are some specific system changes that you should focus on to
+  ensure that users have a good experience.
+</p>
+
+<p>
+  This guide describes the what and how to test preview features with your app. You should
+  prioritize testing of these specific preview features, due to their high potential impact on your
+  app's behavior:
+</p>
+
+<ul>
+  <li><a href="#runtime-permissions">Runtime Permissions</a>
+  </li>
+  <li><a href="#doze-mode">Doze and App Standby</a>
+  </li>
+</ul>
+
+<p>
+  For more information about how to set up devices or virtual devices with a preview system image
+  for testing, see <a href="{@docRoot}preview/setup-sdk.html">Set up the Preview SDK</a>.
+</p>
+
+
+<h2 id="runtime-permissions">Testing Runtime Permissions</h2>
+
+<p>
+  The <a href="{@docRoot}preview/features/runtime-permissions.html">Runtime Permissions</a> feature
+  changes the way that permissions are allocated to your app by the user. Instead of granting all
+  permissions during the install procedure, your app must ask the user for individual permissions
+  at runtime. For users this behavior provides more granular control over each app’s activities, as
+  well as better context for understanding why the app is requesting a specific permission. Users
+  can grant or revoke the permissions granted to an app individually at any time. This feature of
+  the preview is most likely to have an impact on your app's behavior and may prevent some of your
+  app features from working, or they may work in a degraded state.
+</p>
+
+<p>
+  This change that affects all apps running on the new platform, even those not targeting the new
+  platform version. The platform provides a limited compatibility behavior for legacy apps, but you
+  should begin planning your app’s migration to the new permissions model now, with a goal of
+  publishing an updated version of your app at the official platform launch.
+</p>
+
+
+<h3 id="permission-test-tips">Test tips</h3>
+
+<p>
+  Use the following test tips to help you plan and execute testing of your app with the new
+  permissions behavior.
+</p>
+
+<ul>
+  <li>Identify your app’s current permissions and the related code paths.</li>
+  <li>Test user flows across permission-protected services and data.</li>
+  <li>Test with various combinations of granted/revoked permission.</li>
+  <li>Use the {@code adb} tool to manage permssions from the command line:
+    <ul>
+      <li>List permissions and status by group:
+        <pre>adb shell pm list permissions -d -g</pre>
+      </li>
+      <li>Grant or revoke one or more permissions using the following syntax:<br>
+        <pre>adb shell pm [grant|revoke] &lt;permission.name&gt; ...</pre>
+      </li>
+    </ul>
+  </li>
+  <li>Analyze your app for services that use permissions.</li>
+</ul>
+
+<h3 id="permission-test-strategy">Test strategy</h3>
+
+<p>
+  The Runtime Permissions change affects the structure and design of your app, as well as
+  the user experience and flows you provide to users. You should assess your app’s current
+  permissions use and start planning for the new flows you want to offer. The official release of
+  the platform provides compatibility behavior, but you should plan on updating your app and not
+  rely on these behaviors.
+</p>
+
+<p>
+  Identify the permissions that your app actually needs and uses, and then find the various code
+  paths that use the permission-protected services. You can do this through a combination of
+  testing on the new platform and code analysis. In testing, you should focus on opting in to
+  runtime permissions by changing the app’s {@code targetSdkVersion} to the preview version. For
+  more information, see <a href="{@docRoot}preview/setup-sdk.html#">Set up the Preview SDK</a>.
+</p>
+
+<p>
+  Test with various combinations of permissions revoked and added, to highlight the user flows that
+  depend on permissions. Where a dependency is not obvious or logical you should consider
+  refactoring or compartmentalizing that flow to eliminate the dependency or make it clear why the
+  permission is needed.
+</p>
+
+<p>
+  For more information on the behavior of Runtime Permissions, testing, and best practices, see the
+  <a href="{@docRoot}preview/features/runtime-permissions.html">Runtime Permissions</a> developer
+  preview page.
+</p>
+
+
+<h2 id="doze-standby">Testing Doze and App Standby</h2>
+
+<p>
+  The power saving features of Doze and App Standby limits the amount of background processing that
+  your app can perform when a device is in an idle state or while your app is not in focus. The
+  restrictions the system may impose on apps include limited or no network access,
+  suspended background tasks, suspended Notifications, ignored wake requests, and alarms. To ensure
+  that your app behaves properly with these power saving optimizations, you should test your app by
+  simulating these low power states.
+</p>
+
+<h4 id="doze">Testing your app with Doze</h4>
+
+<p>To test Doze with your app:</p>
+
+<ol>
+<li>Configure a hardware device or virtual device with a M Preview system image.</li>
+<li>Connect the device to your development machine and install your app.</li>
+<li>Run your app and leave it active.</li>
+<li>Simulate the device going into Doze mode by running the following commands:
+
+<pre>
+$ adb shell dumpsys battery unplug
+$ adb shell dumpsys deviceidle step
+$ adb shell dumpsys deviceidle -h
+</pre>
+
+  </li>
+  <li>Observe the behavior of your app when the device is re-activated. Make sure it
+    recovers gracefully when the device exits Doze.</li>
+</ol>
+
+
+<h4 id="standby">Testing apps with App Standby</h4>
+
+<p>To test the App Standby mode with your app:</p>
+
+<ol>
+  <li>Configure a hardware device or virtual device with a M Preview system image.</li>
+  <li>Connect the device to your development machine and install your app.</li>
+  <li>Run your app and leave it active.</li>
+  <li>Simulate the app going into standby mode by running the following commands:
+
+<pre>
+$ adb shell am broadcast -a android.os.action.DISCHARGING
+$ adb shell am set-idle &lt;packageName&gt; true
+</pre>
+
+  </li>
+  <li>Simulate waking your app using the following command:
+    <pre>$ adb shell am set-idle &lt;packageName&gt; false</pre>
+  </li>
+  <li>Observe the behavior of your app when it is woken. Make sure it recovers gracefully
+    from standby mode. In particular, you should check if your app's Notifications and background
+    jobs continue to function as expected.</li>
+</ol>
diff --git a/docs/html/preview/testing/performance.jd b/docs/html/preview/testing/performance.jd
new file mode 100644
index 0000000..a61091f
--- /dev/null
+++ b/docs/html/preview/testing/performance.jd
@@ -0,0 +1,667 @@
+page.title=Testing Display Performance
+
+@jd:body
+
+
+<div id="qv-wrapper">
+  <div id="qv">
+    <h2>In this document</h2>
+      <ol>
+        <li><a href="#measure">Measuring UI Performance</a>
+          <ul>
+            <li><a href="#aggregate">Aggregate frame stats</a></li>
+            <li><a href="#timing-info">Precise frame timing info</a></li>
+            <li><a href="#timing-dump">Simple frame timing dump</a></li>
+            <li><a href="#collection-window">Controlling the window of stat collection</a></li>
+            <li><a href="#diagnose">Diagnosing performance regressions</a></li>
+            <li><a href="#resources">Additional resources</a></li>
+          </ul>
+        </li>
+        <li><a href="#automate">Automating UI Perfomance Tests</a>
+          <ul>
+            <li><a href="#ui-tests">Setting up UI tests</a></li>
+            <li><a href="#automated-tests">Setting up automated UI testing</a></li>
+            <li><a href="#triage">Triaging and fixing observed problems</a></li>
+          </ul>
+        </li>
+      </ol>
+  </div>
+</div>
+
+
+<p>
+  User interface (UI) performance testing ensures that your app not only meets its functional
+  requirements, but that user interactions with your app are buttery smooth, running at a
+  consistent 60 frames per second (<a href=
+  "https://www.youtube.com/watch?v=CaMTIgxCSqU&amp;index=25&amp;list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE">why
+  60fps?</a>), without any dropped or delayed frames, or as we like to call it, <em>jank</em>. This
+  document explains tools available to measure UI performance, and lays out an approach to
+  integrate UI performance measurements into your testing practices.
+</p>
+
+
+<h2 id="measure">Measuring UI Performance</h2>
+
+<p>
+  In order to improve performance you first need the ability to measure the performance of
+  your system, and then diagnose and identify problems that may arrive from various parts of your
+  pipeline.
+</p>
+
+<p>
+  <em><a href="https://source.android.com/devices/tech/debug/dumpsys.html">dumpsys</a></em> is an
+  Android tool that runs on the device and dumps interesting information about the status of system
+  services. Passing the <em>gfxinfo</em> command to dumpsys provides an output in logcat with
+  performance information relating to frames of animation that are occurring during the recording
+  phase.
+</p>
+
+<pre>
+&gt; adb shell dumpsys gfxinfo &lt;PACKAGE_NAME&gt;
+</pre>
+
+<p>
+  This command can produce multiple different variants of frame timing data.
+</p>
+
+<h3 id="aggregate">Aggregate frame stats</h3>
+
+<p>
+  With the M Preview the command prints out aggregated analysis of frame data to logcat, collected
+  across the entire lifetime of the process. For example:
+</p>
+
+<pre class="noprettyprint">
+Stats since: 752958278148ns
+Total frames rendered: 82189
+Janky frames: 35335 (42.99%)
+90th percentile: 34ms
+95th percentile: 42ms
+99th percentile: 69ms
+Number Missed Vsync: 4706
+Number High input latency: 142
+Number Slow UI thread: 17270
+Number Slow bitmap uploads: 1542
+Number Slow draw: 23342
+</pre>
+
+<p>
+  These high level statistics convey at a high level the rendering performance of the app, as well
+  as its stability across many frames.
+</p>
+
+
+<h3 id="timing-info">Precise frame timing info</h3>
+
+<p>
+  With the M Preview comes a new command for gfxinfo, and that’s <em>framestats</em> which provides
+  extremely detailed frame timing information from recent frames, so that you can track down and
+  debug problems more accurately.
+</p>
+
+<pre>
+&gt;adb shell dumpsys gfxinfo &lt;PACKAGE_NAME&gt; framestats
+</pre>
+
+<p>
+  This command prints out frame timing information, with nanosecond timestamps, from the last 120
+  frames produced by the app. Below is example raw output from adb dumpsys gfxinfo
+  &lt;PACKAGE_NAME&gt; framestats:
+</p>
+
+<pre class="noprettyprint">
+0,49762224585003,49762241251670,9223372036854775807,0,49762257627204,49762257646058,49762257969704,49762258002100,49762265541631,49762273951162,49762300914808,49762303675954,
+0,49762445152142,49762445152142,9223372036854775807,0,49762446678818,49762446705589,49762447268818,49762447388037,49762453551527,49762457134131,49762474889027,49762476150120,
+0,49762462118845,49762462118845,9223372036854775807,0,49762462595381,49762462619287,49762462919964,49762462968454,49762476194547,49762476483454,49762480214964,49762480911527,
+0,49762479085548,49762479085548,9223372036854775807,0,49762480066370,49762480099339,49762481013089,49762481085850,49762482232152,49762482478350,49762485657620,49762486116683,
+</pre>
+
+<p>
+  Each line of this output represents a frame produced by the app. Each line has a fixed number of
+  columns describing time spent in each stage of the frame-producing pipeline. The next section
+  describes this format in detail, including what each column represents.
+</p>
+
+
+<h4 id="fs-data-format">Framestats data format</h4>
+
+<p>
+  Since the block of data is output in CSV format, it's very straightforward to paste it to your
+  spreadsheet tool of choice, or collect and parse with a script. The following table explains the
+  format of the output data columns. All timestamps are in nanoseconds.
+</p>
+
+<ul>
+  <li>FLAGS
+    <ul>
+      <li>Rows with a ‘0’ for the FLAGS column can have their total frame time computed by
+      subtracting the INTENDED_VSYNC column from the FRAME_COMPLETED column.
+      </li>
+
+      <li>If this is non-zero the row should be ignored, as the frame has been determined as being
+      an outlier from normal performance, where it is expected that layout &amp; draw take longer
+      than 16ms. Here are a few reasons this could occur:
+        <ul>
+          <li>The window layout changed (such as the first frame of the application or after a
+          rotation)
+          </li>
+
+          <li>It is also possible the frame was skipped in which case some of the values will have
+          garbage timestamps. A frame can be skipped if for example it is out-running 60fps or if
+          nothing on-screen ended up being dirty, this is not necessarily a sign of a problem in
+          the app.
+          </li>
+        </ul>
+      </li>
+    </ul>
+  </li>
+
+  <li>VSYNC
+    <ul>
+      <li>The time value that was used in all the vsync listeners and drawing for the frame
+      (Choreographer frame callbacks, animations, View.getDrawingTime(), etc…)
+      </li>
+
+      <li>To understand more about VSYNC and how it influences your application, check out the
+      <a href=
+      "https://www.youtube.com/watch?v=1iaHxmfZGGc&amp;list=PLOU2XLYxmsIKEOXh5TwZEv89aofHzNCiu&amp;index=23">
+        Understanding VSYNC</a> video.
+      </li>
+    </ul>
+  </li>
+
+
+  <li>INTENDED_VSYNC
+    <ul>
+      <li>The intended start point for the frame. If this value is different from VSYNC, there
+      was work occurring on the UI thread that prevented it from responding to the vsync signal
+      in a timely fashion.
+      </li>
+    </ul>
+  </li>
+
+  <li>OLDEST_INPUT_EVENT
+    <ul>
+      <li>The timestamp of the oldest input event in the input queue, or Long.MAX_VALUE if
+      there were no input events for the frame.
+      </li>
+
+      <li>This value is primarily intended for platform work and has limited usefulness to app
+      developers.
+      </li>
+    </ul>
+  </li>
+
+  <li>NEWEST_INPUT_EVENT
+    <ul>
+      <li>The timestamp of the newest input event in the input queue, or 0 if there were no
+      input events for the frame.
+      </li>
+
+      <li>This value is primarily intended for platform work and has limited usefulness to app
+      developers.
+      </li>
+
+      <li>However it’s possible to get a rough idea of how much latency the app is adding by
+      looking at (FRAME_COMPLETED - NEWEST_INPUT_EVENT).
+      </li>
+    </ul>
+  </li>
+
+  <li>HANDLE_INPUT_START
+    <ul>
+      <li>The timestamp at which input events were dispatched to the application.
+      </li>
+
+      <li>By looking at the time between this and ANIMATION_START it is possible to measure how
+      long the application spent handling input events.
+      </li>
+
+      <li>If this number is high (&gt;2ms), this indicates the app is spending an unusually
+      long time processing input events, such as View.onTouchEvent(), which may indicate this
+      work needs to be optimized, or offloaded to a different thread. Note that there are some
+      scenarios, such as click events that launch new activities or similar, where it is
+      expected and acceptable that this number is large.
+      </li>
+    </ul>
+  </li>
+
+  <li>ANIMATION_START
+    <ul>
+      <li>The timestamp at which animations registered with Choreographer were run.
+      </li>
+
+      <li>By looking at the time between this and PERFORM_TRANVERSALS_START it is possible to
+      determine how long it took to evaluate all the animators (ObjectAnimator,
+      ViewPropertyAnimator, and Transitions being the common ones) that are running.
+      </li>
+
+      <li>If this number is high (&gt;2ms), check to see if your app has written any custom
+      animators or what fields ObjectAnimators are animating and ensure they are appropriate
+      for an animation.
+      </li>
+
+      <li>To learn more about Choreographer, check out the <a href=
+      "https://developers.google.com/events/io/sessions/325418001">For Butter or Worse</a>
+      video.
+      </li>
+    </ul>
+  </li>
+
+  <li>PERFORM_TRAVERSALS_START
+    <ul>
+      <li>If you subtract out DRAW_START from this value, you can extract how long the layout
+      &amp; measure phases took to complete. (note, during a scroll, or animation, you would
+      hope this should be close to zero..)
+      </li>
+
+      <li>To learn more about the measure &amp; layout phases of the rendering pipeline, check
+      out the <a href=
+      "https://www.youtube.com/watch?v=we6poP0kw6E&amp;list=PLOU2XLYxmsIKEOXh5TwZEv89aofHzNCiu&amp;index=27">
+        Invalidations, Layouts and Performance</a> video
+      </li>
+    </ul>
+  </li>
+
+  <li>DRAW_START
+    <ul>
+      <li>The time at which the draw phase of performTraversals started. This is the start
+      point of recording the display lists of any views that were invalidated.
+      </li>
+
+      <li>The time between this and SYNC_START is how long it took to call View.draw() on all
+      the invalidated views in the tree.
+      </li>
+
+      <li>For more information on the drawing model, see <a href=
+      "{@docRoot}guide/topics/graphics/hardware-accel.html#hardware-model">Hardware Acceleration</a>
+      or the <a href=
+      "https://www.youtube.com/watch?v=we6poP0kw6E&amp;list=PLOU2XLYxmsIKEOXh5TwZEv89aofHzNCiu&amp;index=27">
+        Invalidations, Layouts and Performance</a> video
+      </li>
+    </ul>
+  </li>
+
+  <li>SYNC_START
+    <ul>
+      <li>The time at which the sync phase of the drawing started.
+      </li>
+
+      <li>If the time between this and ISSUE_DRAW_COMMANDS_START is substantial (&gt;0.4ms or
+      so), it typically indicates a lot of new Bitmaps were drawn which must be uploaded to the
+      GPU.
+      </li>
+
+      <li>To understand more about the sync phase, check out the <a href=
+      "https://www.youtube.com/watch?v=VzYkVL1n4M8&amp;index=24&amp;list=PLOU2XLYxmsIKEOXh5TwZEv89aofHzNCiu">
+        Profile GPU Rendering</a> video
+      </li>
+    </ul>
+  </li>
+
+  <li>ISSUE_DRAW_COMMANDS_START
+    <ul>
+      <li>The time at which the hardware renderer started issuing drawing commands to the GPU.
+      </li>
+
+      <li>The time between this and FRAME_COMPLETED gives a rough idea of how much GPU work the
+      app is producing. Problems like too much overdraw or inefficient rendering effects show
+      up here.
+      </li>
+    </ul>
+  </li>
+
+  <li>SWAP_BUFFERS
+    <ul>
+      <li>The time at which eglSwapBuffers was called, relatively uninteresting outside of
+      platform work.
+      </li>
+    </ul>
+  </li>
+
+  <li>FRAME_COMPLETED
+    <ul>
+      <li>All done! The total time spent working on this frame can be computed by doing
+      FRAME_COMPLETED - INTENDED_VSYNC.
+      </li>
+    </ul>
+  </li>
+
+</ul>
+
+<p>
+  You can use this data in different ways. One simple but useful visualization is a
+  histogram showing the distribution of frames times (FRAME_COMPLETED - INTENDED_VSYNC) in
+  different latency buckets, see figure below. This graph tells us at a glance that most
+  frames were very good - well below the 16ms deadline (depicted in red), but a few frames
+  were significantly over the deadline. We can look at changes in this histogram over time
+  to see wholesale shifts or new outliers being created. You can also graph input latency,
+  time spent in layout, or other similar interesting metrics based on the many timestamps
+  in the data.
+</p>
+
+<img src="{@docRoot}preview/images/perf-test-framestats.png">
+
+
+<h3 id="timing-dump">Simple frame timing dump</h3>
+
+<p>
+  If <strong>Profile GPU rendering</strong> is set to <strong>In adb shell dumpsys gfxinfo</strong>
+  in Developer Options, the <code>adb shell dumpsys gfxinfo</code> command prints out timing
+  information for the most recent 120 frames, broken into a few different categories with
+  tab-separated-values. This data can be useful for indicating which parts of the drawing pipeline
+  may be slow at a high level.
+</p>
+
+<p>
+  Similar to <a href="#fs-data-format">framestats</a> above, it's very
+  straightforward to paste it to your spreadsheet tool of choice, or collect and parse with
+  a script. The following graph shows a breakdown of where many frames produced by the app
+  were spending their time.
+</p>
+
+<img src="{@docRoot}preview/images/perf-test-frame-latency.png">
+
+<p>
+  The result of running gfxinfo, copying the output, pasting it into a spreadsheet
+  application, and graphing the data as stacked bars.
+</p>
+
+<p>
+  Each vertical bar represents one frame of animation; its height represents the number of
+  milliseconds it took to compute that frame of animation. Each colored segment of the bar
+  represents a different stage of the rendering pipeline, so that you can see what parts of
+  your application may be creating a bottleneck. For more information on understanding the
+  rendering pipeline, and how to optimize for it, see the <a href=
+  "https://www.youtube.com/watch?v=we6poP0kw6E&amp;index=27&amp;list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE">
+  Invalidations Layouts and Performance</a> video.
+</p>
+
+
+<h3 id="collection-window">Controlling the window of stat collection</h3>
+
+<p>
+  Both the framestats and simple frame timings gather data over a very short window - about
+  two seconds worth of rendering. In order to precisely control this window of time - for
+  example, to constrain the data to a particular animation - you can reset all counters,
+  and aggregate statistics gathered.
+</p>
+
+<pre>
+&gt;adb shell dumpsys gfxinfo &lt;PACKAGE_NAME&gt; reset
+</pre>
+
+<p>
+  This can also be used in conjunction with the dumping commands themselves to collect and
+  reset at a regular cadence, capturing less-than-two-second windows of frames
+  continuously.
+</p>
+
+
+<h3 id="diagnose">Diagnosing performance regressions</h3>
+
+<p>
+  Identification of regressions is a good first step to tracking down problems, and
+  maintaining high application health. However, dumpsys just identifies the existence and
+  relative severity of problems. You still need to diagnose the particular cause of the
+  performance problems, and find appropriate ways to fix them. For that, it’s highly
+  recommended to use the <a href="{@docRoot}tools/help/systrace.html">systrace</a> tool.
+</p>
+
+
+<h3 id="resources">Additional resources</h3>
+
+<p>
+  For more information on how Android’s rendering pipeline works, common problems that you
+  can find there, and how to fix them, some of the following resources may be useful to
+  you:
+</p>
+
+<ul>
+  <li>Rendering Performance 101
+  </li>
+  <li>Why 60fps?
+  </li>
+  <li>Android UI and the GPU
+  </li>
+  <li>Invalidations Layouts and performance
+  </li>
+  <li>Analyzing UI Performance with Systrace
+  </li>
+</ul>
+
+
+<h2 id="automate">Automating UI Perfomance Tests</h2>
+
+<p>
+  One approach to UI Performance testing is to simply have a human tester perform a set of
+  user operations on the target app, and either visually look for jank, or spend an very
+  large amount of time using a tool-driven approach to find it. But this manual approach is
+  fraught with peril - human ability to perceive frame rate changes varies tremendously,
+  and this is also time consuming, tedious, and error prone.
+</p>
+
+<p>
+  A more efficient approach is to log and analyze key performance metrics from automated UI
+  tests. The Android M developer preview includes new logging capabilities which make it
+  easy to determine the amount and severity of jank in your application’s animations, and
+  that can be used to build a rigorous process to determine your current performance and
+  track future performance objectives.
+</p>
+
+<p>
+  This article walks you through a recommended approach to using that data to automate your
+  performance testing.
+</p>
+
+<p>
+  This is mostly broken down into two key actions. Firstly, identifying what you're
+  testing, and how you’re testing it. and Secondly, setting up, and maintaining an
+  automated testing environment.
+</p>
+
+
+<h3 id="ui-tests">Setting up UI tests</h3>
+
+<p>
+  Before you can get started with automated testing, it’s important to determine a few high
+  level decisions, in order to properly understand your test space, and needs you may have.
+</p>
+
+<h4>
+  Identify key animations / flows to test
+</h4>
+
+<p>
+  Remember that bad performance is most visible to users when it interrupts a smooth
+  animation. As such, when identifying what types of UI actions to test for, it’s useful to
+  focus on the key animations that users see most, or are most important to their
+  experience. For example, here are some common scenarios that may be useful to identify:
+</p>
+
+<ul>
+  <li>Scrolling a primary ListView or RecyclerView
+  </li>
+
+  <li>Animations during async wait cycles
+  </li>
+
+  <li>Any animation that may have bitmap loading / manipulation in it
+  </li>
+
+  <li>Animations including Alpha Blending
+  </li>
+
+  <li>Custom View drawing with Canvas
+  </li>
+</ul>
+
+<p>
+  Work with engineers, designers, and product managers on your team to prioritize these key
+  product animations for test coverage.
+</p>
+
+<h4>
+  Define your future objectives and track against them
+</h4>
+
+<p>
+  From a high-level, it may be critical to identify your specific performance goals, and
+  focus on writing tests, and collecting data around them. For example:
+</p>
+
+<ul>
+  <li>Do you just want to begin tracking UI performance for the first time to learn more?
+  </li>
+
+  <li>Do you want to prevent regressions that might be introduced in the future?
+  </li>
+
+  <li>Are you at 90% of smooth frames today and want to get to 98% this quarter?
+  </li>
+
+  <li>Are you at 98% smooth frames and don’t want to regress?
+  </li>
+
+  <li>Is your goal to improve performance on low end devices?
+  </li>
+</ul>
+
+<p>
+  In all of these cases, you’ll want historical tracking which shows performance across
+  multiple versions of your application.
+</p>
+
+<h4>
+  Identify devices to test on
+</h4>
+
+<p>
+  Application performance varies depending on the device it's running on. Some devices may
+  contain less memory, less powerful GPUs, or slower CPU chips. This means that animations
+  which may perform well on one set of hardware, may not on others, and worse, may be a
+  result of a bottleneck in a different part of the pipeline. So, to account for this
+  variation in what a user might see, pick a range of devices to execute tests on, both
+  current high end devices, low end devices, tablets, etc. Look for variation in CPU
+  performance, RAM, screen density, size, and so on. Tests that pass on a high end device
+  may fail on a low end device.
+</p>
+
+<h4>
+  Basic frameworks for UI Testing
+</h4>
+
+<p>
+  Tool suites like <a href=
+  "https://developer.android.com/tools/testing-support-library/index.html">UIAutomator</a>,
+  and <a href="https://code.google.com/p/android-test-kit/">Espresso</a> are built to help
+  automate the action of a user moving through your application. These are simple
+  frameworks which mimic user interaction with your device. To use these frameworks, you
+  effectively create unique scripts, which run through a set of user-actions, and play them
+  out on the device itself.
+</p>
+
+<p>
+  By combining these automated tests, alongside <code>dumpsys gfxinfo</code> you can quickly
+  create a reproducible system that allows you to execute a test, and measure the
+  performance information of that particular condition.
+</p>
+
+
+<h3 id="automated-tests">Setting up automated UI testing</h3>
+
+<p>
+  Once you have the ability to execute a UI test, and a pipeline to gather the data from a
+  single test, the next important step is to embrace a framework which can execute that
+  test multiple times, across multiple devices, and aggregate the resulting performance
+  data for further analysis by your development team.
+</p>
+
+<h4>
+  A framework for test automation
+</h4>
+
+<p>
+  It’s worth noting that UI testing frameworks (like <a href=
+  "https://developer.android.com/tools/testing-support-library/index.html">UIAutomator</a>)
+  run on the target device/emulator directly. While performance gathering information done
+  by <em>dumpsys gfxinfo</em> is driven by a host machine, sending commands over ADB. To
+  help bridge the automation of these separate entities, <a href=
+  "{@docRoot}tools/help/monkeyrunner_concepts.html">MonkeyRunner</a> framework was
+  developed; A scripting system that runs on your host machine, which can issue commands to
+  a set of connected devices, as well as receive data from them.
+</p>
+
+<p>
+  Building a set of scripts for proper Automation of UI Performance testing, at a minimum,
+  should be able to utilize monkeyRunner to accomplish the following tasks:
+</p>
+
+<ul>
+  <li>Load &amp; Launch a desired APK to a target device, devices, or emulator.
+  </li>
+
+  <li>Launch a UIAutomator UI test, and allow it to be executed
+  </li>
+
+  <li>Collect performance information through <em>dumpsys gfxinfo</em><em>.</em>
+  </li>
+
+  <li>Aggregate information and display it back in a useful fashion to the developer.
+  </li>
+</ul>
+
+
+<h3 id="triage">Triaging and fixing observed problems</h3>
+
+<p>
+  Once problem patterns or regressions are identified, the next step is identifying and
+  applying the fix. If your automated test framework preserves precise timing breakdowns
+  for frames, it can help you scrutinize recent suspicious code/layout changes (in the case
+  of regression), or narrow down the part of the system you’re analyzing when you switch to
+  manual investigation. For manual investigation, <a href=
+  "{@docRoot}tools/help/systrace.html">systrace</a> is a great place to start, showing
+  precise timing information about every stage of the rendering pipeline, every thread and
+  core in the system, as well as any custom event markers you define.
+</p>
+
+<h4>
+  Properly profiling temporal timings
+</h4>
+
+<p>
+  It is important to note the difficulties in obtaining and measuring timings that come from
+  rendering performance. These numbers are, by nature, non deterministic, and often
+  fluctuate depending on the state of the system, amount of memory available, thermal
+  throttling, and the last time a sun flare hit your area of the earth. The point is that
+  you can run the same test, twice and get slightly different numbers that may be close to
+  each other, but not exact.
+</p>
+
+<p>
+  Properly gathering and profiling data in this manner means running the same test,
+  multiple times, and accumulating the results as an average, or median value. (for the
+  sake of simplicity, let’s call this a ‘batch’) This gives you the rough approximation of
+  the performance of the test, while not needing exact timings.
+</p>
+
+<p>
+  Batches can be used between code changes to see the relative impact of those changes on
+  performance. If the average frame rate for the pre-change Batch is larger than the
+  post-change batch, then you generally have an overall win wrt performance for that
+  particular change.
+</p>
+
+<p>
+  This means that any Automated UI testing you do should take this concept into
+  consideration, and also account for any anomalies that might occur during a test. For
+  example, if your application performance suddenly dips, due to some device issue (that
+  isn’t caused by your application) then you may want to re-run the batch in order to get
+  less chaotic timings.
+</p>
+
+<p>
+  So, how many times should you run a test, before the measurements become meaningful? 10
+  times should be the minimum, with higher numbers like 50 or 100 yielding more accurate
+  results (of course, you’re now trading off time for accuracy)
+</p>
diff --git a/docs/html/tools/support-library/features.jd b/docs/html/tools/support-library/features.jd
index 573baad..926578a 100644
--- a/docs/html/tools/support-library/features.jd
+++ b/docs/html/tools/support-library/features.jd
@@ -22,6 +22,8 @@
       <li><a href="#v8">v8 Support Library</a></li>
       <li><a href="#v13">v13 Support Library</a></li>
       <li><a href="#v17-leanback">v17 Leanback Library</a></li>
+      <li><a href="#annotations">Annotations Support Library</a></li>
+      <li><a href="#design">Design Support Library</a></li>
     </ol>
 
     <h2>See also</h2>
@@ -131,11 +133,11 @@
   API reference.
 </p>
 
-<p>This library is located in the {@code &lt;sdk&gt;/extras/android/support/v4/} directory after
-  you download the Android Support Libraries. The library does not contain user interface
-  resources. To include it in your application project, follow the instructions for
-  <a href="{@docRoot}tools/support-library/setup.html#libs-without-res">Adding libraries without
-  resources</a>.</p>
+<p>After you download the Android Support Libraries, this library is located in the
+{@code &lt;sdk&gt;/extras/android/support/v4/} directory. The library does not contain user
+interface resources. To include it in your application project, follow the instructions for
+<a href="{@docRoot}tools/support-library/setup.html#libs-without-res">Adding libraries without
+resources</a>.</p>
 
 <p class="caution"><strong>Caution:</strong> Using dynamic dependencies, especially for higher version
 numbers, can cause unexpected version updates and regression incompatibilities.</p>
@@ -158,10 +160,11 @@
 </p>
 
 <p>
-  This library is located in the {@code &lt;sdk&gt;/extras/android/support/multidex/} directory
-  after you download the Android Support Libraries. The library does not contain user interface
-  resources. To include it in your application project, follow the instructions for <a href=
-  "{@docRoot}tools/support-library/setup.html#libs-without-res">Adding libraries without
+  After you download the Android Support Libraries, this library is located in the
+  {@code &lt;sdk&gt;/extras/android/support/multidex/} directory. The library does not contain
+  user interface resources. To include it in your application project, follow the instructions
+  for
+  <a href= "{@docRoot}tools/support-library/setup.html#libs-without-res">Adding libraries without
   resources</a>.
 </p>
 
@@ -218,11 +221,11 @@
   </li>
 </ul>
 
-<p>This library is located in the {@code &lt;sdk&gt;/extras/android/support/v7/appcompat/}
-  directory after you download the Android Support Libraries. The library contains user
-  interface resources. To include it in your application project, follow the instructions for
-  <a href="{@docRoot}tools/support-library/setup.html#libs-with-res">Adding libraries with
-  resources</a>.</p>
+<p>After you download the Android Support Libraries, this library is located in the
+{@code &lt;sdk&gt;/extras/android/support/v7/appcompat/} directory. The library contains user
+interface resources. To include it in your application project, follow the instructions for
+<a href="{@docRoot}tools/support-library/setup.html#libs-with-res">Adding libraries with
+resources</a>.</p>
 
 <p>The Gradle build script dependency identifier for this library is as follows:</p>
 
@@ -239,9 +242,8 @@
 on any app. These cards are useful for material design
 implementations, and are used extensively in layouts for TV apps.</p>
 
-<p>This library is located in the
-{@code &lt;sdk&gt;/extras/android/support/v7/cardview/} directory after you
-download the Android Support Libraries. The library contains user interface
+<p>After you download the Android Support Libraries, this library is located in the
+{@code &lt;sdk&gt;/extras/android/support/v7/cardview/} directory. The library contains user interface
 resources. To include it in your application project, follow the instructions
 for <a href="{@docRoot}tools/support-library/setup.html#libs-with-res">Adding
 libraries with resources</a>.</p>
@@ -256,13 +258,14 @@
 
 <h3 id="v7-gridlayout">v7 gridlayout library</h3>
 
-<p>This library adds support for the {@link android.support.v7.widget.GridLayout} class, which
-  allows you to arrange user interface elements using a grid of rectangular cells.
-  For detailed information about the v7 gridlayout library APIs, see the
-  {@link android.support.v7.widget android.support.v7.widget} package in the API reference.</p>
+<p>After you download the Android Support Libraries, this library adds support for the
+{@link android.support.v7.widget.GridLayout} class, which
+allows you to arrange user interface elements using a grid of rectangular cells.
+For detailed information about the v7 gridlayout library APIs, see the
+{@link android.support.v7.widget android.support.v7.widget} package in the API reference.</p>
 
 <p>This library is located in the {@code &lt;sdk&gt;/extras/android/support/v7/gridlayout/}
-  directory after you download the Android Support Libraries. The library contains user
+  directory . The library contains user
   interface resources. To include it in your application project, follow the instructions for
   <a href="{@docRoot}tools/support-library/setup.html#libs-with-res">Adding libraries with
   resources</a>.</p>
@@ -323,12 +326,11 @@
 from an album cover, and use those colors to build a color-coordinated song
 title card.</p>
 
-<p>This library is located in the
-{@code &lt;sdk&gt;/extras/android/support/v7/palette/} directory after
-  you download the Android Support Libraries. The library does not contain user interface
-  resources. To include it in your application project, follow the instructions for
-  <a href="{@docRoot}tools/support-library/setup.html#libs-without-res">Adding libraries without
-  resources</a>.</p>
+<p>After you download the Android Support Libraries, this library is located in the
+{@code &lt;sdk&gt;/extras/android/support/v7/palette/} directory. The library does not contain
+user interface resources. To include it in your application project, follow the instructions for
+<a href="{@docRoot}tools/support-library/setup.html#libs-without-res">Adding libraries without
+resources</a>.</p>
 
 <p>The Gradle build script dependency identifier for this library is as follows:</p>
 
@@ -346,10 +348,9 @@
 widget</a>, a view for efficiently displaying large data sets by providing a
 limited window of data items.</p>
 
-<p>This library is located in the
-{@code &lt;sdk&gt;/extras/android/support/v7/recyclerview/} directory after you
-download the Android Support Libraries. The library contains user interface
-resources. To include it in your application project, follow the instructions
+<p>After you download the Android Support Libraries, this library is located in the
+{@code &lt;sdk&gt;/extras/android/support/v7/recyclerview/} directory. The library contains
+user interface resources. To include it in your application project, follow the instructions
 for <a href="{@docRoot}tools/support-library/setup.html#libs-with-res">Adding
 libraries with resources</a>.</p>
 
@@ -363,6 +364,12 @@
 
 <h2 id="v8">v8 Support Library</h2>
 
+<p>This library is designed to be used with Android 2.2 (API level 8) and higher.
+  This library provides specific feature sets and can be included in your application
+  independently from other libraries.</p>
+
+<h3 id="v8-renderscript">v8 renderscript library</h3>
+
 <p>This library is designed to be used with Android (API level 8) and higher. It adds support for
   the <a href="{@docRoot}guide/topics/renderscript/compute.html">RenderScript</a> computation
   framework. These APIs are included in the {@link android.support.v8.renderscript} package. You
@@ -374,9 +381,20 @@
 
 <p class="note">
   <strong>Note:</strong> Use of RenderScript with the support library is supported with Android
-  Studio and Gradle-based builds, as well as the Eclipse plugin and Ant build tools.
+  Studio and Gradle-based builds, as well as the Eclipse plugin and Ant build tools. The
+  renderscript library is located in the <code>build-tools/$VERSION/renderscript/</code> folder. 
 </p>
 
+<p>The following example shows the Gradle build script properties for this library:</p>
+
+<pre>
+defaultConfig {
+    renderscriptTargetApi 18
+    renderscriptSupportModeEnabled true
+}
+</pre>
+
+
 
 <h2 id="v13">v13 Support Library</h2>
 
@@ -389,11 +407,11 @@
   android.support.v13} package in the API reference.
 </p>
 
-<p>This library is located in the {@code &lt;sdk&gt;/extras/android/support/v13/} directory after
-  you download the Android Support Libraries. The library does not contain user interface
-  resources. To include it in your application project, follow the instructions for
-  <a href="{@docRoot}tools/support-library/setup.html#libs-without-res">Adding libraries without
-  resources</a>.</p>
+<p>After you download the Android Support Libraries, this library is located in the
+{@code &lt;sdk&gt;/extras/android/support/v13/} directory. The library does not contain user
+interface resources. To include it in your application project, follow the instructions for
+<a href="{@docRoot}tools/support-library/setup.html#libs-without-res">Adding libraries without
+resources</a>.</p>
 
 <p>The Gradle build script dependency identifier for this library is as follows:</p>
 
@@ -429,9 +447,8 @@
     into a {@link android.support.v17.leanback.app.RowsFragment}.</li>
 </ul>
 
-<p>This library is located in the
-{@code &lt;sdk&gt;/extras/android/support/v17/leanback} directory after
-you download the Android Support Libraries. For more information
+<p>After you download the Android Support Libraries, this library is located in the
+{@code &lt;sdk&gt;/extras/android/support/v17/leanback} directory. For more information
 on how to set up your project, follow the instructions in <a
 href="{@docRoot}tools/support-library/setup.html#libs-with-res">Adding libraries
 with resources</a>. </p>
@@ -444,3 +461,48 @@
 
 
 
+<h2 id="annotations">Annotations Support Library</h2>
+
+<p>The <a href="{@docRoot}reference/android/support/annotation/package-summary.html">Annotation</a>
+package provides APIs to support adding annotation metadata to your apps. </p>
+
+<p></p>
+
+<p>After you download the Android Support Libraries, this library is located in the
+{@code &lt;sdk&gt;/extras/android/support/annotations} directory. For more information
+on how to set up your project, follow the instructions in <a
+href="{@docRoot}tools/support-library/setup.html#libs-with-res">Adding libraries
+with resources</a>. </p>
+
+<p>The Gradle build script dependency identifier for this library is as follows:</p>
+
+<pre>
+com.android.support:support-annotations:22.0.0
+</pre>
+
+
+
+<h2 id="design">Design Support Library</h2>
+
+<p>The
+<a href="{@docRoot}reference/android/support/design/package-summary.html">Design</a> package
+provides APIs to support adding material design components and patterns to your apps. </p>
+
+<p>The Design Support library adds support for various material design components and patterns for
+app developers to build upon, such as navigation drawers, floating action buttons (<i>FAB</i>),
+snackbars, and <a href="{@docRoot}design/building-blocks/tabs.html">tabs</a>.  </p>
+
+
+<p>After you download the Android Support Libraries, this library is located in the
+{@code &lt;sdk&gt;/extras/android/support/design} directory. For more information
+on how to set up your project, follow the instructions in <a
+href="{@docRoot}tools/support-library/setup.html#libs-with-res">Adding libraries
+with resources</a>. </p>
+
+<p>The Gradle build script dependency identifier for this library is as follows:</p>
+
+<pre>
+com.android.support:support-design:22.0.0
+</pre>
+
+
diff --git a/docs/html/tools/support-library/index.jd b/docs/html/tools/support-library/index.jd
index 98c9ad5..1dad6b8 100644
--- a/docs/html/tools/support-library/index.jd
+++ b/docs/html/tools/support-library/index.jd
@@ -59,13 +59,187 @@
 <p>This section provides details about the Support Library package releases.</p>
 
 
-<div class="toggle-content opened">
+<div class="toggle-content open">
   <p id="rev21"><a href="#" onclick="return toggleContent(this)">
-    <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img" alt=""
-/>Android Support Library, revision 22.1.0</a> <em>(April 2015)</em>
+    <img src="{@docRoot}assets/images/triangle-open.png" class="toggle-content-img" alt=""
+/>Android Support Library, revision 22.2.0</a> <em>(May 2015)</em>
   </p>
   <div class="toggle-content-toggleme">
     <dl>
+      <dt>Added <a href="features.html#design">Design Support library:</a></dt>
+      <dd>
+        <ul>
+          <li>Added {@link android.support.design.widget.TextInputLayout} for showing
+            {@link android.widget.EditText} hint and error text as floating labels.
+          </li>
+          <li>Added {@link android.support.design.widget.FloatingActionButton} for implementing a
+            primary action on your interface as a
+            floating action button, supporting either default or mini sizes.
+          </li>
+          <li>Added {@link android.support.design.widget.Snackbar} for providing lightweight
+            feedback with an optional action in an animated snackbar.
+          </li>
+          <li>Added {@link android.support.design.widget.TabLayout} for implementing fixed and
+            scrollable
+           <a href="{@docRoot}design/building-blocks/tabs.html">tabs</a> as well as easy
+             integration with
+             {@link android.support.v4.view.ViewPager}.
+          </li>
+          <li>Added {@link android.support.design.widget.NavigationView} for implementing
+            <a href="{@docRoot}design/patterns/navigation-drawer.html">navigation drawer</a>
+             contents, including the ability to inflate menu items via a
+             <a href="{@docRoot}guide/topics/resources/menu-resource.html">Menu Resource</a>.
+          </li>
+          <li>Added {@link android.support.design.widget.CoordinatorLayout}, a general purpose
+            layout, used for building dependencies between
+            sibling views and allowing easy scrolling reactions between components via
+            {@link android.support.design.widget.CoordinatorLayout.Behavior}. Many of the Design
+            Library components rely on being a child of a
+            {@link android.support.design.widget.CoordinatorLayout}.
+          </li>
+          <li>Added {@link android.support.design.widget.AppBarLayout}, a container for a
+            {@link android.widget.Toolbar}
+            and other views (such as {@link android.support.design.widget.TabLayout}) for
+            reacting to scrolling events by scrolling off the screen, becoming visible in reaction
+            to a downward scroll, or collapsing/uncollapsing before scrolling off/onto the screen.
+          </li>
+          <li>Added {@link android.support.design.widget.CollapsingToolbarLayout} for controlling
+            how a {@link android.widget.Toolbar} collapses. A toolbar may collapse by:
+            pinning components to the top of the screen while it collapses, introducing
+            parallax scrolling of components such as an {@link android.widget.ImageView},
+            or adding a content scrim color when the view is partially collapsed.
+          </li>
+       </ul>
+      </dt>
+
+
+
+      <dt>Changes for <a href="features.html#v4">v4 support library:</a></dt>
+      <dd>
+         <ul>
+
+          <li>Added the
+{@link android.support.v4.view.accessibility.AccessibilityEventCompat#getContentChangeTypes getContentChangeTypes()}
+            and
+{@link android.support.v4.view.accessibility.AccessibilityEventCompat#setContentChangeTypes setContentChangeTypes()}
+            methods and related change type
+            fields to the
+            {@link android.support.v4.view.accessibility.AccessibilityEventCompat}
+            class for accessibility event handling.
+          </li>
+          <li>Added the
+{@link android.support.v4.media.session.PlaybackStateCompat#getActiveQueueItemId getActiveQueueItemId()},
+{@link android.support.v4.media.session.PlaybackStateCompat#getCustomActions getCustomActions()},
+            and
+            {@link android.support.v4.media.session.PlaybackStateCompat#getExtras getExtras()}
+            methods with related state fields to the
+            {@link android.support.v4.media.session.PlaybackStateCompat} class for
+            getting custom actions from the queue.
+          </li>
+          <li>Added the
+{@link android.support.v4.media.session.PlaybackStateCompat.Builder#addCustomAction addCustomAction()},
+{@link android.support.v4.media.session.PlaybackStateCompat.Builder#addCustomAction addCustomAction()},
+{@link android.support.v4.media.session.PlaybackStateCompat.Builder#setActiveQueueItemId setActiveQueueItemId()},
+            and
+            {@link android.support.v4.media.session.PlaybackStateCompat.Builder#setExtras setExtras()}
+            methods to the
+            {@link android.support.v4.media.session.PlaybackStateCompat.Builder} class for adding
+            adding custom actions to a playback state.
+          </li>
+          <li>Added the
+{@link android.support.v4.media.session.PlaybackStateCompat.CustomAction#fromCustomAction fromCustomAction()} and
+{@link android.support.v4.media.session.PlaybackStateCompat.CustomAction#getCustomAction getCustomAction()} methods
+            to the
+            {@link android.support.v4.media.session.PlaybackStateCompat.CustomAction} class
+            for getting custom actions from the queue.
+          </li>
+          <li>Added the {@link android.support.v4.view.ViewCompat#isAttachedToWindow isAttachedToWindow()},
+            {@link android.support.v4.view.ViewCompat#offsetLeftAndRight offsetLeftAndRight()}, and
+            {@link android.support.v4.view.ViewCompat#offsetTopAndBottom offsetTopAndBottom()}
+            methods to the {@link android.support.v4.view.ViewCompat} class for working with views.
+          </li>
+          <li>Added the {@link android.support.v4.view.ViewPager#addOnPageChangeListener addOnPageChangeListener()},
+            {@link android.support.v4.view.ViewPager#clearOnPageChangeListeners clearOnPageChangeListeners()}, and
+            {@link android.support.v4.view.ViewPager#removeOnPageChangeListener removeOnPageChangeListener()}
+            methods to the {@link android.support.v4.view.ViewPager} class for responding to page
+            changes.
+            <p>Deprecated the
+            {@link android.support.v4.view.ViewPager#setOnPageChangeListener setOnPageChangeListener()} method.</p>
+          </li>
+          <li>Added the
+{@link android.support.v4.view.ViewParentCompat#notifySubtreeAccessibilityStateChanged notifySubtreeAccessibilityStateChanged()} method to
+            the {@link android.support.v4.view.ViewParentCompat} class for notifying a view parent
+            that the accessibility state of one of its descendants has changed.
+          </li>
+          <li>Added the {@link android.support.v4.view.ViewPropertyAnimatorCompat#translationZ translationZ()},
+            {@link android.support.v4.view.ViewPropertyAnimatorCompat#translationZBy translationZBy()},
+            {@link android.support.v4.view.ViewPropertyAnimatorCompat#z z()}, and
+            {@link android.support.v4.view.ViewPropertyAnimatorCompat#zBy zBy()}
+            methods to the {@link android.support.v4.view.ViewPropertyAnimatorCompat} class for
+            adding animation.
+          </li>
+       </ul>
+      </dd>
+
+
+
+<dt>Changes for <a href="features.html#v7-appcompat">v7 appcompat library</a>:</dt>
+      <dd>
+<ul>
+          <li>Added the
+            {@link android.support.v7.app.AppCompatActivity#onWindowStartingSupportActionMode onWindowStartingSupportActionMode()}
+            method to the
+            {@link android.support.v7.app.AppCompatActivity},
+            {@link android.support.v7.app.AppCompatCallback}, and
+            {@link android.support.v7.app.AppCompatDialog} classes for handling action modes
+            started from the current window.
+          </li>
+
+          <li>Added the
+{@link android.support.v7.app.AppCompatDelegate#isHandleNativeActionModesEnabled isHandleNativeActionModesEnabled()} and
+{@link android.support.v7.app.AppCompatDelegate#setHandleNativeActionModesEnabled setHandleNativeActionModesEnabled()}
+           methods to the
+           {@link android.support.v7.app.AppCompatDelegate} class for handling native action modes.
+          </li>
+       </ul>
+      </dd>
+
+
+    </dl>
+
+  </div>
+</div> <!-- end of collapsible section -->
+
+
+
+
+
+<div class="toggle-content closed">
+  <p id="rev21"><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img" alt=""
+/>Android Support Library, revision 22.1.0</a> <em>(April 2015)</em>
+  </p>
+
+
+
+  <div class="toggle-content-toggleme">
+    <dl>
+
+
+  <div class="toggle-content-toggleme">
+    <dl>
+      <dt>Changes for <a href="features.html#annotations">annotations library:</a></dt>
+      <dd>
+        <ul>
+          <li>Added the Annotations library to provide support for enhanced code inspections.
+            Annotations are added as metadata tags that you attach to variables, parameters,
+            and return values to inspect method return values, passed parameters, and local
+            variables and fields.
+          </li>
+        </ul>
+      </dd>
+
+
       <dt>Changes for <a href="features.html#v4">v4 support library:</a></dt>
       <dd>
         <ul>
@@ -132,7 +306,7 @@
          <li>Updated the {@link android.support.v4.view.accessibility.AccessibilityNodeInfoCompat}
           class to add methods for errors, content invalidation and labels.
          </li>
-         <li>Added the following interpolation classses for animation:
+         <li>Added the following interpolation classes for animation:
            {@link android.support.v4.view.animation.FastOutLinearInInterpolator},
            {@link android.support.v4.view.animation.FastOutSlowInInterpolator},
            {@link android.support.v4.view.animation.LinearOutSlowInInterpolator},
@@ -245,7 +419,7 @@
       </dd>
 
 
-      <dt>Changes for v8 renderscript library:</dt>
+      <dt>Changes for <a href="features.html#v8-renderscript">v8 renderscript library</a>:</dt>
       <dd>
         <ul>
           <li>Added the {@link android.support.v8.renderscript.ScriptIntrinsicHistogram} class for
@@ -643,7 +817,7 @@
         </ul>
       </dd>
 
-      <dt>Changes for v8 renderscript library:</dt>
+      <dt>Changes for <a href="features.html#v8-renderscript">v8 renderscript library</a></dt>
       <dd>
         <ul>
           <li>Added error propagation for the RenderScript thunking layer.</li>
diff --git a/keystore/java/android/security/KeyStoreParameter.java b/keystore/java/android/security/KeyStoreParameter.java
index 174e03f..66c87ed 100644
--- a/keystore/java/android/security/KeyStoreParameter.java
+++ b/keystore/java/android/security/KeyStoreParameter.java
@@ -19,7 +19,6 @@
 import android.annotation.NonNull;
 import android.app.KeyguardManager;
 import android.content.Context;
-import android.security.keystore.KeyGenParameterSpec;
 import android.security.keystore.KeyProtection;
 
 import java.security.KeyPairGenerator;
@@ -49,28 +48,14 @@
  */
 @Deprecated
 public final class KeyStoreParameter implements ProtectionParameter {
-    private final Context mContext;
     private final int mFlags;
 
     private KeyStoreParameter(
-            Context context,
             int flags) {
-        if (context == null) {
-            throw new IllegalArgumentException("context == null");
-        }
-
-        mContext = context;
         mFlags = flags;
     }
 
     /**
-     * Gets the Android context used for operations with this instance.
-     */
-    public Context getContext() {
-        return mContext;
-    }
-
-    /**
      * @hide
      */
     public int getFlags() {
@@ -115,7 +100,6 @@
      */
     @Deprecated
     public final static class Builder {
-        private final Context mContext;
         private int mFlags;
 
         /**
@@ -128,7 +112,6 @@
             if (context == null) {
                 throw new NullPointerException("context == null");
             }
-            mContext = context;
         }
 
         /**
@@ -163,7 +146,6 @@
         @NonNull
         public KeyStoreParameter build() {
             return new KeyStoreParameter(
-                    mContext,
                     mFlags);
         }
     }
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 223bdf0..d9b40ae 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -439,13 +439,6 @@
             renderer.translate(0.0f, bitmap->height());
             renderer.scale(1.0f, -1.0f);
 
-            mat4 texTransform(layer->getTexTransform());
-
-            mat4 invert;
-            invert.translate(0.0f, 1.0f);
-            invert.scale(1.0f, -1.0f, 1.0f);
-            layer->getTexTransform().multiply(invert);
-
             if ((error = glGetError()) != GL_NO_ERROR) goto error;
 
             {
@@ -459,7 +452,6 @@
                 if ((error = glGetError()) != GL_NO_ERROR) goto error;
             }
 
-            layer->getTexTransform().load(texTransform);
             status = true;
         }
 
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index 0030a39..ee6d661 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -47,10 +47,11 @@
  * at which content is rendered or produced. For instance a sound at a media sample rate of 8000Hz
  * can be played on a device operating at a sample rate of 48000Hz; the sample rate conversion is
  * automatically handled by the platform, it will not play at 6x speed.
- * (more to be added...)
  *
  * <h4 id="encoding">Encoding</h4>
- * <p>To Be Added... stay tuned
+ * <p>For PCM audio, audio encoding is used to describe the bit representation of an audio data
+ * sample; for example, the size as 8 bit, 16 bit, and the representation as integer or float.
+ * <br>For compressed formats, audio encoding is used to describe the compression scheme being used.
  *
  * <h4 id="channelMask">Channel mask</h4>
  * <p>Channel masks are used in <code>AudioTrack</code> and <code>AudioRecord</code> to describe
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 6f28bf6..eec4960 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -23,6 +23,7 @@
 import android.graphics.Rect;
 import android.media.Image;
 import android.media.MediaCodecInfo;
+import android.media.MediaCodecInfo.CodecCapabilities;
 import android.media.MediaCodecList;
 import android.media.MediaCrypto;
 import android.media.MediaFormat;
@@ -42,204 +43,1307 @@
 import java.util.Map;
 
 /**
- * MediaCodec class can be used to access low-level media codec, i.e.
- * encoder/decoder components.
- *
- * <p>MediaCodec is generally used like this:
- * <pre>
- * MediaCodec codec = MediaCodec.createDecoderByType(type);
- * codec.configure(format, ...);
- * codec.start();
- *
- * // if API level <= 20, get input and output buffer arrays here
- * ByteBuffer[] inputBuffers = codec.getInputBuffers();
- * ByteBuffer[] outputBuffers = codec.getOutputBuffers();
- * for (;;) {
- *   int inputBufferIndex = codec.dequeueInputBuffer(timeoutUs);
- *   if (inputBufferIndex &gt;= 0) {
- *     // if API level >= 21, get input buffer here
- *     ByteBuffer inputBuffer = codec.getInputBuffer(inputBufferIndex);
- *     // fill inputBuffers[inputBufferIndex] with valid data
- *     ...
- *     codec.queueInputBuffer(inputBufferIndex, ...);
- *   }
- *
- *   int outputBufferIndex = codec.dequeueOutputBuffer(timeoutUs);
- *   if (outputBufferIndex &gt;= 0) {
- *     // if API level >= 21, get output buffer here
- *     ByteBuffer outputBuffer = codec.getOutputBuffer(outputBufferIndex);
- *     // outputBuffer is ready to be processed or rendered.
- *     ...
- *     codec.releaseOutputBuffer(outputBufferIndex, ...);
- *   } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
- *     // no needed to handle if API level >= 21 and using getOutputBuffer(int)
- *     outputBuffers = codec.getOutputBuffers();
- *   } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
- *     // Subsequent data will conform to new format.
- *     // can ignore if API level >= 21 and using getOutputFormat(outputBufferIndex)
- *     MediaFormat format = codec.getOutputFormat();
- *     ...
- *   }
- * }
- * codec.stop();
- * codec.release();
- * codec = null;
- * </pre>
- *
- * Each codec maintains a number of input and output buffers that are
- * referred to by index in API calls.
- * <p>
- * For API levels 20 and below:
- * The contents of these buffers are represented by the ByteBuffer[] arrays
- * accessible through {@link #getInputBuffers} and {@link #getOutputBuffers}.
- * <p>
- * After a successful call to {@link #start} the client "owns" neither
- * input nor output buffers, subsequent calls to {@link #dequeueInputBuffer}
- * and {@link #dequeueOutputBuffer} then transfer ownership from the codec
- * to the client.<p>
- * The client is not required to resubmit/release buffers immediately
- * to the codec, the sample code above simply does this for simplicity's sake.
- * Nonetheless, it is possible that a codec may hold off on generating
- * output buffers until all outstanding buffers have been
- * released/resubmitted.
- * <p>
- * Once the client has an input buffer available it can fill it with data
- * and submit it it to the codec via a call to {@link #queueInputBuffer}.
- * Do not submit multiple input buffers with the same timestamp (unless
- * it is codec-specific data marked as such using the flag
- * {@link #BUFFER_FLAG_CODEC_CONFIG}).
- * <p>
- * The codec in turn will return an output buffer to the client in response
- * to {@link #dequeueOutputBuffer}. After the output buffer has been processed
- * a call to {@link #releaseOutputBuffer} will return it to the codec.
- * If a video surface has been provided in the call to {@link #configure},
- * {@link #releaseOutputBuffer} optionally allows rendering of the buffer
- * to the surface.<p>
- *
- * Input buffers (for decoders) and Output buffers (for encoders) contain
- * encoded data according to the format's type. For video types this data
- * is all the encoded data representing a single moment in time, for audio
- * data this is slightly relaxed in that a buffer may contain multiple
- * encoded frames of audio. In either case, buffers do not start and end on
- * arbitrary byte boundaries, this is not a stream of bytes, it's a stream
- * of access units.<p>
- *
- * Most formats also require the actual data to be prefixed by a number
- * of buffers containing setup data, or codec specific data, i.e. the
- * first few buffers submitted to the codec object after starting it must
- * be codec specific data marked as such using the flag {@link #BUFFER_FLAG_CODEC_CONFIG}
- * in a call to {@link #queueInputBuffer}.
- * <p>
- * Codec specific data included in the format passed to {@link #configure}
- * (in ByteBuffer entries with keys "csd-0", "csd-1", ...) is automatically
- * submitted to the codec, this data MUST NOT be submitted explicitly by the
- * client.
- * <p>
- * Once the client reaches the end of the input data it signals the end of
- * the input stream by specifying a flag of {@link #BUFFER_FLAG_END_OF_STREAM} in the call to
- * {@link #queueInputBuffer}. The codec will continue to return output buffers
- * until it eventually signals the end of the output stream by specifying
- * the same flag ({@link #BUFFER_FLAG_END_OF_STREAM}) on the BufferInfo returned in
- * {@link #dequeueOutputBuffer}.  Do not submit additional input buffers after
- * signaling the end of the input stream, unless the codec has been flushed,
- * or stopped and restarted.
- * <p>
- * <h3>Seeking &amp; Adaptive Playback Support</h3>
- *
- * You can check if a decoder supports adaptive playback via {@link
- * MediaCodecInfo.CodecCapabilities#isFeatureSupported}.  Adaptive playback
- * is only supported if you configure the codec to decode onto a {@link
- * android.view.Surface}.
- *
- * <h4>For decoders that do not support adaptive playback (including
- * when not decoding onto a Surface)</h4>
- *
- * In order to start decoding data that's not adjacent to previously submitted
- * data (i.e. after a seek) <em>one must</em> {@link #flush} the decoder.
- * Any input or output buffers the client may own at the point of the flush are
- * immediately revoked, i.e. after a call to {@link #flush} the client does not
- * own any buffers anymore.
- * <p>
- * It is important that the input data after a flush starts at a suitable
- * stream boundary.  The first frame must be able to be decoded completely on
- * its own (for most codecs this means an I-frame), and that no frames should
- * refer to frames before that first new frame.
- * Note that the format of the data submitted after a flush must not change,
- * flush does not support format discontinuities,
- * for this a full {@link #stop}, {@link #configure configure()}, {@link #start}
- * cycle is necessary.
- *
- * <h4>For decoders that support adaptive playback</h4>
- *
- * In order to start decoding data that's not adjacent to previously submitted
- * data (i.e. after a seek) it is <em>not necessary</em> to {@link #flush} the
- * decoder.
- * <p>
- * It is still important that the input data after the discontinuity starts
- * at a suitable stream boundary (e.g. I-frame), and that no new frames refer
- * to frames before the first frame of the new input data segment.
- * <p>
- * For some video formats it is also possible to change the picture size
- * mid-stream.  To do this for H.264, the new Sequence Parameter Set (SPS) and
- * Picture Parameter Set (PPS) values must be packaged together with an
- * Instantaneous Decoder Refresh (IDR) frame in a single buffer, which then
- * can be enqueued as a regular input buffer.
- * The client will receive an {@link #INFO_OUTPUT_FORMAT_CHANGED} return
- * value from {@link #dequeueOutputBuffer dequeueOutputBuffer()} or
- * {@link Callback#onOutputBufferAvailable onOutputBufferAvailable()}
- * just after the picture-size change takes place and before any
- * frames with the new size have been returned.
- * <p>
- * Be careful when calling {@link #flush} shortly after you have changed
- * the picture size.  If you have not received confirmation of the picture
- * size change, you will need to repeat the request for the new picture size.
- * E.g. for H.264 you will need to prepend the PPS/SPS to the new IDR
- * frame to ensure that the codec receives the picture size change request.
- *
- * <h3>States and error handling</h3>
- *
- * <p> During its life, a codec conceptually exists in one of the following states:
- * Initialized, Configured, Executing, Error, Uninitialized, (omitting transitory states
- * between them). When created by one of the factory methods,
- * the codec is in the Initialized state; {@link #configure} brings it to the
- * Configured state; {@link #start} brings it to the Executing state.
- * In the Executing state, decoding or encoding occurs through the buffer queue
- * manipulation described above. The method {@link #stop}
- * returns the codec to the Initialized state, whereupon it may be configured again,
- * and {@link #release} brings the codec to the terminal Uninitialized state.  When
- * a codec error occurs, the codec moves to the Error state.  Use {@link #reset} to
- * bring the codec back to the Initialized state, or {@link #release} to move it
- * to the Uninitialized state.
- *
- * <p> The factory methods
- * {@link #createByCodecName},
- * {@link #createDecoderByType},
- * and {@link #createEncoderByType}
- * throw {@link java.io.IOException} on failure which
- * the caller must catch or declare to pass up.
- * MediaCodec methods throw {@link java.lang.IllegalStateException}
- * when the method is called from a codec state that does not allow it;
- * this is typically due to incorrect application API usage.
- * Methods involving secure buffers may throw
- * {@link MediaCodec.CryptoException#MediaCodec.CryptoException}, which
- * has further error information obtainable from {@link MediaCodec.CryptoException#getErrorCode}.
- *
- * <p> Internal codec errors result in a {@link MediaCodec.CodecException},
- * which may be due to media content corruption, hardware failure, resource exhaustion,
- * and so forth, even when the application is correctly using the API.
- * The recommended action when receiving a {@link MediaCodec.CodecException} can be determined by
- * calling {@link MediaCodec.CodecException#isRecoverable} and
- * {@link MediaCodec.CodecException#isTransient}.
- * If {@link MediaCodec.CodecException#isRecoverable} returns true,
- * then a {@link #stop}, {@link #configure}, and {@link #start} can be performed to recover.
- * If {@link MediaCodec.CodecException#isTransient} returns true,
- * then resources are temporarily unavailable and the method may be retried at a later time.
- * If both {@link MediaCodec.CodecException#isRecoverable}
- * and {@link MediaCodec.CodecException#isTransient} return false,
- * then the {@link MediaCodec.CodecException} is fatal and the codec must be
- * {@link #reset reset} or {@link #release released}.
- * Both {@link MediaCodec.CodecException#isRecoverable} and
- * {@link MediaCodec.CodecException#isTransient} do not return true at the same time.
+ MediaCodec class can be used to access low-level media codecs, i.e. encoder/decoder components.
+ It is part of the Android low-level multimedia support infrastructure (normally used together
+ with {@link MediaExtractor}, {@link MediaSync}, {@link MediaMuxer}, {@link MediaCrypto},
+ {@link MediaDrm}, {@link Image}, {@link Surface}, and {@link AudioTrack}.)
+ <p>
+ <center><object style="width: 540px; height: 205px;" type="image/svg+xml"
+   data="../../../images/media/mediacodec_buffers.svg"><img
+   src="../../../images/media/mediacodec_buffers.png" style="width: 540px; height: 205px"
+   alt="MediaCodec buffer flow diagram"></object></center>
+ <p>
+ In broad terms, a codec processes input data to generate output data. It processes data
+ asynchronously and uses a set of input and output buffers. At a simplistic level, you request
+ (or receive) an empty input buffer, fill it up with data and send it to the codec for
+ processing. The codec uses up the data and transforms it into one of its empty output buffers.
+ Finally, you request (or receive) a filled output buffer, consume its contents and release it
+ back to the codec.
+
+ <h3>Data Types</h3>
+ <p>
+ Codecs operate on three kinds of data: compressed data, raw audio data and raw video data.
+ All three kinds of data can be processed using {@link ByteBuffer ByteBuffers}, but you should use
+ a {@link Surface} for raw video data to improve codec performance. Surface uses native video
+ buffers without mapping or copying them to ByteBuffers; thus, it is much more efficient.
+ You normally cannot access the raw video data when using a Surface, but you can use the
+ {@link ImageReader} class to access unsecured decoded (raw) video frames. This may still be more
+ efficient than using ByteBuffers, as some native buffers may be mapped into {@linkplain
+ ByteBuffer#isDirect direct} ByteBuffers. When using ByteBuffer mode, you can access raw video
+ frames using the {@link Image} class and {@link #getInputImage getInput}/{@link #getOutputImage
+ OutputImage(int)}.
+
+ <h4>Compressed Buffers</h4>
+ <p>
+ Input buffers (for decoders) and output buffers (for encoders) contain compressed data according
+ to the {@linkplain MediaFormat#KEY_MIME format's type}. For video types this is a single
+ compressed video frame. For audio data this is normally a single access unit (an encoded audio
+ segment typically containing a few milliseconds of audio as dictated by the format type), but
+ this requirement is slightly relaxed in that a buffer may contain multiple encoded access units
+ of audio. In either case, buffers do not start or end on arbitrary byte boundaries, but rather on
+ frame/access unit boundaries.
+
+ <h4>Raw Audio Buffers</h4>
+ <p>
+ Raw audio buffers contain entire frames of PCM audio data, which is one sample for each channel
+ in channel order. Each sample is a {@linkplain AudioFormat#ENCODING_PCM_16BIT 16-bit signed
+ integer in native byte order}.
+
+ <pre class=prettyprint>
+ short[] getSamplesForChannel(MediaCodec codec, int bufferId, int channelIx) {
+   ByteBuffer outputBuffer = codec.getOutputBuffer(bufferId);
+   MediaFormat format = codec.getOutputFormat(bufferId);
+   ShortBuffer samples = outputBuffer.order(ByteOrder.nativeOrder()).asShortBuffer();
+   int numChannels = formet.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
+   if (channelIx &lt; 0 || channelIx &gt;= numChannels) {
+     return null;
+   }
+   short[] res = new short[samples.remaining() / numChannels];
+   for (int i = 0; i &lt; res.length; ++i) {
+     res[i] = samples.get(i * numChannels + channelIx);
+   }
+   return res;
+ }</pre>
+
+ <h4>Raw Video Buffers</h4>
+ <p>
+ In ByteBuffer mode video buffers are laid out according to their {@linkplain
+ MediaFormat#KEY_COLOR_FORMAT color format}. You can get the supported color formats as an array
+ from {@link #getCodecInfo}{@code .}{@link MediaCodecInfo#getCapabilitiesForType
+ getCapabilitiesForType(&hellip;)}{@code .}{@link CodecCapabilities#colorFormats colorFormats}.
+ Video codecs may support three kinds of color formats:
+ <ul>
+ <li><strong>native raw video format:</strong> This is marked by {@link
+ CodecCapabilities#COLOR_FormatSurface} and it can be used with an input or output Surface.</li>
+ <li><strong>flexible YUV buffers</strong> (such as {@link
+ CodecCapabilities#COLOR_FormatYUV420Flexible}): These can be used with an input/output Surface,
+ as well as in ByteBuffer mode, by using {@link #getInputImage getInput}/{@link #getOutputImage
+ OutputImage(int)}.</li>
+ <li><strong>other, specific formats:</strong> These are normally only supported in ByteBuffer
+ mode. Some color formats are vendor specific. Others are defined in {@link CodecCapabilities}.
+ For color formats that are equivalent to a flexible format, you can still use {@link
+ #getInputImage getInput}/{@link #getOutputImage OutputImage(int)}.</li>
+ </ul>
+ <p>
+ All video codecs support flexible YUV 4:2:0 buffers since {@link
+ android.os.Build.VERSION_CODES#LOLLIPOP_MR1}.
+
+ <h3>States</h3>
+ <p>
+ During its life a codec conceptually exists in one of three states: Stopped, Executing or
+ Released. The Stopped collective state is actually the conglomeration of three states:
+ Uninitialized, Configured and Error, whereas the Executing state conceptually progresses through
+ three sub-states: Flushed, Running and End-of-Stream.
+ <p>
+ <center><object style="width: 516px; height: 353px;" type="image/svg+xml"
+   data="../../../images/media/mediacodec_states.svg"><img
+   src="../../../images/media/mediacodec_states.png" style="width: 519px; height: 356px"
+   alt="MediaCodec state diagram"></object></center>
+ <p>
+ When you create a codec using one of the factory methods, the codec is in the Uninitialized
+ state. First, you need to configure it via {@link #configure configure(&hellip;)}, which brings
+ it to the Configured state, then call {@link #start} to move it to the Executing state. In this
+ state you can process data through the buffer queue manipulation described above.
+ <p>
+ The Executing state has three sub-states: Flushed, Running and End-of-Stream. Immediately after
+ {@link #start} the codec is in the Flushed sub-state, where it holds all the buffers. As soon
+ as the first input buffer is dequeued, the codec moves to the Running sub-state, where it spends
+ most of its life. When you queue an input buffer with the {@linkplain #BUFFER_FLAG_END_OF_STREAM
+ end-of-stream marker}, the codec transitions to the End-of-Stream sub-state. In this state the
+ codec no longer accepts further input buffers, but still generates output buffers until the
+ end-of-stream is reached on the output. You can move back to the Flushed sub-state at any time
+ while in the Executing state using {@link #flush}.
+ <p>
+ Call {@link #stop} to return the codec to the Uninitialized state, whereupon it may be configured
+ again. When you are done using a codec, you must release it by calling {@link #release}.
+ <p>
+ On rare occasions the codec may encounter an error and move to the Error state. This is
+ communicated using an invalid return value from a queuing operation, or sometimes via an
+ exception. Call {@link #reset} to make the codec usable again. You can call it from any state to
+ move the codec back to the Uninitialized state. Otherwise, call {@link #release} to move to the
+ terminal Released state.
+
+ <h3>Creation</h3>
+ <p>
+ Use {@link MediaCodecList} to create a MediaCodec for a specific {@link MediaFormat}. When
+ decoding a file or a stream, you can get the desired format from {@link
+ MediaExtractor#getTrackFormat MediaExtractor.getTrackFormat}. Inject any specific features that
+ you want to add using {@link MediaFormat#setFeatureEnabled MediaFormat.setFeatureEnabled}, then
+ call {@link MediaCodecList#findDecoderForFormat MediaCodecList.findDecoderForFormat} to get the
+ name of a codec that can handle that specific media format. Finally, create the codec using
+ {@link #createByCodecName}.
+ <p class=note>
+ <strong>Note:</strong> On {@link android.os.Build.VERSION_CODES#LOLLIPOP}, the format to
+ {@code MediaCodecList.findDecoder}/{@code EncoderForFormat} must not contain a {@linkplain
+ MediaFormat#KEY_FRAME_RATE frame rate}. Use
+ <code class=prettyprint>format.setString(MediaFormat.KEY_FRAME_RATE, null)</code>
+ to clear any existing frame rate setting in the format.
+ <p>
+ You can also create the preferred codec for a specific MIME type using {@link
+ #createDecoderByType createDecoder}/{@link #createEncoderByType EncoderByType(String)}.
+ This, however, cannot be used to inject features, and may create a codec that cannot handle the
+ specific desired media format.
+
+ <h4>Creating secure decoders</h4>
+ <p>
+ On versions {@link android.os.Build.VERSION_CODES#KITKAT_WATCH} and earlier, secure codecs might
+ not be listed in {@link MediaCodecList}, but may still be available on the system. Secure codecs
+ that exist can be instantiated by name only, by appending {@code ".secure"} to the name of a
+ regular codec (the name of all secure codecs must end in {@code ".secure"}.) {@link
+ #createByCodecName} will throw an {@code IOException} if the codec is not present on the system.
+ <p>
+ From {@link android.os.Build.VERSION_CODES#LOLLIPOP} onwards, you should use the {@link
+ CodecCapabilities#FEATURE_SecurePlayback} feature in the media format to create a secure decoder.
+
+ <h3>Initialization</h3>
+ <p>
+ After creating the codec, you can set a callback using {@link #setCallback setCallback} if you
+ want to process data asynchronously. Then, {@linkplain #configure configure} the codec using the
+ specific media format. This is when you can specify the output {@link Surface} for video
+ producers &ndash; codecs that generate raw video data (e.g. video decoders). This is also when
+ you can set the decryption parameters for secure codecs (see {@link MediaCrypto}). Finally, since
+ some codecs can operate in multiple modes, you must specify whether you want it to work as a
+ decoder or an encoder.
+ <p>
+ Since {@link android.os.Build.VERSION_CODES#LOLLIPOP}, you can query the resulting input and
+ output format in the Configured state. You can use this to verify the resulting configuration,
+ e.g. color formats, before starting the codec.
+ <p>
+ If you want to process raw input video buffers natively with a video consumer &ndash; a codec
+ that processes raw video input, such as a video encoder &ndash; create a destination Surface for
+ your input data using {@link #createInputSurface} after configuration. Alternately, set up the
+ codec to use a previously created {@linkplain #createPersistentInputSurface persistent input
+ surface} by calling {@link #setInputSurface}.
+
+ <h4 id=CSD><a name="CSD"></a>Codec-specific Data</h4>
+ <p>
+ Some formats, notably AAC audio and MPEG4, H.264 and H.265 video formats require the actual data
+ to be prefixed by a number of buffers containing setup data, or codec specific data. When
+ processing such compressed formats, this data must be submitted to the codec after {@link
+ #start} and before any frame data. Such data must be marked using the flag {@link
+ #BUFFER_FLAG_CODEC_CONFIG} in a call to {@link #queueInputBuffer queueInputBuffer}.
+ <p>
+ Codec-specific data can also be included in the format passed to {@link #configure configure} in
+ ByteBuffer entries with keys "csd-0", "csd-1", etc. These keys are always included in the track
+ {@link MediaFormat} obtained from the {@link MediaExtractor#getTrackFormat MediaExtractor}.
+ Codec-specific data in the format is automatically submitted to the codec upon {@link #start};
+ you <strong>MUST NOT</strong> submit this data explicitly. If the format did not contain codec
+ specific data, you can choose to submit it using the specified number of buffers in the correct
+ order, according to the format requirements. Alternately, you can concatenate all codec-specific
+ data and submit it as a single codec-config buffer.
+ <p>
+ Android uses the following codec-specific data buffers. These are also required to be set in
+ the track format for proper {@link MediaMuxer} track configuration. Each parameter set and
+ codec-specific-data must start with a start code of {@code "\x00\x00\x00\x01"}.
+ <p>
+ <style>td.NA { background: #ccc; } .mid > tr > td { vertical-align: middle; }</style>
+ <table>
+  <thead>
+   <th>Format</th>
+   <th>CSD buffer #0</th>
+   <th>CSD buffer #1</th>
+  </thead>
+  <tbody class=mid>
+   <tr>
+    <td>AAC</td>
+    <td>Decoder-specific information from ESDS</td>
+    <td class=NA>Not Used</td>
+   </tr>
+   <tr>
+    <td>MPEG-4</td>
+    <td>Decoder-specific information from ESDS</td>
+    <td class=NA>Not Used</td>
+   </tr>
+   <tr>
+    <td>H.264 AVC</td>
+    <td>SPS (Sequence Parameter Sets)</td>
+    <td>PPS (Picture Parameter Sets)</td>
+   </tr>
+   <tr>
+    <td>H.265 HEVC</td>
+    <td>VPS (Video Parameter Sets) +<br>
+     SPS (Sequence Parameter Sets) +<br>
+     PPS (Picture Parameter Sets)</td>
+    <td class=NA>Not Used</td>
+   </tr>
+  </tbody>
+ </table>
+
+ <p class=note>
+ <strong>Note:</strong> care must be taken if the codec is flushed immediately or shortly
+ after start, before any output buffer or output format change has been returned, as the codec
+ specific data may be lost during the flush. You must resubmit the data using buffers marked with
+ {@link #BUFFER_FLAG_CODEC_CONFIG} after such flush to ensure proper codec operation.
+ <p>
+ Encoders (or codecs that generate compressed data) will create and return the codec specific data
+ before any valid output buffer in output buffers marked with the {@linkplain
+ #BUFFER_FLAG_CODEC_CONFIG codec-config flag}. Buffers containing codec-specific-data have no
+ meaningful timestamps.
+
+ <h3>Data Processing</h3>
+ <p>
+ Each codec maintains a set of input and output buffers that are referred to by a buffer-ID in
+ API calls. After a successful call to {@link #start} the client "owns" neither input nor output
+ buffers. In synchronous mode, call {@link #dequeueInputBuffer dequeueInput}/{@link
+ #dequeueOutputBuffer OutputBuffer(&hellip;)} to obtain (get ownership of) an input or output
+ buffer from the codec. In asynchronous mode, you will automatically receive available buffers via
+ the {@link Callback#onInputBufferAvailable MediaCodec.Callback.onInput}/{@link
+ Callback#onOutputBufferAvailable OutputBufferAvailable(&hellip;)} callbacks.
+ <p>
+ Upon obtaining an input buffer, fill it with data and submit it to the codec using {@link
+ #queueInputBuffer queueInputBuffer} &ndash; or {@link #queueSecureInputBuffer
+ queueSecureInputBuffer} if using decryption. Do not submit multiple input buffers with the same
+ timestamp (unless it is <a href="#CSD">codec-specific data</a> marked as such).
+ <p>
+ The codec in turn will return a read-only output buffer via the {@link
+ Callback#onOutputBufferAvailable onOutputBufferAvailable} callback in asynchronous mode, or in
+ response to a {@link #dequeueOutputBuffer dequeuOutputBuffer} call in synchronous mode. After the
+ output buffer has been processed, call one of the {@link #releaseOutputBuffer
+ releaseOutputBuffer} methods to return the buffer to the codec.
+ <p>
+ While you are not required to resubmit/release buffers immediately to the codec, holding onto
+ input and/or output buffers may stall the codec, and this behavior is device dependent. E.g. it
+ is possible that a codec may hold off on generating output buffers until all outstanding buffers
+ have been released/resubmitted. Therefore, try to hold onto to available buffers as little as
+ possible.
+ <p>
+ Depending on the API version, you can process data in three ways:
+ <table>
+  <thead>
+   <tr>
+    <th>Processing Mode</th>
+    <th>API version <= 20<br>Jelly Bean/KitKat</th>
+    <th>API version >= 21<br>Lollipop and later</th>
+   </tr>
+  </thead>
+  <tbody>
+   <tr>
+    <td>Synchronous API using buffer arrays</td>
+    <td>Supported</td>
+    <td>Deprecated</td>
+   </tr>
+   <tr>
+    <td>Synchronous API using buffers</td>
+    <td class=NA>Not Available</td>
+    <td>Supported</td>
+   </tr>
+   <tr>
+    <td>Asynchronous API using buffers</td>
+    <td class=NA>Not Available</td>
+    <td>Supported</td>
+   </tr>
+  </tbody>
+ </table>
+
+ <h4>Asynchronous Processing using Buffers</h4>
+ <p>
+ Since {@link android.os.Build.VERSION_CODES#LOLLIPOP}, the preferred method is to process data
+ asynchronously by setting a callback before calling {@link #configure configure}. Asynchronous
+ mode changes the state transitions slightly, because you must call {@link #start} after {@link
+ #flush} to transition the codec to the Running sub-state and start receiving input buffers.
+ Similarly, upon an initial call to {@code start} the codec will move directly to the Running
+ sub-state and start passing available input buffers via the callback.
+ <p>
+ <center><object style="width: 516px; height: 353px;" type="image/svg+xml"
+   data="../../../images/media/mediacodec_async_states.svg"><img
+   src="../../../images/media/mediacodec_async_states.png" style="width: 516px; height: 353px"
+   alt="MediaCodec state diagram for asynchronous operation"></object></center>
+ <p>
+ MediaCodec is typically used like this in asynchronous mode:
+ <pre class=prettyprint>
+ MediaCodec codec = MediaCodec.createCodecByName(name);
+ MediaFormat mOutputFormat; // member variable
+ codec.setCallback(new MediaCodec.Callback() {
+   {@literal @Override}
+   void onInputBufferAvailable(MediaCodec mc, int inputBufferId) {
+     ByteBuffer inputBuffer = codec.getInputBuffer(inputBufferId);
+     // fill inputBuffer with valid data
+     &hellip;
+     codec.queueInputBuffer(inputBufferId, &hellip;);
+   }
+
+   {@literal @Override}
+   void onOutputBufferAvailable(MediaCodec mc, int outputBufferId, &hellip;) {
+     ByteBuffer outputBuffer = codec.getOutputBuffer(outputBufferId);
+     MediaFormat bufferFormat = codec.getOutputFormat(outputBufferId); // option A
+     // bufferFormat is equivalent to mOutputFormat
+     // outputBuffer is ready to be processed or rendered.
+     &hellip;
+     codec.releaseOutputBuffer(outputBufferId, &hellip;);
+   }
+
+   {@literal @Override}
+   void onOutputFormatChanged(MediaCodec mc, MediaFormat format) {
+     // Subsequent data will conform to new format.
+     // Can ignore if using getOutputFormat(outputBufferId)
+     mOutputFormat = format; // option B
+   }
+
+   {@literal @Override}
+   void onError(&hellip;) {
+     &hellip;
+   }
+ });
+ codec.configure(format, &hellip;);
+ mOutputFormat = codec.getOutputFormat(); // option B
+ codec.start();
+ // wait for processing to complete
+ codec.stop();
+ codec.release();</pre>
+
+ <h4>Synchronous Processing using Buffers</h4>
+ <p>
+ Since {@link android.os.Build.VERSION_CODES#LOLLIPOP}, you should retrieve input and output
+ buffers using {@link #getInputBuffer getInput}/{@link #getOutputBuffer OutputBuffer(int)} and/or
+ {@link #getInputImage getInput}/{@link #getOutputImage OutputImage(int)} even when using the
+ codec in synchronous mode. This allows certain optimizations by the framework, e.g. when
+ processing dynamic content. This optimization is disabled if you call {@link #getInputBuffers
+ getInput}/{@link #getOutputBuffers OutputBuffers()}.
+
+ <p class=note>
+ <strong>Note:</strong> do not mix the methods of using buffers and buffer arrays at the same
+ time. Specifically, only call {@code getInput}/{@code OutputBuffers} directly after {@link
+ #start} or after having dequeued an output buffer ID with the value of {@link
+ #INFO_OUTPUT_FORMAT_CHANGED}.
+ <p>
+ MediaCodec is typically used like this in synchronous mode:
+ <pre>
+ MediaCodec codec = MediaCodec.createCodecByName(name);
+ codec.configure(format, &hellip;);
+ MediaFormat outputFormat = codec.getOutputFormat(); // option B
+ codec.start();
+ for (;;) {
+   int inputBufferId = codec.dequeueInputBuffer(timeoutUs);
+   if (inputBufferId &gt;= 0) {
+     ByteBuffer inputBuffer = codec.getInputBuffer(&hellip;);
+     // fill inputBuffer with valid data
+     &hellip;
+     codec.queueInputBuffer(inputBufferId, &hellip;);
+   }
+   int outputBufferId = codec.dequeueOutputBuffer(&hellip;);
+   if (outputBufferId &gt;= 0) {
+     ByteBuffer outputBuffer = codec.getOutputBuffer(outputBufferId);
+     MediaFormat bufferFormat = codec.getOutputFormat(outputBufferId); // option A
+     // bufferFormat is identical to outputFormat
+     // outputBuffer is ready to be processed or rendered.
+     &hellip;
+     codec.releaseOutputBuffer(outputBufferId, &hellip;);
+   } else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+     // Subsequent data will conform to new format.
+     // Can ignore if using getOutputFormat(outputBufferId)
+     outputFormat = codec.getOutputFormat(); // option B
+   }
+ }
+ codec.stop();
+ codec.release();</pre>
+
+ <h4>Synchronous Processing using Buffer Arrays (deprecated)</h4>
+ <p>
+ In versions {@link android.os.Build.VERSION_CODES#KITKAT_WATCH} and before, the set of input and
+ output buffers are represented by the {@code ByteBuffer[]} arrays. After a successful call to
+ {@link #start}, retrieve the buffer arrays using {@link #getInputBuffers getInput}/{@link
+ #getOutputBuffers OutputBuffers()}. Use the buffer ID-s as indices into these arrays (when
+ non-negative), as demonstrated in the sample below. Note that there is no inherent correlation
+ between the size of the arrays and the number of input and output buffers used by the system,
+ although the array size provides an upper bound.
+ <pre>
+ MediaCodec codec = MediaCodec.createCodecByName(name);
+ codec.configure(format, &hellip;);
+ codec.start();
+ ByteBuffer[] inputBuffers = codec.getInputBuffers();
+ ByteBuffer[] outputBuffers = codec.getOutputBuffers();
+ for (;;) {
+   int inputBufferId = codec.dequeueInputBuffer(&hellip;);
+   if (inputBufferId &gt;= 0) {
+     // fill inputBuffers[inputBufferId] with valid data
+     &hellip;
+     codec.queueInputBuffer(inputBufferId, &hellip;);
+   }
+   int outputBufferId = codec.dequeueOutputBuffer(&hellip;);
+   if (outputBufferId &gt;= 0) {
+     // outputBuffers[outputBufferId] is ready to be processed or rendered.
+     &hellip;
+     codec.releaseOutputBuffer(outputBufferId, &hellip;);
+   } else if (outputBufferId == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
+     outputBuffers = codec.getOutputBuffers();
+   } else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+     // Subsequent data will conform to new format.
+     MediaFormat format = codec.getOutputFormat();
+   }
+ }
+ codec.stop();
+ codec.release();</pre>
+
+ <h4>End-of-stream Handling</h4>
+ <p>
+ When you reach the end of the input data, you must signal it to the codec by specifying the
+ {@link #BUFFER_FLAG_END_OF_STREAM} flag in the call to {@link #queueInputBuffer
+ queueInputBuffer}. You can do this on the last valid input buffer, or by submitting an additional
+ empty input buffer with the end-of-stream flag set. If using an empty buffer, the timestamp will
+ be ignored.
+ <p>
+ The codec will continue to return output buffers until it eventually signals the end of the
+ output stream by specifying the same end-of-stream flag in the {@link BufferInfo} set in {@link
+ #dequeueOutputBuffer dequeueOutputBuffer} or returned via {@link Callback#onOutputBufferAvailable
+ onOutputBufferAvailable}. This can be set on the last valid output buffer, or on an empty buffer
+ after the last valid output buffer. The timestamp of such empty buffer should be ignored.
+ <p>
+ Do not submit additional input buffers after signaling the end of the input stream, unless the
+ codec has been flushed, or stopped and restarted.
+
+ <h4>Using an Output Surface</h4>
+ <p>
+ The data processing is nearly identical to the ByteBuffer mode when using an output {@link
+ Surface}; however, the output buffers will not be accessible, and are represented as {@code null}
+ values. E.g. {@link #getOutputBuffer getOutputBuffer}/{@link #getOutputImage Image(int)} will
+ return {@code null} and {@link #getOutputBuffers} will return an array containing only {@code
+ null}-s.
+ <p>
+ When using an output Surface, you can select whether or not to render each output buffer on the
+ surface. You have three choices:
+ <ul>
+ <li><strong>Do not render the buffer:</strong> Call {@link #releaseOutputBuffer(int, boolean)
+ releaseOutputBuffer(bufferId, false)}.</li>
+ <li><strong>Render the buffer with the default timestamp:</strong> Call {@link
+ #releaseOutputBuffer(int, boolean) releaseOutputBuffer(bufferId, true)}.</li>
+ <li><strong>Render the buffer with a specific timestamp:</strong> Call {@link
+ #releaseOutputBuffer(int, long) releaseOutputBuffer(bufferId, timestamp)}.</li>
+ </ul>
+ <p>
+ Since {@link android.os.Build.VERSION_CODES#MNC}, the default timestamp is the {@linkplain
+ BufferInfo#presentationTimeUs presentation timestamp} of the buffer (converted to nanoseconds).
+ It was not defined prior to that.
+ <p>
+ Also since {@link android.os.Build.VERSION_CODES#MNC}, you can change the output Surface
+ dynamically using {@link #setOutputSurface setOutputSurface}.
+
+ <h4>Using an Input Surface</h4>
+ <p>
+ When using an input Surface, there are no accessible input buffers, as buffers are automatically
+ passed from the input surface to the codec. Calling {@link #dequeueInputBuffer
+ dequeueInputBuffer} will throw an {@code IllegalStateException}, and {@link #getInputBuffers}
+ returns a bogus {@code ByteBuffer[]} array that <strong>MUST NOT</strong> be written into.
+ <p>
+ Call {@link #signalEndOfInputStream} to signal end-of-stream. The input surface will stop
+ submitting data to the codec immediately after this call.
+ <p>
+
+ <h3>Seeking &amp; Adaptive Playback Support</h3>
+ <p>
+ Video decoders (and in general codecs that consume compressed video data) behave differently
+ regarding seek and format change whether or not they support and are configured for adaptive
+ playback. You can check if a decoder supports {@linkplain
+ CodecCapabilities#FEATURE_AdaptivePlayback adaptive playback} via {@link
+ CodecCapabilities#isFeatureSupported CodecCapabilities.isFeatureSupported(String)}. Adaptive
+ playback support for video decoders is only activated if you configure the codec to decode onto a
+ {@link Surface}.
+
+ <h4 id=KeyFrames><a name="KeyFrames"></a>Stream Boundary and Key Frames</h4>
+ <p>
+ It is important that the input data after {@link #start} or {@link #flush} starts at a suitable
+ stream boundary: the first frame must a key frame. A <em>key frame</em> can be decoded
+ completely on its own (for most codecs this means an I-frame), and no frames that are to be
+ displayed after a key frame refer to frames before the key frame.
+ <p>
+ The following table summarizes suitable key frames for various video formats.
+ <table>
+  <thead>
+   <tr>
+    <th>Format</th>
+    <th>Suitable key frame</th>
+   </tr>
+  </thead>
+  <tbody class=mid>
+   <tr>
+    <td>VP9/VP8</td>
+    <td>a suitable intraframe where no subsequent frames refer to frames prior to this frame.<br>
+      <i>(There is no specific name for such key frame.)</i></td>
+   </tr>
+   <tr>
+    <td>H.265 HEVC</td>
+    <td>IDR or CRA</td>
+   </tr>
+   <tr>
+    <td>H.264 AVC</td>
+    <td>IDR</td>
+   </tr>
+   <tr>
+    <td>MPEG-4<br>H.263<br>MPEG-2</td>
+    <td>a suitable I-frame where no subsequent frames refer to frames prior to this frame.<br>
+      <i>(There is no specific name for such key frame.)</td>
+   </tr>
+  </tbody>
+ </table>
+
+ <h4>For decoders that do not support adaptive playback (including when not decoding onto a
+ Surface)</h4>
+ <p>
+ In order to start decoding data that is not adjacent to previously submitted data (i.e. after a
+ seek) you <strong>MUST</strong> flush the decoder. Since all output buffers are immediately
+ revoked at the point of the flush, you may want to first signal then wait for the end-of-stream
+ before you call {@code flush}. It is important that the input data after a flush starts at a
+ suitable stream boundary/key frame.
+ <p class=note>
+ <strong>Note:</strong> the format of the data submitted after a flush must not change; {@link
+ #flush} does not support format discontinuities; for that, a full {@link #stop} - {@link
+ #configure configure(&hellip;)} - {@link #start} cycle is necessary.
+
+ <p class=note>
+ <strong>Also note:</strong> if you flush the codec too soon after {@link #start} &ndash;
+ generally, before the first output buffer or output format change is received &ndash; you
+ will need to resubmit the codec-specific-data to the codec. See the <a
+ href="#CSD">codec-specific-data section</a> for more info.
+
+ <h4>For decoders that support and are configured for adaptive playback</h4>
+ <p>
+ In order to start decoding data that is not adjacent to previously submitted data (i.e. after a
+ seek) it is <em>not necessary</em> to flush the decoder; however, input data after the
+ discontinuity must start at a suitable stream boundary/key frame.
+ <p>
+ For some video formats - namely H.264, H.265, VP8 and VP9 - it is also possible to change the
+ picture size or configuration mid-stream. To do this you must package the entire new
+ codec-specific configuration data together with the key frame into a single buffer (including
+ any start codes), and submit it as a <strong>regular</strong> input buffer.
+ <p>
+ You will receive an {@link #INFO_OUTPUT_FORMAT_CHANGED} return value from {@link
+ #dequeueOutputBuffer dequeueOutputBuffer} or a {@link Callback#onOutputBufferAvailable
+ onOutputFormatChanged} callback just after the picture-size change takes place and before any
+ frames with the new size have been returned.
+ <p class=note>
+ <strong>Note:</strong> just as the case for codec-specific data, be careful when calling
+ {@link #flush} shortly after you have changed the picture size. If you have not received
+ confirmation of the picture size change, you will need to repeat the request for the new picture
+ size.
+
+ <h3>Error handling</h3>
+ <p>
+ The factory methods {@link #createByCodecName createByCodecName} and {@link #createDecoderByType
+ createDecoder}/{@link #createEncoderByType EncoderByType} throw {@code IOException} on failure
+ which you must catch or declare to pass up. MediaCodec methods throw {@code
+ IllegalStateException} when the method is called from a codec state that does not allow it; this
+ is typically due to incorrect application API usage. Methods involving secure buffers may throw
+ {@link CryptoException}, which has further error information obtainable from {@link
+ CryptoException#getErrorCode}.
+ <p>
+ Internal codec errors result in a {@link CodecException}, which may be due to media content
+ corruption, hardware failure, resource exhaustion, and so forth, even when the application is
+ correctly using the API. The recommended action when receiving a {@code CodecException}
+ can be determined by calling {@link CodecException#isRecoverable} and {@link
+ CodecException#isTransient}:
+ <ul>
+ <li><strong>recoverable errors:</strong> If {@code isRecoverable()} returns true, then call
+ {@link #stop}, {@link #configure configure(&hellip;)}, and {@link #start} to recover.</li>
+ <li><strong>transient errors:</strong> If {@code isTransient()} returns true, then resources are
+ temporarily unavailable and the method may be retried at a later time.</li>
+ <li><strong>fatal errors:</strong> If both {@code isRecoverable()} and {@code isTransient()}
+ return false, then the {@code CodecException} is fatal and the codec must be {@linkplain #reset
+ reset} or {@linkplain #release released}.</li>
+ </ul>
+ <p>
+ Both {@code isRecoverable()} and {@code isTransient()} do not return true at the same time.
+
+ <h2 id=History><a name="History"></a>Valid API Calls and API History</h2>
+ <p>
+ This sections summarizes the valid API calls in each state and the API history of the MediaCodec
+ class. For API version numbers, see {@link android.os.Build.VERSION_CODES}.
+
+ <style>
+ .api > tr > th, td { text-align: center; padding: 4px 4px; }
+ .api > tr > th     { vertical-align: bottom; }
+ .api > tr > td     { vertical-align: middle; }
+ .sml > tr > th, td { text-align: center; padding: 2px 4px; }
+ .fn { text-align: left; }
+ .fn > code > a { font: 14px/19px Roboto Condensed, sans-serif; }
+ .deg45 {
+   white-space: nowrap; background: none; border: none; vertical-align: bottom;
+   width: 30px; height: 83px;
+ }
+ .deg45 > div {
+   transform: skew(-45deg, 0deg) translate(1px, -67px);
+   transform-origin: bottom left 0;
+   width: 30px; height: 20px;
+ }
+ .deg45 > div > div { border: 1px solid #ddd; background: #999; height: 90px; width: 42px; }
+ .deg45 > div > div > div { transform: skew(45deg, 0deg) translate(-55px, 55px) rotate(-45deg); }
+ </style>
+
+ <table align="right" style="width: 0%">
+  <thead>
+   <tr><th>Symbol</th><th>Meaning</th></tr>
+  </thead>
+  <tbody class=sml>
+   <tr><td>&#9679;</td><td>Supported</td></tr>
+   <tr><td>&#8277;</td><td>Semantics changed</td></tr>
+   <tr><td>&#9675;</td><td>Experimental support</td></tr>
+   <tr><td>[ ]</td><td>Deprecated</td></tr>
+   <tr><td>&#9099;</td><td>Restricted to surface input mode</td></tr>
+   <tr><td>&#9094;</td><td>Restricted to surface output mode</td></tr>
+   <tr><td>&#9639;</td><td>Restricted to ByteBuffer input mode</td></tr>
+   <tr><td>&#8617;</td><td>Restricted to synchronous mode</td></tr>
+   <tr><td>&#8644;</td><td>Restricted to asynchronous mode</td></tr>
+   <tr><td>( )</td><td>Can be called, but shouldn't</td></tr>
+  </tbody>
+ </table>
+
+ <table style="width: 100%;">
+  <thead class=api>
+   <tr>
+    <th class=deg45><div><div style="background:#4285f4"><div>Uninitialized</div></div></div></th>
+    <th class=deg45><div><div style="background:#f4b400"><div>Configured</div></div></div></th>
+    <th class=deg45><div><div style="background:#e67c73"><div>Flushed</div></div></div></th>
+    <th class=deg45><div><div style="background:#0f9d58"><div>Running</div></div></div></th>
+    <th class=deg45><div><div style="background:#f7cb4d"><div>End of Stream</div></div></div></th>
+    <th class=deg45><div><div style="background:#db4437"><div>Error</div></div></div></th>
+    <th class=deg45><div><div style="background:#666"><div>Released</div></div></div></th>
+    <th></th>
+    <th colspan="8">SDK Version</th>
+   </tr>
+   <tr>
+    <th colspan="7">State</th>
+    <th>Method</th>
+    <th>16</th>
+    <th>17</th>
+    <th>18</th>
+    <th>19</th>
+    <th>20</th>
+    <th>21</th>
+    <th>22</th>
+    <th>23</th>
+   </tr>
+  </thead>
+  <tbody class=api>
+   <tr>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td class=fn>{@link #createByCodecName createByCodecName}</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+   </tr>
+   <tr>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td class=fn>{@link #createDecoderByType createDecoderByType}</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+   </tr>
+   <tr>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td class=fn>{@link #createEncoderByType createEncoderByType}</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+   </tr>
+   <tr>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td class=fn>{@link #createPersistentInputSurface createPersistentInputSurface}</td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td>&#9679;</td>
+   </tr>
+   <tr>
+    <td>16+</td>
+    <td>-</td>
+    <td>-</td>
+    <td>-</td>
+    <td>-</td>
+    <td>-</td>
+    <td>-</td>
+    <td class=fn>{@link #configure configure}</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#8277;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+   </tr>
+   <tr>
+    <td>-</td>
+    <td>18+</td>
+    <td>-</td>
+    <td>-</td>
+    <td>-</td>
+    <td>-</td>
+    <td>-</td>
+    <td class=fn>{@link #createInputSurface createInputSurface}</td>
+    <td></td>
+    <td></td>
+    <td>&#9099;</td>
+    <td>&#9099;</td>
+    <td>&#9099;</td>
+    <td>&#9099;</td>
+    <td>&#9099;</td>
+    <td>&#9099;</td>
+   </tr>
+   <tr>
+    <td>-</td>
+    <td>-</td>
+    <td>16+</td>
+    <td>16+</td>
+    <td>(16+)</td>
+    <td>-</td>
+    <td>-</td>
+    <td class=fn>{@link #dequeueInputBuffer dequeueInputBuffer}</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9639;</td>
+    <td>&#9639;</td>
+    <td>&#9639;</td>
+    <td>&#8277;&#9639;&#8617;</td>
+    <td>&#9639;&#8617;</td>
+    <td>&#9639;&#8617;</td>
+   </tr>
+   <tr>
+    <td>-</td>
+    <td>-</td>
+    <td>16+</td>
+    <td>16+</td>
+    <td>16+</td>
+    <td>-</td>
+    <td>-</td>
+    <td class=fn>{@link #dequeueOutputBuffer dequeueOutputBuffer}</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#8277;&#8617;</td>
+    <td>&#8617;</td>
+    <td>&#8617;</td>
+   </tr>
+   <tr>
+    <td>-</td>
+    <td>-</td>
+    <td>16+</td>
+    <td>16+</td>
+    <td>16+</td>
+    <td>-</td>
+    <td>-</td>
+    <td class=fn>{@link #flush flush}</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+   </tr>
+   <tr>
+    <td>18+</td>
+    <td>18+</td>
+    <td>18+</td>
+    <td>18+</td>
+    <td>18+</td>
+    <td>18+</td>
+    <td>-</td>
+    <td class=fn>{@link #getCodecInfo getCodecInfo}</td>
+    <td></td>
+    <td></td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+   </tr>
+   <tr>
+    <td>-</td>
+    <td>-</td>
+    <td>(21+)</td>
+    <td>21+</td>
+    <td>(21+)</td>
+    <td>-</td>
+    <td>-</td>
+    <td class=fn>{@link #getInputBuffer getInputBuffer}</td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+   </tr>
+   <tr>
+    <td>-</td>
+    <td>-</td>
+    <td>16+</td>
+    <td>(16+)</td>
+    <td>(16+)</td>
+    <td>-</td>
+    <td>-</td>
+    <td class=fn>{@link #getInputBuffers getInputBuffers}</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>[&#8277;&#8617;]</td>
+    <td>[&#8617;]</td>
+    <td>[&#8617;]</td>
+   </tr>
+   <tr>
+    <td>-</td>
+    <td>21+</td>
+    <td>(21+)</td>
+    <td>(21+)</td>
+    <td>(21+)</td>
+    <td>-</td>
+    <td>-</td>
+    <td class=fn>{@link #getInputFormat getInputFormat}</td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+   </tr>
+   <tr>
+    <td>-</td>
+    <td>-</td>
+    <td>(21+)</td>
+    <td>21+</td>
+    <td>(21+)</td>
+    <td>-</td>
+    <td>-</td>
+    <td class=fn>{@link #getInputImage getInputImage}</td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td>&#9675;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+   </tr>
+   <tr>
+    <td>18+</td>
+    <td>18+</td>
+    <td>18+</td>
+    <td>18+</td>
+    <td>18+</td>
+    <td>18+</td>
+    <td>-</td>
+    <td class=fn>{@link #getName getName}</td>
+    <td></td>
+    <td></td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+   </tr>
+   <tr>
+    <td>-</td>
+    <td>-</td>
+    <td>(21+)</td>
+    <td>21+</td>
+    <td>21+</td>
+    <td>-</td>
+    <td>-</td>
+    <td class=fn>{@link #getOutputBuffer getOutputBuffer}</td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+   </tr>
+   <tr>
+    <td>-</td>
+    <td>-</td>
+    <td>16+</td>
+    <td>16+</td>
+    <td>16+</td>
+    <td>-</td>
+    <td>-</td>
+    <td class=fn>{@link #getOutputBuffers getOutputBuffers}</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>[&#8277;&#8617;]</td>
+    <td>[&#8617;]</td>
+    <td>[&#8617;]</td>
+   </tr>
+   <tr>
+    <td>-</td>
+    <td>21+</td>
+    <td>16+</td>
+    <td>16+</td>
+    <td>16+</td>
+    <td>-</td>
+    <td>-</td>
+    <td class=fn>{@link #getOutputFormat()}</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+   </tr>
+   <tr>
+    <td>-</td>
+    <td>-</td>
+    <td>(21+)</td>
+    <td>21+</td>
+    <td>21+</td>
+    <td>-</td>
+    <td>-</td>
+    <td class=fn>{@link #getOutputFormat(int)}</td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+   </tr>
+   <tr>
+    <td>-</td>
+    <td>-</td>
+    <td>(21+)</td>
+    <td>21+</td>
+    <td>21+</td>
+    <td>-</td>
+    <td>-</td>
+    <td class=fn>{@link #getOutputImage getOutputImage}</td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td>&#9675;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+   </tr>
+   <tr>
+    <td>-</td>
+    <td>-</td>
+    <td>-</td>
+    <td>16+</td>
+    <td>(16+)</td>
+    <td>-</td>
+    <td>-</td>
+    <td class=fn>{@link #queueInputBuffer queueInputBuffer}</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#8277;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+   </tr>
+   <tr>
+    <td>-</td>
+    <td>-</td>
+    <td>-</td>
+    <td>16+</td>
+    <td>(16+)</td>
+    <td>-</td>
+    <td>-</td>
+    <td class=fn>{@link #queueSecureInputBuffer queueSecureInputBuffer}</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#8277;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+   </tr>
+   <tr>
+    <td>16+</td>
+    <td>16+</td>
+    <td>16+</td>
+    <td>16+</td>
+    <td>16+</td>
+    <td>16+</td>
+    <td>16+</td>
+    <td class=fn>{@link #release release}</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+   </tr>
+   <tr>
+    <td>-</td>
+    <td>-</td>
+    <td>-</td>
+    <td>16+</td>
+    <td>16+</td>
+    <td>-</td>
+    <td>-</td>
+    <td class=fn>{@link #releaseOutputBuffer(int, boolean)}</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#8277;</td>
+    <td>&#9679;</td>
+    <td>&#8277;</td>
+   </tr>
+   <tr>
+    <td>-</td>
+    <td>-</td>
+    <td>-</td>
+    <td>21+</td>
+    <td>21+</td>
+    <td>-</td>
+    <td>-</td>
+    <td class=fn>{@link #releaseOutputBuffer(int, long)}</td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td>&#9094;</td>
+    <td>&#9094;</td>
+    <td>&#9094;</td>
+   </tr>
+   <tr>
+    <td>21+</td>
+    <td>21+</td>
+    <td>21+</td>
+    <td>21+</td>
+    <td>21+</td>
+    <td>21+</td>
+    <td>-</td>
+    <td class=fn>{@link #reset reset}</td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+   </tr>
+   <tr>
+    <td>21+</td>
+    <td>-</td>
+    <td>-</td>
+    <td>-</td>
+    <td>-</td>
+    <td>-</td>
+    <td>-</td>
+    <td class=fn>{@link #setCallback(Callback) setCallback}</td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>{@link #setCallback(Callback, Handler) &#8277;}</td>
+   </tr>
+   <tr>
+    <td>-</td>
+    <td>23+</td>
+    <td>-</td>
+    <td>-</td>
+    <td>-</td>
+    <td>-</td>
+    <td>-</td>
+    <td class=fn>{@link #setInputSurface setInputSurface}</td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td>&#9099;</td>
+   </tr>
+   <tr>
+    <td>23+</td>
+    <td>23+</td>
+    <td>23+</td>
+    <td>23+</td>
+    <td>23+</td>
+    <td>(23+)</td>
+    <td>(23+)</td>
+    <td class=fn>{@link #setOnFrameRenderedListener setOnFrameRenderedListener}</td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td>&#9675; &#9094;</td>
+   </tr>
+   <tr>
+    <td>-</td>
+    <td>23+</td>
+    <td>23+</td>
+    <td>23+</td>
+    <td>23+</td>
+    <td>-</td>
+    <td>-</td>
+    <td class=fn>{@link #setOutputSurface setOutputSurface}</td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td>&#9094;</td>
+   </tr>
+   <tr>
+    <td>19+</td>
+    <td>19+</td>
+    <td>19+</td>
+    <td>19+</td>
+    <td>19+</td>
+    <td>(19+)</td>
+    <td>-</td>
+    <td class=fn>{@link #setParameters setParameters}</td>
+    <td></td>
+    <td></td>
+    <td></td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+   </tr>
+   <tr>
+    <td>-</td>
+    <td>16+</td>
+    <td>16+</td>
+    <td>16+</td>
+    <td>16+</td>
+    <td>(16+)</td>
+    <td>-</td>
+    <td class=fn>{@link #setVideoScalingMode setVideoScalingMode}</td>
+    <td>&#9094;</td>
+    <td>&#9094;</td>
+    <td>&#9094;</td>
+    <td>&#9094;</td>
+    <td>&#9094;</td>
+    <td>&#9094;</td>
+    <td>&#9094;</td>
+    <td>&#9094;</td>
+   </tr>
+   <tr>
+    <td>-</td>
+    <td>-</td>
+    <td>18+</td>
+    <td>18+</td>
+    <td>-</td>
+    <td>-</td>
+    <td>-</td>
+    <td class=fn>{@link #signalEndOfInputStream signalEndOfInputStream}</td>
+    <td></td>
+    <td></td>
+    <td>&#9099;</td>
+    <td>&#9099;</td>
+    <td>&#9099;</td>
+    <td>&#9099;</td>
+    <td>&#9099;</td>
+    <td>&#9099;</td>
+   </tr>
+   <tr>
+    <td>-</td>
+    <td>16+</td>
+    <td>21+(&#8644;)</td>
+    <td>-</td>
+    <td>-</td>
+    <td>-</td>
+    <td>-</td>
+    <td class=fn>{@link #start start}</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#8277;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+   </tr>
+   <tr>
+    <td>-</td>
+    <td>-</td>
+    <td>16+</td>
+    <td>16+</td>
+    <td>16+</td>
+    <td>-</td>
+    <td>-</td>
+    <td class=fn>{@link #stop stop}</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+    <td>&#9679;</td>
+   </tr>
+  </tbody>
+ </table>
  */
 final public class MediaCodec {
     /**
@@ -548,14 +1652,14 @@
     }
 
     /**
-     * Returns the codec to its initial (Initialized) state.
+     * Returns the codec to its initial (Uninitialized) state.
      *
      * Call this if an {@link MediaCodec.CodecException#isRecoverable unrecoverable}
      * error has occured to reset the codec to its initial state after creation.
      *
      * @throws CodecException if an unrecoverable error has occured and the codec
      * could not be reset.
-     * @throws IllegalStateException if in the Uninitialized state.
+     * @throws IllegalStateException if in the Released state.
      */
     public final void reset() {
         freeAllTrackedBuffers(); // free buffers first
@@ -607,7 +1711,7 @@
      * or the format is unacceptable (e.g. missing a mandatory key),
      * or the flags are not set properly
      * (e.g. missing {@link #CONFIGURE_FLAG_ENCODE} for an encoder).
-     * @throws IllegalStateException if not in the Initialized state.
+     * @throws IllegalStateException if not in the Uninitialized state.
      * @throws CryptoException upon DRM error.
      * @throws CodecException upon codec error.
      */
@@ -765,7 +1869,7 @@
      * remains active and ready to be {@link #start}ed again.
      * To ensure that it is available to other client call {@link #release}
      * and don't just rely on garbage collection to eventually do this for you.
-     * @throws IllegalStateException if in the Uninitialized state.
+     * @throws IllegalStateException if in the Released state.
      */
     public final void stop() {
         native_stop();
@@ -1771,14 +2875,14 @@
      * If a surface has been specified in a previous call to {@link #configure}
      * specifies the scaling mode to use. The default is "scale to fit".
      * @throws IllegalArgumentException if mode is not recognized.
-     * @throws IllegalStateException if in the Uninitialized state.
+     * @throws IllegalStateException if in the Released state.
      */
     public native final void setVideoScalingMode(@VideoScalingMode int mode);
 
     /**
      * Get the component name. If the codec was created by createDecoderByType
      * or createEncoderByType, what component is chosen is not known beforehand.
-     * @throws IllegalStateException if in the Uninitialized state.
+     * @throws IllegalStateException if in the Released state.
      */
     @NonNull
     public native final String getName();
@@ -1811,7 +2915,7 @@
      * <b>Note:</b> Some of these parameter changes may silently fail to apply.
      *
      * @param params The bundle of parameters to set.
-     * @throws IllegalStateException if in the Uninitialized state.
+     * @throws IllegalStateException if in the Released state.
      */
     public final void setParameters(@Nullable Bundle params) {
         if (params == null) {
@@ -2025,7 +3129,7 @@
      * Get the codec info. If the codec was created by createDecoderByType
      * or createEncoderByType, what component is chosen is not known beforehand,
      * and thus the caller does not have the MediaCodecInfo.
-     * @throws IllegalStateException if in the Uninitialized state.
+     * @throws IllegalStateException if in the Released state.
      */
     @NonNull
     public MediaCodecInfo getCodecInfo() {
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/Relation.java b/packages/StatementService/src/com/android/statementservice/retriever/Relation.java
index 91218c6..124f46d 100644
--- a/packages/StatementService/src/com/android/statementservice/retriever/Relation.java
+++ b/packages/StatementService/src/com/android/statementservice/retriever/Relation.java
@@ -30,16 +30,12 @@
  * <p> We may add other kinds in the future.
  *
  * <p> The detail field is a lowercase alphanumeric string with underscores and periods allowed
- * (matching the regex [a-z0-9_.]+), but otherwise unstructured. It is also possible to specify '*'
- * (the wildcard character) as the detail if the relation applies to any detail in the specified
- * kind.
+ * (matching the regex [a-z0-9_.]+), but otherwise unstructured.
  */
 public final class Relation {
 
     private static final Pattern KIND_PATTERN = Pattern.compile("^[a-z0-9_.]+$");
-    private static final Pattern DETAIL_PATTERN = Pattern.compile("^([a-z0-9_.]+|[*])$");
-
-    private static final String MATCH_ALL_DETAILS = "*";
+    private static final Pattern DETAIL_PATTERN = Pattern.compile("^([a-z0-9_.]+)$");
 
     private final String mKind;
     private final String mDetail;
@@ -92,12 +88,10 @@
     }
 
     /**
-     * Returns true if {@code relation} has the same kind and detail. If {@code
-     * relation.getDetail()} is wildcard (*) then returns true if the kind is the same.
+     * Returns true if {@code relation} has the same kind and detail.
      */
     public boolean matches(Relation relation) {
-        return getKind().equals(relation.getKind()) && (getDetail().equals(MATCH_ALL_DETAILS)
-                || getDetail().equals(relation.getDetail()));
+        return getKind().equals(relation.getKind()) && getDetail().equals(relation.getDetail());
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 9504ea3..9bc5b75 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -326,7 +326,7 @@
                     item.tag = ap;
                     item.icon = mWifiController.getIcon(ap);
                     item.line1 = ap.getSsid();
-                    item.line2 = ap.getSummary();
+                    item.line2 = ap.isActive() ? ap.getSummary() : null;
                     item.overlay = ap.getSecurity() != AccessPoint.SECURITY_NONE
                             ? mContext.getDrawable(R.drawable.qs_ic_wifi_lock)
                             : null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 50cdbb6..1e4aa61 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -745,7 +745,8 @@
         mHandlerThread.start();
 
         // Other icons
-        mLocationController = new LocationControllerImpl(mContext); // will post a notification
+        mLocationController = new LocationControllerImpl(mContext,
+                mHandlerThread.getLooper()); // will post a notification
         mBatteryController = new BatteryController(mContext);
         mBatteryController.addStateChangedCallback(new BatteryStateChangeCallback() {
             @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index d8d7042..93a8fd8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -26,6 +26,8 @@
 import android.content.IntentFilter;
 import android.location.LocationManager;
 import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
@@ -56,31 +58,21 @@
 
     private ArrayList<LocationSettingsChangeCallback> mSettingsChangeCallbacks =
             new ArrayList<LocationSettingsChangeCallback>();
+    private final H mHandler = new H();
 
-    public LocationControllerImpl(Context context) {
+    public LocationControllerImpl(Context context, Looper bgLooper) {
         mContext = context;
 
+        // Register to listen for changes in location settings.
         IntentFilter filter = new IntentFilter();
         filter.addAction(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
-        context.registerReceiverAsUser(this, UserHandle.ALL, filter, null, null);
+        filter.addAction(LocationManager.MODE_CHANGED_ACTION);
+        context.registerReceiverAsUser(this, UserHandle.ALL, filter, null, new Handler(bgLooper));
 
         mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
         mStatusBarManager
                 = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE);
 
-        // Register to listen for changes in location settings.
-        IntentFilter intentFilter = new IntentFilter();
-        intentFilter.addAction(LocationManager.MODE_CHANGED_ACTION);
-        context.registerReceiverAsUser(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                String action = intent.getAction();
-                if (LocationManager.MODE_CHANGED_ACTION.equals(action)) {
-                    locationSettingsChanged();
-                }
-            }
-        }, UserHandle.ALL, intentFilter, null, new Handler());
-
         // Examine the current location state and initialize the status view.
         updateActiveLocationRequests();
         refreshViews();
@@ -91,7 +83,7 @@
      */
     public void addSettingsChangedCallback(LocationSettingsChangeCallback cb) {
         mSettingsChangeCallbacks.add(cb);
-        locationSettingsChanged(cb);
+        mHandler.sendEmptyMessage(H.MSG_LOCATION_SETTINGS_CHANGED);
     }
 
     public void removeSettingsChangedCallback(LocationSettingsChangeCallback cb) {
@@ -181,8 +173,8 @@
     // Updates the status view based on the current state of location requests.
     private void refreshViews() {
         if (mAreActiveLocationRequests) {
-            mStatusBarManager.setIcon(LOCATION_STATUS_ICON_PLACEHOLDER, LOCATION_STATUS_ICON_ID, 0,
-                    mContext.getString(R.string.accessibility_location_active));
+            mStatusBarManager.setIcon(LOCATION_STATUS_ICON_PLACEHOLDER, LOCATION_STATUS_ICON_ID,
+                    0, mContext.getString(R.string.accessibility_location_active));
         } else {
             mStatusBarManager.removeIcon(LOCATION_STATUS_ICON_PLACEHOLDER);
         }
@@ -197,22 +189,33 @@
         }
     }
 
-    private void locationSettingsChanged() {
-        boolean isEnabled = isLocationEnabled();
-        for (LocationSettingsChangeCallback cb : mSettingsChangeCallbacks) {
-            cb.onLocationSettingsChanged(isEnabled);
-        }
-    }
-
-    private void locationSettingsChanged(LocationSettingsChangeCallback cb) {
-        cb.onLocationSettingsChanged(isLocationEnabled());
-    }
-
     @Override
     public void onReceive(Context context, Intent intent) {
         final String action = intent.getAction();
         if (LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)) {
             updateActiveLocationRequests();
+        } else if (LocationManager.MODE_CHANGED_ACTION.equals(action)) {
+            mHandler.sendEmptyMessage(H.MSG_LOCATION_SETTINGS_CHANGED);
+        }
+    }
+
+    private final class H extends Handler {
+        private static final int MSG_LOCATION_SETTINGS_CHANGED = 1;
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_LOCATION_SETTINGS_CHANGED:
+                    locationSettingsChanged();
+                    break;
+            }
+        }
+
+        private void locationSettingsChanged() {
+            boolean isEnabled = isLocationEnabled();
+            for (LocationSettingsChangeCallback cb : mSettingsChangeCallbacks) {
+                cb.onLocationSettingsChanged(isEnabled);
+            }
         }
     }
 }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 7ac2655..edca4b8 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -3640,6 +3640,7 @@
 
     @Override
     public void releasePendingNetworkRequest(PendingIntent operation) {
+        checkNotNull(operation, "PendingIntent cannot be null.");
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT,
                 getCallingUid(), 0, operation));
     }
diff --git a/services/core/java/com/android/server/notification/CalendarTracker.java b/services/core/java/com/android/server/notification/CalendarTracker.java
index 71d7f19..de321fe 100644
--- a/services/core/java/com/android/server/notification/CalendarTracker.java
+++ b/services/core/java/com/android/server/notification/CalendarTracker.java
@@ -26,8 +26,11 @@
 import android.net.Uri;
 import android.provider.BaseColumns;
 import android.provider.CalendarContract.Attendees;
+import android.provider.CalendarContract.Calendars;
+import android.provider.CalendarContract.Events;
 import android.provider.CalendarContract.Instances;
 import android.service.notification.ZenModeConfig.EventInfo;
+import android.util.ArraySet;
 import android.util.Log;
 
 import java.io.PrintWriter;
@@ -63,13 +66,15 @@
     private static final String ATTENDEE_SELECTION = Attendees.EVENT_ID + " = ? AND "
             + Attendees.ATTENDEE_EMAIL + " = ?";
 
-    private final Context mContext;
+    private final Context mSystemContext;
+    private final Context mUserContext;
 
     private Callback mCallback;
     private boolean mRegistered;
 
-    public CalendarTracker(Context context) {
-        mContext = context;
+    public CalendarTracker(Context systemContext, Context userContext) {
+        mSystemContext = systemContext;
+        mUserContext = userContext;
     }
 
     public void setCallback(Callback callback) {
@@ -81,11 +86,12 @@
     public void dump(String prefix, PrintWriter pw) {
         pw.print(prefix); pw.print("mCallback="); pw.println(mCallback);
         pw.print(prefix); pw.print("mRegistered="); pw.println(mRegistered);
+        pw.print(prefix); pw.print("u="); pw.println(mUserContext.getUserId());
     }
 
     public void dumpContent(Uri uri) {
         Log.d(TAG, "dumpContent: " + uri);
-        final Cursor cursor = mContext.getContentResolver().query(uri, null, null, null, null);
+        final Cursor cursor = mUserContext.getContentResolver().query(uri, null, null, null, null);
         try {
             int r = 0;
             while (cursor.moveToNext()) {
@@ -126,36 +132,61 @@
         }
     }
 
-
+    private ArraySet<Long> getPrimaryCalendars() {
+        final long start = System.currentTimeMillis();
+        final ArraySet<Long> rt = new ArraySet<>();
+        final String primary = "\"primary\"";
+        final String[] projection = { Calendars._ID,
+                "(" + Calendars.ACCOUNT_NAME + "=" + Calendars.OWNER_ACCOUNT + ") AS " + primary };
+        final String selection = primary + " = 1";
+        Cursor cursor = null;
+        try {
+            cursor = mUserContext.getContentResolver().query(Calendars.CONTENT_URI, projection,
+                    selection, null, null);
+            while (cursor != null && cursor.moveToNext()) {
+                rt.add(cursor.getLong(0));
+            }
+        } finally {
+            if (cursor != null) {
+                cursor.close();
+            }
+        }
+        if (DEBUG) Log.d(TAG, "getPrimaryCalendars took " + (System.currentTimeMillis() - start));
+        return rt;
+    }
 
     public CheckEventResult checkEvent(EventInfo filter, long time) {
         final Uri.Builder uriBuilder = Instances.CONTENT_URI.buildUpon();
         ContentUris.appendId(uriBuilder, time);
         ContentUris.appendId(uriBuilder, time + EVENT_CHECK_LOOKAHEAD);
         final Uri uri = uriBuilder.build();
-        final Cursor cursor = mContext.getContentResolver().query(uri, INSTANCE_PROJECTION, null,
-                null, INSTANCE_ORDER_BY);
+        final Cursor cursor = mUserContext.getContentResolver().query(uri, INSTANCE_PROJECTION,
+                null, null, INSTANCE_ORDER_BY);
         final CheckEventResult result = new CheckEventResult();
         result.recheckAt = time + EVENT_CHECK_LOOKAHEAD;
         try {
-            while (cursor.moveToNext()) {
+            final ArraySet<Long> primaryCalendars = getPrimaryCalendars();
+            while (cursor != null && cursor.moveToNext()) {
                 final long begin = cursor.getLong(0);
                 final long end = cursor.getLong(1);
                 final String title = cursor.getString(2);
-                final boolean visible = cursor.getInt(3) == 1;
+                final boolean calendarVisible = cursor.getInt(3) == 1;
                 final int eventId = cursor.getInt(4);
                 final String owner = cursor.getString(5);
                 final long calendarId = cursor.getLong(6);
                 final int availability = cursor.getInt(7);
-                if (DEBUG) Log.d(TAG, String.format("%s %s-%s v=%s a=%s eid=%s o=%s cid=%s", title,
-                        new Date(begin), new Date(end), visible, availabilityToString(availability),
-                        eventId, owner, calendarId));
+                final boolean calendarPrimary = primaryCalendars.contains(calendarId);
+                if (DEBUG) Log.d(TAG, String.format("%s %s-%s v=%s a=%s eid=%s o=%s cid=%s p=%s",
+                        title,
+                        new Date(begin), new Date(end), calendarVisible,
+                        availabilityToString(availability), eventId, owner, calendarId,
+                        calendarPrimary));
                 final boolean meetsTime = time >= begin && time < end;
-                final boolean meetsCalendar = visible
-                        && (filter.calendar == ANY_CALENDAR || filter.calendar == calendarId)
-                        && availability != Instances.AVAILABILITY_FREE;
-                if (meetsCalendar) {
-                    if (DEBUG) Log.d(TAG, "  MEETS CALENDAR");
+                final boolean meetsCalendar = calendarVisible && calendarPrimary
+                        && (filter.calendar == ANY_CALENDAR || filter.calendar == calendarId);
+                final boolean meetsAvailability = availability != Instances.AVAILABILITY_FREE;
+                if (meetsCalendar && meetsAvailability) {
+                    if (DEBUG) Log.d(TAG, "  MEETS CALENDAR & AVAILABILITY");
                     final boolean meetsAttendee = meetsAttendee(filter, eventId, owner);
                     if (meetsAttendee) {
                         if (DEBUG) Log.d(TAG, "    MEETS ATTENDEE");
@@ -172,19 +203,22 @@
                 }
             }
         } finally {
-            cursor.close();
+            if (cursor != null) {
+                cursor.close();
+            }
         }
         return result;
     }
 
     private boolean meetsAttendee(EventInfo filter, int eventId, String email) {
+        final long start = System.currentTimeMillis();
         String selection = ATTENDEE_SELECTION;
         String[] selectionArgs = { Integer.toString(eventId), email };
         if (DEBUG_ATTENDEES) {
             selection = null;
             selectionArgs = null;
         }
-        final Cursor cursor = mContext.getContentResolver().query(Attendees.CONTENT_URI,
+        final Cursor cursor = mUserContext.getContentResolver().query(Attendees.CONTENT_URI,
                 ATTENDEE_PROJECTION, selection, selectionArgs, null);
         try {
             if (cursor.getCount() == 0) {
@@ -208,18 +242,25 @@
             return rt;
         } finally {
             cursor.close();
+            if (DEBUG) Log.d(TAG, "meetsAttendee took " + (System.currentTimeMillis() - start));
         }
     }
 
     private void setRegistered(boolean registered) {
         if (mRegistered == registered) return;
-        final ContentResolver cr = mContext.getContentResolver();
+        final ContentResolver cr = mSystemContext.getContentResolver();
+        final int userId = mUserContext.getUserId();
         if (mRegistered) {
+            if (DEBUG) Log.d(TAG, "unregister content observer u=" + userId);
             cr.unregisterContentObserver(mObserver);
         }
         mRegistered = registered;
+        if (DEBUG) Log.d(TAG, "mRegistered = " + registered + " u=" + userId);
         if (mRegistered) {
-            cr.registerContentObserver(Instances.CONTENT_URI, false, mObserver);
+            if (DEBUG) Log.d(TAG, "register content observer u=" + userId);
+            cr.registerContentObserver(Instances.CONTENT_URI, true, mObserver, userId);
+            cr.registerContentObserver(Events.CONTENT_URI, true, mObserver, userId);
+            cr.registerContentObserver(Calendars.CONTENT_URI, true, mObserver, userId);
         }
     }
 
@@ -260,7 +301,8 @@
     private final ContentObserver mObserver = new ContentObserver(null) {
         @Override
         public void onChange(boolean selfChange, Uri u) {
-            if (DEBUG) Log.d(TAG, "onChange selfChange=" + selfChange + " uri=" + u);
+            if (DEBUG) Log.d(TAG, "onChange selfChange=" + selfChange + " uri=" + u
+                    + " u=" + mUserContext.getUserId());
             mCallback.onChanged();
         }
 
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index 8c6afaf..33c666a 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -130,8 +130,8 @@
     }
 
     @Override
-    public void onUserSwitched() {
-        super.onUserSwitched();
+    public void onUserSwitched(int user) {
+        super.onUserSwitched(user);
         if (mCallback != null) {
             mCallback.onUserSwitched();
         }
diff --git a/services/core/java/com/android/server/notification/EventConditionProvider.java b/services/core/java/com/android/server/notification/EventConditionProvider.java
index dea6325..46cc47b 100644
--- a/services/core/java/com/android/server/notification/EventConditionProvider.java
+++ b/services/core/java/com/android/server/notification/EventConditionProvider.java
@@ -23,7 +23,12 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.os.UserManager;
 import android.service.notification.Condition;
 import android.service.notification.IConditionProvider;
 import android.service.notification.ZenModeConfig;
@@ -31,6 +36,7 @@
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseArray;
 
 import com.android.server.notification.CalendarTracker.CheckEventResult;
 import com.android.server.notification.NotificationManagerService.DumpFilter;
@@ -51,17 +57,21 @@
     private static final String ACTION_EVALUATE = SIMPLE_NAME + ".EVALUATE";
     private static final int REQUEST_CODE_EVALUATE = 1;
     private static final String EXTRA_TIME = "time";
+    private static final long CHANGE_DELAY = 2 * 1000;  // coalesce chatty calendar changes
 
     private final Context mContext = this;
     private final ArraySet<Uri> mSubscriptions = new ArraySet<Uri>();
-    private final CalendarTracker mTracker = new CalendarTracker(mContext);
+    private final SparseArray<CalendarTracker> mTrackers = new SparseArray<>();
+    private final Handler mWorker;
 
     private boolean mConnected;
     private boolean mRegistered;
     private boolean mBootComplete;  // don't hammer the calendar provider until boot completes.
+    private long mNextAlarmTime;
 
-    public EventConditionProvider() {
+    public EventConditionProvider(Looper worker) {
         if (DEBUG) Slog.d(TAG, "new " + SIMPLE_NAME + "()");
+        mWorker = new Handler(worker);
     }
 
     @Override
@@ -80,13 +90,17 @@
         pw.print("      mConnected="); pw.println(mConnected);
         pw.print("      mRegistered="); pw.println(mRegistered);
         pw.print("      mBootComplete="); pw.println(mBootComplete);
+        dumpUpcomingTime(pw, "mNextAlarmTime", mNextAlarmTime, System.currentTimeMillis());
         pw.println("      mSubscriptions=");
         for (Uri conditionId : mSubscriptions) {
             pw.print("        ");
             pw.println(conditionId);
         }
-        pw.println("      mTracker=");
-        mTracker.dump("        ", pw);
+        pw.println("      mTrackers=");
+        for (int i = 0; i < mTrackers.size(); i++) {
+            pw.print("        user="); pw.println(mTrackers.keyAt(i));
+            mTrackers.valueAt(i).dump("          ", pw);
+        }
     }
 
     @Override
@@ -94,7 +108,16 @@
         if (DEBUG) Slog.d(TAG, "onBootComplete");
         if (mBootComplete) return;
         mBootComplete = true;
-        evaluateSubscriptions();
+        final IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
+        filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
+        mContext.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                reloadTrackers();
+            }
+        }, filter);
+        reloadTrackers();
     }
 
     @Override
@@ -146,14 +169,39 @@
         return (IConditionProvider) onBind(null);
     }
 
+    private void reloadTrackers() {
+        if (DEBUG) Slog.d(TAG, "reloadTrackers");
+        for (int i = 0; i < mTrackers.size(); i++) {
+            mTrackers.valueAt(i).setCallback(null);
+        }
+        mTrackers.clear();
+        for (UserHandle user : UserManager.get(mContext).getUserProfiles()) {
+            final Context context = user.isOwner() ? mContext : getContextForUser(mContext, user);
+            if (context == null) {
+                Slog.w(TAG, "Unable to create context for user " + user.getIdentifier());
+                continue;
+            }
+            mTrackers.put(user.getIdentifier(), new CalendarTracker(mContext, context));
+        }
+        evaluateSubscriptions();
+    }
+
     private void evaluateSubscriptions() {
-        if (DEBUG) Log.d(TAG, "evaluateSubscriptions");
+        if (!mWorker.hasCallbacks(mEvaluateSubscriptionsW)) {
+            mWorker.post(mEvaluateSubscriptionsW);
+        }
+    }
+
+    private void evaluateSubscriptionsW() {
+        if (DEBUG) Slog.d(TAG, "evaluateSubscriptions");
         if (!mBootComplete) {
-            if (DEBUG) Log.d(TAG, "Skipping evaluate before boot complete");
+            if (DEBUG) Slog.d(TAG, "Skipping evaluate before boot complete");
             return;
         }
         final long now = System.currentTimeMillis();
-        mTracker.setCallback(mSubscriptions.isEmpty() ? null : mTrackerCallback);
+        for (int i = 0; i < mTrackers.size(); i++) {
+            mTrackers.valueAt(i).setCallback(mSubscriptions.isEmpty() ? null : mTrackerCallback);
+        }
         setRegistered(!mSubscriptions.isEmpty());
         long reevaluateAt = 0;
         for (Uri conditionId : mSubscriptions) {
@@ -162,7 +210,30 @@
                 notifyCondition(conditionId, Condition.STATE_FALSE, "badConditionId");
                 continue;
             }
-            final CheckEventResult result = mTracker.checkEvent(event, now);
+            CheckEventResult result = null;
+            if (event.calendar == EventInfo.ANY_CALENDAR) {
+                // event could exist on any tracker
+                for (int i = 0; i < mTrackers.size(); i++) {
+                    final CalendarTracker tracker = mTrackers.valueAt(i);
+                    final CheckEventResult r = tracker.checkEvent(event, now);
+                    if (result == null) {
+                        result = r;
+                    } else {
+                        result.inEvent |= r.inEvent;
+                        result.recheckAt = Math.min(result.recheckAt, r.recheckAt);
+                    }
+                }
+            } else {
+                // event should exist on one tracker
+                final int userId = EventInfo.resolveUserId(event.userId);
+                final CalendarTracker tracker = mTrackers.get(userId);
+                if (tracker == null) {
+                    Slog.w(TAG, "No calendar tracker found for user " + userId);
+                    notifyCondition(conditionId, Condition.STATE_FALSE, "badUserId");
+                    continue;
+                }
+                result = tracker.checkEvent(event, now);
+            }
             if (result.recheckAt != 0 && (reevaluateAt == 0 || result.recheckAt < reevaluateAt)) {
                 reevaluateAt = result.recheckAt;
             }
@@ -172,11 +243,12 @@
             }
             notifyCondition(conditionId, Condition.STATE_TRUE, "inEventNow");
         }
-        updateAlarm(now, reevaluateAt);
-        if (DEBUG) Log.d(TAG, "evaluateSubscriptions took " + (System.currentTimeMillis() - now));
+        rescheduleAlarm(now, reevaluateAt);
+        if (DEBUG) Slog.d(TAG, "evaluateSubscriptions took " + (System.currentTimeMillis() - now));
     }
 
-    private void updateAlarm(long now, long time) {
+    private void rescheduleAlarm(long now, long time) {
+        mNextAlarmTime = time;
         final AlarmManager alarms = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
         final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext,
                 REQUEST_CODE_EVALUATE,
@@ -196,8 +268,8 @@
     }
 
     private void notifyCondition(Uri conditionId, int state, String reason) {
-        if (DEBUG) Slog.d(TAG, "notifyCondition " + Condition.stateToString(state)
-                + " reason=" + reason);
+        if (DEBUG) Slog.d(TAG, "notifyCondition " + conditionId + " "
+                + Condition.stateToString(state) + " reason=" + reason);
         notifyCondition(createCondition(conditionId, state));
     }
 
@@ -223,19 +295,35 @@
         }
     }
 
+    private static Context getContextForUser(Context context, UserHandle user) {
+        try {
+            return context.createPackageContextAsUser(context.getPackageName(), 0, user);
+        } catch (NameNotFoundException e) {
+            return null;
+        }
+    }
+
     private final CalendarTracker.Callback mTrackerCallback = new CalendarTracker.Callback() {
         @Override
         public void onChanged() {
-            if (DEBUG) Log.d(TAG, "mTrackerCallback.onChanged");
-            evaluateSubscriptions();
+            if (DEBUG) Slog.d(TAG, "mTrackerCallback.onChanged");
+            mWorker.removeCallbacks(mEvaluateSubscriptionsW);
+            mWorker.postDelayed(mEvaluateSubscriptionsW, CHANGE_DELAY);
         }
     };
 
-    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             if (DEBUG) Slog.d(TAG, "onReceive " + intent.getAction());
             evaluateSubscriptions();
         }
     };
+
+    private final Runnable mEvaluateSubscriptionsW = new Runnable() {
+        @Override
+        public void run() {
+            evaluateSubscriptionsW();
+        }
+    };
 }
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 6f8e3ca..8f24b46 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -216,8 +216,8 @@
         }
     }
 
-    public void onUserSwitched() {
-        if (DEBUG) Slog.d(TAG, "onUserSwitched");
+    public void onUserSwitched(int user) {
+        if (DEBUG) Slog.d(TAG, "onUserSwitched u=" + user);
         if (Arrays.equals(mLastSeenProfileIds, mUserProfiles.getCurrentProfileIds())) {
             if (DEBUG) Slog.d(TAG, "Current profile IDs didn't change, skipping rebindServices().");
             return;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index ef4da02..2be409a 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -799,12 +799,13 @@
                 mNotificationLight.turnOff();
                 mStatusBar.notificationLightOff();
             } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
+                final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
                 // reload per-user settings
                 mSettingsObserver.update(null);
                 mUserProfiles.updateCache(context);
                 // Refresh managed services
-                mConditionProviders.onUserSwitched();
-                mListeners.onUserSwitched();
+                mConditionProviders.onUserSwitched(user);
+                mListeners.onUserSwitched(user);
             } else if (action.equals(Intent.ACTION_USER_ADDED)) {
                 mUserProfiles.updateCache(context);
             }
diff --git a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
index f06f54c..44448cc 100644
--- a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
+++ b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
@@ -85,12 +85,7 @@
             pw.print(meetsSchedule(conditionId, now) ? "* " : "  ");
             pw.println(conditionId);
         }
-        pw.print("      mNextAlarmTime="); pw.print(mNextAlarmTime);
-        if (mNextAlarmTime > 0) {
-            pw.printf(" (%s, in %s, now=%s)", ts(mNextAlarmTime),
-                    formatDuration(mNextAlarmTime - now), ts(now));
-        }
-        pw.println();
+        dumpUpcomingTime(pw, "mNextAlarmTime", mNextAlarmTime, now);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/notification/SystemConditionProviderService.java b/services/core/java/com/android/server/notification/SystemConditionProviderService.java
index 8a8e063..574f04c 100644
--- a/services/core/java/com/android/server/notification/SystemConditionProviderService.java
+++ b/services/core/java/com/android/server/notification/SystemConditionProviderService.java
@@ -46,4 +46,14 @@
         TimeUtils.formatDuration(millis, sb);
         return sb.toString();
     }
+
+    protected static void dumpUpcomingTime(PrintWriter pw, String var, long time, long now) {
+        pw.print("      "); pw.print(var); pw.print('=');
+        if (time > 0) {
+            pw.printf("%s, in %s, now=%s", ts(time), formatDuration(time - now), ts(now));
+        } else {
+            pw.print(time);
+        }
+        pw.println();
+    }
 }
diff --git a/services/core/java/com/android/server/notification/ZenModeConditions.java b/services/core/java/com/android/server/notification/ZenModeConditions.java
index f1c58bd..d6b7f2f 100644
--- a/services/core/java/com/android/server/notification/ZenModeConditions.java
+++ b/services/core/java/com/android/server/notification/ZenModeConditions.java
@@ -50,7 +50,7 @@
             mConditionProviders.addSystemProvider(new ScheduleConditionProvider());
         }
         if (mConditionProviders.isSystemProviderEnabled(ZenModeConfig.EVENT_PATH)) {
-            mConditionProviders.addSystemProvider(new EventConditionProvider());
+            mConditionProviders.addSystemProvider(new EventConditionProvider(helper.getLooper()));
         }
         mConditionProviders.setCallback(this);
     }
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index a3c36ed..1860673 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -98,6 +98,10 @@
         mConditions = new ZenModeConditions(this, conditionProviders);
     }
 
+    public Looper getLooper() {
+        return mHandler.getLooper();
+    }
+
     @Override
     public String toString() {
         return TAG;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 17368aa..f94c77b 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -6386,8 +6386,8 @@
         immersiveSticky = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
         final boolean navAllowedHidden = immersive || immersiveSticky;
 
-        if (!navAllowedHidden
-                && windowTypeToLayerLw(type) > windowTypeToLayerLw(TYPE_INPUT_CONSUMER)) {
+        if (hideNavBarSysui && !navAllowedHidden && windowTypeToLayerLw(win.getBaseType())
+                > windowTypeToLayerLw(TYPE_INPUT_CONSUMER)) {
             // We can't hide the navbar from this window otherwise the input consumer would not get
             // the input events.
             vis = (vis & ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index ad25462..193d812 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -781,6 +781,15 @@
     }
 
     @Override
+    public int getBaseType() {
+        WindowState win = this;
+        while (win.mAttachedWindow != null) {
+            win = win.mAttachedWindow;
+        }
+        return win.mAttrs.type;
+    }
+
+    @Override
     public IApplicationToken getAppToken() {
         return mAppToken != null ? mAppToken.appToken : null;
     }
diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
index e1d1787..316496f 100644
--- a/services/net/java/android/net/dhcp/DhcpClient.java
+++ b/services/net/java/android/net/dhcp/DhcpClient.java
@@ -225,17 +225,18 @@
      * {@code CONNECTIVITY_INTERNAL} permission.
      *
      * @param cmdName the name of the command. The intent's action will be
-     *         {@code android.net.dhcp.DhcpClient.<cmdName>}
+     *         {@code android.net.dhcp.DhcpClient.<mIfaceName>.<cmdName>}
      * @param cmd the command to send to the state machine when the PendingIntent is triggered.
      * @return the PendingIntent
      */
     private PendingIntent createStateMachineCommandIntent(final String cmdName, final int cmd) {
-        String action = DhcpClient.class.getName() + "." + cmdName;
+        String action = DhcpClient.class.getName() + "." + mIfaceName + "." + cmdName;
 
-        // TODO: figure out what values to pass to intent.setPackage() and intent.setClass() that
-        // result in the Intent being received by this class and nowhere else, and use them.
         Intent intent = new Intent(action, null)
                 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+        // TODO: The intent's package covers the whole of the system server, so it's pretty generic.
+        // Consider adding some sort of token as well.
+        intent.setPackage(mContext.getPackageName());
         PendingIntent pendingIntent =  PendingIntent.getBroadcast(mContext, cmd, intent, 0);
 
         mContext.registerReceiver(
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 0a5b668..6de887b 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -248,6 +248,12 @@
     }
 
     void shutdownLocked() {
+        // If there is an active session, cancel it to allow it to clean up its window and other
+        // state.
+        if (mActiveSession != null) {
+            mActiveSession.cancel();
+            mActiveSession = null;
+        }
         try {
             if (mService != null) {
                 mService.shutdown();