Merge "Allow QS detail items to get bigger when text is large" into mnc-dev
diff --git a/api/current.txt b/api/current.txt
index 29fc7b1..2094c7c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4019,10 +4019,12 @@
     ctor public AssistContent();
     method public android.content.ClipData getClipData();
     method public android.os.Bundle getExtras();
+    method public java.lang.String getStructuredData();
     method public android.net.Uri getWebUri();
     method public boolean isAppProvidedIntent();
     method public void setClipData(android.content.ClipData);
     method public void setIntent(android.content.Intent);
+    method public void setStructuredData(java.lang.String);
     method public void setWebUri(android.net.Uri);
   }
 
@@ -26562,7 +26564,6 @@
     field public static final java.lang.String DEBUG_APP = "debug_app";
     field public static final java.lang.String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
     field public static final java.lang.String DEVICE_PROVISIONED = "device_provisioned";
-    field public static final java.lang.String HIDE_CARRIER_NETWORK_SETTINGS = "hide_carrier_network_settings";
     field public static final java.lang.String HTTP_PROXY = "http_proxy";
     field public static final deprecated java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
     field public static final java.lang.String MODE_RINGER = "mode_ringer";
diff --git a/api/system-current.txt b/api/system-current.txt
index 4b4a77c..9386c50 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4114,10 +4114,12 @@
     ctor public AssistContent();
     method public android.content.ClipData getClipData();
     method public android.os.Bundle getExtras();
+    method public java.lang.String getStructuredData();
     method public android.net.Uri getWebUri();
     method public boolean isAppProvidedIntent();
     method public void setClipData(android.content.ClipData);
     method public void setIntent(android.content.Intent);
+    method public void setStructuredData(java.lang.String);
     method public void setWebUri(android.net.Uri);
   }
 
@@ -28598,7 +28600,6 @@
     field public static final java.lang.String DEBUG_APP = "debug_app";
     field public static final java.lang.String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
     field public static final java.lang.String DEVICE_PROVISIONED = "device_provisioned";
-    field public static final java.lang.String HIDE_CARRIER_NETWORK_SETTINGS = "hide_carrier_network_settings";
     field public static final java.lang.String HTTP_PROXY = "http_proxy";
     field public static final deprecated java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
     field public static final java.lang.String MODE_RINGER = "mode_ringer";
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 21dc1e2..fba462b 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -530,7 +530,7 @@
         if (leaf.size() > 0) {
             for (size_t j=0 ; j<pcount ; j++) {
                 if (path == animation.parts[j].path) {
-                    int method;
+                    uint16_t method;
                     // supports only stored png files
                     if (mZip->getEntryInfo(entry, &method, NULL, NULL, NULL, NULL, NULL)) {
                         if (method == ZipFileRO::kCompressStored) {
diff --git a/cmds/idmap/create.cpp b/cmds/idmap/create.cpp
index 16532b8..41395f1 100644
--- a/cmds/idmap/create.cpp
+++ b/cmds/idmap/create.cpp
@@ -23,7 +23,7 @@
         if (entry == NULL) {
             return -1;
         }
-        if (!zip->getEntryInfo(entry, NULL, NULL, NULL, NULL, NULL, reinterpret_cast<long*>(crc))) {
+        if (!zip->getEntryInfo(entry, NULL, NULL, NULL, NULL, NULL, crc)) {
             return -1;
         }
         zip->releaseEntry(entry);
diff --git a/cmds/idmap/scan.cpp b/cmds/idmap/scan.cpp
index 84158d3..612a7eb 100644
--- a/cmds/idmap/scan.cpp
+++ b/cmds/idmap/scan.cpp
@@ -1,4 +1,5 @@
 #include <dirent.h>
+#include <inttypes.h>
 #include <sys/stat.h>
 
 #include "idmap.h"
@@ -130,14 +131,14 @@
             ALOGW("%s: failed to find entry AndroidManifest.xml\n", __FUNCTION__);
             return -1;
         }
-        size_t uncompLen = 0;
-        int method;
+        uint32_t uncompLen = 0;
+        uint16_t method;
         if (!zip->getEntryInfo(entry, &method, &uncompLen, NULL, NULL, NULL, NULL)) {
             ALOGW("%s: failed to read entry info\n", __FUNCTION__);
             return -1;
         }
         if (method != ZipFileRO::kCompressDeflated) {
-            ALOGW("%s: cannot handle zip compression method %d\n", __FUNCTION__, method);
+            ALOGW("%s: cannot handle zip compression method %" PRIu16 "\n", __FUNCTION__, method);
             return -1;
         }
         FileMap *dataMap = zip->createEntryFileMap(entry);
@@ -147,19 +148,19 @@
         }
         char *buf = new char[uncompLen];
         if (NULL == buf) {
-            ALOGW("%s: failed to allocate %zd byte\n", __FUNCTION__, uncompLen);
+            ALOGW("%s: failed to allocate %" PRIu32 " byte\n", __FUNCTION__, uncompLen);
             delete dataMap;
             return -1;
         }
         StreamingZipInflater inflater(dataMap, uncompLen);
         if (inflater.read(buf, uncompLen) < 0) {
-            ALOGW("%s: failed to inflate %zd byte\n", __FUNCTION__, uncompLen);
+            ALOGW("%s: failed to inflate %" PRIu32 " byte\n", __FUNCTION__, uncompLen);
             delete[] buf;
             delete dataMap;
             return -1;
         }
 
-        int priority = parse_manifest(buf, uncompLen, target_package_name);
+        int priority = parse_manifest(buf, static_cast<size_t>(uncompLen), target_package_name);
         delete[] buf;
         delete dataMap;
         return priority;
diff --git a/core/java/android/app/AssistContent.java b/core/java/android/app/AssistContent.java
index 0df9ce5..ad2ba39 100644
--- a/core/java/android/app/AssistContent.java
+++ b/core/java/android/app/AssistContent.java
@@ -33,6 +33,7 @@
 public class AssistContent {
     private boolean mIsAppProvidedIntent = false;
     private Intent mIntent;
+    private String mStructuredData;
     private ClipData mClipData;
     private Uri mUri;
     private final Bundle mExtras;
@@ -125,6 +126,22 @@
     }
 
     /**
+     * Sets optional structured data regarding the content being viewed. The provided data
+     * must be a string represented with <a href="http://json-ld.org/">JSON-LD</a> using the
+     * <a href="http://schema.org/">schema.org</a> vocabulary.
+     */
+    public void setStructuredData(String structuredData) {
+        mStructuredData = structuredData;
+    }
+
+    /**
+     * Returns the current {@link #setStructuredData}.
+     */
+    public String getStructuredData() {
+        return mStructuredData;
+    }
+
+    /**
      * Set a web URI associated with the current data being shown to the user.
      * This URI could be opened in a web browser, or in the app as an
      * {@link Intent#ACTION_VIEW} Intent, to show the same data that is currently
@@ -163,6 +180,9 @@
         if (in.readInt() != 0) {
             mUri = Uri.CREATOR.createFromParcel(in);
         }
+        if (in.readInt() != 0) {
+            mStructuredData = in.readString();
+        }
         mIsAppProvidedIntent = in.readInt() == 1;
         mExtras = in.readBundle();
     }
@@ -187,6 +207,12 @@
         } else {
             dest.writeInt(0);
         }
+        if (mStructuredData != null) {
+            dest.writeInt(1);
+            dest.writeString(mStructuredData);
+        } else {
+            dest.writeInt(0);
+        }
         dest.writeInt(mIsAppProvidedIntent ? 1 : 0);
         dest.writeBundle(mExtras);
     }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 634f116..ed20086 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -403,8 +403,9 @@
         = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER";
 
     /**
-     * A String extra holding the URL-safe base64 encoded SHA-1 checksum of the file at download
-     * location specified in {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}.
+     * A String extra holding the URL-safe base64 encoded SHA-256 or SHA-1 hash (see notes below) of
+     * the file at download location specified in
+     * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}.
      *
      * <p>Either this extra or {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM} should be
      * present. The provided checksum should match the checksum of the file at the download
@@ -413,12 +414,17 @@
      *
      * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
      * provisioning via an NFC bump.
+     *
+     * <p><strong>Note:</strong> for devices running {@link android.os.Build.VERSION_CODES#LOLLIPOP}
+     * and {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} only SHA-1 hash is supported.
+     * Starting from {@link android.os.Build.VERSION_CODES#MNC}, this parameter accepts SHA-256 in
+     * addition to SHA-1. Support for SHA-1 is likely to be removed in future OS releases.
      */
     public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM
         = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM";
 
     /**
-     * A String extra holding the URL-safe base64 encoded SHA-1 checksum of any signature of the
+     * A String extra holding the URL-safe base64 encoded SHA-256 checksum of any signature of the
      * android package archive at the download location specified in {@link
      * #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}.
      *
@@ -510,7 +516,7 @@
         = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER";
 
     /**
-     * A String extra holding the URL-safe base64 encoded SHA-1 checksum of the file at download
+     * A String extra holding the URL-safe base64 encoded SHA-256 checksum of the file at download
      * location specified in
      * {@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION}.
      *
@@ -526,7 +532,7 @@
         = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM";
 
     /**
-     * A String extra holding the URL-safe base64 encoded SHA-1 checksum of any signature of the
+     * A String extra holding the URL-safe base64 encoded SHA-256 checksum of any signature of the
      * android package archive at the download location specified in {@link
      * #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION}.
      *
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index c92c256..287e0c5 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -4024,7 +4024,7 @@
 
     public static final PublicKey parsePublicKey(final String encodedPublicKey) {
         if (encodedPublicKey == null) {
-            Slog.i(TAG, "Could not parse null public key");
+            Slog.w(TAG, "Could not parse null public key");
             return null;
         }
 
@@ -4033,7 +4033,7 @@
             final byte[] encoded = Base64.decode(encodedPublicKey, Base64.DEFAULT);
             keySpec = new X509EncodedKeySpec(encoded);
         } catch (IllegalArgumentException e) {
-            Slog.i(TAG, "Could not parse verifier public key; invalid Base64");
+            Slog.w(TAG, "Could not parse verifier public key; invalid Base64");
             return null;
         }
 
@@ -4042,23 +4042,32 @@
             final KeyFactory keyFactory = KeyFactory.getInstance("RSA");
             return keyFactory.generatePublic(keySpec);
         } catch (NoSuchAlgorithmException e) {
-            Log.wtf(TAG, "Could not parse public key because RSA isn't included in build");
-            return null;
+            Slog.wtf(TAG, "Could not parse public key: RSA KeyFactory not included in build");
         } catch (InvalidKeySpecException e) {
             // Not a RSA public key.
         }
 
+        /* Now try it as a ECDSA key. */
+        try {
+            final KeyFactory keyFactory = KeyFactory.getInstance("EC");
+            return keyFactory.generatePublic(keySpec);
+        } catch (NoSuchAlgorithmException e) {
+            Slog.wtf(TAG, "Could not parse public key: EC KeyFactory not included in build");
+        } catch (InvalidKeySpecException e) {
+            // Not a ECDSA public key.
+        }
+
         /* Now try it as a DSA key. */
         try {
             final KeyFactory keyFactory = KeyFactory.getInstance("DSA");
             return keyFactory.generatePublic(keySpec);
         } catch (NoSuchAlgorithmException e) {
-            Log.wtf(TAG, "Could not parse public key because DSA isn't included in build");
-            return null;
+            Slog.wtf(TAG, "Could not parse public key: DSA KeyFactory not included in build");
         } catch (InvalidKeySpecException e) {
             // Not a DSA public key.
         }
 
+        /* Not a supported key type */
         return null;
     }
 
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 152bc22..27d14b3 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1093,14 +1093,28 @@
      * <p>so <code>[x_s, y_s]</code> is the pixel coordinates of the world
      * point, <code>z_s = 1</code>, and <code>w_s</code> is a measurement of disparity
      * (depth) in pixel coordinates.</p>
+     * <p>Note that the coordinate system for this transform is the
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} system,
+     * where <code>(0,0)</code> is the top-left of the
+     * preCorrectionActiveArraySize rectangle. Once the pose and
+     * intrinsic calibration transforms have been applied to a
+     * world point, then the android.lens.radialDistortion
+     * transform needs to be applied, and the result adjusted to
+     * be in the {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} coordinate
+     * system (where <code>(0, 0)</code> is the top-left of the
+     * activeArraySize rectangle), to determine the final pixel
+     * coordinate of the world point for processed (non-RAW)
+     * output buffers.</p>
      * <p><b>Units</b>:
-     * Pixels in the {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} coordinate
-     * system.</p>
+     * Pixels in the
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}
+     * coordinate system.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      *
      * @see CameraCharacteristics#LENS_POSE_ROTATION
      * @see CameraCharacteristics#LENS_POSE_TRANSLATION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+     * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
      */
     @PublicKey
     public static final Key<float[]> LENS_INTRINSIC_CALIBRATION =
@@ -2006,19 +2020,19 @@
      * {@link CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE android.sensor.info.pixelArraySize}:</p>
      * <ol>
      * <li>Choose a pixel (x', y') within the active array region of the raw buffer given in
-     * android.sensor.info.preCorrectedActiveArraySize, otherwise this pixel is considered
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, otherwise this pixel is considered
      * to be outside of the FOV, and will not be shown in the processed output image.</li>
      * <li>Apply geometric distortion correction to get the post-distortion pixel coordinate,
      * (x_i, y_i). When applying geometric correction metadata, note that metadata for raw
      * buffers is defined relative to the top, left of the
-     * android.sensor.info.preCorrectedActiveArraySize rectangle.</li>
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} rectangle.</li>
      * <li>If the resulting corrected pixel coordinate is within the region given in
      * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, then the position of this pixel in the
      * processed output image buffer is <code>(x_i - activeArray.left, y_i - activeArray.top)</code>,
      * when the top, left coordinate of that buffer is treated as (0, 0).</li>
      * </ol>
      * <p>Thus, for pixel x',y' = (25, 25) on a sensor where {@link CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE android.sensor.info.pixelArraySize}
-     * is (100,100), android.sensor.info.preCorrectedActiveArraySize is (10, 10, 100, 100),
+     * is (100,100), {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} is (10, 10, 100, 100),
      * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} is (20, 20, 80, 80), and the geometric distortion
      * correction doesn't change the pixel coordinate, the resulting pixel selected in
      * pixel coordinates would be x,y = (25, 25) relative to the top,left of the raw buffer
@@ -2042,6 +2056,7 @@
      *
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
      * @see CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE
+     * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
      */
     @PublicKey
     public static final Key<android.graphics.Rect> SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE =
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 479583c..da216aa 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2655,14 +2655,28 @@
      * <p>so <code>[x_s, y_s]</code> is the pixel coordinates of the world
      * point, <code>z_s = 1</code>, and <code>w_s</code> is a measurement of disparity
      * (depth) in pixel coordinates.</p>
+     * <p>Note that the coordinate system for this transform is the
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} system,
+     * where <code>(0,0)</code> is the top-left of the
+     * preCorrectionActiveArraySize rectangle. Once the pose and
+     * intrinsic calibration transforms have been applied to a
+     * world point, then the android.lens.radialDistortion
+     * transform needs to be applied, and the result adjusted to
+     * be in the {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} coordinate
+     * system (where <code>(0, 0)</code> is the top-left of the
+     * activeArraySize rectangle), to determine the final pixel
+     * coordinate of the world point for processed (non-RAW)
+     * output buffers.</p>
      * <p><b>Units</b>:
-     * Pixels in the {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} coordinate
-     * system.</p>
+     * Pixels in the
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}
+     * coordinate system.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      *
      * @see CameraCharacteristics#LENS_POSE_ROTATION
      * @see CameraCharacteristics#LENS_POSE_TRANSLATION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+     * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
      */
     @PublicKey
     public static final Key<float[]> LENS_INTRINSIC_CALIBRATION =
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index dfd72c2..3e9c9de 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7232,13 +7232,6 @@
                 "preferred_network_mode";
 
         /**
-         * Setting to 1 will hide carrier network settings.
-         * Default is 0.
-         */
-        public static final String HIDE_CARRIER_NETWORK_SETTINGS =
-                "hide_carrier_network_settings";
-
-        /**
          * Name of an application package to be debugged.
          */
         public static final String DEBUG_APP = "debug_app";
diff --git a/core/java/android/speech/srec/MicrophoneInputStream.java b/core/java/android/speech/srec/MicrophoneInputStream.java
deleted file mode 100644
index 94db176..0000000
--- a/core/java/android/speech/srec/MicrophoneInputStream.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  MicrophoneInputStream.java                                               *
- *                                                                           *
- *  Copyright 2007 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  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.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-
-package android.speech.srec;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.IllegalStateException;
-
-
-/**
- * PCM input stream from the microphone, 16 bits per sample.
- */
-public final class MicrophoneInputStream extends InputStream {
-    static {
-        System.loadLibrary("srec_jni");
-    }
-    
-    private final static String TAG = "MicrophoneInputStream";
-    private long mAudioRecord = 0;
-    private byte[] mOneByte = new byte[1];
-    
-    /**
-     * MicrophoneInputStream constructor.
-     * @param sampleRate sample rate of the microphone, typically 11025 or 8000.
-     * @param fifoDepth depth of the real time fifo, measured in sampleRate clock ticks.
-     * This determines how long an application may delay before losing data.
-     */
-    public MicrophoneInputStream(int sampleRate, int fifoDepth) throws IOException {
-        mAudioRecord = AudioRecordNew(sampleRate, fifoDepth);
-        if (mAudioRecord == 0) throw new IOException("AudioRecord constructor failed - busy?");
-        int status = AudioRecordStart(mAudioRecord);
-        if (status != 0) {
-            close();
-            throw new IOException("AudioRecord start failed: " + status);
-        }
-    }
-
-    @Override
-    public int read() throws IOException {
-        if (mAudioRecord == 0) throw new IllegalStateException("not open");
-        int rtn = AudioRecordRead(mAudioRecord, mOneByte, 0, 1);
-        return rtn == 1 ? ((int)mOneByte[0] & 0xff) : -1;
-    }
-
-    @Override
-    public int read(byte[] b) throws IOException {
-        if (mAudioRecord == 0) throw new IllegalStateException("not open");
-        return AudioRecordRead(mAudioRecord, b, 0, b.length);
-    }
-    
-    @Override
-    public int read(byte[] b, int offset, int length) throws IOException {
-        if (mAudioRecord == 0) throw new IllegalStateException("not open");
-        // TODO: should we force all reads to be a multiple of the sample size?
-        return AudioRecordRead(mAudioRecord, b, offset, length);
-    }
-    
-    /**
-     * Closes this stream.
-     */
-    @Override
-    public void close() throws IOException {
-        if (mAudioRecord != 0) {
-            try {
-                AudioRecordStop(mAudioRecord);
-            } finally {
-                try {
-                    AudioRecordDelete(mAudioRecord);
-                } finally {
-                    mAudioRecord = 0;
-                }
-            }
-        }
-    }
-    
-    @Override
-    protected void finalize() throws Throwable {
-        if (mAudioRecord != 0) {
-            close();
-            throw new IOException("someone forgot to close MicrophoneInputStream");
-        }
-    }
-    
-    //
-    // AudioRecord JNI interface
-    //
-    private static native long AudioRecordNew(int sampleRate, int fifoDepth);
-    private static native int AudioRecordStart(long audioRecord);
-    private static native int AudioRecordRead(long audioRecord, byte[] b, int offset, int length) throws IOException;
-    private static native void AudioRecordStop(long audioRecord) throws IOException;
-    private static native void AudioRecordDelete(long audioRecord) throws IOException;
-}
diff --git a/core/java/android/speech/srec/Recognizer.java b/core/java/android/speech/srec/Recognizer.java
deleted file mode 100644
index 6c491a0..0000000
--- a/core/java/android/speech/srec/Recognizer.java
+++ /dev/null
@@ -1,716 +0,0 @@
-/*
- * ---------------------------------------------------------------------------
- * Recognizer.java
- * 
- * Copyright 2007 Nuance Communciations, Inc.
- * 
- * 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.
- * 
- * ---------------------------------------------------------------------------
- */
-
-
-package android.speech.srec;
-
-import java.io.File;
-import java.io.InputStream;
-import java.io.IOException;
-import java.util.Locale;
-
-/**
- * Simple, synchronous speech recognizer, using the Nuance SREC package.
- * Usages proceeds as follows:
- * 
- * <ul>
- * <li>Create a <code>Recognizer</code>.
- * <li>Create a <code>Recognizer.Grammar</code>.
- * <li>Setup the <code>Recognizer.Grammar</code>.
- * <li>Reset the <code>Recognizer.Grammar</code> slots, if needed.
- * <li>Fill the <code>Recognizer.Grammar</code> slots, if needed.
- * <li>Compile the <code>Recognizer.Grammar</code>, if needed.
- * <li>Save the filled <code>Recognizer.Grammar</code>, if needed.
- * <li>Start the <code>Recognizer</code>.
- * <li>Loop over <code>advance</code> and <code>putAudio</code> until recognition complete.
- * <li>Fetch and process results, or notify of failure.
- * <li>Stop the <code>Recognizer</code>.
- * <li>Destroy the <code>Recognizer</code>.
- * </ul>
- * 
- * <p>Below is example code</p>
- * 
- * <pre class="prettyprint">
- * 
- * // create and start audio input
- * InputStream audio = new MicrophoneInputStream(11025, 11025*5);
- * // create a Recognizer
- * String cdir = Recognizer.getConfigDir(null);
- * Recognizer recognizer = new Recognizer(cdir + "/baseline11k.par");
- * // create and load a Grammar
- * Recognizer.Grammar grammar = recognizer.new Grammar(cdir + "/grammars/VoiceDialer.g2g");
- * // setup the Grammar to work with the Recognizer
- * grammar.setupRecognizer();
- * // fill the Grammar slots with names and save, if required
- * grammar.resetAllSlots();
- * for (String name : names) grammar.addWordToSlot("@Names", name, null, 1, "V=1");
- * grammar.compile();
- * grammar.save(".../foo.g2g");
- * // start the Recognizer
- * recognizer.start();
- * // loop over Recognizer events
- * while (true) {
- *     switch (recognizer.advance()) {
- *     case Recognizer.EVENT_INCOMPLETE:
- *     case Recognizer.EVENT_STARTED:
- *     case Recognizer.EVENT_START_OF_VOICING:
- *     case Recognizer.EVENT_END_OF_VOICING:
- *         // let the Recognizer continue to run
- *         continue;
- *     case Recognizer.EVENT_RECOGNITION_RESULT:
- *         // success, so fetch results here!
- *         for (int i = 0; i < recognizer.getResultCount(); i++) {
- *             String result = recognizer.getResult(i, Recognizer.KEY_LITERAL);
- *         }
- *         break;
- *     case Recognizer.EVENT_NEED_MORE_AUDIO:
- *         // put more audio in the Recognizer
- *         recognizer.putAudio(audio);
- *         continue;
- *     default:
- *         notifyFailure();
- *         break;
- *     }
- *     break;
- * }
- * // stop the Recognizer
- * recognizer.stop();
- * // destroy the Recognizer
- * recognizer.destroy();
- * // stop the audio device
- * audio.close();
- * 
- * </pre>
- */
-public final class Recognizer {
-    static {
-        System.loadLibrary("srec_jni");
-    }
-
-    private static String TAG = "Recognizer";
-    
-    /**
-     * Result key corresponding to confidence score.
-     */
-    public static final String KEY_CONFIDENCE = "conf";
-    
-    /**
-     * Result key corresponding to literal text.
-     */
-    public static final String KEY_LITERAL = "literal";
-    
-    /**
-     * Result key corresponding to semantic meaning text.
-     */
-    public static final String KEY_MEANING = "meaning";
-
-    // handle to SR_Vocabulary object
-    private long mVocabulary = 0;
-    
-    // handle to SR_Recognizer object
-    private long mRecognizer = 0;
-    
-    // Grammar currently associated with Recognizer via SR_GrammarSetupRecognizer
-    private Grammar mActiveGrammar = null;
-    
-    /**
-     * Get the pathname of the SREC configuration directory corresponding to the
-     * language indicated by the Locale.
-     * This directory contains dictionaries, speech models,
-     * configuration files, and other data needed by the Recognizer.
-     * @param locale <code>Locale</code> corresponding to the desired language,
-     * or null for default, currently <code>Locale.US</code>.
-     * @return Pathname of the configuration directory.
-     */
-    public static String getConfigDir(Locale locale) {
-        if (locale == null) locale = Locale.US;
-        String dir = "/system/usr/srec/config/" +
-                locale.toString().replace('_', '.').toLowerCase(Locale.ROOT);
-        if ((new File(dir)).isDirectory()) return dir;
-        return null;
-    }
-
-    /**
-     * Create an instance of a SREC speech recognizer.
-     * 
-     * @param configFile pathname of the baseline*.par configuration file,
-     * which in turn contains references to dictionaries, speech models,
-     * and other data needed to configure and operate the recognizer.
-     * A separate config file is needed for each audio sample rate.
-     * Two files, baseline11k.par and baseline8k.par, which correspond to
-     * 11025 and 8000 hz, are present in the directory indicated by
-     * {@link #getConfigDir}.
-     * @throws IOException
-     */
-    public Recognizer(String configFile) throws IOException {
-        PMemInit();
-        SR_SessionCreate(configFile);
-        mRecognizer = SR_RecognizerCreate();
-        SR_RecognizerSetup(mRecognizer);
-        mVocabulary = SR_VocabularyLoad();
-    }
-
-    /**
-     * Represents a grammar loaded into the Recognizer.
-     */
-    public class Grammar {
-        private long mGrammar = 0;
-
-        /**
-         * Create a <code>Grammar</code> instance.
-         * @param g2gFileName pathname of g2g file.
-         */
-        public Grammar(String g2gFileName) throws IOException {
-            mGrammar = SR_GrammarLoad(g2gFileName);
-            SR_GrammarSetupVocabulary(mGrammar, mVocabulary);
-        }
-
-        /**
-         * Reset all slots.
-         */
-        public void resetAllSlots() {
-            SR_GrammarResetAllSlots(mGrammar);
-        }
-
-        /**
-         * Add a word to a slot.
-         * 
-         * @param slot slot name.
-         * @param word word to insert.
-         * @param pron pronunciation, or null to derive from word.
-         * @param weight weight to give the word.  One is normal, 50 is low.
-         * @param tag semantic meaning tag string.
-         */
-        public void addWordToSlot(String slot, String word, String pron, int weight, String tag) {
-            SR_GrammarAddWordToSlot(mGrammar, slot, word, pron, weight, tag); 
-        }
-
-        /**
-         * Compile all slots.
-         */
-        public void compile() {
-            SR_GrammarCompile(mGrammar);
-        }
-
-        /**
-         * Setup <code>Grammar</code> with <code>Recognizer</code>.
-         */
-        public void setupRecognizer() {
-            SR_GrammarSetupRecognizer(mGrammar, mRecognizer);
-            mActiveGrammar = this;
-        }
-
-        /**
-         * Save <code>Grammar</code> to g2g file.
-         * 
-         * @param g2gFileName
-         * @throws IOException
-         */
-        public void save(String g2gFileName) throws IOException {
-            SR_GrammarSave(mGrammar, g2gFileName);
-        }
-
-        /**
-         * Release resources associated with this <code>Grammar</code>.
-         */
-        public void destroy() {
-            // TODO: need to do cleanup and disassociation with Recognizer
-            if (mGrammar != 0) {
-                SR_GrammarDestroy(mGrammar);
-                mGrammar = 0;
-            }
-        }
-
-        /**
-         * Clean up resources.
-         */
-        protected void finalize() {
-            if (mGrammar != 0) {
-                destroy();
-                throw new IllegalStateException("someone forgot to destroy Grammar");
-            }
-        }
-    }
-
-    /**
-     * Start recognition
-     */
-    public void start() {
-        // TODO: shouldn't be here?
-        SR_RecognizerActivateRule(mRecognizer, mActiveGrammar.mGrammar, "trash", 1);
-        SR_RecognizerStart(mRecognizer);
-    }
-    
-    /**
-     * Process some audio and return the current status.
-     * @return recognition event, one of:
-     * <ul>
-     * <li><code>EVENT_INVALID</code>
-     * <li><code>EVENT_NO_MATCH</code>
-     * <li><code>EVENT_INCOMPLETE</code>
-     * <li><code>EVENT_STARTED</code>
-     * <li><code>EVENT_STOPPED</code>
-     * <li><code>EVENT_START_OF_VOICING</code>
-     * <li><code>EVENT_END_OF_VOICING</code>
-     * <li><code>EVENT_SPOKE_TOO_SOON</code>
-     * <li><code>EVENT_RECOGNITION_RESULT</code>
-     * <li><code>EVENT_START_OF_UTTERANCE_TIMEOUT</code>
-     * <li><code>EVENT_RECOGNITION_TIMEOUT</code>
-     * <li><code>EVENT_NEED_MORE_AUDIO</code>
-     * <li><code>EVENT_MAX_SPEECH</code>
-     * </ul>
-     */
-    public int advance() {
-        return SR_RecognizerAdvance(mRecognizer);
-    }
-    
-    /**
-     * Put audio samples into the <code>Recognizer</code>.
-     * @param buf holds the audio samples.
-     * @param offset offset of the first sample.
-     * @param length number of bytes containing samples.
-     * @param isLast indicates no more audio data, normally false.
-     * @return number of bytes accepted.
-     */
-    public int putAudio(byte[] buf, int offset, int length, boolean isLast) {
-        return SR_RecognizerPutAudio(mRecognizer, buf, offset, length, isLast);
-    }
-    
-    /**
-     * Read audio samples from an <code>InputStream</code> and put them in the
-     * <code>Recognizer</code>.
-     * @param audio <code>InputStream</code> containing PCM audio samples.
-     */
-    public void putAudio(InputStream audio) throws IOException {
-        // make sure the audio buffer is allocated
-        if (mPutAudioBuffer == null) mPutAudioBuffer = new byte[512];
-        // read some data
-        int nbytes = audio.read(mPutAudioBuffer);
-        // eof, so signal Recognizer
-        if (nbytes == -1) {
-            SR_RecognizerPutAudio(mRecognizer, mPutAudioBuffer, 0, 0, true);
-        }
-        // put it into the Recognizer
-        else if (nbytes != SR_RecognizerPutAudio(mRecognizer, mPutAudioBuffer, 0, nbytes, false)) {
-            throw new IOException("SR_RecognizerPutAudio failed nbytes=" + nbytes);
-        }
-    }
-    
-    // audio buffer for putAudio(InputStream)
-    private byte[] mPutAudioBuffer = null;
-
-    /**
-     * Get the number of recognition results.  Must be called after
-     * <code>EVENT_RECOGNITION_RESULT</code> is returned by
-     * <code>advance</code>, but before <code>stop</code>.
-     * 
-     * @return number of results in nbest list.
-     */
-    public int getResultCount() {
-        return SR_RecognizerResultGetSize(mRecognizer);
-    }
-
-    /**
-     * Get a set of keys for the result.  Must be called after
-     * <code>EVENT_RECOGNITION_RESULT</code> is returned by
-     * <code>advance</code>, but before <code>stop</code>.
-     * 
-     * @param index index of result.
-     * @return array of keys.
-     */
-    public String[] getResultKeys(int index) {
-        return SR_RecognizerResultGetKeyList(mRecognizer, index);
-    }
-
-    /**
-     * Get a result value.  Must be called after
-     * <code>EVENT_RECOGNITION_RESULT</code> is returned by
-     * <code>advance</code>, but before <code>stop</code>.
-     * 
-     * @param index index of the result.
-     * @param key key of the result.  This is typically one of
-     * <code>KEY_CONFIDENCE</code>, <code>KEY_LITERAL</code>, or
-     * <code>KEY_MEANING</code>, but the user can also define their own keys
-     * in a grxml file, or in the <code>tag</code> slot of
-     * <code>Grammar.addWordToSlot</code>.
-     * @return the result.
-     */
-    public String getResult(int index, String key) {
-        return SR_RecognizerResultGetValue(mRecognizer, index, key);
-    }
-
-    /**
-     * Stop the <code>Recognizer</code>.
-     */
-    public void stop() {
-        SR_RecognizerStop(mRecognizer);
-        SR_RecognizerDeactivateRule(mRecognizer, mActiveGrammar.mGrammar, "trash");
-    }
-    
-    /**
-     * Reset the acoustic state vectorto it's default value.
-     * 
-     * @hide
-     */
-    public void resetAcousticState() {
-        SR_AcousticStateReset(mRecognizer);
-    }
-    
-    /**
-     * Set the acoustic state vector.
-     * @param state String containing the acoustic state vector.
-     * 
-     * @hide
-     */
-    public void setAcousticState(String state) {
-        SR_AcousticStateSet(mRecognizer, state);
-    }
-    
-    /**
-     * Get the acoustic state vector.
-     * @return String containing the acoustic state vector.
-     * 
-     * @hide
-     */
-    public String getAcousticState() {
-        return SR_AcousticStateGet(mRecognizer);
-    }
-
-    /**
-     * Clean up resources.
-     */
-    public void destroy() {
-        try {
-            if (mVocabulary != 0) SR_VocabularyDestroy(mVocabulary);
-        } finally {
-            mVocabulary = 0;
-            try {
-                if (mRecognizer != 0) SR_RecognizerUnsetup(mRecognizer);
-            } finally {
-                try {
-                    if (mRecognizer != 0) SR_RecognizerDestroy(mRecognizer);
-                } finally {
-                    mRecognizer = 0;
-                    try {
-                        SR_SessionDestroy();
-                    } finally {
-                        PMemShutdown();
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Clean up resources.
-     */
-    protected void finalize() throws Throwable {
-        if (mVocabulary != 0 || mRecognizer != 0) {
-            destroy();
-            throw new IllegalStateException("someone forgot to destroy Recognizer");
-        }
-    }
-    
-    /* an example session captured, for reference
-    void doall() {
-        if (PMemInit ( )
-           || lhs_audioinOpen ( WAVE_MAPPER, SREC_TEST_DEFAULT_AUDIO_FREQUENCY, &audio_in_handle )
-           || srec_test_init_application_data ( &applicationData, argc, argv )
-           || SR_SessionCreate ( "/system/usr/srec/config/en.us/baseline11k.par" )
-           || SR_RecognizerCreate ( &applicationData.recognizer )
-           || SR_RecognizerSetup ( applicationData.recognizer)
-           || ESR_SessionGetLCHAR ( L("cmdline.vocabulary"), filename, &flen )
-           || SR_VocabularyLoad ( filename, &applicationData.vocabulary )
-           || SR_VocabularyGetLanguage ( applicationData.vocabulary, &applicationData.locale )
-           || (applicationData.nametag = NULL)
-           || SR_NametagsCreate ( &applicationData.nametags )
-           || (LSTRCPY ( applicationData.grammars [0].grammar_path, "/system/usr/srec/config/en.us/grammars/VoiceDialer.g2g" ), 0)
-           || (LSTRCPY ( applicationData.grammars [0].grammarID, "BothTags" ), 0)
-           || (LSTRCPY ( applicationData.grammars [0].ruleName, "trash" ), 0)
-           || (applicationData.grammars [0].is_ve_grammar = ESR_FALSE, 0)
-           || SR_GrammarLoad (applicationData.grammars [0].grammar_path, &applicationData.grammars [applicationData.grammarCount].grammar )
-           || SR_GrammarSetupVocabulary ( applicationData.grammars [0].grammar, applicationData.vocabulary )
-           || SR_GrammarSetupRecognizer( applicationData.grammars [0].grammar, applicationData.recognizer )
-           || SR_GrammarSetDispatchFunction ( applicationData.grammars [0].grammar, L("myDSMCallback"), NULL, myDSMCallback )
-           || (applicationData.grammarCount++, 0)
-           || SR_RecognizerActivateRule ( applicationData.recognizer, applicationData.grammars [0].grammar,
-                           applicationData.grammars [0].ruleName, 1 )
-           || (applicationData.active_grammar_num = 0, 0)
-           || lhs_audioinStart ( audio_in_handle )
-           || SR_RecognizerStart ( applicationData.recognizer )
-           || strl ( applicationData.grammars [0].grammar, &applicationData, audio_in_handle, &recognition_count )
-           || SR_RecognizerStop ( applicationData.recognizer )
-           || lhs_audioinStop ( audio_in_handle )
-           || SR_RecognizerDeactivateRule ( applicationData.recognizer, applicationData.grammars [0].grammar, applicationData.grammars [0].ruleName )
-           || (applicationData.active_grammar_num = -1, 0)
-           || SR_GrammarDestroy ( applicationData.grammars [0].grammar )
-           || (applicationData.grammarCount--, 0)
-           || SR_NametagsDestroy ( applicationData.nametags )
-           || (applicationData.nametags = NULL, 0)
-           || SR_VocabularyDestroy ( applicationData.vocabulary )
-           || (applicationData.vocabulary = NULL)
-           || SR_RecognizerUnsetup ( applicationData.recognizer) // releases acoustic models
-           || SR_RecognizerDestroy ( applicationData.recognizer )
-           || (applicationData.recognizer = NULL)
-           || SR_SessionDestroy ( )
-           || srec_test_shutdown_application_data ( &applicationData )
-           || lhs_audioinClose ( &audio_in_handle )
-           || PMemShutdown ( )
-    }
-    */
-
-
-    //
-    // PMem native methods
-    //
-    private static native void PMemInit();
-    private static native void PMemShutdown();
-
-
-    //
-    // SR_Session native methods
-    //
-    private static native void SR_SessionCreate(String filename);
-    private static native void SR_SessionDestroy();
-
-
-    //
-    // SR_Recognizer native methods
-    //
-    
-    /**
-     * Reserved value.
-     */
-    public final static int EVENT_INVALID = 0;
-    
-    /**
-     * <code>Recognizer</code> could not find a match for the utterance.
-     */
-    public final static int EVENT_NO_MATCH = 1;
-    
-    /**
-     * <code>Recognizer</code> processed one frame of audio.
-     */
-    public final static int EVENT_INCOMPLETE = 2;
-    
-    /**
-     * <code>Recognizer</code> has just been started.
-     */
-    public final static int EVENT_STARTED = 3;
-    
-    /**
-     * <code>Recognizer</code> is stopped.
-     */
-    public final static int EVENT_STOPPED = 4;
-    
-    /**
-     * Beginning of speech detected.
-     */
-    public final static int EVENT_START_OF_VOICING = 5;
-    
-    /**
-     * End of speech detected.
-     */
-    public final static int EVENT_END_OF_VOICING = 6;
-    
-    /**
-     * Beginning of utterance occured too soon.
-     */
-    public final static int EVENT_SPOKE_TOO_SOON = 7;
-    
-    /**
-     * Recognition match detected.
-     */
-    public final static int EVENT_RECOGNITION_RESULT = 8;
-    
-    /**
-     * Timeout occured before beginning of utterance.
-     */
-    public final static int EVENT_START_OF_UTTERANCE_TIMEOUT = 9;
-    
-    /**
-     * Timeout occured before speech recognition could complete.
-     */
-    public final static int EVENT_RECOGNITION_TIMEOUT = 10;
-    
-    /**
-     * Not enough samples to process one frame.
-     */
-    public final static int EVENT_NEED_MORE_AUDIO = 11;
-    
-    /**
-     * More audio encountered than is allowed by 'swirec_max_speech_duration'.
-     */
-    public final static int EVENT_MAX_SPEECH = 12;
-
-    /**
-     * Produce a displayable string from an <code>advance</code> event.
-     * @param event
-     * @return String representing the event.
-     */
-    public static String eventToString(int event) {
-        switch (event) {
-            case EVENT_INVALID:
-                return "EVENT_INVALID";
-            case EVENT_NO_MATCH:
-                return "EVENT_NO_MATCH";
-            case EVENT_INCOMPLETE:
-                return "EVENT_INCOMPLETE";
-            case EVENT_STARTED:
-                return "EVENT_STARTED";
-            case EVENT_STOPPED:
-                return "EVENT_STOPPED";
-            case EVENT_START_OF_VOICING:
-                return "EVENT_START_OF_VOICING";
-            case EVENT_END_OF_VOICING:
-                return "EVENT_END_OF_VOICING";
-            case EVENT_SPOKE_TOO_SOON:
-                return "EVENT_SPOKE_TOO_SOON";
-            case EVENT_RECOGNITION_RESULT:
-                return "EVENT_RECOGNITION_RESULT";
-            case EVENT_START_OF_UTTERANCE_TIMEOUT:
-                return "EVENT_START_OF_UTTERANCE_TIMEOUT";
-            case EVENT_RECOGNITION_TIMEOUT:
-                return "EVENT_RECOGNITION_TIMEOUT";
-            case EVENT_NEED_MORE_AUDIO:
-                return "EVENT_NEED_MORE_AUDIO";
-            case EVENT_MAX_SPEECH:
-                return "EVENT_MAX_SPEECH";
-        }
-        return "EVENT_" + event;
-    }
-
-    //
-    // SR_Recognizer methods
-    //
-    private static native void SR_RecognizerStart(long recognizer);
-    private static native void SR_RecognizerStop(long recognizer);
-    private static native long SR_RecognizerCreate();
-    private static native void SR_RecognizerDestroy(long recognizer);
-    private static native void SR_RecognizerSetup(long recognizer);
-    private static native void SR_RecognizerUnsetup(long recognizer);
-    private static native boolean SR_RecognizerIsSetup(long recognizer);
-    private static native String SR_RecognizerGetParameter(long recognizer, String key);
-    private static native int SR_RecognizerGetSize_tParameter(long recognizer, String key);
-    private static native boolean SR_RecognizerGetBoolParameter(long recognizer, String key);
-    private static native void SR_RecognizerSetParameter(long recognizer, String key, String value);
-    private static native void SR_RecognizerSetSize_tParameter(long recognizer,
-            String key, int value);
-    private static native void SR_RecognizerSetBoolParameter(long recognizer, String key,
-            boolean value);
-    private static native void SR_RecognizerSetupRule(long recognizer, long grammar,
-            String ruleName);
-    private static native boolean SR_RecognizerHasSetupRules(long recognizer);
-    private static native void SR_RecognizerActivateRule(long recognizer, long grammar,
-            String ruleName, int weight);
-    private static native void SR_RecognizerDeactivateRule(long recognizer, long grammar,
-            String ruleName);
-    private static native void SR_RecognizerDeactivateAllRules(long recognizer);
-    private static native boolean SR_RecognizerIsActiveRule(long recognizer, long grammar,
-            String ruleName);
-    private static native boolean SR_RecognizerCheckGrammarConsistency(long recognizer,
-            long grammar);
-    private static native int SR_RecognizerPutAudio(long recognizer, byte[] buffer, int offset,
-            int length, boolean isLast);
-    private static native int SR_RecognizerAdvance(long recognizer);
-    // private static native void SR_RecognizerLoadUtterance(long recognizer,
-    //         const LCHAR* filename);
-    // private static native void SR_RecognizerLoadWaveFile(long recognizer,
-    //         const LCHAR* filename);
-    // private static native void SR_RecognizerSetLockFunction(long recognizer,
-    //         SR_RecognizerLockFunction function, void* data);
-    private static native boolean SR_RecognizerIsSignalClipping(long recognizer);
-    private static native boolean SR_RecognizerIsSignalDCOffset(long recognizer);
-    private static native boolean SR_RecognizerIsSignalNoisy(long recognizer);
-    private static native boolean SR_RecognizerIsSignalTooQuiet(long recognizer);
-    private static native boolean SR_RecognizerIsSignalTooFewSamples(long recognizer);
-    private static native boolean SR_RecognizerIsSignalTooManySamples(long recognizer);
-    // private static native void SR_Recognizer_Change_Sample_Rate (size_t new_sample_rate);
-    
-    
-    //
-    // SR_AcousticState native methods
-    //
-    private static native void SR_AcousticStateReset(long recognizer);
-    private static native void SR_AcousticStateSet(long recognizer, String state);
-    private static native String SR_AcousticStateGet(long recognizer);
-
-
-    //
-    // SR_Grammar native methods
-    //
-    private static native void SR_GrammarCompile(long grammar);
-    private static native void SR_GrammarAddWordToSlot(long grammar, String slot,
-            String word, String pronunciation, int weight, String tag);
-    private static native void SR_GrammarResetAllSlots(long grammar);
-    // private static native void SR_GrammarAddNametagToSlot(long grammar, String slot,
-    // const struct SR_Nametag_t* nametag, int weight, String tag);
-    private static native void SR_GrammarSetupVocabulary(long grammar, long vocabulary);
-    // private static native void SR_GrammarSetupModels(long grammar, SR_AcousticModels* models);
-    private static native void SR_GrammarSetupRecognizer(long grammar, long recognizer);
-    private static native void SR_GrammarUnsetupRecognizer(long grammar);
-    // private static native void SR_GrammarGetModels(long grammar,SR_AcousticModels** models);
-    private static native long SR_GrammarCreate();
-    private static native void SR_GrammarDestroy(long grammar);
-    private static native long SR_GrammarLoad(String filename);
-    private static native void SR_GrammarSave(long grammar, String filename);
-    // private static native void SR_GrammarSetDispatchFunction(long grammar,
-    //         const LCHAR* name, void* userData, SR_GrammarDispatchFunction function);
-    // private static native void SR_GrammarSetParameter(long grammar, const
-    //         LCHAR* key, void* value);
-    // private static native void SR_GrammarSetSize_tParameter(long grammar,
-    //         const LCHAR* key, size_t value);
-    // private static native void SR_GrammarGetParameter(long grammar, const
-    //         LCHAR* key, void** value);
-    // private static native void SR_GrammarGetSize_tParameter(long grammar,
-    //         const LCHAR* key, size_t* value);
-    // private static native void SR_GrammarCheckParse(long grammar, const LCHAR*
-    //         transcription, SR_SemanticResult** result, size_t* resultCount);
-    private static native void SR_GrammarAllowOnly(long grammar, String transcription);
-    private static native void SR_GrammarAllowAll(long grammar);
-
-
-    //
-    // SR_Vocabulary native methods
-    //
-    // private static native int SR_VocabularyCreate();
-    private static native long SR_VocabularyLoad();
-    // private static native void SR_VocabularySave(SR_Vocabulary* self,
-    //         const LCHAR* filename);
-    // private static native void SR_VocabularyAddWord(SR_Vocabulary* self,
-    //         const LCHAR* word);
-    // private static native void SR_VocabularyGetLanguage(SR_Vocabulary* self,
-    //         ESR_Locale* locale);
-    private static native void SR_VocabularyDestroy(long vocabulary);
-    private static native String SR_VocabularyGetPronunciation(long vocabulary, String word);
-
-
-    //
-    // SR_RecognizerResult native methods
-    //
-    private static native byte[] SR_RecognizerResultGetWaveform(long recognizer);
-    private static native int SR_RecognizerResultGetSize(long recognizer);
-    private static native int SR_RecognizerResultGetKeyCount(long recognizer, int nbest);
-    private static native String[] SR_RecognizerResultGetKeyList(long recognizer, int nbest);
-    private static native String SR_RecognizerResultGetValue(long recognizer,
-            int nbest, String key);
-    // private static native void SR_RecognizerResultGetLocale(long recognizer, ESR_Locale* locale);
-}
diff --git a/core/java/android/speech/srec/UlawEncoderInputStream.java b/core/java/android/speech/srec/UlawEncoderInputStream.java
deleted file mode 100644
index a488ead..0000000
--- a/core/java/android/speech/srec/UlawEncoderInputStream.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * ---------------------------------------------------------------------------
- * UlawEncoderInputStream.java
- *
- * Copyright 2008 Nuance Communciations, Inc.
- *
- * 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.
- *
- * ---------------------------------------------------------------------------
- */
-
-package android.speech.srec;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * InputStream which transforms 16 bit pcm data to ulaw data.
- * 
- * Not yet ready to be supported, so
- * @hide
- */
-public final class UlawEncoderInputStream extends InputStream {
-    private final static String TAG = "UlawEncoderInputStream";
-    
-    private final static int MAX_ULAW = 8192;
-    private final static int SCALE_BITS = 16;
-    
-    private InputStream mIn;
-    
-    private int mMax = 0;
-    
-    private final byte[] mBuf = new byte[1024];
-    private int mBufCount = 0; // should be 0 or 1
-    
-    private final byte[] mOneByte = new byte[1];
-
-    
-    public static void encode(byte[] pcmBuf, int pcmOffset,
-            byte[] ulawBuf, int ulawOffset, int length, int max) {
-        
-        // from  'ulaw' in wikipedia
-        // +8191 to +8159                          0x80
-        // +8158 to +4063 in 16 intervals of 256   0x80 + interval number
-        // +4062 to +2015 in 16 intervals of 128   0x90 + interval number
-        // +2014 to  +991 in 16 intervals of  64   0xA0 + interval number
-        //  +990 to  +479 in 16 intervals of  32   0xB0 + interval number
-        //  +478 to  +223 in 16 intervals of  16   0xC0 + interval number
-        //  +222 to   +95 in 16 intervals of   8   0xD0 + interval number
-        //   +94 to   +31 in 16 intervals of   4   0xE0 + interval number
-        //   +30 to    +1 in 15 intervals of   2   0xF0 + interval number
-        //     0                                   0xFF
-        
-        //    -1                                   0x7F
-        //   -31 to    -2 in 15 intervals of   2   0x70 + interval number
-        //   -95 to   -32 in 16 intervals of   4   0x60 + interval number
-        //  -223 to   -96 in 16 intervals of   8   0x50 + interval number
-        //  -479 to  -224 in 16 intervals of  16   0x40 + interval number
-        //  -991 to  -480 in 16 intervals of  32   0x30 + interval number
-        // -2015 to  -992 in 16 intervals of  64   0x20 + interval number
-        // -4063 to -2016 in 16 intervals of 128   0x10 + interval number
-        // -8159 to -4064 in 16 intervals of 256   0x00 + interval number
-        // -8192 to -8160                          0x00
-        
-        // set scale factors
-        if (max <= 0) max = MAX_ULAW;
-        
-        int coef = MAX_ULAW * (1 << SCALE_BITS) / max;
-        
-        for (int i = 0; i < length; i++) {
-            int pcm = (0xff & pcmBuf[pcmOffset++]) + (pcmBuf[pcmOffset++] << 8);
-            pcm = (pcm * coef) >> SCALE_BITS;
-            
-            int ulaw;
-            if (pcm >= 0) {
-                ulaw = pcm <= 0 ? 0xff :
-                        pcm <=   30 ? 0xf0 + ((  30 - pcm) >> 1) :
-                        pcm <=   94 ? 0xe0 + ((  94 - pcm) >> 2) :
-                        pcm <=  222 ? 0xd0 + (( 222 - pcm) >> 3) :
-                        pcm <=  478 ? 0xc0 + (( 478 - pcm) >> 4) :
-                        pcm <=  990 ? 0xb0 + (( 990 - pcm) >> 5) :
-                        pcm <= 2014 ? 0xa0 + ((2014 - pcm) >> 6) :
-                        pcm <= 4062 ? 0x90 + ((4062 - pcm) >> 7) :
-                        pcm <= 8158 ? 0x80 + ((8158 - pcm) >> 8) :
-                        0x80;
-            } else {
-                ulaw = -1 <= pcm ? 0x7f :
-                          -31 <= pcm ? 0x70 + ((pcm -   -31) >> 1) :
-                          -95 <= pcm ? 0x60 + ((pcm -   -95) >> 2) :
-                         -223 <= pcm ? 0x50 + ((pcm -  -223) >> 3) :
-                         -479 <= pcm ? 0x40 + ((pcm -  -479) >> 4) :
-                         -991 <= pcm ? 0x30 + ((pcm -  -991) >> 5) :
-                        -2015 <= pcm ? 0x20 + ((pcm - -2015) >> 6) :
-                        -4063 <= pcm ? 0x10 + ((pcm - -4063) >> 7) :
-                        -8159 <= pcm ? 0x00 + ((pcm - -8159) >> 8) :
-                        0x00;
-            }
-            ulawBuf[ulawOffset++] = (byte)ulaw;
-        }
-    }
-    
-    /**
-     * Compute the maximum of the absolute value of the pcm samples.
-     * The return value can be used to set ulaw encoder scaling.
-     * @param pcmBuf array containing 16 bit pcm data.
-     * @param offset offset of start of 16 bit pcm data.
-     * @param length number of pcm samples (not number of input bytes)
-     * @return maximum abs of pcm data values
-     */
-    public static int maxAbsPcm(byte[] pcmBuf, int offset, int length) {
-        int max = 0;
-        for (int i = 0; i < length; i++) {
-            int pcm = (0xff & pcmBuf[offset++]) + (pcmBuf[offset++] << 8);
-            if (pcm < 0) pcm = -pcm;
-            if (pcm > max) max = pcm;
-        }
-        return max;
-    }
-
-    /**
-     * Create an InputStream which takes 16 bit pcm data and produces ulaw data.
-     * @param in InputStream containing 16 bit pcm data.
-     * @param max pcm value corresponding to maximum ulaw value.
-     */
-    public UlawEncoderInputStream(InputStream in, int max) {
-        mIn = in;
-        mMax = max;
-    }
-    
-    @Override
-    public int read(byte[] buf, int offset, int length) throws IOException {
-        if (mIn == null) throw new IllegalStateException("not open");
-
-        // return at least one byte, but try to fill 'length'
-        while (mBufCount < 2) {
-            int n = mIn.read(mBuf, mBufCount, Math.min(length * 2, mBuf.length - mBufCount));
-            if (n == -1) return -1;
-            mBufCount += n;
-        }
-        
-        // compand data
-        int n = Math.min(mBufCount / 2, length);
-        encode(mBuf, 0, buf, offset, n, mMax);
-        
-        // move data to bottom of mBuf
-        mBufCount -= n * 2;
-        for (int i = 0; i < mBufCount; i++) mBuf[i] = mBuf[i + n * 2];
-        
-        return n;
-    }
-    
-    @Override
-    public int read(byte[] buf) throws IOException {
-        return read(buf, 0, buf.length);
-    }
-    
-    @Override
-    public int read() throws IOException {
-        int n = read(mOneByte, 0, 1);
-        if (n == -1) return -1;
-        return 0xff & (int)mOneByte[0];
-    }
-    
-    @Override
-    public void close() throws IOException {
-        if (mIn != null) {
-            InputStream in = mIn;
-            mIn = null;
-            in.close();
-        }
-    }
-    
-    @Override
-    public int available() throws IOException {
-        return (mIn.available() + mBufCount) / 2;
-    }
-}
diff --git a/core/java/android/speech/srec/WaveHeader.java b/core/java/android/speech/srec/WaveHeader.java
deleted file mode 100644
index 4c3b172..0000000
--- a/core/java/android/speech/srec/WaveHeader.java
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Copyright (C) 2009 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.
- */
-
-package android.speech.srec;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * This class represents the header of a WAVE format audio file, which usually
- * have a .wav suffix.  The following integer valued fields are contained:
- * <ul>
- * <li> format - usually PCM, ALAW or ULAW.
- * <li> numChannels - 1 for mono, 2 for stereo.
- * <li> sampleRate - usually 8000, 11025, 16000, 22050, or 44100 hz.
- * <li> bitsPerSample - usually 16 for PCM, 8 for ALAW, or 8 for ULAW.
- * <li> numBytes - size of audio data after this header, in bytes.
- * </ul>
- * 
- * Not yet ready to be supported, so
- * @hide
- */
-public class WaveHeader {
-    
-    // follows WAVE format in http://ccrma.stanford.edu/courses/422/projects/WaveFormat
-
-    private static final String TAG = "WaveHeader";
-    
-    private static final int HEADER_LENGTH = 44;
-    
-    /** Indicates PCM format. */
-    public static final short FORMAT_PCM = 1;
-    /** Indicates ALAW format. */
-    public static final short FORMAT_ALAW = 6;
-    /** Indicates ULAW format. */
-    public static final short FORMAT_ULAW = 7;
-    
-    private short mFormat;
-    private short mNumChannels;
-    private int mSampleRate;
-    private short mBitsPerSample;
-    private int mNumBytes;
-    
-    /**
-     * Construct a WaveHeader, with all fields defaulting to zero.
-     */
-    public WaveHeader() {
-    }
-    
-    /**
-     * Construct a WaveHeader, with fields initialized.
-     * @param format format of audio data,
-     * one of {@link #FORMAT_PCM}, {@link #FORMAT_ULAW}, or {@link #FORMAT_ALAW}. 
-     * @param numChannels 1 for mono, 2 for stereo.
-     * @param sampleRate typically 8000, 11025, 16000, 22050, or 44100 hz.
-     * @param bitsPerSample usually 16 for PCM, 8 for ULAW or 8 for ALAW.
-     * @param numBytes size of audio data after this header, in bytes.
-     */
-    public WaveHeader(short format, short numChannels, int sampleRate, short bitsPerSample, int numBytes) {
-        mFormat = format;
-        mSampleRate = sampleRate;
-        mNumChannels = numChannels;
-        mBitsPerSample = bitsPerSample;
-        mNumBytes = numBytes;
-    }
-    
-    /**
-     * Get the format field.
-     * @return format field,
-     * one of {@link #FORMAT_PCM}, {@link #FORMAT_ULAW}, or {@link #FORMAT_ALAW}.
-     */
-    public short getFormat() {
-        return mFormat;
-    }
-    
-    /**
-     * Set the format field.
-     * @param format
-     * one of {@link #FORMAT_PCM}, {@link #FORMAT_ULAW}, or {@link #FORMAT_ALAW}.
-     * @return reference to this WaveHeader instance.
-     */
-    public WaveHeader setFormat(short format) {
-        mFormat = format;
-        return this;
-    }
-    
-    /**
-     * Get the number of channels.
-     * @return number of channels, 1 for mono, 2 for stereo.
-     */
-    public short getNumChannels() {
-        return mNumChannels;
-    }
-    
-    /**
-     * Set the number of channels.
-     * @param numChannels 1 for mono, 2 for stereo.
-     * @return reference to this WaveHeader instance.
-     */
-    public WaveHeader setNumChannels(short numChannels) {
-        mNumChannels = numChannels;
-        return this;
-    }
-    
-    /**
-     * Get the sample rate.
-     * @return sample rate, typically 8000, 11025, 16000, 22050, or 44100 hz.
-     */
-    public int getSampleRate() {
-        return mSampleRate;
-    }
-    
-    /**
-     * Set the sample rate.
-     * @param sampleRate sample rate, typically 8000, 11025, 16000, 22050, or 44100 hz.
-     * @return reference to this WaveHeader instance.
-     */
-    public WaveHeader setSampleRate(int sampleRate) {
-        mSampleRate = sampleRate;
-        return this;
-    }
-    
-    /**
-     * Get the number of bits per sample.
-     * @return number of bits per sample,
-     * usually 16 for PCM, 8 for ULAW or 8 for ALAW.
-     */
-    public short getBitsPerSample() {
-        return mBitsPerSample;
-    }
-    
-    /**
-     * Set the number of bits per sample.
-     * @param bitsPerSample number of bits per sample,
-     * usually 16 for PCM, 8 for ULAW or 8 for ALAW.
-     * @return reference to this WaveHeader instance.
-     */
-    public WaveHeader setBitsPerSample(short bitsPerSample) {
-        mBitsPerSample = bitsPerSample;
-        return this;
-    }
-    
-    /**
-     * Get the size of audio data after this header, in bytes.
-     * @return size of audio data after this header, in bytes.
-     */
-    public int getNumBytes() {
-        return mNumBytes;
-    }
-    
-    /**
-     * Set the size of audio data after this header, in bytes.
-     * @param numBytes size of audio data after this header, in bytes.
-     * @return reference to this WaveHeader instance.
-     */
-    public WaveHeader setNumBytes(int numBytes) {
-        mNumBytes = numBytes;
-        return this;
-    }
-    
-    /**
-     * Read and initialize a WaveHeader.
-     * @param in {@link java.io.InputStream} to read from.
-     * @return number of bytes consumed.
-     * @throws IOException
-     */
-    public int read(InputStream in) throws IOException {
-        /* RIFF header */
-        readId(in, "RIFF");
-        int numBytes = readInt(in) - 36;
-        readId(in, "WAVE");
-
-        /* fmt chunk */
-        readId(in, "fmt ");
-        if (16 != readInt(in)) throw new IOException("fmt chunk length not 16");
-        mFormat = readShort(in);
-        mNumChannels = readShort(in);
-        mSampleRate = readInt(in);
-        int byteRate = readInt(in);
-        short blockAlign = readShort(in);
-        mBitsPerSample = readShort(in);
-        if (byteRate != mNumChannels * mSampleRate * mBitsPerSample / 8) {
-            throw new IOException("fmt.ByteRate field inconsistent");
-        }
-        if (blockAlign != mNumChannels * mBitsPerSample / 8) {
-            throw new IOException("fmt.BlockAlign field inconsistent");
-        }
-
-        /* data chunk */
-        readId(in, "data");
-        mNumBytes = readInt(in);
-        
-        return HEADER_LENGTH;
-    }
-
-    private static void readId(InputStream in, String id) throws IOException {
-        for (int i = 0; i < id.length(); i++) {
-            if (id.charAt(i) != in.read()) throw new IOException( id + " tag not present");
-        }
-    }
-
-    private static int readInt(InputStream in) throws IOException {
-        return in.read() | (in.read() << 8) | (in.read() << 16) | (in.read() << 24);
-    }
-
-    private static short readShort(InputStream in) throws IOException {
-        return (short)(in.read() | (in.read() << 8));
-    }
-
-    /**
-     * Write a WAVE file header.
-     * @param out {@link java.io.OutputStream} to receive the header.
-     * @return number of bytes written.
-     * @throws IOException
-     */
-    public int write(OutputStream out) throws IOException {
-        /* RIFF header */
-        writeId(out, "RIFF");
-        writeInt(out, 36 + mNumBytes);
-        writeId(out, "WAVE");
-
-        /* fmt chunk */
-        writeId(out, "fmt ");
-        writeInt(out, 16);
-        writeShort(out, mFormat);
-        writeShort(out, mNumChannels);
-        writeInt(out, mSampleRate);
-        writeInt(out, mNumChannels * mSampleRate * mBitsPerSample / 8);
-        writeShort(out, (short)(mNumChannels * mBitsPerSample / 8));
-        writeShort(out, mBitsPerSample);
-
-        /* data chunk */
-        writeId(out, "data");
-        writeInt(out, mNumBytes);
-        
-        return HEADER_LENGTH;
-    }
-
-    private static void writeId(OutputStream out, String id) throws IOException {
-        for (int i = 0; i < id.length(); i++) out.write(id.charAt(i));
-    }
-
-    private static void writeInt(OutputStream out, int val) throws IOException {
-        out.write(val >> 0);
-        out.write(val >> 8);
-        out.write(val >> 16);
-        out.write(val >> 24);
-    }
-
-    private static void writeShort(OutputStream out, short val) throws IOException {
-        out.write(val >> 0);
-        out.write(val >> 8);
-    }
-    
-    @Override
-    public String toString() {
-        return String.format(
-                "WaveHeader format=%d numChannels=%d sampleRate=%d bitsPerSample=%d numBytes=%d",
-                mFormat, mNumChannels, mSampleRate, mBitsPerSample, mNumBytes);
-    }
-
-}
diff --git a/core/java/android/speech/srec/package.html b/core/java/android/speech/srec/package.html
deleted file mode 100644
index 9a99df8..0000000
--- a/core/java/android/speech/srec/package.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<HTML>
-<BODY>
-Simple, synchronous SREC speech recognition API.
-@hide
-</BODY>
-</HTML>
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
index bac668a..8b74a1e 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -557,7 +557,7 @@
                 if (mIsForcedVisibility) {
                     mView.setTransitionAlpha(0);
                 } else {
-                    mView.setTransitionVisibility(mFinalVisibility);
+                    mView.setVisibility(mFinalVisibility);
                 }
             }
         }
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 89743e5..73cfd8c 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2939,11 +2939,9 @@
         }
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(ViewGroup.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return ViewGroup.class.getName();
     }
 
     @Override
diff --git a/core/java/android/view/textservice/SpellCheckerSession.java b/core/java/android/view/textservice/SpellCheckerSession.java
index 195a335..e77dc0d 100644
--- a/core/java/android/view/textservice/SpellCheckerSession.java
+++ b/core/java/android/view/textservice/SpellCheckerSession.java
@@ -28,9 +28,6 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.util.Log;
-import android.view.textservice.SpellCheckerInfo;
-import android.view.textservice.SuggestionsInfo;
-import android.view.textservice.TextInfo;
 
 import java.util.LinkedList;
 import java.util.Queue;
@@ -226,17 +223,44 @@
         private static final int TASK_GET_SUGGESTIONS_MULTIPLE = 2;
         private static final int TASK_CLOSE = 3;
         private static final int TASK_GET_SUGGESTIONS_MULTIPLE_FOR_SENTENCE = 4;
-        private final Queue<SpellCheckerParams> mPendingTasks =
-                new LinkedList<SpellCheckerParams>();
+        private static String taskToString(int task) {
+            switch (task) {
+                case TASK_CANCEL:
+                    return "TASK_CANCEL";
+                case TASK_GET_SUGGESTIONS_MULTIPLE:
+                    return "TASK_GET_SUGGESTIONS_MULTIPLE";
+                case TASK_CLOSE:
+                    return "TASK_CLOSE";
+                case TASK_GET_SUGGESTIONS_MULTIPLE_FOR_SENTENCE:
+                    return "TASK_GET_SUGGESTIONS_MULTIPLE_FOR_SENTENCE";
+                default:
+                    return "Unexpected task=" + task;
+            }
+        }
+
+        private final Queue<SpellCheckerParams> mPendingTasks = new LinkedList<>();
         private Handler mHandler;
 
-        private boolean mOpened;
+        private static final int STATE_WAIT_CONNECTION = 0;
+        private static final int STATE_CONNECTED = 1;
+        private static final int STATE_CLOSED_AFTER_CONNECTION = 2;
+        private static final int STATE_CLOSED_BEFORE_CONNECTION = 3;
+        private static String stateToString(int state) {
+            switch (state) {
+                case STATE_WAIT_CONNECTION: return "STATE_WAIT_CONNECTION";
+                case STATE_CONNECTED: return "STATE_CONNECTED";
+                case STATE_CLOSED_AFTER_CONNECTION: return "STATE_CLOSED_AFTER_CONNECTION";
+                case STATE_CLOSED_BEFORE_CONNECTION: return "STATE_CLOSED_BEFORE_CONNECTION";
+                default: return "Unexpected state=" + state;
+            }
+        }
+        private int mState = STATE_WAIT_CONNECTION;
+
         private ISpellCheckerSession mISpellCheckerSession;
         private HandlerThread mThread;
         private Handler mAsyncHandler;
 
         public SpellCheckerSessionListenerImpl(Handler handler) {
-            mOpened = false;
             mHandler = handler;
         }
 
@@ -257,12 +281,18 @@
 
         private void processTask(ISpellCheckerSession session, SpellCheckerParams scp,
                 boolean async) {
+            if (DBG) {
+                synchronized (this) {
+                    Log.d(TAG, "entering processTask:"
+                            + " session.hashCode()=#" + Integer.toHexString(session.hashCode())
+                            + " scp.mWhat=" + taskToString(scp.mWhat) + " async=" + async
+                            + " mAsyncHandler=" + mAsyncHandler
+                            + " mState=" + stateToString(mState));
+                }
+            }
             if (async || mAsyncHandler == null) {
                 switch (scp.mWhat) {
                     case TASK_CANCEL:
-                        if (DBG) {
-                            Log.w(TAG, "Cancel spell checker tasks.");
-                        }
                         try {
                             session.onCancel();
                         } catch (RemoteException e) {
@@ -270,9 +300,6 @@
                         }
                         break;
                     case TASK_GET_SUGGESTIONS_MULTIPLE:
-                        if (DBG) {
-                            Log.w(TAG, "Get suggestions from the spell checker.");
-                        }
                         try {
                             session.onGetSuggestionsMultiple(scp.mTextInfos,
                                     scp.mSuggestionsLimit, scp.mSequentialWords);
@@ -281,9 +308,6 @@
                         }
                         break;
                     case TASK_GET_SUGGESTIONS_MULTIPLE_FOR_SENTENCE:
-                        if (DBG) {
-                            Log.w(TAG, "Get sentence suggestions from the spell checker.");
-                        }
                         try {
                             session.onGetSentenceSuggestionsMultiple(
                                     scp.mTextInfos, scp.mSuggestionsLimit);
@@ -292,9 +316,6 @@
                         }
                         break;
                     case TASK_CLOSE:
-                        if (DBG) {
-                            Log.w(TAG, "Close spell checker tasks.");
-                        }
                         try {
                             session.onClose();
                         } catch (RemoteException e) {
@@ -313,21 +334,62 @@
                 // If we are closing, we want to clean up our state now even
                 // if it is pending as an async operation.
                 synchronized (this) {
-                    mISpellCheckerSession = null;
-                    mHandler = null;
-                    if (mThread != null) {
-                        mThread.quit();
-                    }
-                    mThread = null;
-                    mAsyncHandler = null;
+                    processCloseLocked();
                 }
             }
         }
 
+        private void processCloseLocked() {
+            if (DBG) Log.d(TAG, "entering processCloseLocked:"
+                    + " session" + (mISpellCheckerSession != null ? ".hashCode()=#"
+                            + Integer.toHexString(mISpellCheckerSession.hashCode()) : "=null")
+                    + " mState=" + stateToString(mState));
+            mISpellCheckerSession = null;
+            if (mThread != null) {
+                mThread.quit();
+            }
+            mHandler = null;
+            mPendingTasks.clear();
+            mThread = null;
+            mAsyncHandler = null;
+            switch (mState) {
+                case STATE_WAIT_CONNECTION:
+                    mState = STATE_CLOSED_BEFORE_CONNECTION;
+                    break;
+                case STATE_CONNECTED:
+                    mState = STATE_CLOSED_AFTER_CONNECTION;
+                    break;
+                default:
+                    Log.e(TAG, "processCloseLocked is called unexpectedly. mState=" +
+                            stateToString(mState));
+                    break;
+            }
+        }
+
         public synchronized void onServiceConnected(ISpellCheckerSession session) {
             synchronized (this) {
+                switch (mState) {
+                    case STATE_WAIT_CONNECTION:
+                        // OK, go ahead.
+                        break;
+                    case STATE_CLOSED_BEFORE_CONNECTION:
+                        // This is possible, and not an error.  The client no longer is interested
+                        // in this connection. OK to ignore.
+                        if (DBG) Log.i(TAG, "ignoring onServiceConnected since the session is"
+                                + " already closed.");
+                        return;
+                    default:
+                        Log.e(TAG, "ignoring onServiceConnected due to unexpected mState="
+                                + stateToString(mState));
+                        return;
+                }
+                if (session == null) {
+                    Log.e(TAG, "ignoring onServiceConnected due to session=null");
+                    return;
+                }
                 mISpellCheckerSession = session;
                 if (session.asBinder() instanceof Binder && mThread == null) {
+                    if (DBG) Log.d(TAG, "starting HandlerThread in onServiceConnected.");
                     // If this is a local object, we need to do our own threading
                     // to make sure we handle it asynchronously.
                     mThread = new HandlerThread("SpellCheckerSession",
@@ -340,62 +402,65 @@
                         }
                     };
                 }
-                mOpened = true;
+                mState = STATE_CONNECTED;
+                if (DBG) {
+                    Log.d(TAG, "processed onServiceConnected: mISpellCheckerSession.hashCode()=#"
+                            + Integer.toHexString(mISpellCheckerSession.hashCode())
+                            + " mPendingTasks.size()=" + mPendingTasks.size());
+                }
             }
-            if (DBG)
-                Log.d(TAG, "onServiceConnected - Success");
             while (!mPendingTasks.isEmpty()) {
                 processTask(session, mPendingTasks.poll(), false);
             }
         }
 
         public void cancel() {
-            if (DBG) {
-                Log.w(TAG, "cancel");
-            }
             processOrEnqueueTask(new SpellCheckerParams(TASK_CANCEL, null, 0, false));
         }
 
         public void getSuggestionsMultiple(
                 TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) {
-            if (DBG) {
-                Log.w(TAG, "getSuggestionsMultiple");
-            }
             processOrEnqueueTask(
                     new SpellCheckerParams(TASK_GET_SUGGESTIONS_MULTIPLE, textInfos,
                             suggestionsLimit, sequentialWords));
         }
 
         public void getSentenceSuggestionsMultiple(TextInfo[] textInfos, int suggestionsLimit) {
-            if (DBG) {
-                Log.w(TAG, "getSentenceSuggestionsMultiple");
-            }
             processOrEnqueueTask(
                     new SpellCheckerParams(TASK_GET_SUGGESTIONS_MULTIPLE_FOR_SENTENCE,
                             textInfos, suggestionsLimit, false));
         }
 
         public void close() {
-            if (DBG) {
-                Log.w(TAG, "close");
-            }
             processOrEnqueueTask(new SpellCheckerParams(TASK_CLOSE, null, 0, false));
         }
 
         public boolean isDisconnected() {
-            return mOpened && mISpellCheckerSession == null;
+            synchronized (this) {
+                return mState != STATE_CONNECTED;
+            }
         }
 
         private void processOrEnqueueTask(SpellCheckerParams scp) {
-            if (DBG) {
-                Log.d(TAG, "process or enqueue task: " + mISpellCheckerSession);
-            }
             ISpellCheckerSession session;
             synchronized (this) {
-                session = mISpellCheckerSession;
-                if (session == null) {
+                if (mState != STATE_WAIT_CONNECTION && mState != STATE_CONNECTED) {
+                    Log.e(TAG, "ignoring processOrEnqueueTask due to unexpected mState="
+                            + taskToString(scp.mWhat)
+                            + " scp.mWhat=" + taskToString(scp.mWhat));
+                    return;
+                }
+
+                if (mState == STATE_WAIT_CONNECTION) {
+                    // If we are still waiting for the connection. Need to pay special attention.
+                    if (scp.mWhat == TASK_CLOSE) {
+                        processCloseLocked();
+                        return;
+                    }
+                    // Enqueue the task to task queue.
                     SpellCheckerParams closeTask = null;
                     if (scp.mWhat == TASK_CANCEL) {
+                        if (DBG) Log.d(TAG, "canceling pending tasks in processOrEnqueueTask.");
                         while (!mPendingTasks.isEmpty()) {
                             final SpellCheckerParams tmp = mPendingTasks.poll();
                             if (tmp.mWhat == TASK_CLOSE) {
@@ -409,9 +474,15 @@
                     if (closeTask != null) {
                         mPendingTasks.offer(closeTask);
                     }
+                    if (DBG) Log.d(TAG, "queueing tasks in processOrEnqueueTask since the"
+                            + " connection is not established."
+                            + " mPendingTasks.size()=" + mPendingTasks.size());
                     return;
                 }
+
+                session = mISpellCheckerSession;
             }
+            // session must never be null here.
             processTask(session, scp, false);
         }
 
@@ -467,9 +538,6 @@
 
         @Override
         public void onServiceConnected(ISpellCheckerSession session) {
-            if (DBG) {
-                Log.w(TAG, "SpellCheckerSession connected.");
-            }
             mParentSpellCheckerSessionListenerImpl.onServiceConnected(session);
         }
     }
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index cf6a018..f89ee91 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -244,15 +244,6 @@
 
     final CursorAnchorInfoNotifier mCursorAnchorInfoNotifier = new CursorAnchorInfoNotifier();
 
-    private final Runnable mHideFloatingToolbar = new Runnable() {
-        @Override
-        public void run() {
-            if (mTextActionMode != null) {
-                mTextActionMode.hide(ActionMode.DEFAULT_HIDE_DURATION);
-            }
-        }
-    };
-
     private final Runnable mShowFloatingToolbar = new Runnable() {
         @Override
         public void run() {
@@ -389,7 +380,6 @@
             mTextView.removeCallbacks(mInsertionActionModeRunnable);
         }
 
-        mTextView.removeCallbacks(mHideFloatingToolbar);
         mTextView.removeCallbacks(mShowFloatingToolbar);
 
         destroyDisplayListsData();
@@ -1248,14 +1238,12 @@
     private void hideFloatingToolbar() {
         if (mTextActionMode != null) {
             mTextView.removeCallbacks(mShowFloatingToolbar);
-            // Delay the "hide" a little bit just in case a "show" will happen almost immediately.
-            mTextView.postDelayed(mHideFloatingToolbar, 100);
+            mTextActionMode.hide(ActionMode.DEFAULT_HIDE_DURATION);
         }
     }
 
     private void showFloatingToolbar() {
         if (mTextActionMode != null) {
-            mTextView.removeCallbacks(mHideFloatingToolbar);
             // Delay "show" so it doesn't interfere with click confirmations
             // or double-clicks that could "dismiss" the floating toolbar.
             int delay = ViewConfiguration.getDoubleTapTimeout();
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index 8ace0f3..2ea2667 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -26,7 +26,6 @@
 import android.app.ActionBar;
 import android.content.Context;
 import android.content.res.TypedArray;
-import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -148,6 +147,9 @@
     // Clear me after use.
     private final ArrayList<View> mTempViews = new ArrayList<View>();
 
+    // Used to hold views that will be removed while we have an expanded action view.
+    private final ArrayList<View> mHiddenViews = new ArrayList<>();
+
     private final int[] mTempMargins = new int[2];
 
     private OnMenuItemClickListener mOnMenuItemClickListener;
@@ -435,12 +437,12 @@
     public void setLogo(Drawable drawable) {
         if (drawable != null) {
             ensureLogoView();
-            if (mLogoView.getParent() == null) {
-                addSystemView(mLogoView);
-                updateChildVisibilityForExpandedActionView(mLogoView);
+            if (!isChildOrHidden(mLogoView)) {
+                addSystemView(mLogoView, true);
             }
-        } else if (mLogoView != null && mLogoView.getParent() != null) {
+        } else if (mLogoView != null && isChildOrHidden(mLogoView)) {
             removeView(mLogoView);
+            mHiddenViews.remove(mLogoView);
         }
         if (mLogoView != null) {
             mLogoView.setImageDrawable(drawable);
@@ -577,12 +579,12 @@
                     mTitleTextView.setTextColor(mTitleTextColor);
                 }
             }
-            if (mTitleTextView.getParent() == null) {
-                addSystemView(mTitleTextView);
-                updateChildVisibilityForExpandedActionView(mTitleTextView);
+            if (!isChildOrHidden(mTitleTextView)) {
+                addSystemView(mTitleTextView, true);
             }
-        } else if (mTitleTextView != null && mTitleTextView.getParent() != null) {
+        } else if (mTitleTextView != null && isChildOrHidden(mTitleTextView)) {
             removeView(mTitleTextView);
+            mHiddenViews.remove(mTitleTextView);
         }
         if (mTitleTextView != null) {
             mTitleTextView.setText(title);
@@ -631,12 +633,12 @@
                     mSubtitleTextView.setTextColor(mSubtitleTextColor);
                 }
             }
-            if (mSubtitleTextView.getParent() == null) {
-                addSystemView(mSubtitleTextView);
-                updateChildVisibilityForExpandedActionView(mSubtitleTextView);
+            if (!isChildOrHidden(mSubtitleTextView)) {
+                addSystemView(mSubtitleTextView, true);
             }
-        } else if (mSubtitleTextView != null && mSubtitleTextView.getParent() != null) {
+        } else if (mSubtitleTextView != null && isChildOrHidden(mSubtitleTextView)) {
             removeView(mSubtitleTextView);
+            mHiddenViews.remove(mSubtitleTextView);
         }
         if (mSubtitleTextView != null) {
             mSubtitleTextView.setText(subtitle);
@@ -772,12 +774,12 @@
     public void setNavigationIcon(@Nullable Drawable icon) {
         if (icon != null) {
             ensureNavButtonView();
-            if (mNavButtonView.getParent() == null) {
-                addSystemView(mNavButtonView);
-                updateChildVisibilityForExpandedActionView(mNavButtonView);
+            if (!isChildOrHidden(mNavButtonView)) {
+                addSystemView(mNavButtonView, true);
             }
-        } else if (mNavButtonView != null && mNavButtonView.getParent() != null) {
+        } else if (mNavButtonView != null && isChildOrHidden(mNavButtonView)) {
             removeView(mNavButtonView);
+            mHiddenViews.remove(mNavButtonView);
         }
         if (mNavButtonView != null) {
             mNavButtonView.setImageDrawable(icon);
@@ -866,7 +868,7 @@
             final LayoutParams lp = generateDefaultLayoutParams();
             lp.gravity = Gravity.END | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
             mMenuView.setLayoutParams(lp);
-            addSystemView(mMenuView);
+            addSystemView(mMenuView, false);
         }
     }
 
@@ -1041,7 +1043,7 @@
         }
     }
 
-    private void addSystemView(View v) {
+    private void addSystemView(View v, boolean allowHide) {
         final ViewGroup.LayoutParams vlp = v.getLayoutParams();
         final LayoutParams lp;
         if (vlp == null) {
@@ -1052,7 +1054,13 @@
             lp = (LayoutParams) vlp;
         }
         lp.mViewType = LayoutParams.SYSTEM;
-        addView(v, lp);
+
+        if (allowHide && mExpandedActionView != null) {
+            v.setLayoutParams(lp);
+            mHiddenViews.add(v);
+        } else {
+            addView(v, lp);
+        }
     }
 
     @Override
@@ -1741,22 +1749,30 @@
         return mWrapper;
     }
 
-    private void setChildVisibilityForExpandedActionView(boolean expand) {
+    void removeChildrenForExpandedActionView() {
         final int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
+        // Go backwards since we're removing from the list
+        for (int i = childCount - 1; i >= 0; i--) {
             final View child = getChildAt(i);
             final LayoutParams lp = (LayoutParams) child.getLayoutParams();
             if (lp.mViewType != LayoutParams.EXPANDED && child != mMenuView) {
-                child.setVisibility(expand ? GONE : VISIBLE);
+                removeViewAt(i);
+                mHiddenViews.add(child);
             }
         }
     }
 
-    private void updateChildVisibilityForExpandedActionView(View child) {
-        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-        if (lp.mViewType != LayoutParams.EXPANDED && child != mMenuView) {
-            child.setVisibility(mExpandedActionView != null ? GONE : VISIBLE);
+    void addChildrenForExpandedActionView() {
+        final int count = mHiddenViews.size();
+        // Re-add in reverse order since we removed in reverse order
+        for (int i = count - 1; i >= 0; i--) {
+            addView(mHiddenViews.get(i));
         }
+        mHiddenViews.clear();
+    }
+
+    private boolean isChildOrHidden(View child) {
+        return child.getParent() == this || mHiddenViews.contains(child);
     }
 
     /**
@@ -1971,7 +1987,7 @@
                 addView(mExpandedActionView);
             }
 
-            setChildVisibilityForExpandedActionView(true);
+            removeChildrenForExpandedActionView();
             requestLayout();
             item.setActionViewExpanded(true);
 
@@ -1994,7 +2010,7 @@
             removeView(mCollapseButtonView);
             mExpandedActionView = null;
 
-            setChildVisibilityForExpandedActionView(false);
+            addChildrenForExpandedActionView();
             mCurrentExpandedItem = null;
             requestLayout();
             item.setActionViewExpanded(false);
diff --git a/core/java/com/android/internal/app/ToolbarActionBar.java b/core/java/com/android/internal/app/ToolbarActionBar.java
index 34b9dcb..2b162af 100644
--- a/core/java/com/android/internal/app/ToolbarActionBar.java
+++ b/core/java/com/android/internal/app/ToolbarActionBar.java
@@ -83,7 +83,9 @@
 
     @Override
     public void setCustomView(View view, LayoutParams layoutParams) {
-        view.setLayoutParams(layoutParams);
+        if (view != null) {
+            view.setLayoutParams(layoutParams);
+        }
         mDecorToolbar.setCustomView(view);
     }
 
diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java
index 661dce1..99c1277 100644
--- a/core/java/com/android/internal/view/FloatingActionMode.java
+++ b/core/java/com/android/internal/view/FloatingActionMode.java
@@ -48,12 +48,14 @@
     private final Runnable mMovingOff = new Runnable() {
         public void run() {
             mFloatingToolbarVisibilityHelper.setMoving(false);
+            mFloatingToolbarVisibilityHelper.updateToolbarVisibility();
         }
     };
 
     private final Runnable mHideOff = new Runnable() {
         public void run() {
             mFloatingToolbarVisibilityHelper.setHideRequested(false);
+            mFloatingToolbarVisibilityHelper.updateToolbarVisibility();
         }
     };
 
@@ -87,6 +89,7 @@
                     }
                 });
         mFloatingToolbarVisibilityHelper = new FloatingToolbarVisibilityHelper(mFloatingToolbar);
+        mFloatingToolbarVisibilityHelper.activate();
     }
 
     @Override
@@ -108,8 +111,7 @@
     public void invalidate() {
         checkToolbarInitialized();
         mCallback.onPrepareActionMode(this, mMenu);
-        mFloatingToolbar.updateLayout();
-        invalidateContentRect();
+        invalidateContentRect();  // Will re-layout and show the toolbar if necessary.
     }
 
     @Override
@@ -131,44 +133,43 @@
 
         mContentRectOnWindow.set(mContentRect);
         mContentRectOnWindow.offset(mViewPosition[0], mViewPosition[1]);
-        // Make sure that content rect is not out of the view's visible bounds.
-        mContentRectOnWindow.set(
-                Math.max(mContentRectOnWindow.left, mViewRect.left),
-                Math.max(mContentRectOnWindow.top, mViewRect.top),
-                Math.min(mContentRectOnWindow.right, mViewRect.right),
-                Math.min(mContentRectOnWindow.bottom, mViewRect.bottom));
-
-        if (!mContentRectOnWindow.equals(mPreviousContentRectOnWindow)) {
-            if (!mPreviousContentRectOnWindow.isEmpty()) {
-                notifyContentRectMoving();
-            }
-            mFloatingToolbar.setContentRect(mContentRectOnWindow);
-            mFloatingToolbar.updateLayout();
-        }
-        mPreviousContentRectOnWindow.set(mContentRectOnWindow);
 
         if (isContentRectWithinBounds()) {
             mFloatingToolbarVisibilityHelper.setOutOfBounds(false);
+            // Make sure that content rect is not out of the view's visible bounds.
+            mContentRectOnWindow.set(
+                    Math.max(mContentRectOnWindow.left, mViewRect.left),
+                    Math.max(mContentRectOnWindow.top, mViewRect.top),
+                    Math.min(mContentRectOnWindow.right, mViewRect.right),
+                    Math.min(mContentRectOnWindow.bottom, mViewRect.bottom));
+
+            if (!mContentRectOnWindow.equals(mPreviousContentRectOnWindow)) {
+                // Content rect is moving.
+                mOriginatingView.removeCallbacks(mMovingOff);
+                mFloatingToolbarVisibilityHelper.setMoving(true);
+                mOriginatingView.postDelayed(mMovingOff, MOVING_HIDE_DELAY);
+
+                mFloatingToolbar.setContentRect(mContentRectOnWindow);
+                mFloatingToolbar.updateLayout();
+            }
         } else {
             mFloatingToolbarVisibilityHelper.setOutOfBounds(true);
+            mContentRectOnWindow.setEmpty();
         }
+        mFloatingToolbarVisibilityHelper.updateToolbarVisibility();
+
+        mPreviousContentRectOnWindow.set(mContentRectOnWindow);
     }
 
     private boolean isContentRectWithinBounds() {
-       mScreenRect.set(
-           0,
-           0,
-           mContext.getResources().getDisplayMetrics().widthPixels,
-           mContext.getResources().getDisplayMetrics().heightPixels);
+        mScreenRect.set(
+            0,
+            0,
+            mContext.getResources().getDisplayMetrics().widthPixels,
+            mContext.getResources().getDisplayMetrics().heightPixels);
 
-       return Rect.intersects(mContentRectOnWindow, mScreenRect)
-           && Rect.intersects(mContentRectOnWindow, mViewRect);
-    }
-
-    private void notifyContentRectMoving() {
-        mOriginatingView.removeCallbacks(mMovingOff);
-        mFloatingToolbarVisibilityHelper.setMoving(true);
-        mOriginatingView.postDelayed(mMovingOff, MOVING_HIDE_DELAY);
+        return Rect.intersects(mContentRectOnWindow, mScreenRect)
+            && Rect.intersects(mContentRectOnWindow, mViewRect);
     }
 
     @Override
@@ -184,6 +185,7 @@
             mHideOff.run();
         } else {
             mFloatingToolbarVisibilityHelper.setHideRequested(true);
+            mFloatingToolbarVisibilityHelper.updateToolbarVisibility();
             mOriginatingView.postDelayed(mHideOff, duration);
         }
     }
@@ -221,7 +223,7 @@
     }
 
     /**
-     * @throws IlllegalStateException
+     * @throws IllegalStateException
      */
     private void checkToolbarInitialized() {
         Preconditions.checkState(mFloatingToolbar != null);
@@ -229,13 +231,14 @@
     }
 
     private void reset() {
+        mFloatingToolbarVisibilityHelper.deactivate();
         mOriginatingView.removeCallbacks(mMovingOff);
         mOriginatingView.removeCallbacks(mHideOff);
     }
 
 
     /**
-     * A helper that shows/hides the floating toolbar depending on certain states.
+     * A helper for showing/hiding the floating toolbar depending on certain states.
      */
     private static final class FloatingToolbarVisibilityHelper {
 
@@ -245,29 +248,45 @@
         private boolean mMoving;
         private boolean mOutOfBounds;
 
+        private boolean mActive;
+
         public FloatingToolbarVisibilityHelper(FloatingToolbar toolbar) {
             mToolbar = Preconditions.checkNotNull(toolbar);
         }
 
+        public void activate() {
+            mHideRequested = false;
+            mMoving = false;
+            mOutOfBounds = false;
+
+            mActive = true;
+        }
+
+        public void deactivate() {
+            mActive = false;
+            mToolbar.dismiss();
+        }
+
         public void setHideRequested(boolean hide) {
             mHideRequested = hide;
-            updateToolbarVisibility();
         }
 
         public void setMoving(boolean moving) {
             mMoving = moving;
-            updateToolbarVisibility();
         }
 
         public void setOutOfBounds(boolean outOfBounds) {
             mOutOfBounds = outOfBounds;
-            updateToolbarVisibility();
         }
 
-        private void updateToolbarVisibility() {
+        public void updateToolbarVisibility() {
+            if (!mActive) {
+                return;
+            }
+
             if (mHideRequested || mMoving || mOutOfBounds) {
                 mToolbar.hide();
-            } else if (mToolbar.isHidden()) {
+            } else {
                 mToolbar.show();
             }
         }
diff --git a/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java b/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java
index 3f4b980..c0215a8 100644
--- a/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java
+++ b/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java
@@ -28,8 +28,6 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.SyncAdapterType;
-import android.content.SyncStatusObserver;
-import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.util.Log;
 
@@ -47,8 +45,6 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
 
 /**
  * Helper for backing up account sync settings (whether or not a service should be synced). The
@@ -270,6 +266,10 @@
                     // yet won't be restored.
                     if (currentAccounts.contains(account)) {
                         restoreExistingAccountSyncSettingsFromJSON(accountJSON);
+                    } else {
+                        // TODO:
+                        // Stash the data to a file that the SyncManager can read from to restore
+                        // settings at a later date.
                     }
                 }
             } finally {
@@ -300,6 +300,31 @@
     /**
      * Restore account sync settings using the given JSON. This function won't work if the account
      * doesn't exist yet.
+     * This function will only be called during Setup Wizard, where we are guaranteed that there
+     * are no active syncs.
+     * There are 2 pieces of data to restore -
+     *      isSyncable (corresponds to {@link ContentResolver#getIsSyncable(Account, String)}
+     *      syncEnabled (corresponds to {@link ContentResolver#getSyncAutomatically(Account, String)}
+     * <strong>The restore favours adapters that were enabled on the old device, and doesn't care
+     * about adapters that were disabled.</strong>
+     *
+     * syncEnabled=true in restore data.
+     * syncEnabled will be true on this device. isSyncable will be left as the default in order to
+     * give the enabled adapter the chance to run an initialization sync.
+     *
+     * syncEnabled=false in restore data.
+     * syncEnabled will be false on this device. isSyncable will be set to 2, unless it was 0 on the
+     * old device in which case it will be set to 0 on this device. This is because isSyncable=0 is
+     * a rare state and was probably set to 0 for good reason (historically isSyncable is a way by
+     * which adapters control their own sync state independently of sync settings which is
+     * toggleable by the user).
+     * isSyncable=2 is a new isSyncable state we introduced specifically to allow adapters that are
+     * disabled after a restore to run initialization logic when the adapter is later enabled.
+     * See com.android.server.content.SyncStorageEngine#setSyncAutomatically
+     *
+     * The end result is that an adapter that the user had on will be turned on and get an
+     * initialization sync, while an adapter that the user had off will be off until the user
+     * enables it on this device at which point it will get an initialization sync.
      */
     private void restoreExistingAccountSyncSettingsFromJSON(JSONObject accountJSON)
             throws JSONException {
@@ -307,72 +332,27 @@
         JSONArray authorities = accountJSON.getJSONArray(KEY_ACCOUNT_AUTHORITIES);
         String accountName = accountJSON.getString(KEY_ACCOUNT_NAME);
         String accountType = accountJSON.getString(KEY_ACCOUNT_TYPE);
+
         final Account account = new Account(accountName, accountType);
         for (int i = 0; i < authorities.length(); i++) {
             JSONObject authority = (JSONObject) authorities.get(i);
             final String authorityName = authority.getString(KEY_AUTHORITY_NAME);
-            boolean syncEnabled = authority.getBoolean(KEY_AUTHORITY_SYNC_ENABLED);
+            boolean wasSyncEnabled = authority.getBoolean(KEY_AUTHORITY_SYNC_ENABLED);
+            int wasSyncable = authority.getInt(KEY_AUTHORITY_SYNC_STATE);
 
-            // Cancel any active syncs.
-            if (ContentResolver.isSyncActive(account, authorityName)) {
-                ContentResolver.cancelSync(account, authorityName);
-            }
+            ContentResolver.setSyncAutomaticallyAsUser(
+                    account, authorityName, wasSyncEnabled, 0 /* user Id */);
 
-            boolean overwriteSync = true;
-            Bundle initializationExtras = createSyncInitializationBundle();
-            int currentSyncState = ContentResolver.getIsSyncable(account, authorityName);
-            if (currentSyncState < 0) {
-                // Requesting a sync is an asynchronous operation, so we setup a countdown latch to
-                // wait for it to finish. Initialization syncs are generally very brief and
-                // shouldn't take too much time to finish.
-                final CountDownLatch latch = new CountDownLatch(1);
-                Object syncStatusObserverHandle = ContentResolver.addStatusChangeListener(
-                        ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE, new SyncStatusObserver() {
-                            @Override
-                            public void onStatusChanged(int which) {
-                                if (!ContentResolver.isSyncActive(account, authorityName)) {
-                                    latch.countDown();
-                                }
-                            }
-                        });
-
-                // If we set sync settings for a sync that hasn't been initialized yet, we run the
-                // risk of having our changes overwritten later on when the sync gets initialized.
-                // To prevent this from happening we will manually initiate the sync adapter. We
-                // also explicitly pass in a Bundle with SYNC_EXTRAS_INITIALIZE to prevent a data
-                // sync from running after the initialization sync. Two syncs will be scheduled, but
-                // the second one (data sync) will override the first one (initialization sync) and
-                // still behave as an initialization sync because of the Bundle.
-                ContentResolver.requestSync(account, authorityName, initializationExtras);
-
-                boolean done = false;
-                try {
-                    done = latch.await(SYNC_REQUEST_LATCH_TIMEOUT_SECONDS, TimeUnit.SECONDS);
-                } catch (InterruptedException e) {
-                    Log.e(TAG, "CountDownLatch interrupted\n" + e);
-                    done = false;
-                }
-                if (!done) {
-                    overwriteSync = false;
-                    Log.i(TAG, "CountDownLatch timed out, skipping '" + authorityName
-                            + "' authority.");
-                }
-                ContentResolver.removeStatusChangeListener(syncStatusObserverHandle);
-            }
-
-            if (overwriteSync) {
-                ContentResolver.setSyncAutomatically(account, authorityName, syncEnabled);
-                Log.i(TAG, "Set sync automatically for '" + authorityName + "': " + syncEnabled);
+            if (!wasSyncEnabled) {
+                ContentResolver.setIsSyncable(
+                        account,
+                        authorityName,
+                        wasSyncable == 0 ?
+                                0 /* not syncable */ : 2 /* syncable but needs initialization */);
             }
         }
     }
 
-    private Bundle createSyncInitializationBundle() {
-        Bundle extras = new Bundle();
-        extras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
-        return extras;
-    }
-
     @Override
     public void writeNewStateDescription(ParcelFileDescriptor newState) {
 
diff --git a/core/jni/android_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp
index 2229071..7d8d151 100644
--- a/core/jni/android_hardware_camera2_DngCreator.cpp
+++ b/core/jni/android_hardware_camera2_DngCreator.cpp
@@ -371,8 +371,8 @@
         realCount = count;
     }
 
-    jobject chainingBuf = mEnv->CallObjectMethod(mInBuf, gInputByteBufferClassInfo.mGetMethod, mByteArray, 0,
-            realCount);
+    jobject chainingBuf = mEnv->CallObjectMethod(mInBuf, gInputByteBufferClassInfo.mGetMethod,
+            mByteArray, 0, realCount);
     mEnv->DeleteLocalRef(chainingBuf);
 
     if (mEnv->ExceptionCheck()) {
@@ -630,8 +630,10 @@
     bool hasThumbnail = writer->hasIfd(TIFF_IFD_SUB1);
 
     // TODO: handle lens shading map, etc. conversions for other raw buffer sizes.
-    uint32_t metadataWidth = *(writer->getEntry(TAG_IMAGEWIDTH, (hasThumbnail) ? TIFF_IFD_SUB1 : TIFF_IFD_0)->getData<uint32_t>());
-    uint32_t metadataHeight = *(writer->getEntry(TAG_IMAGELENGTH, (hasThumbnail) ? TIFF_IFD_SUB1 : TIFF_IFD_0)->getData<uint32_t>());
+    uint32_t metadataWidth = *(writer->getEntry(TAG_IMAGEWIDTH, (hasThumbnail) ? TIFF_IFD_SUB1 :
+            TIFF_IFD_0)->getData<uint32_t>());
+    uint32_t metadataHeight = *(writer->getEntry(TAG_IMAGELENGTH, (hasThumbnail) ? TIFF_IFD_SUB1 :
+            TIFF_IFD_0)->getData<uint32_t>());
 
     if (width < 0 || metadataWidth != static_cast<uint32_t>(width)) {
         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", \
@@ -641,7 +643,8 @@
 
     if (height < 0 || metadataHeight != static_cast<uint32_t>(height)) {
         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", \
-                        "Metadata height %d doesn't match image height %d", metadataHeight, height);
+                        "Metadata height %d doesn't match image height %d",
+                        metadataHeight, height);
         return false;
     }
 
@@ -1428,7 +1431,11 @@
     }
 
     {
-        // Setup opcode List 2
+        // Set up opcode List 2
+        OpcodeListBuilder builder;
+        status_t err = OK;
+
+        // Set up lens shading map
         camera_metadata_entry entry1 =
                 characteristics.find(ANDROID_LENS_INFO_SHADING_MAP_SIZE);
 
@@ -1444,34 +1451,71 @@
                 results.find(ANDROID_STATISTICS_LENS_SHADING_MAP);
 
         if (entry2.count > 0 && entry2.count == lsmWidth * lsmHeight * 4) {
-
-            OpcodeListBuilder builder;
-            status_t err = builder.addGainMapsForMetadata(lsmWidth,
-                                                          lsmHeight,
-                                                          0,
-                                                          0,
-                                                          imageHeight,
-                                                          imageWidth,
-                                                          opcodeCfaLayout,
-                                                          entry2.data.f);
-            if (err == OK) {
-                size_t listSize = builder.getSize();
-                uint8_t opcodeListBuf[listSize];
-                err = builder.buildOpList(opcodeListBuf);
-                if (err == OK) {
-                    BAIL_IF_INVALID(writer->addEntry(TAG_OPCODELIST2, listSize, opcodeListBuf,
-                            TIFF_IFD_0), env, TAG_OPCODELIST2, writer);
-                } else {
-                    ALOGE("%s: Could not build Lens shading map opcode.", __FUNCTION__);
-                    jniThrowRuntimeException(env, "failed to construct lens shading map opcode.");
-                }
-            } else {
+            err = builder.addGainMapsForMetadata(lsmWidth,
+                                                 lsmHeight,
+                                                 0,
+                                                 0,
+                                                 imageHeight,
+                                                 imageWidth,
+                                                 opcodeCfaLayout,
+                                                 entry2.data.f);
+            if (err != OK) {
                 ALOGE("%s: Could not add Lens shading map.", __FUNCTION__);
                 jniThrowRuntimeException(env, "failed to add lens shading map.");
+                return;
             }
+        }
+
+        size_t listSize = builder.getSize();
+        uint8_t opcodeListBuf[listSize];
+        err = builder.buildOpList(opcodeListBuf);
+        if (err == OK) {
+            BAIL_IF_INVALID(writer->addEntry(TAG_OPCODELIST2, listSize, opcodeListBuf,
+                    TIFF_IFD_0), env, TAG_OPCODELIST2, writer);
         } else {
-            ALOGW("%s: No lens shading map found in result metadata. Image quality may be reduced.",
-                    __FUNCTION__);
+            ALOGE("%s: Could not build list of opcodes for distortion correction and lens shading"
+                    "map.", __FUNCTION__);
+            jniThrowRuntimeException(env, "failed to construct opcode list for distortion"
+                    " correction and lens shading map");
+            return;
+        }
+    }
+
+    {
+        // Set up opcode List 3
+        OpcodeListBuilder builder;
+        status_t err = OK;
+
+        // Set up rectilinear distortion correction
+        camera_metadata_entry entry3 =
+                results.find(ANDROID_LENS_RADIAL_DISTORTION);
+        camera_metadata_entry entry4 =
+                results.find(ANDROID_LENS_INTRINSIC_CALIBRATION);
+
+        if (entry3.count == 6 && entry4.count == 5) {
+            float cx = entry4.data.f[/*c_x*/2];
+            float cy = entry4.data.f[/*c_y*/3];
+            err = builder.addWarpRectilinearForMetadata(entry3.data.f, imageWidth, imageHeight, cx,
+                    cy);
+            if (err != OK) {
+                ALOGE("%s: Could not add distortion correction.", __FUNCTION__);
+                jniThrowRuntimeException(env, "failed to add distortion correction.");
+                return;
+            }
+        }
+
+        size_t listSize = builder.getSize();
+        uint8_t opcodeListBuf[listSize];
+        err = builder.buildOpList(opcodeListBuf);
+        if (err == OK) {
+            BAIL_IF_INVALID(writer->addEntry(TAG_OPCODELIST3, listSize, opcodeListBuf,
+                    TIFF_IFD_0), env, TAG_OPCODELIST3, writer);
+        } else {
+            ALOGE("%s: Could not build list of opcodes for distortion correction and lens shading"
+                    "map.", __FUNCTION__);
+            jniThrowRuntimeException(env, "failed to construct opcode list for distortion"
+                    " correction and lens shading map");
+            return;
         }
     }
 
@@ -1693,6 +1737,7 @@
         tagsToMove.add(TAG_DEFAULTCROPORIGIN);
         tagsToMove.add(TAG_DEFAULTCROPSIZE);
         tagsToMove.add(TAG_OPCODELIST2);
+        tagsToMove.add(TAG_OPCODELIST3);
 
         if (moveEntries(writer, TIFF_IFD_0, TIFF_IFD_SUB1, tagsToMove) != OK) {
             jniThrowException(env, "java/lang/IllegalStateException", "Failed to move entries");
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 1cd07d1..ac00532 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -677,13 +677,14 @@
         // constructed by java code with correct class type (device, mix etc...)
         // and reference to AudioPort instance in this client
         jAudioPort = env->NewObject(gAudioPortClass, gAudioPortCstor,
-                                           jHandle,
-                                           0,
-                                           NULL,
-                                           NULL,
-                                           NULL,
-                                           NULL,
-                                           NULL);
+                                           jHandle, // handle
+                                           0,       // role
+                                           NULL,    // name
+                                           NULL,    // samplingRates
+                                           NULL,    // channelMasks
+                                           NULL,    // channelIndexMasks
+                                           NULL,    // formats
+                                           NULL);   // gains
         env->DeleteLocalRef(jHandle);
         if (jAudioPort == NULL) {
             return (jint)AUDIO_JAVA_ERROR;
@@ -837,11 +838,14 @@
     jint jStatus = (jint)AUDIO_JAVA_SUCCESS;
     jintArray jSamplingRates = NULL;
     jintArray jChannelMasks = NULL;
+    jintArray jChannelIndexMasks = NULL;
     jintArray jFormats = NULL;
     jobjectArray jGains = NULL;
     jobject jHandle = NULL;
     jstring jDeviceName = NULL;
     bool useInMask;
+    size_t numPositionMasks = 0;
+    size_t numIndexMasks = 0;
 
     ALOGV("convertAudioPortFromNative id %d role %d type %d name %s",
         nAudioPort->id, nAudioPort->role, nAudioPort->type, nAudioPort->name);
@@ -856,23 +860,43 @@
                                (jint *)nAudioPort->sample_rates);
     }
 
-    jChannelMasks = env->NewIntArray(nAudioPort->num_channel_masks);
+    // count up how many masks are positional and indexed
+    for(size_t index = 0; index < nAudioPort->num_channel_masks; index++) {
+        const audio_channel_mask_t mask = nAudioPort->channel_masks[index];
+        if (audio_channel_mask_get_representation(mask) == AUDIO_CHANNEL_REPRESENTATION_INDEX) {
+            numIndexMasks++;
+        } else {
+            numPositionMasks++;
+        }
+    }
+
+    jChannelMasks = env->NewIntArray(numPositionMasks);
     if (jChannelMasks == NULL) {
         jStatus = (jint)AUDIO_JAVA_ERROR;
         goto exit;
     }
+    jChannelIndexMasks = env->NewIntArray(numIndexMasks);
+    if (jChannelIndexMasks == NULL) {
+        jStatus = (jint)AUDIO_JAVA_ERROR;
+        goto exit;
+    }
     useInMask = useInChannelMask(nAudioPort->type, nAudioPort->role);
 
-    jint jMask;
-    for (size_t j = 0; j < nAudioPort->num_channel_masks; j++) {
-        if (useInMask) {
-            jMask = inChannelMaskFromNative(nAudioPort->channel_masks[j]);
+    // put the masks in the output arrays
+    for (size_t maskIndex = 0, posMaskIndex = 0, indexedMaskIndex = 0;
+         maskIndex < nAudioPort->num_channel_masks; maskIndex++) {
+        const audio_channel_mask_t mask = nAudioPort->channel_masks[maskIndex];
+        if (audio_channel_mask_get_representation(mask) == AUDIO_CHANNEL_REPRESENTATION_INDEX) {
+            jint jMask = audio_channel_mask_get_bits(mask);
+            env->SetIntArrayRegion(jChannelIndexMasks, indexedMaskIndex++, 1, &jMask);
         } else {
-            jMask = outChannelMaskFromNative(nAudioPort->channel_masks[j]);
+            jint jMask = useInMask ? inChannelMaskFromNative(mask)
+                                   : outChannelMaskFromNative(mask);
+            env->SetIntArrayRegion(jChannelMasks, posMaskIndex++, 1, &jMask);
         }
-        env->SetIntArrayRegion(jChannelMasks, j, 1, &jMask);
     }
 
+    // formats
     jFormats = env->NewIntArray(nAudioPort->num_formats);
     if (jFormats == NULL) {
         jStatus = (jint)AUDIO_JAVA_ERROR;
@@ -883,14 +907,17 @@
         env->SetIntArrayRegion(jFormats, j, 1, &jFormat);
     }
 
+    // gains
     jGains = env->NewObjectArray(nAudioPort->num_gains,
                                           gAudioGainClass, NULL);
     if (jGains == NULL) {
         jStatus = (jint)AUDIO_JAVA_ERROR;
         goto exit;
     }
+
     for (size_t j = 0; j < nAudioPort->num_gains; j++) {
         audio_channel_mask_t nMask = nAudioPort->gains[j].channel_mask;
+        jint jMask;
         if (useInMask) {
             jMask = inChannelMaskFromNative(nMask);
             ALOGV("convertAudioPortConfigFromNative IN mask java %x native %x", jMask, nMask);
@@ -931,7 +958,8 @@
         jstring jAddress = env->NewStringUTF(nAudioPort->ext.device.address);
         *jAudioPort = env->NewObject(gAudioDevicePortClass, gAudioDevicePortCstor,
                                      jHandle, jDeviceName,
-                                     jSamplingRates, jChannelMasks, jFormats, jGains,
+                                     jSamplingRates, jChannelMasks, jChannelIndexMasks,
+                                     jFormats, jGains,
                                      nAudioPort->ext.device.type, jAddress);
         env->DeleteLocalRef(jAddress);
     } else if (nAudioPort->type == AUDIO_PORT_TYPE_MIX) {
@@ -939,7 +967,7 @@
         *jAudioPort = env->NewObject(gAudioMixPortClass, gAudioMixPortCstor,
                                      jHandle, nAudioPort->ext.mix.handle,
                                      nAudioPort->role, jDeviceName,
-                                     jSamplingRates, jChannelMasks,
+                                     jSamplingRates, jChannelMasks, jChannelIndexMasks,
                                      jFormats, jGains);
     } else {
         ALOGE("convertAudioPortFromNative unknown nAudioPort type %d", nAudioPort->type);
@@ -1634,7 +1662,7 @@
     jclass audioPortClass = FindClassOrDie(env, "android/media/AudioPort");
     gAudioPortClass = MakeGlobalRefOrDie(env, audioPortClass);
     gAudioPortCstor = GetMethodIDOrDie(env, audioPortClass, "<init>",
-            "(Landroid/media/AudioHandle;ILjava/lang/String;[I[I[I[Landroid/media/AudioGain;)V");
+            "(Landroid/media/AudioHandle;ILjava/lang/String;[I[I[I[I[Landroid/media/AudioGain;)V");
     gAudioPortFields.mHandle = GetFieldIDOrDie(env, audioPortClass, "mHandle",
                                                "Landroid/media/AudioHandle;");
     gAudioPortFields.mRole = GetFieldIDOrDie(env, audioPortClass, "mRole", "I");
@@ -1672,12 +1700,12 @@
     jclass audioDevicePortClass = FindClassOrDie(env, "android/media/AudioDevicePort");
     gAudioDevicePortClass = MakeGlobalRefOrDie(env, audioDevicePortClass);
     gAudioDevicePortCstor = GetMethodIDOrDie(env, audioDevicePortClass, "<init>",
-            "(Landroid/media/AudioHandle;Ljava/lang/String;[I[I[I[Landroid/media/AudioGain;ILjava/lang/String;)V");
+            "(Landroid/media/AudioHandle;Ljava/lang/String;[I[I[I[I[Landroid/media/AudioGain;ILjava/lang/String;)V");
 
     jclass audioMixPortClass = FindClassOrDie(env, "android/media/AudioMixPort");
     gAudioMixPortClass = MakeGlobalRefOrDie(env, audioMixPortClass);
     gAudioMixPortCstor = GetMethodIDOrDie(env, audioMixPortClass, "<init>",
-            "(Landroid/media/AudioHandle;IILjava/lang/String;[I[I[I[Landroid/media/AudioGain;)V");
+            "(Landroid/media/AudioHandle;IILjava/lang/String;[I[I[I[I[Landroid/media/AudioGain;)V");
 
     jclass audioGainClass = FindClassOrDie(env, "android/media/AudioGain");
     gAudioGainClass = MakeGlobalRefOrDie(env, audioGainClass);
diff --git a/core/jni/android_util_Log.cpp b/core/jni/android_util_Log.cpp
index 9a80f1d..2b1067b 100644
--- a/core/jni/android_util_Log.cpp
+++ b/core/jni/android_util_Log.cpp
@@ -41,32 +41,8 @@
 };
 static levels_t levels;
 
-static int toLevel(const char* value)
-{
-    switch (value[0]) {
-        case 'V': return levels.verbose;
-        case 'D': return levels.debug;
-        case 'I': return levels.info;
-        case 'W': return levels.warn;
-        case 'E': return levels.error;
-        case 'A': return levels.assert;
-        case 'S': return -1; // SUPPRESS
-    }
-    return levels.info;
-}
-
 static jboolean isLoggable(const char* tag, jint level) {
-    String8 key;
-    key.append(LOG_NAMESPACE);
-    key.append(tag);
-
-    char buf[PROPERTY_VALUE_MAX];
-    if (property_get(key.string(), buf, "") <= 0) {
-        buf[0] = '\0';
-    }
-
-    int logLevel = toLevel(buf);
-    return logLevel >= 0 && level >= logLevel;
+    return __android_log_is_loggable(level, tag, ANDROID_LOG_INFO);
 }
 
 static jboolean android_util_Log_isLoggable(JNIEnv* env, jobject clazz, jstring tag, jint level)
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index 9307ff9..a526223 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -105,8 +105,8 @@
 }
 
 static bool
-isFileDifferent(const char* filePath, size_t fileSize, time_t modifiedTime,
-        long zipCrc, struct stat64* st)
+isFileDifferent(const char* filePath, uint32_t fileSize, time_t modifiedTime,
+        uint32_t zipCrc, struct stat64* st)
 {
     if (lstat64(filePath, st) < 0) {
         // File is not found or cannot be read.
@@ -134,7 +134,9 @@
         return true;
     }
 
-    long crc = crc32(0L, Z_NULL, 0);
+    // uLong comes from zlib.h. It's a bit of a wart that they're
+    // potentially using a 64-bit type for a 32-bit CRC.
+    uLong crc = crc32(0L, Z_NULL, 0);
     unsigned char crcBuffer[16384];
     ssize_t numBytes;
     while ((numBytes = TEMP_FAILURE_RETRY(read(fd, crcBuffer, sizeof(crcBuffer)))) > 0) {
@@ -142,9 +144,9 @@
     }
     close(fd);
 
-    ALOGV("%s: crc = %lx, zipCrc = %lx\n", filePath, crc, zipCrc);
+    ALOGV("%s: crc = %lx, zipCrc = %" PRIu32 "\n", filePath, crc, zipCrc);
 
-    if (crc != zipCrc) {
+    if (crc != static_cast<uLong>(zipCrc)) {
         return true;
     }
 
@@ -155,13 +157,13 @@
 sumFiles(JNIEnv*, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntry, const char*)
 {
     size_t* total = (size_t*) arg;
-    size_t uncompLen;
+    uint32_t uncompLen;
 
     if (!zipFile->getEntryInfo(zipEntry, NULL, &uncompLen, NULL, NULL, NULL, NULL)) {
         return INSTALL_FAILED_INVALID_APK;
     }
 
-    *total += uncompLen;
+    *total += static_cast<size_t>(uncompLen);
 
     return INSTALL_SUCCEEDED;
 }
@@ -181,12 +183,11 @@
 
     ScopedUtfChars nativeLibPath(env, *javaNativeLibPath);
 
-    size_t uncompLen;
-    long when;
-    long crc;
-    time_t modTime;
+    uint32_t uncompLen;
+    uint32_t when;
+    uint32_t crc;
 
-    int method;
+    uint16_t method;
     off64_t offset;
 
     if (!zipFile->getEntryInfo(zipEntry, &method, &uncompLen, NULL, &offset, &when, &crc)) {
@@ -233,7 +234,7 @@
     // Only copy out the native file if it's different.
     struct tm t;
     ZipUtils::zipTimeToTimespec(when, &t);
-    modTime = mktime(&t);
+    const time_t modTime = mktime(&t);
     struct stat64 st;
     if (!isFileDifferent(localFileName, uncompLen, modTime, crc, &st)) {
         return INSTALL_SUCCEEDED;
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index fb0455d..510f6a5 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1969,9 +1969,9 @@
     <string name="lockscreen_access_pattern_start">Pattern started</string>
     <!-- Accessibility description sent when the pattern times out and is cleared. [CHAR LIMIT=NONE] -->
     <string name="lockscreen_access_pattern_cleared">Pattern cleared</string>
-    <!-- Accessibility description sent when user adds a cell to the pattern. [CHAR LIMIT=NONE]  -->
+    <!-- Accessibility description sent when user adds a dot to the pattern. [CHAR LIMIT=NONE]  -->
     <string name="lockscreen_access_pattern_cell_added">Cell added</string>
-    <!-- Accessibility description sent when user adds a cell to the pattern. Announces the 
+    <!-- Accessibility description sent when user adds a dot to the pattern. Announces the 
     actual cell when headphones are connected [CHAR LIMIT=NONE]  -->
     <string name="lockscreen_access_pattern_cell_added_verbose">
             Cell <xliff:g id="cell_index" example="3">%1$s</xliff:g> added</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index d7b565c..5ba57c4 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2311,5 +2311,6 @@
   <java-symbol type="string" name="ext_media_unsupported_notification_message" />
   <java-symbol type="string" name="ext_media_unsupported_notification_title" />
   <java-symbol type="plurals" name="selected_count" />
+  <java-symbol type="drawable" name="ic_dialog_alert_material" />
 
 </resources>
diff --git a/docs/html/index.jd b/docs/html/index.jd
index 3989b92..cd129d4 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -26,9 +26,9 @@
         <p class="dac-hero-description">Get your apps ready for the next version
         of Android. Test on Nexus 5, 6, 9, and Player. </p>
 
-        <a class="dac-hero-cta" href="{@docRoot}preview/index.html">
+        <a class="dac-hero-cta" href="{@docRoot}preview/overview.html">
           <span class="dac-sprite dac-auto-chevron"></span>
-          Learn more
+          Get started
         </a>
       </div>
     </div>
diff --git a/docs/html/jd_collections.js b/docs/html/jd_collections.js
index 82836e2..86089e6 100644
--- a/docs/html/jd_collections.js
+++ b/docs/html/jd_collections.js
@@ -1594,7 +1594,8 @@
       "training/enterprise/app-restrictions.html",
       "https://www.youtube.com/watch?v=39NkpWkaH8M&index=2&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX",
       "samples/AppRestrictionSchema/index.html",
-      "samples/AppRestrictionEnforcer/index.html"
+      "samples/AppRestrictionEnforcer/index.html",
+      "https://www.youtube.com/watch?v=dH41OutAMNM"
     ]
   },
   "training/work/admin": {
diff --git a/docs/html/preview/index.jd b/docs/html/preview/index.jd
index eb18aa6..68186bd 100644
--- a/docs/html/preview/index.jd
+++ b/docs/html/preview/index.jd
@@ -26,7 +26,7 @@
 
         <a class="dac-hero-cta" href="{@docRoot}preview/overview.html">
           <span class="dac-sprite dac-auto-chevron"></span>
-          Get Started!
+          Get started
         </a><br>
       </div>
     </div>
@@ -44,7 +44,7 @@
   <div class="dac-section-subtitle">
     Essential information to help you get your apps ready for Android M.
   </div>
- 
+
   <div class="resource-widget resource-flow-layout col-16"
        data-query="collection:preview/landing/more"
        data-cardSizes="6x6"
@@ -56,7 +56,7 @@
           <span class="dac-sprite dac-auto-chevron"></span>
           Report Issues
         </a>
-      </li> 
+      </li>
       <li class="dac-section-link"><a href="http://g.co/dev/AndroidMDevPreview">
         <span class="dac-sprite dac-auto-chevron"></span>
         Join G+ Community
diff --git a/docs/html/training/tv/discovery/searchable.jd b/docs/html/training/tv/discovery/searchable.jd
index 27a1c33..4ca7abb 100644
--- a/docs/html/training/tv/discovery/searchable.jd
+++ b/docs/html/training/tv/discovery/searchable.jd
@@ -90,7 +90,7 @@
    <td>The production year of your content <strong>(required)</strong></td>
 </tr><tr>
    <td>{@code SUGGEST_COLUMN_DURATION}</td>
-   <td>The duration in milliseconds of your media</td>
+   <td>The duration in milliseconds of your media <strong>(required)</strong></td>
 </tr>
 </table>
 
@@ -99,6 +99,7 @@
   <li>{@link android.app.SearchManager#SUGGEST_COLUMN_TEXT_1}</li>
   <li>{@link android.app.SearchManager#SUGGEST_COLUMN_CONTENT_TYPE}</li>
   <li>{@link android.app.SearchManager#SUGGEST_COLUMN_PRODUCTION_YEAR}</li>
+  <li>{@link android.app.SearchManager#SUGGEST_COLUMN_DURATION}</li>
 </ul>
 
 <p>When the values of these columns for your content match the values for the same content from other
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 82a592a..a0c407f 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -815,6 +815,9 @@
         if (tileModeY != TILE_MODE_UNDEFINED) {
             setTileModeY(parseTileMode(tileModeY));
         }
+
+        final int densityDpi = r.getDisplayMetrics().densityDpi;
+        state.mTargetDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi;
     }
 
     @Override
@@ -977,7 +980,8 @@
      */
     private void updateLocalState(Resources res) {
         if (res != null) {
-            mTargetDensity = res.getDisplayMetrics().densityDpi;
+            final int densityDpi = res.getDisplayMetrics().densityDpi;
+            mTargetDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi;
         } else {
             mTargetDensity = mBitmapState.mTargetDensity;
         }
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 532c888..415af0d 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -1147,6 +1147,7 @@
      * document, tries to create a Drawable from that tag. Returns {@code null}
      * if the tag is not a valid drawable.
      */
+    @SuppressWarnings("deprecation")
     public static Drawable createFromXmlInner(Resources r, XmlPullParser parser, AttributeSet attrs,
             Theme theme) throws XmlPullParserException, IOException {
         final Drawable drawable;
@@ -1202,16 +1203,10 @@
                 drawable = new InsetDrawable();
                 break;
             case "bitmap":
-                drawable = new BitmapDrawable(r);
-                if (r != null) {
-                    ((BitmapDrawable) drawable).setTargetDensity(r.getDisplayMetrics());
-                }
+                drawable = new BitmapDrawable();
                 break;
             case "nine-patch":
                 drawable = new NinePatchDrawable();
-                if (r != null) {
-                    ((NinePatchDrawable) drawable).setTargetDensity(r.getDisplayMetrics());
-                }
                 break;
             default:
                 throw new XmlPullParserException(parser.getPositionDescription() +
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 91bbff7..0b7869b 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -482,6 +482,9 @@
         if (tint != null) {
             state.mTint = tint;
         }
+
+        final int densityDpi = r.getDisplayMetrics().densityDpi;
+        state.mTargetDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi;
     }
 
     @Override
@@ -713,7 +716,8 @@
         final NinePatchState state = mNinePatchState;
 
         if (res != null) {
-            mTargetDensity = res.getDisplayMetrics().densityDpi;
+            final int densityDpi = res.getDisplayMetrics().densityDpi;
+            mTargetDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi;
         } else {
             mTargetDensity = state.mTargetDensity;
         }
diff --git a/include/androidfw/Asset.h b/include/androidfw/Asset.h
index 1fe0e06..ee77e97 100644
--- a/include/androidfw/Asset.h
+++ b/include/androidfw/Asset.h
@@ -182,11 +182,11 @@
 
     /*
      * Create the asset from a memory-mapped file segment with compressed
-     * data.  "method" is a Zip archive compression method constant.
+     * data.
      *
      * The asset takes ownership of the FileMap.
      */
-    static Asset* createFromCompressedMap(FileMap* dataMap, int method,
+    static Asset* createFromCompressedMap(FileMap* dataMap,
         size_t uncompressedLen, AccessMode mode);
 
 
@@ -286,8 +286,7 @@
      *
      * On success, the object takes ownership of "fd".
      */
-    status_t openChunk(FileMap* dataMap, int compressionMethod,
-        size_t uncompressedLen);
+    status_t openChunk(FileMap* dataMap, size_t uncompressedLen);
 
     /*
      * Standard Asset interfaces.
diff --git a/include/androidfw/ZipFileRO.h b/include/androidfw/ZipFileRO.h
index ad5be12..1410d87 100644
--- a/include/androidfw/ZipFileRO.h
+++ b/include/androidfw/ZipFileRO.h
@@ -35,6 +35,7 @@
 #include <utils/FileMap.h>
 #include <utils/threads.h>
 
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -68,9 +69,9 @@
 class ZipFileRO {
 public:
     /* Zip compression methods we support */
-    enum {
-        kCompressStored     = 0,        // no compression
-        kCompressDeflated   = 8,        // standard deflate
+    enum : uint16_t {
+        kCompressStored = 0,
+        kCompressDeflated = 8
     };
 
     /*
@@ -108,10 +109,10 @@
 
     /*
      * Copy the filename into the supplied buffer.  Returns 0 on success,
-     * -1 if "entry" is invalid, or the filename length if it didn't fit.  The
+     * -1 if "entry" is invalid, or the filename length if it didn't fit. The
      * length, and the returned string, include the null-termination.
      */
-    int getEntryFileName(ZipEntryRO entry, char* buffer, int bufLen) const;
+    int getEntryFileName(ZipEntryRO entry, char* buffer, size_t bufLen) const;
 
     /*
      * Get the vital stats for an entry.  Pass in NULL pointers for anything
@@ -122,8 +123,9 @@
      * Returns "false" if "entry" is bogus or if the data in the Zip file
      * appears to be bad.
      */
-    bool getEntryInfo(ZipEntryRO entry, int* pMethod, size_t* pUncompLen,
-        size_t* pCompLen, off64_t* pOffset, long* pModWhen, long* pCrc32) const;
+    bool getEntryInfo(ZipEntryRO entry, uint16_t* pMethod, uint32_t* pUncompLen,
+        uint32_t* pCompLen, off64_t* pOffset, uint32_t* pModWhen,
+        uint32_t* pCrc32) const;
 
     /*
      * Create a new FileMap object that maps a subset of the archive.  For
diff --git a/include/androidfw/ZipUtils.h b/include/androidfw/ZipUtils.h
index 6bea25a..094eaa8 100644
--- a/include/androidfw/ZipUtils.h
+++ b/include/androidfw/ZipUtils.h
@@ -20,6 +20,7 @@
 #ifndef __LIBS_ZIPUTILS_H
 #define __LIBS_ZIPUTILS_H
 
+#include <stdint.h>
 #include <stdio.h>
 #include <time.h>
 
@@ -63,8 +64,8 @@
     /*
      * Utility function to convert ZIP's time format to a timespec struct.
      */
-    static inline void zipTimeToTimespec(long when, struct tm* timespec) {
-        const long date = when >> 16;
+    static inline void zipTimeToTimespec(uint32_t when, struct tm* timespec) {
+        const uint32_t date = when >> 16;
         timespec->tm_year = ((date >> 9) & 0x7F) + 80; // Zip is years since 1980
         timespec->tm_mon = (date >> 5) & 0x0F;
         timespec->tm_mday = date & 0x1F;
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index 4c0631f..8d4bfcd 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -70,6 +70,8 @@
  * <p>NOTE: The key material of the generated symmetric and private keys is not accessible. The key
  * material of the public keys is accessible.
  *
+ * <p>Instances of this class are immutable.
+ *
  * <p><h3>Example: Asymmetric key pair</h3>
  * The following example illustrates how to generate an EC key pair in the Android KeyStore system
  * under alias {@code key1} authorized to be used only for signing using SHA-256, SHA-384,
@@ -79,11 +81,12 @@
  *         KeyProperties.KEY_ALGORITHM_EC,
  *         "AndroidKeyStore");
  * keyPairGenerator.initialize(
- *         new KeyGenParameterSpec.Builder("key1",
+ *         new KeyGenParameterSpec.Builder(
+ *                 "key1",
  *                 KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
- *                 .setDigests(KeyProperties.DIGEST_SHA256
- *                         | KeyProperties.DIGEST_SHA384
- *                         | KeyProperties.DIGEST_SHA512)
+ *                 .setDigests(KeyProperties.DIGEST_SHA256,
+ *                         KeyProperties.DIGEST_SHA384,
+ *                         KeyProperties.DIGEST_SHA512)
  *                 // Only permit this key to be used if the user authenticated
  *                 // within the last five minutes.
  *                 .setUserAuthenticationRequired(true)
@@ -100,16 +103,17 @@
  *
  * <p><h3>Example: Symmetric key</h3>
  * The following example illustrates how to generate an AES key in the Android KeyStore system under
- * alias {@code key2} authorized to be used only for encryption/decryption in CTR mode.
+ * alias {@code key2} authorized to be used only for encryption/decryption in CBC mode with PKCS#7
+ * padding.
  * <pre> {@code
  * KeyGenerator keyGenerator = KeyGenerator.getInstance(
- *         KeyProperties.KEY_ALGORITHM_HMAC_SHA256,
+ *         KeyProperties.KEY_ALGORITHM_AES,
  *         "AndroidKeyStore");
  * keyGenerator.initialize(
  *         new KeyGenParameterSpec.Builder("key2",
  *                 KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
- *                 .setBlockModes(KeyProperties.BLOCK_MODE_CTR)
- *                 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+ *                 .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
+ *                 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
  *                 .build());
  * SecretKey key = keyGenerator.generateKey();
  *
@@ -169,10 +173,6 @@
             int userAuthenticationValidityDurationSeconds) {
         if (TextUtils.isEmpty(keyStoreAlias)) {
             throw new IllegalArgumentException("keyStoreAlias must not be empty");
-        } else if ((userAuthenticationValidityDurationSeconds < 0)
-                && (userAuthenticationValidityDurationSeconds != -1)) {
-            throw new IllegalArgumentException(
-                    "userAuthenticationValidityDurationSeconds must not be negative");
         }
 
         if (certificateSubject == null) {
@@ -197,11 +197,11 @@
         mSpec = spec;
         mCertificateSubject = certificateSubject;
         mCertificateSerialNumber = certificateSerialNumber;
-        mCertificateNotBefore = certificateNotBefore;
-        mCertificateNotAfter = certificateNotAfter;
-        mKeyValidityStart = keyValidityStart;
-        mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
-        mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
+        mCertificateNotBefore = Utils.cloneIfNotNull(certificateNotBefore);
+        mCertificateNotAfter = Utils.cloneIfNotNull(certificateNotAfter);
+        mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart);
+        mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd);
+        mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd);
         mPurposes = purposes;
         mDigests = ArrayUtils.cloneIfNotEmpty(digests);
         mEncryptionPaddings =
@@ -217,6 +217,7 @@
      * Returns the alias that will be used in the {@code java.security.KeyStore}
      * in conjunction with the {@code AndroidKeyStore}.
      */
+    @NonNull
     public String getKeystoreAlias() {
         return mKeystoreAlias;
     }
@@ -231,10 +232,10 @@
     }
 
     /**
-     * Returns the {@link AlgorithmParameterSpec} that will be used for creation
-     * of the key pair.
+     * Returns the key algorithm-specific {@link AlgorithmParameterSpec} that will be used for
+     * creation of the key or {@code null} if algorithm-specific defaults should be used.
      */
-    @NonNull
+    @Nullable
     public AlgorithmParameterSpec getAlgorithmParameterSpec() {
         return mSpec;
     }
@@ -263,7 +264,7 @@
      */
     @NonNull
     public Date getCertificateNotBefore() {
-        return mCertificateNotBefore;
+        return Utils.cloneIfNotNull(mCertificateNotBefore);
     }
 
     /**
@@ -272,7 +273,7 @@
      */
     @NonNull
     public Date getCertificateNotAfter() {
-        return mCertificateNotAfter;
+        return Utils.cloneIfNotNull(mCertificateNotAfter);
     }
 
     /**
@@ -281,7 +282,7 @@
      */
     @Nullable
     public Date getKeyValidityStart() {
-        return mKeyValidityStart;
+        return Utils.cloneIfNotNull(mKeyValidityStart);
     }
 
     /**
@@ -290,7 +291,7 @@
      */
     @Nullable
     public Date getKeyValidityForConsumptionEnd() {
-        return mKeyValidityForConsumptionEnd;
+        return Utils.cloneIfNotNull(mKeyValidityForConsumptionEnd);
     }
 
     /**
@@ -299,7 +300,7 @@
      */
     @Nullable
     public Date getKeyValidityForOriginationEnd() {
-        return mKeyValidityForOriginationEnd;
+        return Utils.cloneIfNotNull(mKeyValidityForOriginationEnd);
     }
 
     /**
@@ -411,7 +412,7 @@
      * restricted.
      *
      * @return duration in seconds or {@code -1} if authentication is required for every use of the
-     *         key.
+     * key.
      *
      * @see #isUserAuthenticationRequired()
      */
@@ -447,7 +448,7 @@
          * Creates a new instance of the {@code Builder}.
          *
          * @param keystoreAlias alias of the entry in which the generated key will appear in
-         *        Android KeyStore.
+         *        Android KeyStore. Must not be empty.
          * @param purposes set of purposes (e.g., encrypt, decrypt, sign) for which the key can be
          *        used. Attempts to use the key for any other purpose will be rejected.
          *
@@ -462,6 +463,8 @@
         public Builder(@NonNull String keystoreAlias, @KeyProperties.PurposeEnum int purposes) {
             if (keystoreAlias == null) {
                 throw new NullPointerException("keystoreAlias == null");
+            } else if (keystoreAlias.isEmpty()) {
+                throw new IllegalArgumentException("keystoreAlias must not be empty");
             }
             mKeystoreAlias = keystoreAlias;
             mPurposes = purposes;
@@ -488,7 +491,11 @@
 
         /**
          * Sets the algorithm-specific key generation parameters. For example, for RSA keys this may
-         * be an instance of {@link java.security.spec.RSAKeyGenParameterSpec}.
+         * be an instance of {@link java.security.spec.RSAKeyGenParameterSpec} whereas for EC keys
+         * this may be an instance of {@link java.security.spec.ECGenParameterSpec}.
+         *
+         * <p>These key generation parameters must match other explicitly set parameters (if any),
+         * such as key size.
          */
         public Builder setAlgorithmParameterSpec(@NonNull AlgorithmParameterSpec spec) {
             if (spec == null) {
@@ -537,7 +544,7 @@
             if (date == null) {
                 throw new NullPointerException("date == null");
             }
-            mCertificateNotBefore = date;
+            mCertificateNotBefore = Utils.cloneIfNotNull(date);
             return this;
         }
 
@@ -552,7 +559,7 @@
             if (date == null) {
                 throw new NullPointerException("date == null");
             }
-            mCertificateNotAfter = date;
+            mCertificateNotAfter = Utils.cloneIfNotNull(date);
             return this;
         }
 
@@ -565,7 +572,7 @@
          */
         @NonNull
         public Builder setKeyValidityStart(Date startDate) {
-            mKeyValidityStart = startDate;
+            mKeyValidityStart = Utils.cloneIfNotNull(startDate);
             return this;
         }
 
@@ -594,7 +601,7 @@
          */
         @NonNull
         public Builder setKeyValidityForOriginationEnd(Date endDate) {
-            mKeyValidityForOriginationEnd = endDate;
+            mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(endDate);
             return this;
         }
 
@@ -608,7 +615,7 @@
          */
         @NonNull
         public Builder setKeyValidityForConsumptionEnd(Date endDate) {
-            mKeyValidityForConsumptionEnd = endDate;
+            mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(endDate);
             return this;
         }
 
@@ -768,14 +775,15 @@
         @NonNull
         public Builder setUserAuthenticationValidityDurationSeconds(
                 @IntRange(from = -1) int seconds) {
+            if (seconds < -1) {
+                throw new IllegalArgumentException("seconds must be -1 or larger");
+            }
             mUserAuthenticationValidityDurationSeconds = seconds;
             return this;
         }
 
         /**
          * Builds an instance of {@code KeyGenParameterSpec}.
-         *
-         * @throws IllegalArgumentException if a required field is missing
          */
         @NonNull
         public KeyGenParameterSpec build() {
diff --git a/keystore/java/android/security/keystore/KeyInfo.java b/keystore/java/android/security/keystore/KeyInfo.java
index e4f921e..03b4100 100644
--- a/keystore/java/android/security/keystore/KeyInfo.java
+++ b/keystore/java/android/security/keystore/KeyInfo.java
@@ -33,6 +33,8 @@
  * is authorized for (e.g., only in {@code CBC} mode, or signing only), whether the key should be
  * encrypted at rest, the key's and validity start and end dates.
  *
+ * <p>Instances of this class are immutable.
+ *
  * <p><h3>Example: Symmetric Key</h3>
  * The following example illustrates how to obtain a {@code KeyInfo} describing the provided Android
  * Keystore {@link SecretKey}.
@@ -102,9 +104,9 @@
         mInsideSecureHardware = insideSecureHardware;
         mOrigin = origin;
         mKeySize = keySize;
-        mKeyValidityStart = keyValidityStart;
-        mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
-        mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
+        mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart);
+        mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd);
+        mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd);
         mPurposes = purposes;
         mEncryptionPaddings =
                 ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings));
@@ -155,7 +157,7 @@
      */
     @Nullable
     public Date getKeyValidityStart() {
-        return mKeyValidityStart;
+        return Utils.cloneIfNotNull(mKeyValidityStart);
     }
 
     /**
@@ -165,7 +167,7 @@
      */
     @Nullable
     public Date getKeyValidityForConsumptionEnd() {
-        return mKeyValidityForConsumptionEnd;
+        return Utils.cloneIfNotNull(mKeyValidityForConsumptionEnd);
     }
 
     /**
@@ -175,7 +177,7 @@
      */
     @Nullable
     public Date getKeyValidityForOriginationEnd() {
-        return mKeyValidityForOriginationEnd;
+        return Utils.cloneIfNotNull(mKeyValidityForOriginationEnd);
     }
 
     /**
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index 432fc12..1e0611c 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -47,6 +47,8 @@
  *
  * <p>NOTE: The key material of keys stored in the Android KeyStore is not accessible.
  *
+ * <p>Instances of this class are immutable.
+ *
  * <p><h3>Example: Symmetric Key</h3>
  * The following example illustrates how to import an AES key into the Android KeyStore under alias
  * {@code key1} authorized to be used only for encryption/decryption in CBC mode with PKCS#7
@@ -122,15 +124,9 @@
             boolean randomizedEncryptionRequired,
             boolean userAuthenticationRequired,
             int userAuthenticationValidityDurationSeconds) {
-        if ((userAuthenticationValidityDurationSeconds < 0)
-                && (userAuthenticationValidityDurationSeconds != -1)) {
-            throw new IllegalArgumentException(
-                    "userAuthenticationValidityDurationSeconds must not be negative");
-        }
-
-        mKeyValidityStart = keyValidityStart;
-        mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
-        mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
+        mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart);
+        mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd);
+        mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd);
         mPurposes = purposes;
         mEncryptionPaddings =
                 ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings));
@@ -150,7 +146,7 @@
      */
     @Nullable
     public Date getKeyValidityStart() {
-        return mKeyValidityStart;
+        return Utils.cloneIfNotNull(mKeyValidityStart);
     }
 
     /**
@@ -160,7 +156,7 @@
      */
     @Nullable
     public Date getKeyValidityForConsumptionEnd() {
-        return mKeyValidityForConsumptionEnd;
+        return Utils.cloneIfNotNull(mKeyValidityForConsumptionEnd);
     }
 
     /**
@@ -170,7 +166,7 @@
      */
     @Nullable
     public Date getKeyValidityForOriginationEnd() {
-        return mKeyValidityForOriginationEnd;
+        return Utils.cloneIfNotNull(mKeyValidityForOriginationEnd);
     }
 
     /**
@@ -320,7 +316,7 @@
          */
         @NonNull
         public Builder setKeyValidityStart(Date startDate) {
-            mKeyValidityStart = startDate;
+            mKeyValidityStart = Utils.cloneIfNotNull(startDate);
             return this;
         }
 
@@ -349,7 +345,7 @@
          */
         @NonNull
         public Builder setKeyValidityForOriginationEnd(Date endDate) {
-            mKeyValidityForOriginationEnd = endDate;
+            mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(endDate);
             return this;
         }
 
@@ -363,7 +359,7 @@
          */
         @NonNull
         public Builder setKeyValidityForConsumptionEnd(Date endDate) {
-            mKeyValidityForConsumptionEnd = endDate;
+            mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(endDate);
             return this;
         }
 
@@ -517,6 +513,9 @@
         @NonNull
         public Builder setUserAuthenticationValidityDurationSeconds(
                 @IntRange(from = -1) int seconds) {
+            if (seconds < -1) {
+                throw new IllegalArgumentException("seconds must be -1 or larger");
+            }
             mUserAuthenticationValidityDurationSeconds = seconds;
             return this;
         }
diff --git a/keystore/java/android/security/keystore/Utils.java b/keystore/java/android/security/keystore/Utils.java
new file mode 100644
index 0000000..9bec682
--- /dev/null
+++ b/keystore/java/android/security/keystore/Utils.java
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+package android.security.keystore;
+
+import java.util.Date;
+
+/**
+ * Assorted utility methods.
+ *
+ * @hide
+ */
+abstract class Utils {
+    private Utils() {}
+
+    static Date cloneIfNotNull(Date value) {
+        return (value != null) ? (Date) value.clone() : null;
+    }
+}
diff --git a/libs/androidfw/Asset.cpp b/libs/androidfw/Asset.cpp
index 782806e..4e14b13 100644
--- a/libs/androidfw/Asset.cpp
+++ b/libs/androidfw/Asset.cpp
@@ -296,13 +296,13 @@
  * Create a new Asset from compressed data in a memory mapping.
  */
 /*static*/ Asset* Asset::createFromCompressedMap(FileMap* dataMap,
-    int method, size_t uncompressedLen, AccessMode mode)
+    size_t uncompressedLen, AccessMode mode)
 {
     _CompressedAsset* pAsset;
     status_t result;
 
     pAsset = new _CompressedAsset;
-    result = pAsset->openChunk(dataMap, method, uncompressedLen);
+    result = pAsset->openChunk(dataMap, uncompressedLen);
     if (result != NO_ERROR)
         return NULL;
 
@@ -734,18 +734,12 @@
  *
  * Nothing is expanded until the first read call.
  */
-status_t _CompressedAsset::openChunk(FileMap* dataMap, int compressionMethod,
-    size_t uncompressedLen)
+status_t _CompressedAsset::openChunk(FileMap* dataMap, size_t uncompressedLen)
 {
     assert(mFd < 0);        // no re-open
     assert(mMap == NULL);
     assert(dataMap != NULL);
 
-    if (compressionMethod != ZipFileRO::kCompressDeflated) {
-        assert(false);
-        return UNKNOWN_ERROR;
-    }
-
     mMap = dataMap;
     mStart = -1;        // not used
     mCompressedLen = dataMap->getDataLength();
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 25cd363..2dc1c96 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -1156,13 +1156,11 @@
     Asset* pAsset = NULL;
 
     // TODO: look for previously-created shared memory slice?
-    int method;
-    size_t uncompressedLen;
+    uint16_t method;
+    uint32_t uncompressedLen;
 
     //printf("USING Zip '%s'\n", pEntry->getFileName());
 
-    //pZipFile->getEntryInfo(entry, &method, &uncompressedLen, &compressedLen,
-    //    &offset);
     if (!pZipFile->getEntryInfo(entry, &method, &uncompressedLen, NULL, NULL,
             NULL, NULL))
     {
@@ -1181,8 +1179,8 @@
         ALOGV("Opened uncompressed entry %s in zip %s mode %d: %p", entryName.string(),
                 dataMap->getFileName(), mode, pAsset);
     } else {
-        pAsset = Asset::createFromCompressedMap(dataMap, method,
-            uncompressedLen, mode);
+        pAsset = Asset::createFromCompressedMap(dataMap,
+            static_cast<size_t>(uncompressedLen), mode);
         ALOGV("Opened compressed entry %s in zip %s mode %d: %p", entryName.string(),
                 dataMap->getFileName(), mode, pAsset);
     }
diff --git a/libs/androidfw/ZipFileRO.cpp b/libs/androidfw/ZipFileRO.cpp
index 93b1d56..6f927b4 100644
--- a/libs/androidfw/ZipFileRO.cpp
+++ b/libs/androidfw/ZipFileRO.cpp
@@ -97,8 +97,9 @@
  * Returns "false" if the offsets to the fields or the contents of the fields
  * appear to be bogus.
  */
-bool ZipFileRO::getEntryInfo(ZipEntryRO entry, int* pMethod, size_t* pUncompLen,
-    size_t* pCompLen, off64_t* pOffset, long* pModWhen, long* pCrc32) const
+bool ZipFileRO::getEntryInfo(ZipEntryRO entry, uint16_t* pMethod,
+    uint32_t* pUncompLen, uint32_t* pCompLen, off64_t* pOffset,
+    uint32_t* pModWhen, uint32_t* pCrc32) const
 {
     const _ZipEntryRO* zipEntry = reinterpret_cast<_ZipEntryRO*>(entry);
     const ZipEntry& ze = zipEntry->entry;
@@ -166,7 +167,7 @@
 /*
  * Copy the entry's filename to the buffer.
  */
-int ZipFileRO::getEntryFileName(ZipEntryRO entry, char* buffer, int bufLen)
+int ZipFileRO::getEntryFileName(ZipEntryRO entry, char* buffer, size_t bufLen)
     const
 {
     const _ZipEntryRO* zipEntry = reinterpret_cast<_ZipEntryRO*>(entry);
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index b4cbc36..fc18491 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -241,8 +241,12 @@
         animatorDirtyMask = mAnimatorManager.animate(info);
     }
 
-    bool willHaveFunctor = info.mode == TreeInfo::MODE_FULL && mStagingDisplayListData
-            ? !mStagingDisplayListData->functors.isEmpty() : !mDisplayListData->functors.isEmpty();
+    bool willHaveFunctor = false;
+    if (info.mode == TreeInfo::MODE_FULL && mStagingDisplayListData) {
+        willHaveFunctor = !mStagingDisplayListData->functors.isEmpty();
+    } else if (mDisplayListData) {
+        willHaveFunctor = !mDisplayListData->functors.isEmpty();
+    }
     bool childFunctorsNeedLayer = mProperties.prepareForFunctorPresence(
             willHaveFunctor, functorsNeedLayer);
 
diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java
index 431d37e..173d349 100644
--- a/media/java/android/media/AudioDeviceInfo.java
+++ b/media/java/android/media/AudioDeviceInfo.java
@@ -173,8 +173,7 @@
      * @see AudioFormat
      */
     public @NonNull int[] getChannelIndexMasks() {
-        // TODO: implement
-        return new int[0];
+        return mPort.channelIndexMasks();
     }
 
     /**
diff --git a/media/java/android/media/AudioDevicePort.java b/media/java/android/media/AudioDevicePort.java
index c078260..aea39a3 100644
--- a/media/java/android/media/AudioDevicePort.java
+++ b/media/java/android/media/AudioDevicePort.java
@@ -37,12 +37,12 @@
     private final String mAddress;
 
     AudioDevicePort(AudioHandle handle, String deviceName,
-            int[] samplingRates, int[] channelMasks,
+            int[] samplingRates, int[] channelMasks, int[] channelIndexMasks,
             int[] formats, AudioGain[] gains, int type, String address) {
         super(handle,
              (AudioManager.isInputDevice(type) == true)  ?
                         AudioPort.ROLE_SOURCE : AudioPort.ROLE_SINK,
-             deviceName, samplingRates, channelMasks, formats, gains);
+             deviceName, samplingRates, channelMasks, channelIndexMasks, formats, gains);
         mType = type;
         mAddress = address;
     }
diff --git a/media/java/android/media/AudioMixPort.java b/media/java/android/media/AudioMixPort.java
index ab55c8d..ba144bf 100644
--- a/media/java/android/media/AudioMixPort.java
+++ b/media/java/android/media/AudioMixPort.java
@@ -31,9 +31,10 @@
     private final int mIoHandle;
 
     AudioMixPort(AudioHandle handle, int ioHandle, int role, String deviceName,
-            int[] samplingRates, int[] channelMasks,
+            int[] samplingRates, int[] channelMasks, int[] channelIndexMasks,
             int[] formats, AudioGain[] gains) {
-        super(handle, role, deviceName, samplingRates, channelMasks, formats, gains);
+        super(handle, role, deviceName, samplingRates, channelMasks, channelIndexMasks,
+                formats, gains);
         mIoHandle = ioHandle;
     }
 
diff --git a/media/java/android/media/AudioPort.java b/media/java/android/media/AudioPort.java
index 7328d7a..19bf51d 100644
--- a/media/java/android/media/AudioPort.java
+++ b/media/java/android/media/AudioPort.java
@@ -71,12 +71,13 @@
     private final String mName;
     private final int[] mSamplingRates;
     private final int[] mChannelMasks;
+    private final int[] mChannelIndexMasks;
     private final int[] mFormats;
     private final AudioGain[] mGains;
     private AudioPortConfig mActiveConfig;
 
     AudioPort(AudioHandle handle, int role, String name,
-            int[] samplingRates, int[] channelMasks,
+            int[] samplingRates, int[] channelMasks, int[] channelIndexMasks,
             int[] formats, AudioGain[] gains) {
 
         mHandle = handle;
@@ -84,6 +85,7 @@
         mName = name;
         mSamplingRates = samplingRates;
         mChannelMasks = channelMasks;
+        mChannelIndexMasks = channelIndexMasks;
         mFormats = formats;
         mGains = gains;
     }
@@ -133,6 +135,15 @@
     }
 
     /**
+     * Get the list of supported channel index mask configurations
+     * (e.g 0x0003 means 2 channel, 0x000F means 4 channel....)
+     * Empty array if channel index mask is not relevant for this audio port
+     */
+    public int[] channelIndexMasks() {
+        return mChannelIndexMasks;
+    }
+
+    /**
      * Get the list of supported audio format configurations
      * (e.g AudioFormat.ENCODING_PCM_16BIT)
      * Empty array if format is not relevant for this audio port
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index bba33be..fc46716 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -25,7 +25,6 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.concurrent.Executor;
 
@@ -97,6 +96,22 @@
     }
 
     @Override
+    public void onResume() {
+        super.onResume();
+
+        final State state = getDisplayState();
+        final RootInfo root = getCurrentRoot();
+
+        // If we're browsing a specific root, and that root went away, then we
+        // have no reason to hang around
+        if (state.action == State.ACTION_BROWSE && root != null) {
+            if (mRoots.getRootBlocking(root.authority, root.rootId) == null) {
+                finish();
+            }
+        }
+    }
+
+    @Override
     public boolean onCreateOptionsMenu(Menu menu) {
         boolean showMenu = super.onCreateOptionsMenu(menu);
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 7bf2223..5a14967 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -2682,9 +2682,6 @@
             // Set default cdma call auto retry
             loadSetting(stmt, Settings.Global.CALL_AUTO_RETRY, 0);
 
-            // Set default simplified carrier network settings to 0
-            loadSetting(stmt, Settings.Global.HIDE_CARRIER_NETWORK_SETTINGS, 0);
-
             // Set the preferred network mode to target desired value or Default
             // value defined in RILConstants
             int type;
diff --git a/packages/Shell/src/com/android/shell/BugreportReceiver.java b/packages/Shell/src/com/android/shell/BugreportReceiver.java
index e1bfc43..13747ed 100644
--- a/packages/Shell/src/com/android/shell/BugreportReceiver.java
+++ b/packages/Shell/src/com/android/shell/BugreportReceiver.java
@@ -33,11 +33,23 @@
 import android.os.SystemProperties;
 import android.support.v4.content.FileProvider;
 import android.text.format.DateUtils;
+import android.util.Log;
 import android.util.Patterns;
 
 import com.google.android.collect.Lists;
+import libcore.io.Streams;
 
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
 import java.util.ArrayList;
 
 /**
@@ -73,30 +85,14 @@
         final Uri bugreportUri = FileProvider.getUriForFile(context, AUTHORITY, bugreportFile);
         final Uri screenshotUri = FileProvider.getUriForFile(context, AUTHORITY, screenshotFile);
 
-        Intent sendIntent = buildSendIntent(context, bugreportUri, screenshotUri);
-        Intent notifIntent;
-
-        // Send through warning dialog by default
-        if (getWarningState(context, STATE_SHOW) == STATE_SHOW) {
-            notifIntent = buildWarningIntent(context, sendIntent);
+        boolean isPlainText = bugreportFile.getName().toLowerCase().endsWith(".txt");
+        if (!isPlainText) {
+            // Already zipped, send it right away.
+            sendBugreportNotification(context, bugreportFile, screenshotFile);
         } else {
-            notifIntent = sendIntent;
+            // Asynchronously zip the file first, then send it.
+            sendZippedBugreportNotification(context, bugreportFile, screenshotFile);
         }
-        notifIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-        final Notification.Builder builder = new Notification.Builder(context)
-                .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
-                .setContentTitle(context.getString(R.string.bugreport_finished_title))
-                .setTicker(context.getString(R.string.bugreport_finished_title))
-                .setContentText(context.getString(R.string.bugreport_finished_text))
-                .setContentIntent(PendingIntent.getActivity(
-                        context, 0, notifIntent, PendingIntent.FLAG_CANCEL_CURRENT))
-                .setAutoCancel(true)
-                .setLocalOnly(true)
-                .setColor(context.getColor(
-                        com.android.internal.R.color.system_notification_accent_color));
-
-        NotificationManager.from(context).notify(TAG, 0, builder.build());
 
         // Clean up older bugreports in background
         final PendingResult result = goAsync();
@@ -141,6 +137,88 @@
     }
 
     /**
+     * Sends a bugreport notitication.
+     */
+    private static void sendBugreportNotification(Context context, File bugreportFile,
+            File screenshotFile) {
+        // Files are kept on private storage, so turn into Uris that we can
+        // grant temporary permissions for.
+        final Uri bugreportUri = FileProvider.getUriForFile(context, AUTHORITY, bugreportFile);
+        final Uri screenshotUri = FileProvider.getUriForFile(context, AUTHORITY, screenshotFile);
+
+        Intent sendIntent = buildSendIntent(context, bugreportUri, screenshotUri);
+        Intent notifIntent;
+
+        // Send through warning dialog by default
+        if (getWarningState(context, STATE_SHOW) == STATE_SHOW) {
+            notifIntent = buildWarningIntent(context, sendIntent);
+        } else {
+            notifIntent = sendIntent;
+        }
+        notifIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+        final Notification.Builder builder = new Notification.Builder(context)
+                .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
+                .setContentTitle(context.getString(R.string.bugreport_finished_title))
+                .setTicker(context.getString(R.string.bugreport_finished_title))
+                .setContentText(context.getString(R.string.bugreport_finished_text))
+                .setContentIntent(PendingIntent.getActivity(
+                        context, 0, notifIntent, PendingIntent.FLAG_CANCEL_CURRENT))
+                .setAutoCancel(true)
+                .setLocalOnly(true)
+                .setColor(context.getColor(
+                        com.android.internal.R.color.system_notification_accent_color));
+
+        NotificationManager.from(context).notify(TAG, 0, builder.build());
+    }
+
+    /**
+     * Sends a zipped bugreport notification.
+     */
+    private static void sendZippedBugreportNotification(final Context context,
+            final File bugreportFile, final File screenshotFile) {
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... params) {
+                File zippedFile = zipBugreport(bugreportFile);
+                sendBugreportNotification(context, zippedFile, screenshotFile);
+                return null;
+            }
+        }.execute();
+    }
+
+    /**
+     * Zips a bugreport file, returning the path to the new file (or to the
+     * original in case of failure).
+     */
+    private static File zipBugreport(File bugreportFile) {
+        String bugreportPath = bugreportFile.getAbsolutePath();
+        String zippedPath = bugreportPath.replace(".txt", ".zip");
+        Log.v(TAG, "zipping " + bugreportPath + " as " + zippedPath);
+        File bugreportZippedFile = new File(zippedPath);
+        try (InputStream is = new FileInputStream(bugreportFile);
+            ZipOutputStream zos = new ZipOutputStream(
+                new BufferedOutputStream(new FileOutputStream(bugreportZippedFile)))) {
+            ZipEntry entry = new ZipEntry("bugreport.txt");
+            zos.putNextEntry(entry);
+            int totalBytes = Streams.copy(is, zos);
+            Log.v(TAG, "size of original bugreport: " + totalBytes + " bytes");
+            zos.closeEntry();
+            // Delete old file;
+            boolean deleted = bugreportFile.delete();
+            if (deleted) {
+                Log.v(TAG, "deleted original bugreport (" + bugreportPath + ")");
+            } else {
+                Log.e(TAG, "could not delete original bugreport (" + bugreportPath + ")");
+            }
+            return bugreportZippedFile;
+        } catch (IOException e) {
+          Log.e(TAG, "exception zipping file " + zippedPath, e);
+          return bugreportFile;  // Return original.
+        }
+    }
+
+    /**
      * Find the best matching {@link Account} based on build properties.
      */
     private static Account findSendToAccount(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index 05ee9c2..d360875 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -53,6 +53,7 @@
     private static final int MOVE_ID = 0x534d4f56; // SMOV
 
     private static final String ACTION_SNOOZE_VOLUME = "com.android.systemui.action.SNOOZE_VOLUME";
+    private static final String ACTION_FINISH_WIZARD = "com.android.systemui.action.FINISH_WIZARD";
 
     // TODO: delay some notifications to avoid bumpy fast operations
 
@@ -107,6 +108,15 @@
         }
     };
 
+    private final BroadcastReceiver mFinishReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            // When finishing the adoption wizard, clean up any notifications
+            // for moving primary storage
+            mNotificationManager.cancelAsUser(null, MOVE_ID, UserHandle.ALL);
+        }
+    };
+
     private final MoveCallback mMoveCallback = new MoveCallback() {
         @Override
         public void onCreated(int moveId, Bundle extras) {
@@ -146,6 +156,8 @@
 
         mContext.registerReceiver(mSnoozeReceiver, new IntentFilter(ACTION_SNOOZE_VOLUME),
                 android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS, null);
+        mContext.registerReceiver(mFinishReceiver, new IntentFilter(ACTION_FINISH_WIZARD),
+                android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS, null);
 
         // Kick current state into place
         final List<DiskInfo> disks = mStorageManager.getDisks();
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e9b9767..667abb6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -31,7 +31,6 @@
 import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
 import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
@@ -10338,11 +10337,12 @@
     void startRunningVoiceLocked(IVoiceInteractionSession session, int targetUid) {
         mVoiceWakeLock.setWorkSource(new WorkSource(targetUid));
         if (mRunningVoice == null || mRunningVoice.asBinder() != session.asBinder()) {
-            if (mRunningVoice == null) {
+            boolean wasRunningVoice = mRunningVoice != null;
+            mRunningVoice = session;
+            if (!wasRunningVoice) {
                 mVoiceWakeLock.acquire();
                 updateSleepIfNeededLocked();
             }
-            mRunningVoice = session;
         }
     }
 
@@ -11495,7 +11495,7 @@
             for (int i=0; i<ris.size(); i++) {
                 ActivityInfo ai = ris.get(i).activityInfo;
                 ComponentName comp = new ComponentName(ai.packageName, ai.name);
-                if (false && lastDoneReceivers.contains(comp)) {
+                if (lastDoneReceivers.contains(comp)) {
                     // We already did the pre boot receiver for this app with the current
                     // platform version, so don't do it again...
                     ris.remove(i);
@@ -18595,29 +18595,24 @@
             return;
         }
         boolean isInteraction;
-        if (!mSleeping) {
-            isInteraction = app.curProcState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+        // To avoid some abuse patterns, we are going to be careful about what we consider
+        // to be an app interaction.  Being the top activity doesn't count while the display
+        // is sleeping, nor do short foreground services.
+        if (app.curProcState <= ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
+            isInteraction = true;
             app.fgInteractionTime = 0;
-        } else {
-            // If the display is off, we are going to be more restrictive about what we consider
-            // to be an app interaction.  Being the top activity doesn't count, nor do generally
-            // foreground services.
-            if (app.curProcState <= ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
-                isInteraction = true;
-                app.fgInteractionTime = 0;
-            } else if (app.curProcState <= ActivityManager.PROCESS_STATE_TOP_SLEEPING) {
-                final long now = SystemClock.elapsedRealtime();
-                if (app.fgInteractionTime == 0) {
-                    app.fgInteractionTime = now;
-                    isInteraction = false;
-                } else {
-                    isInteraction = now > app.fgInteractionTime + SERVICE_USAGE_INTERACTION_TIME;
-                }
+        } else if (app.curProcState <= ActivityManager.PROCESS_STATE_TOP_SLEEPING) {
+            final long now = SystemClock.elapsedRealtime();
+            if (app.fgInteractionTime == 0) {
+                app.fgInteractionTime = now;
+                isInteraction = false;
             } else {
-                isInteraction = app.curProcState
-                        <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
-                app.fgInteractionTime = 0;
+                isInteraction = now > app.fgInteractionTime + SERVICE_USAGE_INTERACTION_TIME;
             }
+        } else {
+            isInteraction = app.curProcState
+                    <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+            app.fgInteractionTime = 0;
         }
         if (isInteraction && !app.reportedInteraction) {
             String[] packages = app.getPackageList();
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index f222dba..2eb8797 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -801,7 +801,7 @@
             for (String authority : syncableAuthorities) {
                 int isSyncable = getIsSyncable(account.account, account.userId,
                         authority);
-                if (isSyncable == 0) {
+                if (isSyncable == AuthorityInfo.NOT_SYNCABLE) {
                     continue;
                 }
                 final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
@@ -813,8 +813,9 @@
                 final boolean allowParallelSyncs = syncAdapterInfo.type.allowParallelSyncs();
                 final boolean isAlwaysSyncable = syncAdapterInfo.type.isAlwaysSyncable();
                 if (isSyncable < 0 && isAlwaysSyncable) {
-                    mSyncStorageEngine.setIsSyncable(account.account, account.userId, authority, 1);
-                    isSyncable = 1;
+                    mSyncStorageEngine.setIsSyncable(
+                            account.account, account.userId, authority, AuthorityInfo.SYNCABLE);
+                    isSyncable = AuthorityInfo.SYNCABLE;
                 }
                 if (onlyThoseWithUnkownSyncableState && isSyncable >= 0) {
                     continue;
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index d68b615..cca0c16 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -301,6 +301,30 @@
     }
 
     public static class AuthorityInfo {
+        // Legal values of getIsSyncable
+        /**
+         * Default state for a newly installed adapter. An uninitialized adapter will receive an
+         * initialization sync which are governed by a different set of rules to that of regular
+         * syncs.
+         */
+        public static final int NOT_INITIALIZED = -1;
+        /**
+         * The adapter will not receive any syncs. This is behaviourally equivalent to
+         * setSyncAutomatically -> false. However setSyncAutomatically is surfaced to the user
+         * while this is generally meant to be controlled by the developer.
+         */
+        public static final int NOT_SYNCABLE = 0;
+        /**
+         * The adapter is initialized and functioning. This is the normal state for an adapter.
+         */
+        public static final int SYNCABLE = 1;
+        /**
+         * The adapter is syncable but still requires an initialization sync. For example an adapter
+         * than has been restored from a previous device will be in this state. Not meant for
+         * external use.
+         */
+        public static final int SYNCABLE_NOT_INITIALIZED = 2;
+
         final EndPoint target;
         final int ident;
         boolean enabled;
@@ -349,12 +373,11 @@
         }
 
         private void defaultInitialisation() {
-            syncable = -1; // default to "unknown"
+            syncable = NOT_INITIALIZED; // default to "unknown"
             backoffTime = -1; // if < 0 then we aren't in backoff mode
             backoffDelay = -1; // if < 0 then we aren't in backoff mode
             PeriodicSync defaultSync;
-            // Old version is one sync a day. Empty bundle gets replaced by any addPeriodicSync()
-            // call.
+            // Old version is one sync a day.
             if (target.target_provider) {
                 defaultSync =
                         new PeriodicSync(target.account, target.provider,
@@ -663,6 +686,12 @@
                 }
                 return;
             }
+            // If the adapter was syncable but missing its initialization sync, set it to
+            // uninitialized now. This is to give it a chance to run any one-time initialization
+            // logic.
+            if (sync && authority.syncable == AuthorityInfo.SYNCABLE_NOT_INITIALIZED) {
+                authority.syncable = AuthorityInfo.NOT_INITIALIZED;
+            }
             authority.enabled = sync;
             writeAccountInfoLocked();
         }
@@ -682,7 +711,7 @@
                         new EndPoint(account, providerName, userId),
                         "get authority syncable");
                 if (authority == null) {
-                    return -1;
+                    return AuthorityInfo.NOT_INITIALIZED;
                 }
                 return authority.syncable;
             }
@@ -696,7 +725,7 @@
                     return authorityInfo.syncable;
                 }
             }
-            return -1;
+            return AuthorityInfo.NOT_INITIALIZED;
         }
     }
 
@@ -720,7 +749,8 @@
     }
 
     public void setIsTargetServiceActive(ComponentName cname, int userId, boolean active) {
-        setSyncableStateForEndPoint(new EndPoint(cname, userId), active ? 1 : 0);
+        setSyncableStateForEndPoint(new EndPoint(cname, userId), active ?
+                AuthorityInfo.SYNCABLE : AuthorityInfo.NOT_SYNCABLE);
     }
 
     /**
@@ -733,10 +763,8 @@
         AuthorityInfo aInfo;
         synchronized (mAuthorities) {
             aInfo = getOrCreateAuthorityLocked(target, -1, false);
-            if (syncable > 1) {
-                syncable = 1;
-            } else if (syncable < -1) {
-                syncable = -1;
+            if (syncable < AuthorityInfo.NOT_INITIALIZED) {
+                syncable = AuthorityInfo.NOT_INITIALIZED;
             }
             if (Log.isLoggable(TAG, Log.VERBOSE)) {
                 Log.d(TAG, "setIsSyncable: " + aInfo.toString() + " -> " + syncable);
@@ -750,7 +778,7 @@
             aInfo.syncable = syncable;
             writeAccountInfoLocked();
         }
-        if (syncable > 0) {
+        if (syncable == AuthorityInfo.SYNCABLE) {
             requestSync(aInfo, SyncOperation.REASON_IS_SYNCABLE, new Bundle());
         }
         reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
@@ -2012,7 +2040,7 @@
             int userId = user == null ? 0 : Integer.parseInt(user);
             if (accountType == null && packageName == null) {
                 accountType = "com.google";
-                syncable = "unknown";
+                syncable = String.valueOf(AuthorityInfo.NOT_INITIALIZED);
             }
             authority = mAuthorities.get(id);
             if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
@@ -2052,11 +2080,19 @@
             }
             if (authority != null) {
                 authority.enabled = enabled == null || Boolean.parseBoolean(enabled);
-                if ("unknown".equals(syncable)) {
-                    authority.syncable = -1;
-                } else {
-                    authority.syncable =
-                            (syncable == null || Boolean.parseBoolean(syncable)) ? 1 : 0;
+                try {
+                    authority.syncable = (syncable == null) ?
+                            AuthorityInfo.NOT_INITIALIZED : Integer.parseInt(syncable);
+                } catch (NumberFormatException e) {
+                    // On L we stored this as {"unknown", "true", "false"} so fall back to this
+                    // format.
+                    if ("unknown".equals(syncable)) {
+                        authority.syncable = AuthorityInfo.NOT_INITIALIZED;
+                    } else {
+                        authority.syncable = Boolean.parseBoolean(syncable) ?
+                                AuthorityInfo.SYNCABLE : AuthorityInfo.NOT_SYNCABLE;
+                    }
+
                 }
             } else {
                 Log.w(TAG, "Failure adding authority: account="
@@ -2190,11 +2226,7 @@
                     out.attribute(null, "package", info.service.getPackageName());
                     out.attribute(null, "class", info.service.getClassName());
                 }
-                if (authority.syncable < 0) {
-                    out.attribute(null, "syncable", "unknown");
-                } else {
-                    out.attribute(null, "syncable", Boolean.toString(authority.syncable != 0));
-                }
+                out.attribute(null, "syncable", Integer.toString(authority.syncable));
                 for (PeriodicSync periodicSync : authority.periodicSyncs) {
                     out.startTag(null, "periodicSync");
                     out.attribute(null, "period", Long.toString(periodicSync.period));
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 77b800e..7999321 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -246,6 +246,8 @@
                 return handleRequestActiveSource(message);
             case Constants.MESSAGE_GET_MENU_LANGUAGE:
                 return handleGetMenuLanguage(message);
+            case Constants.MESSAGE_SET_MENU_LANGUAGE:
+                return handleSetMenuLanguage(message);
             case Constants.MESSAGE_GIVE_PHYSICAL_ADDRESS:
                 return handleGivePhysicalAddress();
             case Constants.MESSAGE_GIVE_OSD_NAME:
@@ -377,6 +379,14 @@
     }
 
     @ServiceThreadOnly
+    protected boolean handleSetMenuLanguage(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+        Slog.w(TAG, "Only Playback device can handle <Set Menu Language>:" + message.toString());
+        // 'return false' will cause to reply with <Feature Abort>.
+        return false;
+    }
+
+    @ServiceThreadOnly
     protected boolean handleGiveOsdName(HdmiCecMessage message) {
         assertRunOnServiceThread();
         // Note that since this method is called after logical address allocation is done,
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 30a9b43..493471b 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -26,9 +26,14 @@
 import android.provider.Settings.Global;
 import android.util.Slog;
 
+import com.android.internal.app.LocalePicker;
+import com.android.internal.app.LocalePicker.LocaleInfo;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
 
+import java.io.UnsupportedEncodingException;
+import java.util.List;
+
 /**
  * Represent a logical device of type Playback residing in Android system.
  */
@@ -306,6 +311,35 @@
         return true;  // Broadcast message.
     }
 
+    @ServiceThreadOnly
+    protected boolean handleSetMenuLanguage(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+
+        try {
+            String iso3Language = new String(message.getParams(), 0, 3, "US-ASCII");
+
+            // Don't use Locale.getAvailableLocales() since it returns a locale
+            // which is not available on Settings.
+            final List<LocaleInfo> localeInfos = LocalePicker.getAllAssetLocales(
+                    mService.getContext(), false);
+            for (LocaleInfo localeInfo : localeInfos) {
+                if (localeInfo.getLocale().getISO3Language().equals(iso3Language)) {
+                    // WARNING: CEC adopts ISO/FDIS-2 for language code, while Android requires
+                    // additional country variant to pinpoint the locale. This keeps the right
+                    // locale from being chosen. 'eng' in the CEC command, for instance,
+                    // will always be mapped to en-AU among other variants like en-US, en-GB,
+                    // an en-IN, which may not be the expected one.
+                    LocalePicker.updateLocale(localeInfo.getLocale());
+                    return true;
+                }
+            }
+            Slog.w(TAG, "Can't handle <Set Menu Language> of " + iso3Language);
+            return false;
+        } catch (UnsupportedEncodingException e) {
+            return false;
+        }
+    }
+
     @Override
     @ServiceThreadOnly
     protected void sendStandby(int deviceId) {
diff --git a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
index 10f1696..4af7d4e 100644
--- a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
+++ b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
@@ -51,7 +51,7 @@
 public class ValidateNotificationPeople implements NotificationSignalExtractor {
     // Using a shorter log tag since setprop has a limit of 32chars on variable name.
     private static final String TAG = "ValidateNoPeople";
-    private static final boolean INFO = true;
+    private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);;
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     private static final boolean ENABLE_PEOPLE_VALIDATOR = true;
@@ -100,7 +100,7 @@
                 public void onChange(boolean selfChange, Uri uri, int userId) {
                     super.onChange(selfChange, uri, userId);
                     if (DEBUG || mEvictionCount % 100 == 0) {
-                        if (INFO) Slog.i(TAG, "mEvictionCount: " + mEvictionCount);
+                        if (VERBOSE) Slog.i(TAG, "mEvictionCount: " + mEvictionCount);
                     }
                     mPeopleCache.evictAll();
                     mEvictionCount++;
@@ -113,20 +113,20 @@
 
     public RankingReconsideration process(NotificationRecord record) {
         if (!mEnabled) {
-            if (INFO) Slog.i(TAG, "disabled");
+            if (VERBOSE) Slog.i(TAG, "disabled");
             return null;
         }
         if (record == null || record.getNotification() == null) {
-            if (INFO) Slog.i(TAG, "skipping empty notification");
+            if (VERBOSE) Slog.i(TAG, "skipping empty notification");
             return null;
         }
         if (record.getUserId() == UserHandle.USER_ALL) {
-            if (INFO) Slog.i(TAG, "skipping global notification");
+            if (VERBOSE) Slog.i(TAG, "skipping global notification");
             return null;
         }
         Context context = getContextAsUser(record.getUser());
         if (context == null) {
-            if (INFO) Slog.i(TAG, "skipping notification that lacks a context");
+            if (VERBOSE) Slog.i(TAG, "skipping notification that lacks a context");
             return null;
         }
         return validatePeople(context, record);
@@ -220,7 +220,7 @@
             return null;
         }
 
-        if (INFO) Slog.i(TAG, "Validating: " + key + " for " + context.getUserId());
+        if (VERBOSE) Slog.i(TAG, "Validating: " + key + " for " + context.getUserId());
         final LinkedList<String> pendingLookups = new LinkedList<String>();
         for (int personIdx = 0; personIdx < people.length && personIdx < MAX_PEOPLE; personIdx++) {
             final String handle = people[personIdx];
@@ -244,7 +244,7 @@
         affinityOut[0] = affinity;
 
         if (pendingLookups.isEmpty()) {
-            if (INFO) Slog.i(TAG, "final affinity: " + affinity);
+            if (VERBOSE) Slog.i(TAG, "final affinity: " + affinity);
             if (affinity != NONE) MetricsLogger.count(mBaseContext, "note_with_people", 1);
             return null;
         }
@@ -422,7 +422,7 @@
 
         @Override
         public void work() {
-            if (INFO) Slog.i(TAG, "Executing: validation for: " + mKey);
+            if (VERBOSE) Slog.i(TAG, "Executing: validation for: " + mKey);
             long timeStartMs = System.currentTimeMillis();
             for (final String handle: mPendingLookups) {
                 LookupResult lookupResult = null;
@@ -463,7 +463,7 @@
         public void applyChangesLocked(NotificationRecord operand) {
             float affinityBound = operand.getContactAffinity();
             operand.setContactAffinity(Math.max(mContactAffinity, affinityBound));
-            if (INFO) Slog.i(TAG, "final affinity: " + operand.getContactAffinity());
+            if (VERBOSE) Slog.i(TAG, "final affinity: " + operand.getContactAffinity());
         }
 
         public float getContactAffinity() {
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index 1ee07a5..0de0c92 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -16,6 +16,9 @@
 
 package com.android.server.pm;
 
+import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
+
+import com.android.internal.util.Preconditions;
 import android.content.pm.PackageParser;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -98,6 +101,7 @@
             mRefCount++;
             return;
         }
+
         public long decrRefCountLPw() {
             mRefCount--;
             return mRefCount;
@@ -168,25 +172,82 @@
     }
 
     /**
+     * addScannedPackageLPw directly modifies the package metadata in  pm.Settings
+     * at a point of no-return.  We need to make sure that the scanned package does
+     * not contain bad keyset meta-data that could generate an incorrect
+     * PackageSetting. Verify that there is a signing keyset, there are no issues
+     * with null objects, and the upgrade and defined keysets match.
+     *
+     * Returns true if the package can safely be added to the keyset metadata.
+     */
+    public void assertScannedPackageValid(PackageParser.Package pkg)
+            throws PackageManagerException {
+        if (pkg == null || pkg.packageName == null) {
+            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+                    "Passed invalid package to keyset validation.");
+        }
+        ArraySet<PublicKey> signingKeys = pkg.mSigningKeys;
+        if (signingKeys == null || !(signingKeys.size() > 0) || signingKeys.contains(null)) {
+            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+                    "Package has invalid signing-key-set.");
+        }
+        ArrayMap<String, ArraySet<PublicKey>> definedMapping = pkg.mKeySetMapping;
+        if (definedMapping != null) {
+            if (definedMapping.containsKey(null) || definedMapping.containsValue(null)) {
+                throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+                        "Package has null defined key set.");
+            }
+            int defMapSize = definedMapping.size();
+            for (int i = 0; i < defMapSize; i++) {
+                if (!(definedMapping.valueAt(i).size() > 0)
+                        || definedMapping.valueAt(i).contains(null)) {
+                    throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+                            "Package has null/no public keys for defined key-sets.");
+                }
+            }
+        }
+        ArraySet<String> upgradeAliases = pkg.mUpgradeKeySets;
+        if (upgradeAliases != null) {
+            if (definedMapping == null || !(definedMapping.keySet().containsAll(upgradeAliases))) {
+                throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+                        "Package has upgrade-key-sets without corresponding definitions.");
+            }
+        }
+    }
+
+    public void addScannedPackageLPw(PackageParser.Package pkg) {
+        Preconditions.checkNotNull(pkg, "Attempted to add null pkg to ksms.");
+        Preconditions.checkNotNull(pkg.packageName, "Attempted to add null pkg to ksms.");
+        PackageSetting ps = mPackages.get(pkg.packageName);
+        Preconditions.checkNotNull(ps, "pkg: " + pkg.packageName
+                    + "does not have a corresponding entry in mPackages.");
+        addSigningKeySetToPackageLPw(ps, pkg.mSigningKeys);
+        if (pkg.mKeySetMapping != null) {
+            addDefinedKeySetsToPackageLPw(ps, pkg.mKeySetMapping);
+            if (pkg.mUpgradeKeySets != null) {
+                addUpgradeKeySetsToPackageLPw(ps, pkg.mUpgradeKeySets);
+            }
+        }
+    }
+
+    /**
      * Informs the system that the given package was signed by the provided KeySet.
      */
-    public void addSigningKeySetToPackageLPw(String packageName,
+    void addSigningKeySetToPackageLPw(PackageSetting pkg,
             ArraySet<PublicKey> signingKeys) {
 
         /* check existing keyset for reuse or removal */
-        PackageSetting pkg = mPackages.get(packageName);
         long signingKeySetId = pkg.keySetData.getProperSigningKeySet();
 
         if (signingKeySetId != PackageKeySetData.KEYSET_UNASSIGNED) {
             ArraySet<PublicKey> existingKeys = getPublicKeysFromKeySetLPr(signingKeySetId);
-            if (existingKeys.equals(signingKeys)) {
+            if (existingKeys != null && existingKeys.equals(signingKeys)) {
 
                 /* no change in signing keys, leave PackageSetting alone */
                 return;
             } else {
 
                 /* old keyset no longer valid, remove ref */
-                KeySetHandle ksh = mKeySets.get(signingKeySetId);
                 decrementKeySetLPw(signingKeySetId);
             }
         }
@@ -212,13 +273,12 @@
         return KEYSET_NOT_FOUND;
     }
 
-    /*
+    /**
      * Inform the system that the given package defines the given KeySets.
      * Remove any KeySets the package no longer defines.
      */
-    public void addDefinedKeySetsToPackageLPw(String packageName,
+    void addDefinedKeySetsToPackageLPw(PackageSetting pkg,
             ArrayMap<String, ArraySet<PublicKey>> definedMapping) {
-        PackageSetting pkg = mPackages.get(packageName);
         ArrayMap<String, Long> prevDefinedKeySets = pkg.keySetData.getAliases();
 
         /* add all of the newly defined KeySets */
@@ -227,7 +287,7 @@
         for (int i = 0; i < defMapSize; i++) {
             String alias = definedMapping.keyAt(i);
             ArraySet<PublicKey> pubKeys = definedMapping.valueAt(i);
-            if (alias != null && pubKeys != null && pubKeys.size() > 0) {
+            if (alias != null && pubKeys != null || pubKeys.size() > 0) {
                 KeySetHandle ks = addKeySetLPw(pubKeys);
                 newKeySetAliases.put(alias, ks.getId());
             }
@@ -250,9 +310,8 @@
      * alias in its manifest to be an upgradeKeySet.  This must be called
      * after all of the defined KeySets have been added.
      */
-    public void addUpgradeKeySetsToPackageLPw(String packageName,
-        ArraySet<String> upgradeAliases) {
-        PackageSetting pkg = mPackages.get(packageName);
+    void addUpgradeKeySetsToPackageLPw(PackageSetting pkg,
+            ArraySet<String> upgradeAliases) {
         final int uaSize = upgradeAliases.size();
         for (int i = 0; i < uaSize; i++) {
             pkg.keySetData.addUpgradeKeySet(upgradeAliases.valueAt(i));
@@ -290,11 +349,11 @@
      * identify a {@link KeySetHandle}.
      */
     public ArraySet<PublicKey> getPublicKeysFromKeySetLPr(long id) {
-        if(mKeySetMapping.get(id) == null) {
+        ArraySet<Long> pkIds = mKeySetMapping.get(id);
+        if (pkIds == null) {
             return null;
         }
         ArraySet<PublicKey> mPubKeys = new ArraySet<PublicKey>();
-        ArraySet<Long> pkIds = mKeySetMapping.get(id);
         final int pkSize = pkIds.size();
         for (int i = 0; i < pkSize; i++) {
             mPubKeys.add(mPublicKeys.get(pkIds.valueAt(i)).getKey());
@@ -376,6 +435,10 @@
      */
     private void decrementKeySetLPw(long id) {
         KeySetHandle ks = mKeySets.get(id);
+        if (ks == null) {
+            /* nothing to do */
+            return;
+        }
         if (ks.decrRefCountLPw() <= 0) {
             ArraySet<Long> pubKeys = mKeySetMapping.get(id);
             final int pkSize = pubKeys.size();
@@ -385,7 +448,6 @@
             mKeySets.delete(id);
             mKeySetMapping.delete(id);
         }
-        return;
     }
 
     /*
@@ -394,16 +456,20 @@
      */
     private void decrementPublicKeyLPw(long id) {
         PublicKeyHandle pk = mPublicKeys.get(id);
+        if (pk == null) {
+            /* nothing to do */
+            return;
+        }
         if (pk.decrRefCountLPw() <= 0) {
             mPublicKeys.delete(id);
         }
-        return;
     }
 
     /**
      * Adds the given PublicKey to the system, deduping as it goes.
      */
     private long addPublicKeyLPw(PublicKey key) {
+        Preconditions.checkNotNull(key, "Cannot add null public key!");
         long id = getIdForPublicKeyLPr(key);
         if (id != PUBLIC_KEY_NOT_FOUND) {
 
@@ -473,6 +539,8 @@
 
         /* remove refs from common keysets and public keys */
         PackageSetting pkg = mPackages.get(packageName);
+        Preconditions.checkNotNull(pkg, "pkg name: " + packageName
+                + "does not have a corresponding entry in mPackages.");
         long signingKeySetId = pkg.keySetData.getProperSigningKeySet();
         decrementKeySetLPw(signingKeySetId);
         ArrayMap<String, Long> definedKeySets = pkg.keySetData.getAliases();
@@ -715,16 +783,36 @@
         final int numRefCounts = keySetRefCounts.size();
         for (int i = 0; i < numRefCounts; i++) {
             KeySetHandle ks = mKeySets.get(keySetRefCounts.keyAt(i));
+            if (ks == null) {
+                /* something went terribly wrong and we have references to a non-existent key-set */
+                Slog.wtf(TAG, "Encountered non-existent key-set reference when reading settings");
+                continue;
+            }
             ks.setRefCountLPw(keySetRefCounts.valueAt(i));
         }
 
+        /*
+         * In case something went terribly wrong and we have keysets with no associated packges
+         * that refer to them, record the orphaned keyset ids, and remove them using
+         * decrementKeySetLPw() after all keyset references have been set so that the associtaed
+         * public keys have the appropriate references from all keysets.
+         */
+        ArraySet<Long> orphanedKeySets = new ArraySet<Long>();
         final int numKeySets = mKeySets.size();
         for (int i = 0; i < numKeySets; i++) {
+            if (mKeySets.valueAt(i).getRefCountLPr() == 0) {
+                Slog.wtf(TAG, "Encountered key-set w/out package references when reading settings");
+                orphanedKeySets.add(mKeySets.keyAt(i));
+            }
             ArraySet<Long> pubKeys = mKeySetMapping.valueAt(i);
             final int pkSize = pubKeys.size();
             for (int j = 0; j < pkSize; j++) {
                 mPublicKeys.get(pubKeys.valueAt(j)).incrRefCountLPw();
             }
         }
+        final int numOrphans = orphanedKeySets.size();
+        for (int i = 0; i < numOrphans; i++) {
+            decrementKeySetLPw(orphanedKeySets.valueAt(i));
+        }
     }
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 548d93c..5b7dd70 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -5109,16 +5109,18 @@
                 && !isCompatSignatureUpdateNeeded(pkg)
                 && !isRecoverSignatureUpdateNeeded(pkg)) {
             long mSigningKeySetId = ps.keySetData.getProperSigningKeySet();
+            KeySetManagerService ksms = mSettings.mKeySetManagerService;
+            ArraySet<PublicKey> signingKs;
+            synchronized (mPackages) {
+                signingKs = ksms.getPublicKeysFromKeySetLPr(mSigningKeySetId);
+            }
             if (ps.signatures.mSignatures != null
                     && ps.signatures.mSignatures.length != 0
-                    && mSigningKeySetId != PackageKeySetData.KEYSET_UNASSIGNED) {
+                    && signingKs != null) {
                 // Optimization: reuse the existing cached certificates
                 // if the package appears to be unchanged.
                 pkg.mSignatures = ps.signatures.mSignatures;
-                KeySetManagerService ksms = mSettings.mKeySetManagerService;
-                synchronized (mPackages) {
-                    pkg.mSigningKeys = ksms.getPublicKeysFromKeySetLPr(mSigningKeySetId);
-                }
+                pkg.mSigningKeys = signingKs;
                 return;
             }
 
@@ -6590,6 +6592,10 @@
             }
         }
 
+        // Make sure we're not adding any bogus keyset info
+        KeySetManagerService ksms = mSettings.mKeySetManagerService;
+        ksms.assertScannedPackageValid(pkg);
+
         // writer
         synchronized (mPackages) {
             // We don't expect installation to fail beyond this point
@@ -6626,20 +6632,7 @@
             }
 
             // Add the package's KeySets to the global KeySetManagerService
-            KeySetManagerService ksms = mSettings.mKeySetManagerService;
-            try {
-                ksms.addSigningKeySetToPackageLPw(pkg.packageName, pkg.mSigningKeys);
-                if (pkg.mKeySetMapping != null) {
-                    ksms.addDefinedKeySetsToPackageLPw(pkg.packageName, pkg.mKeySetMapping);
-                    if (pkg.mUpgradeKeySets != null) {
-                        ksms.addUpgradeKeySetsToPackageLPw(pkg.packageName, pkg.mUpgradeKeySets);
-                    }
-                }
-            } catch (NullPointerException e) {
-                Slog.e(TAG, "Could not add KeySet to " + pkg.packageName, e);
-            } catch (IllegalArgumentException e) {
-                Slog.e(TAG, "Could not add KeySet to malformed package" + pkg.packageName, e);
-            }
+            ksms.addScannedPackageLPw(pkg);
 
             int N = pkg.providers.size();
             StringBuilder r = null;
@@ -11188,7 +11181,7 @@
         KeySetManagerService ksms = mSettings.mKeySetManagerService;
         for (int i = 0; i < upgradeKeySets.length; i++) {
             Set<PublicKey> upgradeSet = ksms.getPublicKeysFromKeySetLPr(upgradeKeySets[i]);
-            if (newPkg.mSigningKeys.containsAll(upgradeSet)) {
+            if (upgradeSet != null && newPkg.mSigningKeys.containsAll(upgradeSet)) {
                 return true;
             }
         }
diff --git a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
index 2557974..7f9a0de 100644
--- a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
@@ -118,7 +118,7 @@
         ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
         PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         signingKeys.add(keyA);
-        mKsms.addSigningKeySetToPackageLPw(ps.name, signingKeys);
+        mKsms.addSigningKeySetToPackageLPw(ps, signingKeys);
 
         assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 1));
         assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 1));
@@ -145,10 +145,10 @@
         ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
         PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         signingKeys.add(keyA);
-        mKsms.addSigningKeySetToPackageLPw(ps.name, signingKeys);
+        mKsms.addSigningKeySetToPackageLPw(ps, signingKeys);
 
         /* add again, to represent upgrade of package */
-        mKsms.addSigningKeySetToPackageLPw(ps.name, signingKeys);
+        mKsms.addSigningKeySetToPackageLPw(ps, signingKeys);
 
         assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 1));
         assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 1));
@@ -175,13 +175,13 @@
         ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
         PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         signingKeys.add(keyA);
-        mKsms.addSigningKeySetToPackageLPw(ps.name, signingKeys);
+        mKsms.addSigningKeySetToPackageLPw(ps, signingKeys);
 
         /* now upgrade with new key */
         PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
         signingKeys.removeAt(0);
         signingKeys.add(keyB);
-        mKsms.addSigningKeySetToPackageLPw(ps.name, signingKeys);
+        mKsms.addSigningKeySetToPackageLPw(ps, signingKeys);
 
         assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 1));
         assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 2));
@@ -212,14 +212,14 @@
         ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
         PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         signingKeys.add(keyA);
-        mKsms.addSigningKeySetToPackageLPw(ps1.name, signingKeys);
-        mKsms.addSigningKeySetToPackageLPw(ps2.name, signingKeys);
+        mKsms.addSigningKeySetToPackageLPw(ps1, signingKeys);
+        mKsms.addSigningKeySetToPackageLPw(ps2, signingKeys);
 
         /* now upgrade with new key */
         PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
         signingKeys.removeAt(0);
         signingKeys.add(keyB);
-        mKsms.addSigningKeySetToPackageLPw(ps1.name, signingKeys);
+        mKsms.addSigningKeySetToPackageLPw(ps1, signingKeys);
 
         assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 1));
         assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 2));
@@ -255,13 +255,13 @@
         ArraySet<PublicKey> signingKeys1 = new ArraySet<PublicKey>();
         PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         signingKeys1.add(keyA);
-        mKsms.addSigningKeySetToPackageLPw(ps1.name, signingKeys1);
+        mKsms.addSigningKeySetToPackageLPw(ps1, signingKeys1);
 
         /* collect second signing key and add */
         ArraySet<PublicKey> signingKeys2 = new ArraySet<PublicKey>();
         PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
         signingKeys2.add(keyB);
-        mKsms.addSigningKeySetToPackageLPw(ps2.name, signingKeys2);
+        mKsms.addSigningKeySetToPackageLPw(ps2, signingKeys2);
 
         /* verify first is unchanged */
         assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 1));
@@ -300,10 +300,10 @@
         ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
         PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         signingKeys.add(keyA);
-        mKsms.addSigningKeySetToPackageLPw(ps1.name, signingKeys);
+        mKsms.addSigningKeySetToPackageLPw(ps1, signingKeys);
 
         /* add again for second package */
-        mKsms.addSigningKeySetToPackageLPw(ps2.name, signingKeys);
+        mKsms.addSigningKeySetToPackageLPw(ps2, signingKeys);
 
         assertEquals(2, KeySetUtils.getKeySetRefCount(mKsms, 1));
         assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 1));
@@ -333,12 +333,12 @@
         ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
         PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         signingKeys.add(keyA);
-        mKsms.addSigningKeySetToPackageLPw(ps1.name, signingKeys);
+        mKsms.addSigningKeySetToPackageLPw(ps1, signingKeys);
 
         /* give ps2 a superset (add keyB) */
         PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
         signingKeys.add(keyB);
-        mKsms.addSigningKeySetToPackageLPw(ps2.name, signingKeys);
+        mKsms.addSigningKeySetToPackageLPw(ps2, signingKeys);
 
         assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 1));
         assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 2));
@@ -374,12 +374,12 @@
         ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
         PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         signingKeys.add(keyA);
-        mKsms.addSigningKeySetToPackageLPw(ps.name, signingKeys);
+        mKsms.addSigningKeySetToPackageLPw(ps, signingKeys);
 
         /* now with additional key */
         PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
         signingKeys.add(keyB);
-        mKsms.addSigningKeySetToPackageLPw(ps.name, signingKeys);
+        mKsms.addSigningKeySetToPackageLPw(ps, signingKeys);
 
         assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 1));
         assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 2));
@@ -413,7 +413,7 @@
         PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         keys.add(keyA);
         definedKS.put("aliasA", keys);
-        mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS);
+        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
 
         assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 1));
         assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 1));
@@ -441,7 +441,7 @@
         keys.add(keyA);
         definedKS.put("aliasA", keys);
         definedKS.put("aliasA2", keys);
-        mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS);
+        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
 
         assertEquals(2, KeySetUtils.getKeySetRefCount(mKsms, 1));
         assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 1));
@@ -470,7 +470,7 @@
         PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         keys.add(keyA);
         definedKS.put("aliasA", keys);
-        mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS);
+        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
 
         /* now upgrade to different defined key-set */
         keys = new ArraySet<PublicKey>();
@@ -478,7 +478,7 @@
         keys.add(keyB);
         definedKS.remove("aliasA");
         definedKS.put("aliasB", keys);
-        mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS);
+        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
 
         assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 1));
         assertEquals(0, KeySetUtils.getPubKeyRefCount(mKsms, 1));
@@ -510,14 +510,14 @@
         PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         keys.add(keyA);
         definedKS.put("aliasA", keys);
-        mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS);
+        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
 
         /* now upgrade to different set w/same alias as before */
         keys = new ArraySet<PublicKey>();
         PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
         keys.add(keyB);
         definedKS.put("aliasA", keys);
-        mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS);
+        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
 
         assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 1));
         assertEquals(0, KeySetUtils.getPubKeyRefCount(mKsms, 1));
@@ -551,7 +551,7 @@
         keys2.add(keyB);
         definedKS.put("aliasA", keys1);
         definedKS.put("aliasB", keys2);
-        mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS);
+        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
 
         /* now upgrade to different set (B, C) */
         keys1 = new ArraySet<PublicKey>();
@@ -559,7 +559,7 @@
         keys1.add(keyC);
         definedKS.remove("aliasA");
         definedKS.put("aliasC", keys1);
-        mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS);
+        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
 
         assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 3));
         assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 3));
@@ -612,7 +612,7 @@
         PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         keys1.add(keyA);
         definedKS.put("aliasA", keys1);
-        mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS);
+        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
 
         /* now upgrade to different set */
         ArraySet<PublicKey> keys2 = new ArraySet<PublicKey>();
@@ -620,12 +620,12 @@
         keys2.add(keyB);
         definedKS.remove("aliasA");
         definedKS.put("aliasB", keys2);
-        mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS);
+        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
 
         /* upgrade back to original */
         definedKS.remove("aliasB");
         definedKS.put("aliasA", keys1);
-        mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS);
+        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
 
         assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 1));
         assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 2));
@@ -655,10 +655,10 @@
         PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         keys.add(keyA);
         definedKS.put("aliasA", keys);
-        mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS);
+        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
         ArraySet<String> upgradeKS = new ArraySet<String>();
         upgradeKS.add("aliasA");
-        mKsms.addUpgradeKeySetsToPackageLPw(ps.name, upgradeKS);
+        mKsms.addUpgradeKeySetsToPackageLPw(ps, upgradeKS);
 
         assertEquals(1, ps.keySetData.getUpgradeKeySets().length);
         assertEquals(1, ps.keySetData.getUpgradeKeySets()[0]);
@@ -677,11 +677,11 @@
         PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         keys.add(keyA);
         definedKS.put("aliasA", keys);
-        mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS);
+        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
         ArraySet<String> upgradeKS = new ArraySet<String>();
         upgradeKS.add("aliasB");
         try {
-            mKsms.addUpgradeKeySetsToPackageLPw(ps.name, upgradeKS);
+            mKsms.addUpgradeKeySetsToPackageLPw(ps, upgradeKS);
         } catch (IllegalArgumentException e) {
 
             /* should have been caught in packagemanager, so exception thrown */
@@ -704,17 +704,17 @@
         PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         keys.add(keyA);
         definedKS.put("aliasA", keys);
-        mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS);
+        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
         ArraySet<String> upgradeKS = new ArraySet<String>();
         upgradeKS.add("aliasA");
-        mKsms.addUpgradeKeySetsToPackageLPw(ps.name, upgradeKS);
+        mKsms.addUpgradeKeySetsToPackageLPw(ps, upgradeKS);
 
         keys = new ArraySet<PublicKey>();
         PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
         keys.add(keyB);
         definedKS.remove("aliasA");
         definedKS.put("aliasB", keys);
-        mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS);
+        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
         assertNull(ps.keySetData.getUpgradeKeySets());
     }
 
@@ -729,7 +729,7 @@
         ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
         PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         signingKeys.add(keyA);
-        mKsms.addSigningKeySetToPackageLPw(ps.name, signingKeys);
+        mKsms.addSigningKeySetToPackageLPw(ps, signingKeys);
 
         /* remove its references */
         mKsms.removeAppKeySetDataLPw(ps.name);
@@ -754,8 +754,8 @@
         ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
         PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         signingKeys.add(keyA);
-        mKsms.addSigningKeySetToPackageLPw(ps1.name, signingKeys);
-        mKsms.addSigningKeySetToPackageLPw(ps2.name, signingKeys);
+        mKsms.addSigningKeySetToPackageLPw(ps1, signingKeys);
+        mKsms.addSigningKeySetToPackageLPw(ps2, signingKeys);
 
         /* remove references from first package */
         mKsms.removeAppKeySetDataLPw(ps1.name);
@@ -784,13 +784,13 @@
         /* removal requires signing keyset to be specified (since all apps are
          * assumed to have it).  We skipped this in the defined tests, but can't
          * here. */
-        mKsms.addSigningKeySetToPackageLPw(ps.name, keys);
+        mKsms.addSigningKeySetToPackageLPw(ps, keys);
 
         definedKS.put("aliasA", keys);
-        mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS);
+        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
         ArraySet<String> upgradeKS = new ArraySet<String>();
         upgradeKS.add("aliasA");
-        mKsms.addUpgradeKeySetsToPackageLPw(ps.name, upgradeKS);
+        mKsms.addUpgradeKeySetsToPackageLPw(ps, upgradeKS);
         mKsms.removeAppKeySetDataLPw(ps.name);
 
         assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 1));
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index b0fca95..fafe44a 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -853,7 +853,38 @@
         PackageMonitor mPackageMonitor = new PackageMonitor() {
             @Override
             public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
-                return super.onHandleForceStop(intent, packages, uid, doit);
+                if (DEBUG) Slog.d(TAG, "onHandleForceStop uid=" + uid + " doit=" + doit);
+
+                int userHandle = UserHandle.getUserId(uid);
+                ComponentName curInteractor = getCurInteractor(userHandle);
+                ComponentName curRecognizer = getCurRecognizer(userHandle);
+                boolean hit = false;
+                for (String pkg : packages) {
+                    if (curInteractor != null && pkg.equals(curInteractor.getPackageName())) {
+                        hit = true;
+                        break;
+                    } else if (curRecognizer != null
+                            && pkg.equals(curRecognizer.getPackageName())) {
+                        hit = true;
+                        break;
+                    }
+                }
+                if (hit && doit) {
+                    // The user is force stopping our current interactor/recognizer.
+                    // Clear the current settings and restore default state.
+                    synchronized (VoiceInteractionManagerService.this) {
+                        mSoundTriggerHelper.stopAllRecognitions();
+                        if (mImpl != null) {
+                            mImpl.shutdownLocked();
+                            mImpl = null;
+                        }
+                        setCurInteractor(null, userHandle);
+                        setCurRecognizer(null, userHandle);
+                        initForUser(userHandle);
+                        switchImplementationIfNeededLocked(true);
+                    }
+                }
+                return hit;
             }
 
             @Override
@@ -865,51 +896,53 @@
                 int userHandle = getChangingUserId();
                 if (DEBUG) Slog.d(TAG, "onSomePackagesChanged user=" + userHandle);
 
-                ComponentName curInteractor = getCurInteractor(userHandle);
-                ComponentName curRecognizer = getCurRecognizer(userHandle);
-                if (curRecognizer == null) {
-                    // Could a new recognizer appear when we don't have one pre-installed?
-                    if (anyPackagesAppearing()) {
-                        curRecognizer = findAvailRecognizer(null, userHandle);
-                        if (curRecognizer != null) {
-                            setCurRecognizer(curRecognizer, userHandle);
+                synchronized (VoiceInteractionManagerService.this) {
+                    ComponentName curInteractor = getCurInteractor(userHandle);
+                    ComponentName curRecognizer = getCurRecognizer(userHandle);
+                    if (curRecognizer == null) {
+                        // Could a new recognizer appear when we don't have one pre-installed?
+                        if (anyPackagesAppearing()) {
+                            curRecognizer = findAvailRecognizer(null, userHandle);
+                            if (curRecognizer != null) {
+                                setCurRecognizer(curRecognizer, userHandle);
+                            }
                         }
-                    }
-                    return;
-                }
-
-                if (curInteractor != null) {
-                    int change = isPackageDisappearing(curInteractor.getPackageName());
-                    if (change == PACKAGE_PERMANENT_CHANGE) {
-                        // The currently set interactor is permanently gone; fall back to
-                        // the default config.
-                        setCurInteractor(null, userHandle);
-                        setCurRecognizer(null, userHandle);
-                        initForUser(userHandle);
                         return;
                     }
 
-                    change = isPackageAppearing(curInteractor.getPackageName());
-                    if (change != PACKAGE_UNCHANGED) {
-                        // If current interactor is now appearing, for any reason, then
-                        // restart our connection with it.
-                        if (mImpl != null && curInteractor.getPackageName().equals(
-                                mImpl.mComponent.getPackageName())) {
-                            switchImplementationIfNeededLocked(true);
+                    if (curInteractor != null) {
+                        int change = isPackageDisappearing(curInteractor.getPackageName());
+                        if (change == PACKAGE_PERMANENT_CHANGE) {
+                            // The currently set interactor is permanently gone; fall back to
+                            // the default config.
+                            setCurInteractor(null, userHandle);
+                            setCurRecognizer(null, userHandle);
+                            initForUser(userHandle);
+                            return;
                         }
+
+                        change = isPackageAppearing(curInteractor.getPackageName());
+                        if (change != PACKAGE_UNCHANGED) {
+                            // If current interactor is now appearing, for any reason, then
+                            // restart our connection with it.
+                            if (mImpl != null && curInteractor.getPackageName().equals(
+                                    mImpl.mComponent.getPackageName())) {
+                                switchImplementationIfNeededLocked(true);
+                            }
+                        }
+                        return;
                     }
-                    return;
-                }
 
-                // There is no interactor, so just deal with a simple recognizer.
-                int change = isPackageDisappearing(curRecognizer.getPackageName());
-                if (change == PACKAGE_PERMANENT_CHANGE
-                        || change == PACKAGE_TEMPORARY_CHANGE) {
-                    setCurRecognizer(findAvailRecognizer(null, userHandle), userHandle);
+                    // There is no interactor, so just deal with a simple recognizer.
+                    int change = isPackageDisappearing(curRecognizer.getPackageName());
+                    if (change == PACKAGE_PERMANENT_CHANGE
+                            || change == PACKAGE_TEMPORARY_CHANGE) {
+                        setCurRecognizer(findAvailRecognizer(null, userHandle), userHandle);
 
-                } else if (isPackageModified(curRecognizer.getPackageName())) {
-                    setCurRecognizer(findAvailRecognizer(curRecognizer.getPackageName(),
-                            userHandle), userHandle);
+                    } else if (isPackageModified(curRecognizer.getPackageName())) {
+                        setCurRecognizer(findAvailRecognizer(curRecognizer.getPackageName(),
+                                userHandle), userHandle);
+                    }
                 }
             }
         };
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 1cc275d..8291a30 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -667,7 +667,7 @@
             IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
-            return info.getDeviceSvnUsingSubId(subId[0]);
+            return info.getDeviceSvnUsingSubId(subId[0], mContext.getOpPackageName());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -744,7 +744,7 @@
             IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
-            return info.getImeiForSubscriber(subId[0]);
+            return info.getImeiForSubscriber(subId[0], mContext.getOpPackageName());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -773,7 +773,7 @@
             IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
-            String nai = info.getNaiForSubscriber(subId[0]);
+            String nai = info.getNaiForSubscriber(subId[0], mContext.getOpPackageName());
             if (Log.isLoggable(TAG, Log.VERBOSE)) {
                 Rlog.v(TAG, "Nai = " + nai);
             }
@@ -1856,7 +1856,7 @@
             IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
-            return info.getIccSerialNumberForSubscriber(subId);
+            return info.getIccSerialNumberForSubscriber(subId, mContext.getOpPackageName());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -1938,7 +1938,7 @@
             IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
-            return info.getSubscriberIdForSubscriber(subId);
+            return info.getSubscriberIdForSubscriber(subId, mContext.getOpPackageName());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -1959,7 +1959,7 @@
             IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
-            return info.getGroupIdLevel1();
+            return info.getGroupIdLevel1(mContext.getOpPackageName());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -1983,7 +1983,7 @@
             IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
-            return info.getGroupIdLevel1ForSubscriber(subId);
+            return info.getGroupIdLevel1ForSubscriber(subId, mContext.getOpPackageName());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -2029,7 +2029,7 @@
             IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
-            return info.getLine1NumberForSubscriber(subId);
+            return info.getLine1NumberForSubscriber(subId, mContext.getOpPackageName());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -2122,7 +2122,7 @@
             IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
-            return info.getLine1AlphaTagForSubscriber(subId);
+            return info.getLine1AlphaTagForSubscriber(subId, mContext.getOpPackageName());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -2178,7 +2178,7 @@
             IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
-            return info.getMsisdnForSubscriber(subId);
+            return info.getMsisdnForSubscriber(subId, mContext.getOpPackageName());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -2211,7 +2211,7 @@
             IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
-            return info.getVoiceMailNumberForSubscriber(subId);
+            return info.getVoiceMailNumberForSubscriber(subId, mContext.getOpPackageName());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -2350,7 +2350,7 @@
             IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
-            return info.getVoiceMailAlphaTagForSubscriber(subId);
+            return info.getVoiceMailAlphaTagForSubscriber(subId, mContext.getOpPackageName());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
index c91a59c..ed85392 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
@@ -25,12 +25,12 @@
     /**
      * Retrieves the unique device ID, e.g., IMEI for GSM phones.
      */
-    String getDeviceId();
+    String getDeviceId(String callingPackage);
 
      /**
      * Retrieves the unique Network Access ID
      */
-    String getNaiForSubscriber(int subId);
+    String getNaiForSubscriber(int subId, String callingPackage);
 
     /**
      * Retrieves the unique device ID of a phone for the device, e.g., IMEI
@@ -41,91 +41,91 @@
     /**
      * Retrieves the IMEI.
      */
-    String getImeiForSubscriber(int subId);
+    String getImeiForSubscriber(int subId, String callingPackage);
 
     /**
      * Retrieves the software version number for the device, e.g., IMEI/SV
      * for GSM phones.
      */
-    String getDeviceSvn();
+    String getDeviceSvn(String callingPackage);
 
     /**
      * Retrieves the software version number of a subId for the device, e.g., IMEI/SV
      * for GSM phones.
      */
-    String getDeviceSvnUsingSubId(int subId);
+    String getDeviceSvnUsingSubId(int subId, String callingPackage);
 
     /**
      * Retrieves the unique sbuscriber ID, e.g., IMSI for GSM phones.
      */
-    String getSubscriberId();
+    String getSubscriberId(String callingPackage);
 
     /**
      * Retrieves the unique subscriber ID of a given subId, e.g., IMSI for GSM phones.
      */
-    String getSubscriberIdForSubscriber(int subId);
+    String getSubscriberIdForSubscriber(int subId, String callingPackage);
 
     /**
      * Retrieves the Group Identifier Level1 for GSM phones.
      */
-    String getGroupIdLevel1();
+    String getGroupIdLevel1(String callingPackage);
 
     /**
      * Retrieves the Group Identifier Level1 for GSM phones of a subId.
      */
-    String getGroupIdLevel1ForSubscriber(int subId);
+    String getGroupIdLevel1ForSubscriber(int subId, String callingPackage);
 
     /**
      * Retrieves the serial number of the ICC, if applicable.
      */
-    String getIccSerialNumber();
+    String getIccSerialNumber(String callingPackage);
 
     /**
      * Retrieves the serial number of a given subId.
      */
-    String getIccSerialNumberForSubscriber(int subId);
+    String getIccSerialNumberForSubscriber(int subId, String callingPackage);
 
     /**
      * Retrieves the phone number string for line 1.
      */
-    String getLine1Number();
+    String getLine1Number(String callingPackage);
 
     /**
      * Retrieves the phone number string for line 1 of a subcription.
      */
-    String getLine1NumberForSubscriber(int subId);
+    String getLine1NumberForSubscriber(int subId, String callingPackage);
 
 
     /**
      * Retrieves the alpha identifier for line 1.
      */
-    String getLine1AlphaTag();
+    String getLine1AlphaTag(String callingPackage);
 
     /**
      * Retrieves the alpha identifier for line 1 of a subId.
      */
-    String getLine1AlphaTagForSubscriber(int subId);
+    String getLine1AlphaTagForSubscriber(int subId, String callingPackage);
 
 
     /**
      * Retrieves MSISDN Number.
      */
-    String getMsisdn();
+    String getMsisdn(String callingPackage);
 
     /**
      * Retrieves the Msisdn of a subId.
      */
-    String getMsisdnForSubscriber(int subId);
+    String getMsisdnForSubscriber(int subId, String callingPackage);
 
     /**
      * Retrieves the voice mail number.
      */
-    String getVoiceMailNumber();
+    String getVoiceMailNumber(String callingPackage);
 
     /**
      * Retrieves the voice mail number of a given subId.
      */
-    String getVoiceMailNumberForSubscriber(int subId);
+    String getVoiceMailNumberForSubscriber(int subId, String callingPackage);
 
     /**
      * Retrieves the complete voice mail number.
@@ -140,13 +140,13 @@
     /**
      * Retrieves the alpha identifier associated with the voice mail number.
      */
-    String getVoiceMailAlphaTag();
+    String getVoiceMailAlphaTag(String callingPackage);
 
     /**
      * Retrieves the alpha identifier associated with the voice mail number
      * of a subId.
      */
-    String getVoiceMailAlphaTagForSubscriber(int subId);
+    String getVoiceMailAlphaTagForSubscriber(int subId, String callingPackage);
 
     /**
      * Returns the IMS private user identity (IMPI) that was loaded from the ISIM.
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index a1d5dd5..5d55ec6 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -684,6 +684,18 @@
 
     /**
      * @hide
+     * For debug: date at which the config was last updated
+     */
+    public String updateTime;
+
+    /**
+     * @hide
+     * For debug: date at which the config was last updated
+     */
+    public String creationTime;
+
+    /**
+     * @hide
      * The WiFi configuration is considered to have no internet access for purpose of autojoining
      * if there has been a report of it having no internet access, and, it never have had
      * internet access in the past.
@@ -1000,6 +1012,12 @@
             sbuf.append(" numNoInternetAccessReports ");
             sbuf.append(this.numNoInternetAccessReports).append("\n");
         }
+        if (this.updateTime != null) {
+            sbuf.append("creation=").append(this.updateTime).append("\n");
+        }
+        if (this.creationTime != null) {
+            sbuf.append("update=").append(this.creationTime).append("\n");
+        }
         if (this.didSelfAdd) sbuf.append(" didSelfAdd");
         if (this.selfAdded) sbuf.append(" selfAdded");
         if (this.validatedInternetAccess) sbuf.append(" validatedInternetAccess");
@@ -1505,6 +1523,8 @@
             userApproved = source.userApproved;
             numNoInternetAccessReports = source.numNoInternetAccessReports;
             noInternetAccessExpected = source.noInternetAccessExpected;
+            creationTime = source.creationTime;
+            updateTime = source.updateTime;
         }
     }