Merge "Restore windowMinWidthMajor/Minor in alert dialog overlay theme"
diff --git a/api/current.txt b/api/current.txt
index 2ddbcce..180f0d41 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -13178,6 +13178,7 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AF;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AWB;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> DEPTH_DEPTH_IS_EXCLUSIVE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> EDGE_AVAILABLE_EDGE_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> FLASH_INFO_AVAILABLE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES;
@@ -13406,6 +13407,7 @@
     field public static final int HOT_PIXEL_MODE_HIGH_QUALITY = 2; // 0x2
     field public static final int HOT_PIXEL_MODE_OFF = 0; // 0x0
     field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_FULL = 1; // 0x1
+    field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_HIGH_RESOLUTION = 3; // 0x3
     field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY = 2; // 0x2
     field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED = 0; // 0x0
     field public static final int LENS_FACING_BACK = 1; // 0x1
@@ -13424,6 +13426,7 @@
     field public static final int NOISE_REDUCTION_MODE_OFF = 0; // 0x0
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE = 0; // 0x0
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE = 6; // 0x6
+    field public static final int REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT = 8; // 0x8
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING = 2; // 0x2
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR = 1; // 0x1
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_OPAQUE_REPROCESSING = 4; // 0x4
@@ -14911,9 +14914,12 @@
     method public int getSampleRate();
     method public int getState();
     method public int read(byte[], int, int);
+    method public int read(byte[], int, int, int);
     method public int read(short[], int, int);
+    method public int read(short[], int, int, int);
     method public int read(float[], int, int, int);
     method public int read(java.nio.ByteBuffer, int);
+    method public int read(java.nio.ByteBuffer, int, int);
     method public void release();
     method public int setNotificationMarkerPosition(int);
     method public int setPositionNotificationPeriod(int);
@@ -14996,7 +15002,9 @@
     method public int setVolume(float);
     method public void stop() throws java.lang.IllegalStateException;
     method public int write(byte[], int, int);
+    method public int write(byte[], int, int, int);
     method public int write(short[], int, int);
+    method public int write(short[], int, int, int);
     method public int write(float[], int, int, int);
     method public int write(java.nio.ByteBuffer, int, int);
     field public static final int ERROR = -1; // 0xffffffff
diff --git a/api/system-current.txt b/api/system-current.txt
index ea97e1a..76c0261 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -13474,6 +13474,7 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AF;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AWB;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> DEPTH_DEPTH_IS_EXCLUSIVE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> EDGE_AVAILABLE_EDGE_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> FLASH_INFO_AVAILABLE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES;
@@ -13702,6 +13703,7 @@
     field public static final int HOT_PIXEL_MODE_HIGH_QUALITY = 2; // 0x2
     field public static final int HOT_PIXEL_MODE_OFF = 0; // 0x0
     field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_FULL = 1; // 0x1
+    field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_HIGH_RESOLUTION = 3; // 0x3
     field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY = 2; // 0x2
     field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED = 0; // 0x0
     field public static final int LENS_FACING_BACK = 1; // 0x1
@@ -13720,6 +13722,7 @@
     field public static final int NOISE_REDUCTION_MODE_OFF = 0; // 0x0
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE = 0; // 0x0
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE = 6; // 0x6
+    field public static final int REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT = 8; // 0x8
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING = 2; // 0x2
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR = 1; // 0x1
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_OPAQUE_REPROCESSING = 4; // 0x4
@@ -16121,9 +16124,12 @@
     method public int getSampleRate();
     method public int getState();
     method public int read(byte[], int, int);
+    method public int read(byte[], int, int, int);
     method public int read(short[], int, int);
+    method public int read(short[], int, int, int);
     method public int read(float[], int, int, int);
     method public int read(java.nio.ByteBuffer, int);
+    method public int read(java.nio.ByteBuffer, int, int);
     method public void release();
     method public int setNotificationMarkerPosition(int);
     method public int setPositionNotificationPeriod(int);
@@ -16208,7 +16214,9 @@
     method public int setVolume(float);
     method public void stop() throws java.lang.IllegalStateException;
     method public int write(byte[], int, int);
+    method public int write(byte[], int, int, int);
     method public int write(short[], int, int);
+    method public int write(short[], int, int, int);
     method public int write(float[], int, int, int);
     method public int write(java.nio.ByteBuffer, int, int);
     field public static final int ERROR = -1; // 0xffffffff
@@ -32712,10 +32720,6 @@
     field public static final java.lang.String BOOL_CARRIER_VOLTE_TTY_SUPPORTED = "bool_carrier_volte_tty_supported";
     field public static final java.lang.String BOOL_SHOW_APN_SETTING_CDMA = "bool_show_apn_setting_cdma";
     field public static final java.lang.String INT_VOLTE_REPLACEMENT_RAT = "int_volte_replacement_rat";
-    field public static final java.lang.String SHORT_VVM_PORT_NUMBER = "string_vvm_port_number";
-    field public static final java.lang.String STRING_VVM_DESTINATION_NUMBER = "string_vvm_destination_number";
-    field public static final java.lang.String STRING_VVM_TYPE = "string_vvm_type";
-    field public static final java.lang.String VVM_TYPE_OMTP = "vvm_type_omtp";
   }
 
   public final class CellIdentityCdma implements android.os.Parcelable {
diff --git a/cmds/app_process/Android.mk b/cmds/app_process/Android.mk
index dd5e0ea..ce6d7b5 100644
--- a/cmds/app_process/Android.mk
+++ b/cmds/app_process/Android.mk
@@ -56,6 +56,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)/asan
 LOCAL_MODULE_STEM := app_process
 LOCAL_ADDRESS_SANITIZER := true
+LOCAL_CLANG := true
 
 LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
 
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 256d87d..add7af2 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -93,15 +93,20 @@
     }
     static boolean sSystemReady = false;
 
+    static public void broadcastStickyIntent(Intent intent, String permission, int userId) {
+        broadcastStickyIntent(intent, permission, AppOpsManager.OP_NONE, userId);
+    }
+
     /**
      * Convenience for sending a sticky broadcast.  For internal use only.
      * If you don't care about permission, use null.
      */
-    static public void broadcastStickyIntent(Intent intent, String permission, int userId) {
+    static public void broadcastStickyIntent(Intent intent, String permission, int appOp,
+            int userId) {
         try {
             getDefault().broadcastIntent(
                 null, intent, null, null, Activity.RESULT_OK, null, null,
-                null /*permission*/, AppOpsManager.OP_NONE, false, true, userId);
+                null /*permission*/, appOp, false, true, userId);
         } catch (RemoteException ex) {
         }
     }
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 381c20c..06ece8e 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.Manifest;
 import android.annotation.SystemApi;
 import android.app.usage.UsageStatsManager;
 import android.content.Context;
@@ -212,8 +213,10 @@
     public static final int OP_ASSIST_STRUCTURE = 49;
     /** @hide Received a screenshot from assist. */
     public static final int OP_ASSIST_SCREENSHOT = 50;
+    /** @hide Read the phone state. */
+    public static final int OP_READ_PHONE_STATE = 51;
     /** @hide */
-    public static final int _NUM_OP = 51;
+    public static final int _NUM_OP = 52;
 
     /** Access to coarse location information. */
     public static final String OPSTR_COARSE_LOCATION =
@@ -294,6 +297,7 @@
             OP_WRITE_WALLPAPER,
             OP_ASSIST_STRUCTURE,
             OP_ASSIST_SCREENSHOT,
+            OP_READ_PHONE_STATE
     };
 
     /**
@@ -352,6 +356,7 @@
             null,
             null,
             null,
+            null
     };
 
     /**
@@ -409,7 +414,8 @@
             "ACTIVATE_VPN",
             "WRITE_WALLPAPER",
             "ASSIST_STRUCTURE",
-            "ASSIST_SCREENSHOT"
+            "ASSIST_SCREENSHOT",
+            "OP_READ_PHONE_STATE"
     };
 
     /**
@@ -468,6 +474,7 @@
             null, // no permission for supporting wallpaper
             null, // no permission for receiving assist structure
             null, // no permission for receiving assist screenshot
+            Manifest.permission.READ_PHONE_STATE
     };
 
     /**
@@ -527,6 +534,7 @@
             UserManager.DISALLOW_WALLPAPER, // WRITE_WALLPAPER
             null, // ASSIST_STRUCTURE
             null, // ASSIST_SCREENSHOT
+            null  // READ_PHONE_STATE
     };
 
     /**
@@ -585,6 +593,7 @@
             false, //WALLPAPER
             false, //ASSIST_STRUCTURE
             false, //ASSIST_SCREENSHOT
+            false, //READ_PHONE_STATE
     };
 
     /**
@@ -642,6 +651,7 @@
             AppOpsManager.MODE_ALLOWED,
             AppOpsManager.MODE_ALLOWED,
             AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED
     };
 
     /**
@@ -703,6 +713,7 @@
             false,
             false,
             false,
+            false
     };
 
     private static HashMap<String, Integer> sOpStrToOp = new HashMap<String, Integer>();
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 4ccd69f..81a78f6 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -860,13 +860,19 @@
     @Override
     public void sendBroadcastAsUser(Intent intent, UserHandle user,
             String receiverPermission) {
+        sendBroadcastAsUser(intent, user, receiverPermission, AppOpsManager.OP_NONE);
+    }
+
+    @Override
+    public void sendBroadcastAsUser(Intent intent, UserHandle user,
+            String receiverPermission, int appOp) {
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
             intent.prepareToLeaveProcess();
             ActivityManagerNative.getDefault().broadcastIntent(
-                mMainThread.getApplicationThread(), intent, resolvedType, null,
-                Activity.RESULT_OK, null, null, receiverPermission, AppOpsManager.OP_NONE, false, false,
-                user.getIdentifier());
+                    mMainThread.getApplicationThread(), intent, resolvedType, null,
+                    Activity.RESULT_OK, null, null, receiverPermission, appOp, false, false,
+                    user.getIdentifier());
         } catch (RemoteException e) {
         }
     }
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index e446700..46da025 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -332,10 +332,10 @@
             }});
 
         registerService(Context.NETWORK_POLICY_SERVICE, NetworkPolicyManager.class,
-                new StaticServiceFetcher<NetworkPolicyManager>() {
+                new CachedServiceFetcher<NetworkPolicyManager>() {
             @Override
-            public NetworkPolicyManager createService() {
-                return new NetworkPolicyManager(INetworkPolicyManager.Stub.asInterface(
+            public NetworkPolicyManager createService(ContextImpl ctx) {
+                return new NetworkPolicyManager(ctx, INetworkPolicyManager.Stub.asInterface(
                         ServiceManager.getService(Context.NETWORK_POLICY_SERVICE)));
             }});
 
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 370f61c..3bf3f85 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1608,6 +1608,28 @@
     public abstract void sendBroadcastAsUser(Intent intent, UserHandle user,
             @Nullable String receiverPermission);
 
+
+    /**
+     * Version of {@link #sendBroadcast(Intent, String)} that allows you to specify the
+     * user the broadcast will be sent to.  This is not available to applications
+     * that are not pre-installed on the system image.  Using it requires holding
+     * the INTERACT_ACROSS_USERS permission.
+     *
+     * @param intent The Intent to broadcast; all receivers matching this
+     *               Intent will receive the broadcast.
+     * @param user UserHandle to send the intent to.
+     * @param receiverPermission (optional) String naming a permission that
+     *               a receiver must hold in order to receive your broadcast.
+     *               If null, no permission is required.
+     * @param appOp The app op associated with the broadcast.
+     *
+     * @see #sendBroadcast(Intent, String)
+     *
+     * @hide
+     */
+    public abstract void sendBroadcastAsUser(Intent intent, UserHandle user,
+            @Nullable String receiverPermission, int appOp);
+
     /**
      * Version of
      * {@link #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)}
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 92f0079..fb9e194 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -444,6 +444,13 @@
         mBase.sendBroadcastAsUser(intent, user, receiverPermission);
     }
 
+    /** @hide */
+    @Override
+    public void sendBroadcastAsUser(Intent intent, UserHandle user,
+            String receiverPermission, int appOp) {
+        mBase.sendBroadcastAsUser(intent, user, receiverPermission, appOp);
+    }
+
     @Override
     public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
             String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 8f7aed4..87a1ca9 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1030,12 +1030,13 @@
      * point, <code>z_s = 1</code>, and <code>w_s</code> is a measurement of disparity
      * (depth) in pixel coordinates.</p>
      * <p><b>Units</b>:
-     * Pixels in the android.sensor.activeArraySize coordinate
+     * Pixels in the {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} 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
      */
     @PublicKey
     public static final Key<float[]> LENS_INTRINSIC_CALIBRATION =
@@ -1330,6 +1331,7 @@
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS READ_SENSOR_SETTINGS}</li>
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE BURST_CAPTURE}</li>
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING YUV_REPROCESSING}</li>
+     *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT DEPTH_OUTPUT}</li>
      * </ul></p>
      * <p>This key is available on all devices.</p>
      *
@@ -1342,6 +1344,7 @@
      * @see #REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS
      * @see #REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE
      * @see #REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING
+     * @see #REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT
      */
     @PublicKey
     public static final Key<int[]> REQUEST_AVAILABLE_CAPABILITIES =
@@ -2542,11 +2545,23 @@
      * post-processing, arbitrary cropping regions, and has relaxed performance constraints.</p>
      * <p>Each higher level supports everything the lower level supports
      * in this order: FULL <code>&gt;</code> LIMITED <code>&gt;</code> LEGACY.</p>
+     * <p>A HIGH_RESOLUTION device is equivalent to a FULL device, except that:</p>
+     * <ul>
+     * <li>At least one output resolution of 8 megapixels or higher in uncompressed YUV is
+     *   supported at <code>&gt;=</code> 20 fps.</li>
+     * <li>Maximum-size (sensor resolution) uncompressed YUV is supported  at <code>&gt;=</code> 10
+     *   fps.</li>
+     * <li>For devices that list the RAW capability and support either RAW10 or RAW12 output,
+     *   maximum-resolution RAW10 or RAW12 capture will operate at least at the rate of
+     *   maximum-resolution YUV capture, and at least one supported output resolution of
+     *   8 megapixels or higher in RAW10 or RAW12 is supported <code>&gt;=</code> 20 fps.</li>
+     * </ul>
      * <p><b>Possible values:</b>
      * <ul>
      *   <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED}</li>
      *   <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL}</li>
      *   <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY LEGACY}</li>
+     *   <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_HIGH_RESOLUTION HIGH_RESOLUTION}</li>
      * </ul></p>
      * <p>This key is available on all devices.</p>
      *
@@ -2564,6 +2579,7 @@
      * @see #INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED
      * @see #INFO_SUPPORTED_HARDWARE_LEVEL_FULL
      * @see #INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY
+     * @see #INFO_SUPPORTED_HARDWARE_LEVEL_HIGH_RESOLUTION
      */
     @PublicKey
     public static final Key<Integer> INFO_SUPPORTED_HARDWARE_LEVEL =
@@ -2694,6 +2710,29 @@
     public static final Key<android.hardware.camera2.params.StreamConfigurationDuration[]> DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS =
             new Key<android.hardware.camera2.params.StreamConfigurationDuration[]>("android.depth.availableDepthStallDurations", android.hardware.camera2.params.StreamConfigurationDuration[].class);
 
+    /**
+     * <p>Indicates whether a capture request may target both a
+     * DEPTH16 / DEPTH_POINT_CLOUD output, and normal color outputs (such as
+     * YUV_420_888, JPEG, or RAW) simultaneously.</p>
+     * <p>If TRUE, including both depth and color outputs in a single
+     * capture request is not supported. An application must interleave color
+     * and depth requests.  If FALSE, a single request can target both types
+     * of output.</p>
+     * <p>Typically, this restriction exists on camera devices that
+     * need to emit a specific pattern or wavelength of light to
+     * measure depth values, which causes the color image to be
+     * corrupted during depth measurement.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Limited capability</b> -
+     * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
+     * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
+     *
+     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     */
+    @PublicKey
+    public static final Key<Boolean> DEPTH_DEPTH_IS_EXCLUSIVE =
+            new Key<Boolean>("android.depth.depthIsExclusive", boolean.class);
+
     /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
      * End generated code
      *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 4a5bd08..e3f1d73 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -303,10 +303,13 @@
      * <p>The minimal set of capabilities that every camera
      * device (regardless of {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel})
      * supports.</p>
-     * <p>This capability is listed by all devices, and
+     * <p>This capability is listed by all normal devices, and
      * indicates that the camera device has a feature set
      * that's comparable to the baseline requirements for the
      * older android.hardware.Camera API.</p>
+     * <p>Devices with the DEPTH_OUTPUT capability might not list this
+     * capability, indicating that they support only depth measurement,
+     * not standard color output.</p>
      *
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
      * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
@@ -545,6 +548,11 @@
      * {@link CameraCharacteristics#CONTROL_AWB_LOCK_AVAILABLE android.control.awbLockAvailable} are also guaranteed
      * to be <code>true</code> so burst capture with these two locks ON
      * yields consistent image output.</p>
+     * <p>On a camera device that reports the HIGH_RESOLUTION hardware
+     * level, meaning the device supports very large capture sizes,
+     * BURST_CAPTURE means that at least 8-megapixel images can be
+     * captured at <code>&gt;=</code> 20 fps, and maximum-resolution images can be
+     * captured at <code>&gt;=</code> 10 fps.</p>
      *
      * @see CameraCharacteristics#CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES
      * @see CameraCharacteristics#CONTROL_AE_LOCK_AVAILABLE
@@ -596,6 +604,42 @@
      */
     public static final int REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING = 7;
 
+    /**
+     * <p>The camera device can produce depth measurements from its field of view.</p>
+     * <p>This capability requires the camera device to support the following:</p>
+     * <ul>
+     * <li>DEPTH16 is supported as an output format.</li>
+     * <li>DEPTH_POINT_CLOUD is optionally supported as an output format.</li>
+     * <li>This camera device, and all camera devices with the same android.lens.info.facing,
+     *   will list the following calibration entries in both CameraCharacteristics and
+     *   CaptureResults:<ul>
+     * <li>{@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}</li>
+     * <li>{@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}</li>
+     * <li>android.lens.intrinsicCalibration</li>
+     * <li>android.lens.radialDistortion</li>
+     * </ul>
+     * </li>
+     * <li>The {@link CameraCharacteristics#DEPTH_DEPTH_IS_EXCLUSIVE android.depth.depthIsExclusive} entry is listed by this device.</li>
+     * <li>A LIMITED camera with only the DEPTH_OUTPUT capability does not have to support
+     *   normal YUV_420_888, JPEG, and PRIV-format outputs. It only has to support the DEPTH16
+     *   format.</li>
+     * </ul>
+     * <p>Generally, depth output operates at a slower frame rate than standard color capture,
+     * so the DEPTH16 and DEPTH_POINT_CLOUD formats will commonly have a stall duration that
+     * should be accounted for (see
+     * android.hardware.camera2.StreamConfigurationMap#getOutputStallDuration).  On a device
+     * that supports both depth and color-based output, to enable smooth preview, using a
+     * repeating burst is recommended, where a depth-output target is only included once
+     * every N frames, where N is the ratio between preview output rate and depth output
+     * rate, including depth stall time.</p>
+     *
+     * @see CameraCharacteristics#DEPTH_DEPTH_IS_EXCLUSIVE
+     * @see CameraCharacteristics#LENS_POSE_ROTATION
+     * @see CameraCharacteristics#LENS_POSE_TRANSLATION
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     */
+    public static final int REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT = 8;
+
     //
     // Enumeration values for CameraCharacteristics#SCALER_CROPPING_TYPE
     //
@@ -808,6 +852,13 @@
      */
     public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY = 2;
 
+    /**
+     * <p>This camera device is capable of supporting advanced imaging applications at full rate,
+     * and additional high-resolution outputs at lower rates.</p>
+     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     */
+    public static final int INFO_SUPPORTED_HARDWARE_LEVEL_HIGH_RESOLUTION = 3;
+
     //
     // Enumeration values for CameraCharacteristics#SYNC_MAX_LATENCY
     //
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 4134d28..ef5d75c 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2628,12 +2628,13 @@
      * point, <code>z_s = 1</code>, and <code>w_s</code> is a measurement of disparity
      * (depth) in pixel coordinates.</p>
      * <p><b>Units</b>:
-     * Pixels in the android.sensor.activeArraySize coordinate
+     * Pixels in the {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} 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
      */
     @PublicKey
     public static final Key<float[]> LENS_INTRINSIC_CALIBRATION =
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 7e92de2..db7c35c 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -45,7 +45,7 @@
 
     /** Control network policies atomically. */
     void setNetworkPolicies(in NetworkPolicy[] policies);
-    NetworkPolicy[] getNetworkPolicies();
+    NetworkPolicy[] getNetworkPolicies(String callingPackage);
 
     /** Snooze limit on policy matching given template. */
     void snoozeLimit(in NetworkTemplate template);
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index a7ffee9..25ad9285 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -61,12 +61,14 @@
      */
     public static final String EXTRA_NETWORK_TEMPLATE = "android.net.NETWORK_TEMPLATE";
 
+    private final Context mContext;
     private INetworkPolicyManager mService;
 
-    public NetworkPolicyManager(INetworkPolicyManager service) {
+    public NetworkPolicyManager(Context context, INetworkPolicyManager service) {
         if (service == null) {
             throw new IllegalArgumentException("missing INetworkPolicyManager");
         }
+        mContext = context;
         mService = service;
     }
 
@@ -158,7 +160,7 @@
 
     public NetworkPolicy[] getNetworkPolicies() {
         try {
-            return mService.getNetworkPolicies();
+            return mService.getNetworkPolicies(mContext.getOpPackageName());
         } catch (RemoteException e) {
             return null;
         }
diff --git a/core/java/android/view/DisplayListCanvas.java b/core/java/android/view/DisplayListCanvas.java
index e9f2353..ec8f802 100644
--- a/core/java/android/view/DisplayListCanvas.java
+++ b/core/java/android/view/DisplayListCanvas.java
@@ -283,7 +283,7 @@
         Bitmap bitmap = patch.getBitmap();
         throwIfCannotDraw(bitmap);
         final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
-        nDrawPatch(mNativeCanvasWrapper, bitmap, patch.mNativeChunk,
+        nDrawPatch(mNativeCanvasWrapper, bitmap.getSkBitmap(), patch.mNativeChunk,
                 dst.left, dst.top, dst.right, dst.bottom, nativePaint);
     }
 
@@ -293,11 +293,11 @@
         Bitmap bitmap = patch.getBitmap();
         throwIfCannotDraw(bitmap);
         final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
-        nDrawPatch(mNativeCanvasWrapper, bitmap, patch.mNativeChunk,
+        nDrawPatch(mNativeCanvasWrapper, bitmap.getSkBitmap(), patch.mNativeChunk,
                 dst.left, dst.top, dst.right, dst.bottom, nativePaint);
     }
 
-    private static native void nDrawPatch(long renderer, Bitmap bitmap, long chunk,
+    private static native void nDrawPatch(long renderer, long bitmap, long chunk,
             float left, float top, float right, float bottom, long paint);
 
     public void drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy,
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 25c5127..87d5d9a 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -360,7 +360,7 @@
     @Override
     boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) {
         return nCopyLayerInto(mNativeProxy,
-                layer.getDeferredLayerUpdater(), bitmap);
+                layer.getDeferredLayerUpdater(), bitmap.getSkBitmap());
     }
 
     @Override
@@ -460,6 +460,8 @@
                     if (buffer != null) {
                         long[] map = atlas.getMap();
                         if (map != null) {
+                            // TODO Remove after fixing b/15425820
+                            validateMap(context, map);
                             nSetAtlas(renderProxy, buffer, map);
                         }
                         // If IAssetAtlas is not the same class as the IBinder
@@ -474,6 +476,32 @@
                 Log.w(LOG_TAG, "Could not acquire atlas", e);
             }
         }
+
+        private static void validateMap(Context context, long[] map) {
+            Log.d("Atlas", "Validating map...");
+            HashSet<Long> preloadedPointers = new HashSet<Long>();
+
+            // We only care about drawables that hold bitmaps
+            final Resources resources = context.getResources();
+            final LongSparseArray<Drawable.ConstantState> drawables = resources.getPreloadedDrawables();
+
+            final int count = drawables.size();
+            ArrayList<Bitmap> tmpList = new ArrayList<Bitmap>();
+            for (int i = 0; i < count; i++) {
+                drawables.valueAt(i).addAtlasableBitmaps(tmpList);
+                for (int j = 0; j < tmpList.size(); j++) {
+                    preloadedPointers.add(tmpList.get(j).getSkBitmap());
+                }
+                tmpList.clear();
+            }
+
+            for (int i = 0; i < map.length; i += 4) {
+                if (!preloadedPointers.contains(map[i])) {
+                    Log.w("Atlas", String.format("Pointer 0x%X, not in getPreloadedDrawables?", map[i]));
+                    map[i] = 0;
+                }
+            }
+        }
     }
 
     static native void setupShadersDiskCache(String cacheFile);
@@ -503,7 +531,7 @@
 
     private static native long nCreateTextureLayer(long nativeProxy);
     private static native void nBuildLayer(long nativeProxy, long node);
-    private static native boolean nCopyLayerInto(long nativeProxy, long layer, Bitmap bitmap);
+    private static native boolean nCopyLayerInto(long nativeProxy, long layer, long bitmap);
     private static native void nPushLayerUpdate(long nativeProxy, long layer);
     private static native void nCancelLayerUpdate(long nativeProxy, long layer);
     private static native void nDetachSurfaceTexture(long nativeProxy, long layer);
diff --git a/core/java/android/widget/CalendarViewMaterialDelegate.java b/core/java/android/widget/CalendarViewMaterialDelegate.java
index 7bce756..0ed75d5 100644
--- a/core/java/android/widget/CalendarViewMaterialDelegate.java
+++ b/core/java/android/widget/CalendarViewMaterialDelegate.java
@@ -19,6 +19,7 @@
 import android.annotation.StyleRes;
 import android.content.Context;
 import android.util.AttributeSet;
+import android.widget.DayPickerView.OnDaySelectedListener;
 
 import java.util.Calendar;
 
@@ -109,8 +110,7 @@
         mOnDateChangeListener = listener;
     }
 
-    private final DayPickerView.OnDaySelectedListener mOnDaySelectedListener =
-            new DayPickerView.OnDaySelectedListener() {
+    private final OnDaySelectedListener mOnDaySelectedListener = new OnDaySelectedListener() {
         @Override
         public void onDaySelected(DayPickerView view, Calendar day) {
             if (mOnDateChangeListener != null) {
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index 06a5bd2..d38a225 100755
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -34,8 +34,6 @@
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.animation.AlphaAnimation;
-import android.view.animation.Animation;
 import android.widget.DayPickerView.OnDaySelectedListener;
 import android.widget.YearPickerView.OnYearSelectedListener;
 
@@ -549,7 +547,7 @@
         final int listPosition = ss.getListPosition();
         if (listPosition != -1) {
             if (currentView == VIEW_MONTH_DAY) {
-                mDayPickerView.setCurrentItem(listPosition);
+                mDayPickerView.setPosition(listPosition);
             } else if (currentView == VIEW_YEAR) {
                 final int listPositionOffset = ss.getListPositionOffset();
                 mYearPickerView.setSelectionFromTop(listPosition, listPositionOffset);
diff --git a/core/java/android/widget/DayPickerAdapter.java b/core/java/android/widget/DayPickerPagerAdapter.java
similarity index 92%
rename from core/java/android/widget/DayPickerAdapter.java
rename to core/java/android/widget/DayPickerPagerAdapter.java
index 9a4b6f5..478fa00 100644
--- a/core/java/android/widget/DayPickerAdapter.java
+++ b/core/java/android/widget/DayPickerPagerAdapter.java
@@ -36,7 +36,7 @@
 /**
  * An adapter for a list of {@link android.widget.SimpleMonthView} items.
  */
-class DayPickerAdapter extends PagerAdapter {
+class DayPickerPagerAdapter extends PagerAdapter {
     private static final int MONTHS_IN_YEAR = 12;
 
     private final Calendar mMinDate = Calendar.getInstance();
@@ -63,7 +63,7 @@
     private int mCount;
     private int mFirstDayOfWeek;
 
-    public DayPickerAdapter(@NonNull Context context, @LayoutRes int layoutResId,
+    public DayPickerPagerAdapter(@NonNull Context context, @LayoutRes int layoutResId,
             @IdRes int calendarViewId) {
         mInflater = LayoutInflater.from(context);
         mLayoutResId = layoutResId;
@@ -200,7 +200,8 @@
 
         final int yearOffset = (day.get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR));
         final int monthOffset = (day.get(Calendar.MONTH) - mMinDate.get(Calendar.MONTH));
-        return yearOffset * MONTHS_IN_YEAR + monthOffset;
+        final int position = yearOffset * MONTHS_IN_YEAR + monthOffset;
+        return position;
     }
 
     @Override
@@ -253,8 +254,6 @@
 
         v.setMonthParams(selectedDay, month, year, mFirstDayOfWeek,
                 enabledDayRangeStart, enabledDayRangeEnd);
-        v.setPrevEnabled(position > 0);
-        v.setNextEnabled(position < mCount - 1);
 
         final ViewHolder holder = new ViewHolder(position, itemView, v);
         mItems.put(position, holder);
@@ -298,17 +297,10 @@
                 setSelectedDay(day);
 
                 if (mOnDaySelectedListener != null) {
-                    mOnDaySelectedListener.onDaySelected(DayPickerAdapter.this, day);
+                    mOnDaySelectedListener.onDaySelected(DayPickerPagerAdapter.this, day);
                 }
             }
         }
-
-        @Override
-        public void onNavigationClick(SimpleMonthView view, int direction, boolean animate) {
-            if (mOnDaySelectedListener != null) {
-                mOnDaySelectedListener.onNavigationClick(DayPickerAdapter.this, direction, animate);
-            }
-        }
     };
 
     private static class ViewHolder {
@@ -324,7 +316,6 @@
     }
 
     public interface OnDaySelectedListener {
-        public void onDaySelected(DayPickerAdapter view, Calendar day);
-        public void onNavigationClick(DayPickerAdapter view, int direction, boolean animate);
+        public void onDaySelected(DayPickerPagerAdapter view, Calendar day);
     }
 }
diff --git a/core/java/android/widget/DayPickerView.java b/core/java/android/widget/DayPickerView.java
index 0e0b2d3..c6b4d7e 100644
--- a/core/java/android/widget/DayPickerView.java
+++ b/core/java/android/widget/DayPickerView.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -16,37 +16,44 @@
 
 package android.widget;
 
-import com.android.internal.widget.ViewPager;
 import com.android.internal.R;
+import com.android.internal.widget.ViewPager;
+import com.android.internal.widget.ViewPager.OnPageChangeListener;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
-import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.MathUtils;
+import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityManager;
 
-import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Locale;
 
 import libcore.icu.LocaleData;
 
-/**
- * This displays a list of months in a calendar format with selectable days.
- */
-class DayPickerView extends ViewPager {
+class DayPickerView extends ViewGroup {
+    private static final int DEFAULT_LAYOUT = R.layout.day_picker_content_material;
     private static final int DEFAULT_START_YEAR = 1900;
     private static final int DEFAULT_END_YEAR = 2100;
 
+    private static final int[] ATTRS_TEXT_COLOR = new int[] { R.attr.textColor };
+
     private final Calendar mSelectedDay = Calendar.getInstance();
     private final Calendar mMinDate = Calendar.getInstance();
     private final Calendar mMaxDate = Calendar.getInstance();
 
-    private final ArrayList<View> mMatchParentChildren = new ArrayList<>(1);
+    private final AccessibilityManager mAccessibilityManager;
 
-    private final DayPickerAdapter mAdapter;
+    private final ViewPager mViewPager;
+    private final ImageButton mPrevButton;
+    private final ImageButton mNextButton;
+
+    private final DayPickerPagerAdapter mAdapter;
 
     /** Temporary calendar used for date calculations. */
     private Calendar mTempCalendar;
@@ -57,17 +64,21 @@
         this(context, null);
     }
 
-    public DayPickerView(Context context, AttributeSet attrs) {
+    public DayPickerView(Context context, @Nullable AttributeSet attrs) {
         this(context, attrs, R.attr.calendarViewStyle);
     }
 
-    public DayPickerView(Context context, AttributeSet attrs, int defStyleAttr) {
+    public DayPickerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
     }
 
-    public DayPickerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+    public DayPickerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
 
+        mAccessibilityManager = (AccessibilityManager) context.getSystemService(
+                Context.ACCESSIBILITY_SERVICE);
+
         final TypedArray a = context.obtainStyledAttributes(attrs,
                 R.styleable.CalendarView, defStyleAttr, defStyleRes);
 
@@ -93,14 +104,44 @@
         a.recycle();
 
         // Set up adapter.
-        mAdapter = new DayPickerAdapter(context,
+        mAdapter = new DayPickerPagerAdapter(context,
                 R.layout.date_picker_month_item_material, R.id.month_view);
         mAdapter.setMonthTextAppearance(monthTextAppearanceResId);
         mAdapter.setDayOfWeekTextAppearance(dayOfWeekTextAppearanceResId);
         mAdapter.setDayTextAppearance(dayTextAppearanceResId);
         mAdapter.setDaySelectorColor(daySelectorColor);
 
-        setAdapter(mAdapter);
+        final LayoutInflater inflater = LayoutInflater.from(context);
+        final ViewGroup content = (ViewGroup) inflater.inflate(DEFAULT_LAYOUT, this, false);
+
+        // Transfer all children from content to here.
+        while (content.getChildCount() > 0) {
+            final View child = content.getChildAt(0);
+            content.removeViewAt(0);
+            addView(child);
+        }
+
+        mPrevButton = (ImageButton) findViewById(R.id.prev);
+        mPrevButton.setOnClickListener(mOnClickListener);
+
+        mNextButton = (ImageButton) findViewById(R.id.next);
+        mNextButton.setOnClickListener(mOnClickListener);
+
+        mViewPager = (ViewPager) findViewById(R.id.day_picker_view_pager);
+        mViewPager.setAdapter(mAdapter);
+        mViewPager.setOnPageChangeListener(mOnPageChangedListener);
+
+        // Proxy the month text color into the previous and next buttons.
+        if (monthTextAppearanceResId != 0) {
+            final TypedArray ta = mContext.obtainStyledAttributes(null,
+                    ATTRS_TEXT_COLOR, 0, monthTextAppearanceResId);
+            final ColorStateList monthColor = ta.getColorStateList(0);
+            if (monthColor != null) {
+                mPrevButton.setImageTintList(monthColor);
+                mNextButton.setImageTintList(monthColor);
+            }
+            ta.recycle();
+        }
 
         // Set up min and max dates.
         final Calendar tempDate = Calendar.getInstance();
@@ -127,109 +168,68 @@
         setDate(setDateMillis, false);
 
         // Proxy selection callbacks to our own listener.
-        mAdapter.setOnDaySelectedListener(new DayPickerAdapter.OnDaySelectedListener() {
+        mAdapter.setOnDaySelectedListener(new DayPickerPagerAdapter.OnDaySelectedListener() {
             @Override
-            public void onDaySelected(DayPickerAdapter adapter, Calendar day) {
+            public void onDaySelected(DayPickerPagerAdapter adapter, Calendar day) {
                 if (mOnDaySelectedListener != null) {
                     mOnDaySelectedListener.onDaySelected(DayPickerView.this, day);
                 }
             }
-
-            @Override
-            public void onNavigationClick(DayPickerAdapter view, int direction, boolean animate) {
-                // ViewPager clamps input values, so we don't need to worry
-                // about passing invalid indices.
-                final int nextItem = getCurrentItem() + direction;
-                setCurrentItem(nextItem, animate);
-            }
         });
     }
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        populate();
+        final ViewPager viewPager = mViewPager;
+        measureChild(viewPager, widthMeasureSpec, heightMeasureSpec);
 
-        // Everything below is mostly copied from FrameLayout.
-        int count = getChildCount();
+        final int measuredWidthAndState = viewPager.getMeasuredWidthAndState();
+        final int measuredHeightAndState = viewPager.getMeasuredHeightAndState();
+        setMeasuredDimension(measuredWidthAndState, measuredHeightAndState);
 
-        final boolean measureMatchParentChildren =
-                MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY ||
-                        MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY;
+        final int pagerWidth = viewPager.getMeasuredWidth();
+        final int pagerHeight = viewPager.getMeasuredHeight();
+        final int buttonWidthSpec = MeasureSpec.makeMeasureSpec(pagerWidth, MeasureSpec.AT_MOST);
+        final int buttonHeightSpec = MeasureSpec.makeMeasureSpec(pagerHeight, MeasureSpec.AT_MOST);
+        mPrevButton.measure(buttonWidthSpec, buttonHeightSpec);
+        mNextButton.measure(buttonWidthSpec, buttonHeightSpec);
+    }
 
-        int maxHeight = 0;
-        int maxWidth = 0;
-        int childState = 0;
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        final ImageButton leftButton = mPrevButton;
+        final ImageButton rightButton = mNextButton;
 
-        for (int i = 0; i < count; i++) {
-            final View child = getChildAt(i);
-            if (child.getVisibility() != GONE) {
-                measureChild(child, widthMeasureSpec, heightMeasureSpec);
-                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-                maxWidth = Math.max(maxWidth, child.getMeasuredWidth());
-                maxHeight = Math.max(maxHeight, child.getMeasuredHeight());
-                childState = combineMeasuredStates(childState, child.getMeasuredState());
-                if (measureMatchParentChildren) {
-                    if (lp.width == LayoutParams.MATCH_PARENT ||
-                            lp.height == LayoutParams.MATCH_PARENT) {
-                        mMatchParentChildren.add(child);
-                    }
-                }
-            }
+        final int width = right - left;
+        final int height = bottom - top;
+        mViewPager.layout(0, 0, width, height);
+
+        if (mViewPager.getChildCount() < 1) {
+            leftButton.setVisibility(View.INVISIBLE);
+            rightButton.setVisibility(View.INVISIBLE);
+            return;
         }
 
-        // Account for padding too
-        maxWidth += getPaddingLeft() + getPaddingRight();
-        maxHeight += getPaddingTop() + getPaddingBottom();
+        final SimpleMonthView monthView = (SimpleMonthView) mViewPager.getChildAt(0);
+        final int monthHeight = monthView.getMonthHeight();
+        final int cellWidth = monthView.getCellWidth();
 
-        // Check against our minimum height and width
-        maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
-        maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
+        // Vertically center the previous/next buttons within the month
+        // header, horizontally center within the day cell.
+        final int leftDW = leftButton.getMeasuredWidth();
+        final int leftDH = leftButton.getMeasuredHeight();
+        final int leftIconTop = monthView.getPaddingTop() + (monthHeight - leftDH) / 2;
+        final int leftIconLeft = monthView.getPaddingLeft() + (cellWidth - leftDW) / 2;
+        leftButton.layout(leftIconLeft, leftIconTop, leftIconLeft + leftDW, leftIconTop + leftDH);
+        leftButton.setVisibility(View.VISIBLE);
 
-        // Check against our foreground's minimum height and width
-        final Drawable drawable = getForeground();
-        if (drawable != null) {
-            maxHeight = Math.max(maxHeight, drawable.getMinimumHeight());
-            maxWidth = Math.max(maxWidth, drawable.getMinimumWidth());
-        }
-
-        setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
-                resolveSizeAndState(maxHeight, heightMeasureSpec,
-                        childState << MEASURED_HEIGHT_STATE_SHIFT));
-
-        count = mMatchParentChildren.size();
-        if (count > 1) {
-            for (int i = 0; i < count; i++) {
-                final View child = mMatchParentChildren.get(i);
-
-                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-                final int childWidthMeasureSpec;
-                final int childHeightMeasureSpec;
-
-                if (lp.width == LayoutParams.MATCH_PARENT) {
-                    childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
-                            getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
-                            MeasureSpec.EXACTLY);
-                } else {
-                    childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
-                            getPaddingLeft() + getPaddingRight(),
-                            lp.width);
-                }
-
-                if (lp.height == LayoutParams.MATCH_PARENT) {
-                    childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
-                            getMeasuredHeight() - getPaddingTop() - getPaddingBottom(),
-                            MeasureSpec.EXACTLY);
-                } else {
-                    childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
-                            getPaddingTop() + getPaddingBottom(),
-                            lp.height);
-                }
-
-                child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
-            }
-        }
-
-        mMatchParentChildren.clear();
+        final int rightDW = rightButton.getMeasuredWidth();
+        final int rightDH = rightButton.getMeasuredHeight();
+        final int rightIconTop = monthView.getPaddingTop() + (monthHeight - rightDH) / 2;
+        final int rightIconRight = width - monthView.getPaddingRight() - (cellWidth - rightDW) / 2;
+        rightButton.layout(rightIconRight - rightDW, rightIconTop,
+                rightIconRight, rightIconTop + rightDH);
+        rightButton.setVisibility(View.VISIBLE);
     }
 
     public void setDayOfWeekTextAppearance(int resId) {
@@ -284,8 +284,8 @@
         }
 
         final int position = getPositionFromDay(timeInMillis);
-        if (position != getCurrentItem()) {
-            setCurrentItem(position, animate);
+        if (position != mViewPager.getCurrentItem()) {
+            mViewPager.setCurrentItem(position, animate);
         }
 
         mTempCalendar.setTimeInMillis(timeInMillis);
@@ -365,10 +365,57 @@
      * Gets the position of the view that is most prominently displayed within the list view.
      */
     public int getMostVisiblePosition() {
-        return getCurrentItem();
+        return mViewPager.getCurrentItem();
     }
 
+    public void setPosition(int position) {
+        mViewPager.setCurrentItem(position, false);
+    }
+
+    private final OnPageChangeListener mOnPageChangedListener = new OnPageChangeListener() {
+        @Override
+        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+            final float alpha = Math.abs(0.5f - positionOffset) * 2.0f;
+            mPrevButton.setAlpha(alpha);
+            mNextButton.setAlpha(alpha);
+        }
+
+        @Override
+        public void onPageScrollStateChanged(int state) {}
+
+        @Override
+        public void onPageSelected(int position) {
+            mPrevButton.setVisibility(
+                    position > 0 ? View.VISIBLE : View.INVISIBLE);
+            mNextButton.setVisibility(
+                    position < (mAdapter.getCount() - 1) ? View.VISIBLE : View.INVISIBLE);
+        }
+    };
+
+    private final OnClickListener mOnClickListener = new OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            final int direction;
+            if (v == mPrevButton) {
+                direction = -1;
+            } else if (v == mNextButton) {
+                direction = 1;
+            } else {
+                return;
+            }
+
+            // Animation is expensive for accessibility services since it sends
+            // lots of scroll and content change events.
+            final boolean animate = !mAccessibilityManager.isEnabled();
+
+            // ViewPager clamps input values, so we don't need to worry
+            // about passing invalid indices.
+            final int nextItem = mViewPager.getCurrentItem() + direction;
+            mViewPager.setCurrentItem(nextItem, animate);
+        }
+    };
+
     public interface OnDaySelectedListener {
-        public void onDaySelected(DayPickerView view, Calendar day);
+        void onDaySelected(DayPickerView view, Calendar day);
     }
 }
diff --git a/core/java/android/widget/DayPickerViewPager.java b/core/java/android/widget/DayPickerViewPager.java
new file mode 100644
index 0000000..bb6e3a4
--- /dev/null
+++ b/core/java/android/widget/DayPickerViewPager.java
@@ -0,0 +1,137 @@
+/*
+ * 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.widget;
+
+import com.android.internal.widget.ViewPager;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.View;
+
+import java.util.ArrayList;
+
+/**
+ * This displays a list of months in a calendar format with selectable days.
+ */
+class DayPickerViewPager extends ViewPager {
+    private final ArrayList<View> mMatchParentChildren = new ArrayList<>(1);
+
+    public DayPickerViewPager(Context context) {
+        this(context, null);
+    }
+
+    public DayPickerViewPager(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public DayPickerViewPager(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public DayPickerViewPager(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        populate();
+
+        // Everything below is mostly copied from FrameLayout.
+        int count = getChildCount();
+
+        final boolean measureMatchParentChildren =
+                MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY ||
+                        MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY;
+
+        int maxHeight = 0;
+        int maxWidth = 0;
+        int childState = 0;
+
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() != GONE) {
+                measureChild(child, widthMeasureSpec, heightMeasureSpec);
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                maxWidth = Math.max(maxWidth, child.getMeasuredWidth());
+                maxHeight = Math.max(maxHeight, child.getMeasuredHeight());
+                childState = combineMeasuredStates(childState, child.getMeasuredState());
+                if (measureMatchParentChildren) {
+                    if (lp.width == LayoutParams.MATCH_PARENT ||
+                            lp.height == LayoutParams.MATCH_PARENT) {
+                        mMatchParentChildren.add(child);
+                    }
+                }
+            }
+        }
+
+        // Account for padding too
+        maxWidth += getPaddingLeft() + getPaddingRight();
+        maxHeight += getPaddingTop() + getPaddingBottom();
+
+        // Check against our minimum height and width
+        maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
+        maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
+
+        // Check against our foreground's minimum height and width
+        final Drawable drawable = getForeground();
+        if (drawable != null) {
+            maxHeight = Math.max(maxHeight, drawable.getMinimumHeight());
+            maxWidth = Math.max(maxWidth, drawable.getMinimumWidth());
+        }
+
+        setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
+                resolveSizeAndState(maxHeight, heightMeasureSpec,
+                        childState << MEASURED_HEIGHT_STATE_SHIFT));
+
+        count = mMatchParentChildren.size();
+        if (count > 1) {
+            for (int i = 0; i < count; i++) {
+                final View child = mMatchParentChildren.get(i);
+
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                final int childWidthMeasureSpec;
+                final int childHeightMeasureSpec;
+
+                if (lp.width == LayoutParams.MATCH_PARENT) {
+                    childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
+                            getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
+                            MeasureSpec.EXACTLY);
+                } else {
+                    childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
+                            getPaddingLeft() + getPaddingRight(),
+                            lp.width);
+                }
+
+                if (lp.height == LayoutParams.MATCH_PARENT) {
+                    childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
+                            getMeasuredHeight() - getPaddingTop() - getPaddingBottom(),
+                            MeasureSpec.EXACTLY);
+                } else {
+                    childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
+                            getPaddingTop() + getPaddingBottom(),
+                            lp.height);
+                }
+
+                child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+            }
+        }
+
+        mMatchParentChildren.clear();
+    }
+}
diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java
index aa7f0b6..0249c22 100644
--- a/core/java/android/widget/SimpleMonthView.java
+++ b/core/java/android/widget/SimpleMonthView.java
@@ -26,7 +26,6 @@
 import android.graphics.Paint.Style;
 import android.graphics.Rect;
 import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.text.TextPaint;
 import android.text.format.DateFormat;
@@ -60,12 +59,6 @@
     private static final String DEFAULT_TITLE_FORMAT = "MMMMy";
     private static final String DAY_OF_WEEK_FORMAT = "EEEEE";
 
-    /** Virtual view ID for previous button. */
-    private static final int ITEM_ID_PREV = 0x101;
-
-    /** Virtual view ID for next button. */
-    private static final int ITEM_ID_NEXT = 0x100;
-
     private final TextPaint mMonthPaint = new TextPaint();
     private final TextPaint mDayOfWeekPaint = new TextPaint();
     private final TextPaint mDayPaint = new TextPaint();
@@ -87,14 +80,6 @@
     private final int mDesiredCellWidth;
     private final int mDesiredDaySelectorRadius;
 
-    // Next/previous drawables.
-    private final Drawable mPrevDrawable;
-    private final Drawable mNextDrawable;
-    private final Rect mPrevHitArea;
-    private final Rect mNextHitArea;
-    private final CharSequence mPrevContentDesc;
-    private final CharSequence mNextContentDesc;
-
     private CharSequence mTitle;
 
     private int mMonth;
@@ -137,9 +122,6 @@
     /** The day of month for the last (inclusive) enabled day. */
     private int mEnabledDayEnd = 31;
 
-    /** The number of week rows needed to display the current month. */
-    private int mNumWeeks = MAX_WEEKS_IN_MONTH;
-
     /** Optional listener for handling day click actions. */
     private OnDayClickListener mOnDayClickListener;
 
@@ -147,9 +129,6 @@
 
     private int mTouchedItem = -1;
 
-    private boolean mPrevEnabled;
-    private boolean mNextEnabled;
-
     public SimpleMonthView(Context context) {
         this(context, null);
     }
@@ -170,14 +149,8 @@
         mDesiredDayOfWeekHeight = res.getDimensionPixelSize(R.dimen.date_picker_day_of_week_height);
         mDesiredDayHeight = res.getDimensionPixelSize(R.dimen.date_picker_day_height);
         mDesiredCellWidth = res.getDimensionPixelSize(R.dimen.date_picker_day_width);
-        mDesiredDaySelectorRadius = res.getDimensionPixelSize(R.dimen.date_picker_day_selector_radius);
-
-        mPrevDrawable = context.getDrawable(R.drawable.ic_chevron_left);
-        mNextDrawable = context.getDrawable(R.drawable.ic_chevron_right);
-        mPrevHitArea = mPrevDrawable != null ? new Rect() : null;
-        mNextHitArea = mNextDrawable != null ? new Rect() : null;
-        mPrevContentDesc = res.getText(R.string.date_picker_prev_month_button);
-        mNextContentDesc = res.getText(R.string.date_picker_next_month_button);
+        mDesiredDaySelectorRadius = res.getDimensionPixelSize(
+                R.dimen.date_picker_day_selector_radius);
 
         // Set up accessibility components.
         mTouchHelper = new MonthViewTouchHelper(this);
@@ -193,18 +166,6 @@
         initPaints(res);
     }
 
-    public void setNextEnabled(boolean enabled) {
-        mNextEnabled = enabled;
-        mTouchHelper.invalidateRoot();
-        invalidate();
-    }
-
-    public void setPrevEnabled(boolean enabled) {
-        mPrevEnabled = enabled;
-        mTouchHelper.invalidateRoot();
-        invalidate();
-    }
-
     /**
      * Applies the specified text appearance resource to a paint, returning the
      * text color if one is set in the text appearance.
@@ -236,16 +197,16 @@
         return textColor;
     }
 
+    public int getMonthHeight() {
+        return mMonthHeight;
+    }
+
+    public int getCellWidth() {
+        return mCellWidth;
+    }
+
     public void setMonthTextAppearance(int resId) {
-        final ColorStateList monthColor = applyTextAppearance(mMonthPaint, resId);
-        if (monthColor != null) {
-            if (mPrevDrawable != null) {
-                mPrevDrawable.setTintList(monthColor);
-            }
-            if (mNextDrawable != null) {
-                mNextDrawable.setTintList(monthColor);
-            }
-        }
+        applyTextAppearance(mMonthPaint, resId);
 
         invalidate();
     }
@@ -360,7 +321,7 @@
         switch (event.getAction()) {
             case MotionEvent.ACTION_DOWN:
             case MotionEvent.ACTION_MOVE:
-                final int touchedItem = getItemAtLocation(x, y);
+                final int touchedItem = getDayAtLocation(x, y);
                 if (mTouchedItem != touchedItem) {
                     mTouchedItem = touchedItem;
                     invalidate();
@@ -368,8 +329,8 @@
                 break;
 
             case MotionEvent.ACTION_UP:
-                final int clickedItem = getItemAtLocation(x, y);
-                onItemClicked(clickedItem, true);
+                final int clickedDay = getDayAtLocation(x, y);
+                onDayClicked(clickedDay);
                 // Fall through.
             case MotionEvent.ACTION_CANCEL:
                 // Reset touched day on stream end.
@@ -389,7 +350,6 @@
         drawMonth(canvas);
         drawDaysOfWeek(canvas);
         drawDays(canvas);
-        drawButtons(canvas);
 
         canvas.translate(-paddingLeft, -paddingTop);
     }
@@ -482,16 +442,6 @@
         }
     }
 
-    private void drawButtons(Canvas canvas) {
-        if (mPrevEnabled && mPrevDrawable != null) {
-            mPrevDrawable.draw(canvas);
-        }
-
-        if (mNextEnabled && mNextDrawable != null) {
-            mNextDrawable.draw(canvas);
-        }
-    }
-
     private static boolean isValidDayOfWeek(int day) {
         return day >= Calendar.SUNDAY && day <= Calendar.SATURDAY;
     }
@@ -674,33 +624,6 @@
         mDaySelectorRadius = Math.min(mDesiredDaySelectorRadius,
                 Math.min(maxSelectorWidth, maxSelectorHeight));
 
-        // Vertically center the previous/next drawables within the month
-        // header, horizontally center within the day cell, then expand the
-        // hit area to ensure it's at least 48x48dp.
-        final Drawable prevDrawable = mPrevDrawable;
-        if (prevDrawable != null) {
-            final int dW = prevDrawable.getIntrinsicWidth();
-            final int dH = prevDrawable.getIntrinsicHeight();
-            final int iconTop = (monthHeight - dH) / 2;
-            final int iconLeft = (cellWidth - dW) / 2;
-
-            // Button bounds don't include padding, but hit area does.
-            prevDrawable.setBounds(iconLeft, iconTop, iconLeft + dW, iconTop + dH);
-            mPrevHitArea.set(0, 0, paddingLeft + cellWidth, paddingTop + monthHeight);
-        }
-
-        final Drawable nextDrawable = mNextDrawable;
-        if (nextDrawable != null) {
-            final int dW = nextDrawable.getIntrinsicWidth();
-            final int dH = nextDrawable.getIntrinsicHeight();
-            final int iconTop = (monthHeight - dH) / 2;
-            final int iconRight = paddedWidth - (cellWidth - dW) / 2;
-
-            // Button bounds don't include padding, but hit area does.
-            nextDrawable.setBounds(iconRight - dW, iconTop, iconRight, iconTop + dH);
-            mNextHitArea.set(paddedRight - cellWidth, 0, w, paddingTop + monthHeight);
-        }
-
         // Invalidate cached accessibility information.
         mTouchHelper.invalidateRoot();
     }
@@ -714,22 +637,15 @@
     }
 
     /**
-     * Calculates the day of the month or item identifier at the specified
-     * touch position. Returns the day of the month or -1 if the position
-     * wasn't in a valid day.
+     * Calculates the day of the month at the specified touch position. Returns
+     * the day of the month or -1 if the position wasn't in a valid day.
      *
      * @param x the x position of the touch event
      * @param y the y position of the touch event
-     * @return the day of the month at (x, y), an item identifier, or -1 if the
-     *         position wasn't in a valid day or item
+     * @return the day of the month at (x, y), or -1 if the position wasn't in
+     *         a valid day
      */
-    private int getItemAtLocation(int x, int y) {
-        if (mNextEnabled && mNextDrawable != null && mNextHitArea.contains(x, y)) {
-            return ITEM_ID_NEXT;
-        } else if (mPrevEnabled && mPrevDrawable != null && mPrevHitArea.contains(x, y)) {
-            return ITEM_ID_PREV;
-        }
-
+    private int getDayAtLocation(int x, int y) {
         final int paddedX = x - getPaddingLeft();
         if (paddedX < 0 || paddedX >= mPaddedWidth) {
             return -1;
@@ -755,22 +671,10 @@
     /**
      * Calculates the bounds of the specified day.
      *
-     * @param id the day of the month, or an item identifier
+     * @param id the day of the month
      * @param outBounds the rect to populate with bounds
      */
-    private boolean getBoundsForItem(int id, Rect outBounds) {
-        if (mNextEnabled && id == ITEM_ID_NEXT) {
-            if (mNextDrawable != null) {
-                outBounds.set(mNextHitArea);
-                return true;
-            }
-        } else if (mPrevEnabled && id == ITEM_ID_PREV) {
-            if (mPrevDrawable != null) {
-                outBounds.set(mPrevHitArea);
-                return true;
-            }
-        }
-
+    private boolean getBoundsForDay(int id, Rect outBounds) {
         if (id < 1 || id > mDaysInMonth) {
             return false;
         }
@@ -789,16 +693,8 @@
         final int top = getPaddingTop() + headerHeight + row * rowHeight;
 
         outBounds.set(left, top, left + colWidth, top + rowHeight);
-        return true;
-    }
 
-    /**
-     * Called when an item is clicked.
-     *
-     * @param id the day number or item identifier
-     */
-    private boolean onItemClicked(int id, boolean animate) {
-        return onNavigationClicked(id, animate) || onDayClicked(id);
+        return true;
     }
 
     /**
@@ -824,31 +720,6 @@
     }
 
     /**
-     * Called when the user clicks on a navigation button. Handles callbacks to
-     * the {@link OnDayClickListener} if one is set.
-     *
-     * @param id the item identifier
-     */
-    private boolean onNavigationClicked(int id, boolean animate) {
-        final int direction;
-        if (id == ITEM_ID_NEXT) {
-            direction = 1;
-        } else if (id == ITEM_ID_PREV) {
-            direction = -1;
-        } else {
-            return false;
-        }
-
-        if (mOnDayClickListener != null) {
-            mOnDayClickListener.onNavigationClick(this, direction, animate);
-        }
-
-        // This is a no-op if accessibility is turned off.
-        mTouchHelper.sendEventForVirtualView(id, AccessibilityEvent.TYPE_VIEW_CLICKED);
-        return true;
-    }
-
-    /**
      * Provides a virtual view hierarchy for interfacing with an accessibility
      * service.
      */
@@ -864,7 +735,7 @@
 
         @Override
         protected int getVirtualViewAt(float x, float y) {
-            final int day = getItemAtLocation((int) (x + 0.5f), (int) (y + 0.5f));
+            final int day = getDayAtLocation((int) (x + 0.5f), (int) (y + 0.5f));
             if (day >= 0) {
                 return day;
             }
@@ -873,14 +744,6 @@
 
         @Override
         protected void getVisibleVirtualViews(IntArray virtualViewIds) {
-            if (mNextEnabled && mNextDrawable != null) {
-                virtualViewIds.add(ITEM_ID_PREV);
-            }
-
-            if (mPrevEnabled && mPrevDrawable != null) {
-                virtualViewIds.add(ITEM_ID_NEXT);
-            }
-
             for (int day = 1; day <= mDaysInMonth; day++) {
                 virtualViewIds.add(day);
             }
@@ -888,12 +751,12 @@
 
         @Override
         protected void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) {
-            event.setContentDescription(getItemDescription(virtualViewId));
+            event.setContentDescription(getDayDescription(virtualViewId));
         }
 
         @Override
         protected void onPopulateNodeForVirtualView(int virtualViewId, AccessibilityNodeInfo node) {
-            final boolean hasBounds = getBoundsForItem(virtualViewId, mTempRect);
+            final boolean hasBounds = getBoundsForDay(virtualViewId, mTempRect);
 
             if (!hasBounds) {
                 // The day is invalid, kill the node.
@@ -904,8 +767,8 @@
                 return;
             }
 
-            node.setText(getItemText(virtualViewId));
-            node.setContentDescription(getItemDescription(virtualViewId));
+            node.setText(getDayText(virtualViewId));
+            node.setContentDescription(getDayDescription(virtualViewId));
             node.setBoundsInParent(mTempRect);
             node.addAction(AccessibilityAction.ACTION_CLICK);
 
@@ -921,7 +784,7 @@
                 Bundle arguments) {
             switch (action) {
                 case AccessibilityNodeInfo.ACTION_CLICK:
-                    return onItemClicked(virtualViewId, false);
+                    return onDayClicked(virtualViewId);
             }
 
             return false;
@@ -930,15 +793,11 @@
         /**
          * Generates a description for a given virtual view.
          *
-         * @param id the day or item identifier to generate a description for
+         * @param id the day to generate a description for
          * @return a description of the virtual view
          */
-        private CharSequence getItemDescription(int id) {
-            if (id == ITEM_ID_NEXT) {
-                return mNextContentDesc;
-            } else if (id == ITEM_ID_PREV) {
-                return mPrevContentDesc;
-            } else if (id >= 1 && id <= mDaysInMonth) {
+        private CharSequence getDayDescription(int id) {
+            if (id >= 1 && id <= mDaysInMonth) {
                 mTempCalendar.set(mYear, mMonth, id);
                 return DateFormat.format(DATE_FORMAT, mTempCalendar.getTimeInMillis());
             }
@@ -949,13 +808,11 @@
         /**
          * Generates displayed text for a given virtual view.
          *
-         * @param id the day or item identifier to generate text for
+         * @param id the day to generate text for
          * @return the visible text of the virtual view
          */
-        private CharSequence getItemText(int id) {
-            if (id == ITEM_ID_NEXT || id == ITEM_ID_PREV) {
-                return null;
-            } else if (id >= 1 && id <= mDaysInMonth) {
+        private CharSequence getDayText(int id) {
+            if (id >= 1 && id <= mDaysInMonth) {
                 return Integer.toString(id);
             }
 
@@ -967,7 +824,6 @@
      * Handles callbacks when the user clicks on a time object.
      */
     public interface OnDayClickListener {
-        public void onDayClick(SimpleMonthView view, Calendar day);
-        public void onNavigationClick(SimpleMonthView view, int direction, boolean animate);
+        void onDayClick(SimpleMonthView view, Calendar day);
     }
 }
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 5c95f8a..7a934bd 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -857,13 +857,6 @@
     bitmap->unlockPixels();
 }
 
-static jlong Bitmap_refPixelRef(JNIEnv* env, jobject, jlong bitmapHandle) {
-    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
-    SkPixelRef* pixelRef = bitmap ? bitmap->pixelRef() : nullptr;
-    SkSafeRef(pixelRef);
-    return reinterpret_cast<jlong>(pixelRef);
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 
 static JNINativeMethod gBitmapMethods[] = {
@@ -903,7 +896,6 @@
                                             (void*)Bitmap_copyPixelsFromBuffer },
     {   "nativeSameAs",             "(JJ)Z", (void*)Bitmap_sameAs },
     {   "nativePrepareToDraw",      "(J)V", (void*)Bitmap_prepareToDraw },
-    {   "nativeRefPixelRef",        "(J)J", (void*)Bitmap_refPixelRef },
 };
 
 int register_android_graphics_Bitmap(JNIEnv* env)
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index f0bd8d1..f0bd5dd 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -373,7 +373,7 @@
     return legacyBitmapConfigToColorType(c);
 }
 
-android::Canvas* GraphicsJNI::getNativeCanvas(JNIEnv* env, jobject canvas) {
+SkCanvas* GraphicsJNI::getNativeCanvas(JNIEnv* env, jobject canvas) {
     SkASSERT(env);
     SkASSERT(canvas);
     SkASSERT(env->IsInstanceOf(canvas, gCanvas_class));
@@ -381,7 +381,9 @@
     if (!canvasHandle) {
         return NULL;
     }
-    return reinterpret_cast<android::Canvas*>(canvasHandle);
+    SkCanvas* c = reinterpret_cast<android::Canvas*>(canvasHandle)->asSkCanvas();
+    SkASSERT(c);
+    return c;
 }
 
 SkRegion* GraphicsJNI::getNativeRegion(JNIEnv* env, jobject region)
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index 8eb43f8..49def13 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -8,7 +8,6 @@
 #include "SkPoint.h"
 #include "SkRect.h"
 #include "SkImageDecoder.h"
-#include <Canvas.h>
 #include <jni.h>
 
 class SkBitmapRegionDecoder;
@@ -48,7 +47,7 @@
     static SkPoint* jpointf_to_point(JNIEnv*, jobject jpointf, SkPoint* point);
     static void point_to_jpointf(const SkPoint& point, JNIEnv*, jobject jpointf);
 
-    static android::Canvas* getNativeCanvas(JNIEnv*, jobject canvas);
+    static SkCanvas* getNativeCanvas(JNIEnv*, jobject canvas);
     static SkBitmap* getSkBitmapDeprecated(JNIEnv*, jobject bitmap);
     static void getSkBitmap(JNIEnv*, jobject bitmap, SkBitmap* outBitmap);
     static SkPixelRef* getSkPixelRef(JNIEnv*, jobject bitmap);
diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp
index 348b0ec..3f8bfe2 100644
--- a/core/jni/android/graphics/NinePatch.cpp
+++ b/core/jni/android/graphics/NinePatch.cpp
@@ -64,7 +64,7 @@
         return JNI_FALSE;
     }
 
-    static jlong validateNinePatchChunk(JNIEnv* env, jobject, jbyteArray obj) {
+    static jlong validateNinePatchChunk(JNIEnv* env, jobject, jlong, jbyteArray obj) {
         size_t chunkSize = env->GetArrayLength(obj);
         if (chunkSize < (int) (sizeof(Res_png_9patch))) {
             jniThrowRuntimeException(env, "Array too small for chunk.");
@@ -88,13 +88,13 @@
         }
     }
 
-    static void draw(JNIEnv* env, SkCanvas* canvas, SkRect& bounds, const SkBitmap& bitmap,
+    static void draw(JNIEnv* env, SkCanvas* canvas, SkRect& bounds, const SkBitmap* bitmap,
             Res_png_9patch* chunk, const SkPaint* paint, jint destDensity, jint srcDensity) {
         if (destDensity == srcDensity || destDensity == 0 || srcDensity == 0) {
             ALOGV("Drawing unscaled 9-patch: (%g,%g)-(%g,%g)",
                     SkScalarToFloat(bounds.fLeft), SkScalarToFloat(bounds.fTop),
                     SkScalarToFloat(bounds.fRight), SkScalarToFloat(bounds.fBottom));
-            NinePatch_Draw(canvas, bounds, bitmap, *chunk, paint, NULL);
+            NinePatch_Draw(canvas, bounds, *bitmap, *chunk, paint, NULL);
         } else {
             canvas->save();
 
@@ -111,25 +111,25 @@
                     SkScalarToFloat(bounds.fRight), SkScalarToFloat(bounds.fBottom),
                     srcDensity, destDensity);
 
-            NinePatch_Draw(canvas, bounds, bitmap, *chunk, paint, NULL);
+            NinePatch_Draw(canvas, bounds, *bitmap, *chunk, paint, NULL);
 
             canvas->restore();
         }
     }
 
     static void drawF(JNIEnv* env, jobject, jlong canvasHandle, jobject boundsRectF,
-            jobject jbitmap, jlong chunkHandle, jlong paintHandle,
+            jlong bitmapHandle, jlong chunkHandle, jlong paintHandle,
             jint destDensity, jint srcDensity) {
         SkCanvas* canvas       = reinterpret_cast<Canvas*>(canvasHandle)->asSkCanvas();
+        const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
         Res_png_9patch* chunk  = reinterpret_cast<Res_png_9patch*>(chunkHandle);
         const Paint* paint     = reinterpret_cast<Paint*>(paintHandle);
         SkASSERT(canvas);
         SkASSERT(boundsRectF);
+        SkASSERT(bitmap);
         SkASSERT(chunk);
         // paint is optional
 
-        SkBitmap bitmap;
-        GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
         SkRect bounds;
         GraphicsJNI::jrectf_to_rect(env, boundsRectF, &bounds);
 
@@ -137,36 +137,36 @@
     }
 
     static void drawI(JNIEnv* env, jobject, jlong canvasHandle, jobject boundsRect,
-            jobject jbitmap, jlong chunkHandle, jlong paintHandle,
+            jlong bitmapHandle, jlong chunkHandle, jlong paintHandle,
             jint destDensity, jint srcDensity) {
         SkCanvas* canvas       = reinterpret_cast<Canvas*>(canvasHandle)->asSkCanvas();
+        const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
         Res_png_9patch* chunk  = reinterpret_cast<Res_png_9patch*>(chunkHandle);
         const Paint* paint     = reinterpret_cast<Paint*>(paintHandle);
         SkASSERT(canvas);
         SkASSERT(boundsRect);
+        SkASSERT(bitmap);
         SkASSERT(chunk);
         // paint is optional
 
-        SkBitmap bitmap;
-        GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
         SkRect bounds;
         GraphicsJNI::jrect_to_rect(env, boundsRect, &bounds);
         draw(env, canvas, bounds, bitmap, chunk, paint, destDensity, srcDensity);
     }
 
-    static jlong getTransparentRegion(JNIEnv* env, jobject, jobject jbitmap,
+    static jlong getTransparentRegion(JNIEnv* env, jobject, jlong bitmapHandle,
             jlong chunkHandle, jobject boundsRect) {
+        const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
         Res_png_9patch* chunk = reinterpret_cast<Res_png_9patch*>(chunkHandle);
+        SkASSERT(bitmap);
         SkASSERT(chunk);
         SkASSERT(boundsRect);
 
-        SkBitmap bitmap;
-        GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
         SkRect bounds;
         GraphicsJNI::jrect_to_rect(env, boundsRect, &bounds);
 
         SkRegion* region = NULL;
-        NinePatch_Draw(NULL, bounds, bitmap, *chunk, NULL, &region);
+        NinePatch_Draw(NULL, bounds, *bitmap, *chunk, NULL, &region);
 
         return reinterpret_cast<jlong>(region);
     }
@@ -176,16 +176,13 @@
 /////////////////////////////////////////////////////////////////////////////////////////
 
 static JNINativeMethod gNinePatchMethods[] = {
-    { "isNinePatchChunk", "([B)Z", (void*) SkNinePatchGlue::isNinePatchChunk },
-    { "validateNinePatchChunk", "([B)J",
-            (void*) SkNinePatchGlue::validateNinePatchChunk },
-    { "nativeFinalize", "(J)V", (void*) SkNinePatchGlue::finalize },
-    { "nativeDraw", "(JLandroid/graphics/RectF;Landroid/graphics/Bitmap;JJII)V",
-            (void*) SkNinePatchGlue::drawF },
-    { "nativeDraw", "(JLandroid/graphics/Rect;Landroid/graphics/Bitmap;JJII)V",
-            (void*) SkNinePatchGlue::drawI },
-    { "nativeGetTransparentRegion", "(Landroid/graphics/Bitmap;JLandroid/graphics/Rect;)J",
-            (void*) SkNinePatchGlue::getTransparentRegion }
+    { "isNinePatchChunk", "([B)Z",                        (void*) SkNinePatchGlue::isNinePatchChunk },
+    { "validateNinePatchChunk", "(J[B)J",                 (void*) SkNinePatchGlue::validateNinePatchChunk },
+    { "nativeFinalize", "(J)V",                           (void*) SkNinePatchGlue::finalize },
+    { "nativeDraw", "(JLandroid/graphics/RectF;JJJII)V",  (void*) SkNinePatchGlue::drawF },
+    { "nativeDraw", "(JLandroid/graphics/Rect;JJJII)V",   (void*) SkNinePatchGlue::drawI },
+    { "nativeGetTransparentRegion", "(JJLandroid/graphics/Rect;)J",
+                                                          (void*) SkNinePatchGlue::getTransparentRegion }
 };
 
 int register_android_graphics_NinePatch(JNIEnv* env) {
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index d0f7591..6591d29 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -80,12 +80,11 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
-static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jobject jbitmap,
+static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong bitmapHandle,
                                       jint tileModeX, jint tileModeY)
 {
-    SkBitmap bitmap;
-    GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
-    SkShader* s = SkShader::CreateBitmapShader(bitmap,
+    const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    SkShader* s = SkShader::CreateBitmapShader(*bitmap,
                                         (SkShader::TileMode)tileModeX,
                                         (SkShader::TileMode)tileModeY);
 
@@ -250,7 +249,7 @@
 };
 
 static JNINativeMethod gBitmapShaderMethods[] = {
-    { "nativeCreate",     "(Landroid/graphics/Bitmap;II)J",  (void*)BitmapShader_constructor },
+    { "nativeCreate",     "(JII)J",  (void*)BitmapShader_constructor },
 };
 
 static JNINativeMethod gLinearGradientMethods[] = {
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index 9b5fb3a..a2c1609 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -39,22 +39,17 @@
 }
 
 // Native wrapper constructor used by Canvas(Bitmap)
-static jlong initRaster(JNIEnv* env, jobject, jobject jbitmap) {
-    SkBitmap bitmap;
-    if (jbitmap != NULL) {
-        GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
-    }
+static jlong initRaster(JNIEnv* env, jobject, jlong bitmapHandle) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
     return reinterpret_cast<jlong>(Canvas::create_canvas(bitmap));
 }
 
 // Set the given bitmap as the new draw target (wrapped in a new SkCanvas),
 // optionally copying canvas matrix & clip state.
-static void setBitmap(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap) {
-    SkBitmap bitmap;
-    if (jbitmap != NULL) {
-        GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
-    }
-    get_canvas(canvasHandle)->setBitmap(bitmap);
+static void setBitmap(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
+                      jboolean copyState) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    get_canvas(canvasHandle)->setBitmap(bitmap, copyState);
 }
 
 static jboolean isOpaque(JNIEnv*, jobject, jlong canvasHandle) {
@@ -318,12 +313,11 @@
                                            indices, indexCount, *paint);
 }
 
-static void drawBitmap(JNIEnv* env, jobject jcanvas, jlong canvasHandle, jobject jbitmap,
+static void drawBitmap(JNIEnv* env, jobject jcanvas, jlong canvasHandle, jlong bitmapHandle,
                        jfloat left, jfloat top, jlong paintHandle, jint canvasDensity,
                        jint screenDensity, jint bitmapDensity) {
     Canvas* canvas = get_canvas(canvasHandle);
-    SkBitmap bitmap;
-    GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
+    const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
 
     if (canvasDensity == bitmapDensity || canvasDensity == 0 || bitmapDensity == 0) {
@@ -333,9 +327,9 @@
                 filteredPaint = *paint;
             }
             filteredPaint.setFilterQuality(kLow_SkFilterQuality);
-            canvas->drawBitmap(bitmap, left, top, &filteredPaint);
+            canvas->drawBitmap(*bitmap, left, top, &filteredPaint);
         } else {
-            canvas->drawBitmap(bitmap, left, top, paint);
+            canvas->drawBitmap(*bitmap, left, top, paint);
         }
     } else {
         canvas->save(SkCanvas::kMatrixClip_SaveFlag);
@@ -349,39 +343,37 @@
         }
         filteredPaint.setFilterQuality(kLow_SkFilterQuality);
 
-        canvas->drawBitmap(bitmap, 0, 0, &filteredPaint);
+        canvas->drawBitmap(*bitmap, 0, 0, &filteredPaint);
         canvas->restore();
     }
 }
 
-static void drawBitmapMatrix(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap,
+static void drawBitmapMatrix(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
                              jlong matrixHandle, jlong paintHandle) {
+    const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
     const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-    SkBitmap bitmap;
-    GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
-    get_canvas(canvasHandle)->drawBitmap(bitmap, *matrix, paint);
+    get_canvas(canvasHandle)->drawBitmap(*bitmap, *matrix, paint);
 }
 
-static void drawBitmapRect(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap,
+static void drawBitmapRect(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
                            float srcLeft, float srcTop, float srcRight, float srcBottom,
                            float dstLeft, float dstTop, float dstRight, float dstBottom,
                            jlong paintHandle, jint screenDensity, jint bitmapDensity) {
     Canvas* canvas = get_canvas(canvasHandle);
+    const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
 
-    SkBitmap bitmap;
-    GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
     if (screenDensity != 0 && screenDensity != bitmapDensity) {
         Paint filteredPaint;
         if (paint) {
             filteredPaint = *paint;
         }
         filteredPaint.setFilterQuality(kLow_SkFilterQuality);
-        canvas->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
+        canvas->drawBitmap(*bitmap, srcLeft, srcTop, srcRight, srcBottom,
                            dstLeft, dstTop, dstRight, dstBottom, &filteredPaint);
     } else {
-        canvas->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
+        canvas->drawBitmap(*bitmap, srcLeft, srcTop, srcRight, srcBottom,
                            dstLeft, dstTop, dstRight, dstBottom, paint);
     }
 }
@@ -409,17 +401,16 @@
     get_canvas(canvasHandle)->drawBitmap(bitmap, x, y, paint);
 }
 
-static void drawBitmapMesh(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap,
+static void drawBitmapMesh(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
                            jint meshWidth, jint meshHeight, jfloatArray jverts,
                            jint vertIndex, jintArray jcolors, jint colorIndex, jlong paintHandle) {
     const int ptCount = (meshWidth + 1) * (meshHeight + 1);
     AutoJavaFloatArray vertA(env, jverts, vertIndex + (ptCount << 1));
     AutoJavaIntArray colorA(env, jcolors, colorIndex + ptCount);
 
+    const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-    SkBitmap bitmap;
-    GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
-    get_canvas(canvasHandle)->drawBitmapMesh(bitmap, meshWidth, meshHeight,
+    get_canvas(canvasHandle)->drawBitmapMesh(*bitmap, meshWidth, meshHeight,
                                              vertA.ptr(), colorA.ptr(), paint);
 }
 
@@ -667,8 +658,8 @@
 
 static JNINativeMethod gMethods[] = {
     {"finalizer", "(J)V", (void*) CanvasJNI::finalizer},
-    {"initRaster", "(Landroid/graphics/Bitmap;)J", (void*) CanvasJNI::initRaster},
-    {"native_setBitmap", "(JLandroid/graphics/Bitmap;)V", (void*) CanvasJNI::setBitmap},
+    {"initRaster", "(J)J", (void*) CanvasJNI::initRaster},
+    {"native_setBitmap", "(JJZ)V", (void*) CanvasJNI::setBitmap},
     {"native_isOpaque","(J)Z", (void*) CanvasJNI::isOpaque},
     {"native_getWidth","(J)I", (void*) CanvasJNI::getWidth},
     {"native_getHeight","(J)I", (void*) CanvasJNI::getHeight},
@@ -704,11 +695,11 @@
     {"native_drawArc","(JFFFFFFZJ)V", (void*) CanvasJNI::drawArc},
     {"native_drawPath","(JJJ)V", (void*) CanvasJNI::drawPath},
     {"nativeDrawVertices", "(JII[FI[FI[II[SIIJ)V", (void*)CanvasJNI::drawVertices},
-    {"native_drawBitmap","(JLandroid/graphics/Bitmap;FFJIII)V", (void*) CanvasJNI::drawBitmap},
-    {"nativeDrawBitmapMatrix", "(JLandroid/graphics/Bitmap;JJ)V", (void*)CanvasJNI::drawBitmapMatrix},
-    {"native_drawBitmap","(JLandroid/graphics/Bitmap;FFFFFFFFJII)V", (void*) CanvasJNI::drawBitmapRect},
+    {"native_drawBitmap","(JJFFJIII)V", (void*) CanvasJNI::drawBitmap},
+    {"nativeDrawBitmapMatrix", "(JJJJ)V", (void*)CanvasJNI::drawBitmapMatrix},
+    {"native_drawBitmap","(JJFFFFFFFFJII)V", (void*) CanvasJNI::drawBitmapRect},
     {"native_drawBitmap", "(J[IIIFFIIZJ)V", (void*)CanvasJNI::drawBitmapArray},
-    {"nativeDrawBitmapMesh", "(JLandroid/graphics/Bitmap;II[FI[IIJ)V", (void*)CanvasJNI::drawBitmapMesh},
+    {"nativeDrawBitmapMesh", "(JJII[FI[IIJ)V", (void*)CanvasJNI::drawBitmapMesh},
     {"native_drawText","(J[CIIFFIJJ)V", (void*) CanvasJNI::drawTextChars},
     {"native_drawText","(JLjava/lang/String;IIFFIJJ)V", (void*) CanvasJNI::drawTextString},
     {"native_drawTextRun","(J[CIIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunChars},
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index c9b0e76..33db4a85 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -356,95 +356,58 @@
     android_media_AudioRecord_release(env, thiz);
 }
 
-
-// ----------------------------------------------------------------------------
-static jint android_media_AudioRecord_readInByteArray(JNIEnv *env,  jobject thiz,
-                                                        jbyteArray javaAudioData,
-                                                        jint offsetInBytes, jint sizeInBytes) {
-    jbyte* recordBuff = NULL;
-    // get the audio recorder from which we'll read new audio samples
-    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
-    if (lpRecorder == NULL) {
-        ALOGE("Unable to retrieve AudioRecord object, can't record");
-        return 0;
-    }
-
-    if (!javaAudioData) {
-        ALOGE("Invalid Java array to store recorded audio, can't record");
-        return 0;
-    }
-
-    // get the pointer to where we'll record the audio
-    // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
-    // a way that it becomes much more efficient. When doing so, we will have to prevent the
-    // AudioSystem callback to be called while in critical section (in case of media server
-    // process crash for instance)
-    recordBuff = (jbyte *)env->GetByteArrayElements(javaAudioData, NULL);
-
-    if (recordBuff == NULL) {
-        ALOGE("Error retrieving destination for recorded audio data, can't record");
-        return 0;
-    }
-
-    // read the new audio data from the native AudioRecord object
-    ssize_t readSize = lpRecorder->read(recordBuff + offsetInBytes, sizeInBytes);
-    env->ReleaseByteArrayElements(javaAudioData, recordBuff, 0);
-
-    if (readSize < 0) {
-        readSize = (jint)AUDIO_JAVA_INVALID_OPERATION;
-    }
-    return (jint) readSize;
+// overloaded JNI array helper functions
+static inline
+jbyte *envGetArrayElements(JNIEnv *env, jbyteArray array, jboolean *isCopy) {
+    return env->GetByteArrayElements(array, isCopy);
 }
 
-// ----------------------------------------------------------------------------
-static jint android_media_AudioRecord_readInShortArray(JNIEnv *env,  jobject thiz,
-                                                        jshortArray javaAudioData,
-                                                        jint offsetInShorts, jint sizeInShorts) {
-
-    jshort* recordBuff = NULL;
-    // get the audio recorder from which we'll read new audio samples
-    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
-    if (lpRecorder == NULL) {
-        ALOGE("Unable to retrieve AudioRecord object, can't record");
-        return 0;
-    }
-
-    if (!javaAudioData) {
-        ALOGE("Invalid Java array to store recorded audio, can't record");
-        return 0;
-    }
-
-    // get the pointer to where we'll record the audio
-    // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
-    // a way that it becomes much more efficient. When doing so, we will have to prevent the
-    // AudioSystem callback to be called while in critical section (in case of media server
-    // process crash for instance)
-    recordBuff = (jshort *)env->GetShortArrayElements(javaAudioData, NULL);
-
-    if (recordBuff == NULL) {
-        ALOGE("Error retrieving destination for recorded audio data, can't record");
-        return 0;
-    }
-
-    // read the new audio data from the native AudioRecord object
-    const size_t sizeInBytes = sizeInShorts * sizeof(short);
-    ssize_t readSize = lpRecorder->read(recordBuff + offsetInShorts, sizeInBytes);
-
-    env->ReleaseShortArrayElements(javaAudioData, recordBuff, 0);
-
-    if (readSize < 0) {
-        readSize = (jint)AUDIO_JAVA_INVALID_OPERATION;
-    } else {
-        readSize /= sizeof(short);
-    }
-    return (jint) readSize;
+static inline
+void envReleaseArrayElements(JNIEnv *env, jbyteArray array, jbyte *elems, jint mode) {
+    env->ReleaseByteArrayElements(array, elems, mode);
 }
 
-// ----------------------------------------------------------------------------
-static jint android_media_AudioRecord_readInFloatArray(JNIEnv *env,  jobject thiz,
-                                                        jfloatArray javaAudioData,
-                                                        jint offsetInFloats, jint sizeInFloats,
-                                                        jboolean isReadBlocking) {
+static inline
+jshort *envGetArrayElements(JNIEnv *env, jshortArray array, jboolean *isCopy) {
+    return env->GetShortArrayElements(array, isCopy);
+}
+
+static inline
+void envReleaseArrayElements(JNIEnv *env, jshortArray array, jshort *elems, jint mode) {
+    env->ReleaseShortArrayElements(array, elems, mode);
+}
+
+static inline
+jfloat *envGetArrayElements(JNIEnv *env, jfloatArray array, jboolean *isCopy) {
+    return env->GetFloatArrayElements(array, isCopy);
+}
+
+static inline
+void envReleaseArrayElements(JNIEnv *env, jfloatArray array, jfloat *elems, jint mode) {
+    env->ReleaseFloatArrayElements(array, elems, mode);
+}
+
+static inline
+jint interpretReadSizeError(ssize_t readSize) {
+    ALOGE_IF(readSize != WOULD_BLOCK, "Error %zd during AudioRecord native read", readSize);
+    switch (readSize) {
+    case WOULD_BLOCK:
+        return (jint)0;
+    case BAD_VALUE:
+        return (jint)AUDIO_JAVA_BAD_VALUE;
+    default:
+        // may be possible for other errors such as
+        // NO_INIT to happen if restoreRecord_l fails.
+    case INVALID_OPERATION:
+        return (jint)AUDIO_JAVA_INVALID_OPERATION;
+    }
+}
+
+template <typename T>
+static jint android_media_AudioRecord_readInArray(JNIEnv *env,  jobject thiz,
+                                                  T javaAudioData,
+                                                  jint offsetInSamples, jint sizeInSamples,
+                                                  jboolean isReadBlocking) {
     // get the audio recorder from which we'll read new audio samples
     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
     if (lpRecorder == NULL) {
@@ -453,76 +416,68 @@
     }
 
     if (javaAudioData == NULL) {
-         ALOGE("Invalid Java array to store recorded audio");
-         return (jint)AUDIO_JAVA_BAD_VALUE;
-     }
+        ALOGE("Invalid Java array to store recorded audio");
+        return (jint)AUDIO_JAVA_BAD_VALUE;
+    }
 
-    // get the pointer to where we'll record the audio
     // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
     // a way that it becomes much more efficient. When doing so, we will have to prevent the
     // AudioSystem callback to be called while in critical section (in case of media server
     // process crash for instance)
-    jfloat *recordBuff = (jfloat *)env->GetFloatArrayElements(javaAudioData, NULL);
+
+    // get the pointer to where we'll record the audio
+    auto *recordBuff = envGetArrayElements(env, javaAudioData, NULL);
     if (recordBuff == NULL) {
         ALOGE("Error retrieving destination for recorded audio data");
         return (jint)AUDIO_JAVA_BAD_VALUE;
     }
 
     // read the new audio data from the native AudioRecord object
-    const size_t sizeInBytes = sizeInFloats * sizeof(float);
-    ssize_t readSize = lpRecorder->read(recordBuff + offsetInFloats, sizeInBytes);
+    const size_t sizeInBytes = sizeInSamples * sizeof(*recordBuff);
+    ssize_t readSize = lpRecorder->read(
+            recordBuff + offsetInSamples, sizeInBytes, isReadBlocking == JNI_TRUE /* blocking */);
 
-    env->ReleaseFloatArrayElements(javaAudioData, recordBuff, 0);
+    envReleaseArrayElements(env, javaAudioData, recordBuff, 0);
 
     if (readSize < 0) {
-        ALOGE_IF(readSize != WOULD_BLOCK, "Error %zd during AudioRecord native read", readSize);
-        switch (readSize) {
-        case WOULD_BLOCK:
-            return (jint)0;
-        case BAD_VALUE:
-            return (jint)AUDIO_JAVA_BAD_VALUE;
-        default:
-            // may be possible for other errors such as
-            // NO_INIT to happen if restoreRecord_l fails.
-        case INVALID_OPERATION:
-            return (jint)AUDIO_JAVA_INVALID_OPERATION;
-        }
+        return interpretReadSizeError(readSize);
     }
-    return (jint)(readSize / sizeof(float));
+    return (jint)(readSize / sizeof(*recordBuff));
 }
 
 // ----------------------------------------------------------------------------
 static jint android_media_AudioRecord_readInDirectBuffer(JNIEnv *env,  jobject thiz,
-                                                  jobject jBuffer, jint sizeInBytes) {
+                                                         jobject jBuffer, jint sizeInBytes,
+                                                         jboolean isReadBlocking) {
     // get the audio recorder from which we'll read new audio samples
     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
     if (lpRecorder==NULL)
-        return 0;
+        return (jint)AUDIO_JAVA_INVALID_OPERATION;
 
     // direct buffer and direct access supported?
     long capacity = env->GetDirectBufferCapacity(jBuffer);
     if (capacity == -1) {
         // buffer direct access is not supported
         ALOGE("Buffer direct access is not supported, can't record");
-        return 0;
+        return (jint)AUDIO_JAVA_BAD_VALUE;
     }
     //ALOGV("capacity = %ld", capacity);
     jbyte* nativeFromJavaBuf = (jbyte*) env->GetDirectBufferAddress(jBuffer);
     if (nativeFromJavaBuf==NULL) {
         ALOGE("Buffer direct access is not supported, can't record");
-        return 0;
+        return (jint)AUDIO_JAVA_BAD_VALUE;
     }
 
     // read new data from the recorder
     ssize_t readSize = lpRecorder->read(nativeFromJavaBuf,
-                                   capacity < sizeInBytes ? capacity : sizeInBytes);
+                                        capacity < sizeInBytes ? capacity : sizeInBytes,
+                                        isReadBlocking == JNI_TRUE /* blocking */);
     if (readSize < 0) {
-        readSize = (jint)AUDIO_JAVA_INVALID_OPERATION;
+        return interpretReadSizeError(readSize);
     }
     return (jint)readSize;
 }
 
-
 // ----------------------------------------------------------------------------
 static jint android_media_AudioRecord_get_native_frame_count(JNIEnv *env,  jobject thiz) {
     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
@@ -633,12 +588,15 @@
     {"native_finalize",      "()V",    (void *)android_media_AudioRecord_finalize},
     {"native_release",       "()V",    (void *)android_media_AudioRecord_release},
     {"native_read_in_byte_array",
-                             "([BII)I", (void *)android_media_AudioRecord_readInByteArray},
+                             "([BIIZ)I",
+                                     (void *)android_media_AudioRecord_readInArray<jbyteArray>},
     {"native_read_in_short_array",
-                             "([SII)I", (void *)android_media_AudioRecord_readInShortArray},
+                             "([SIIZ)I",
+                                     (void *)android_media_AudioRecord_readInArray<jshortArray>},
     {"native_read_in_float_array",
-                             "([FIIZ)I", (void *)android_media_AudioRecord_readInFloatArray},
-    {"native_read_in_direct_buffer","(Ljava/lang/Object;I)I",
+                             "([FIIZ)I",
+                                     (void *)android_media_AudioRecord_readInArray<jfloatArray>},
+    {"native_read_in_direct_buffer","(Ljava/lang/Object;IZ)I",
                                        (void *)android_media_AudioRecord_readInDirectBuffer},
     {"native_get_native_frame_count",
                              "()I",    (void *)android_media_AudioRecord_get_native_frame_count},
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 610c7ed..8d3a9aa 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -510,14 +510,47 @@
     android_media_AudioTrack_release(env, thiz);
 }
 
+// overloaded JNI array helper functions (same as in android_media_AudioRecord)
+static inline
+jbyte *envGetArrayElements(JNIEnv *env, jbyteArray array, jboolean *isCopy) {
+    return env->GetByteArrayElements(array, isCopy);
+}
+
+static inline
+void envReleaseArrayElements(JNIEnv *env, jbyteArray array, jbyte *elems, jint mode) {
+    env->ReleaseByteArrayElements(array, elems, mode);
+}
+
+static inline
+jshort *envGetArrayElements(JNIEnv *env, jshortArray array, jboolean *isCopy) {
+    return env->GetShortArrayElements(array, isCopy);
+}
+
+static inline
+void envReleaseArrayElements(JNIEnv *env, jshortArray array, jshort *elems, jint mode) {
+    env->ReleaseShortArrayElements(array, elems, mode);
+}
+
+static inline
+jfloat *envGetArrayElements(JNIEnv *env, jfloatArray array, jboolean *isCopy) {
+    return env->GetFloatArrayElements(array, isCopy);
+}
+
+static inline
+void envReleaseArrayElements(JNIEnv *env, jfloatArray array, jfloat *elems, jint mode) {
+    env->ReleaseFloatArrayElements(array, elems, mode);
+}
+
 // ----------------------------------------------------------------------------
-jint writeToTrack(const sp<AudioTrack>& track, jint audioFormat, const jbyte* data,
-                  jint offsetInBytes, jint sizeInBytes, bool blocking = true) {
+template <typename T>
+static jint writeToTrack(const sp<AudioTrack>& track, jint audioFormat, const T *data,
+                         jint offsetInSamples, jint sizeInSamples, bool blocking) {
     // give the data to the native AudioTrack object (the data starts at the offset)
     ssize_t written = 0;
     // regular write() or copy the data to the AudioTrack's shared memory?
+    size_t sizeInBytes = sizeInSamples * sizeof(T);
     if (track->sharedBuffer() == 0) {
-        written = track->write(data + offsetInBytes, sizeInBytes, blocking);
+        written = track->write(data + offsetInSamples, sizeInBytes, blocking);
         // for compatibility with earlier behavior of write(), return 0 in this case
         if (written == (ssize_t) WOULD_BLOCK) {
             written = 0;
@@ -527,55 +560,59 @@
         if ((size_t)sizeInBytes > track->sharedBuffer()->size()) {
             sizeInBytes = track->sharedBuffer()->size();
         }
-        memcpy(track->sharedBuffer()->pointer(), data + offsetInBytes, sizeInBytes);
+        memcpy(track->sharedBuffer()->pointer(), data + offsetInSamples, sizeInBytes);
         written = sizeInBytes;
     }
+    if (written > 0) {
+        return written / sizeof(T);
+    }
+    // for compatibility, error codes pass through unchanged
     return written;
 }
 
 // ----------------------------------------------------------------------------
-static jint android_media_AudioTrack_write_byte(JNIEnv *env,  jobject thiz,
-                                                  jbyteArray javaAudioData,
-                                                  jint offsetInBytes, jint sizeInBytes,
-                                                  jint javaAudioFormat,
-                                                  jboolean isWriteBlocking) {
-    //ALOGV("android_media_AudioTrack_write_byte(offset=%d, sizeInBytes=%d) called",
-    //    offsetInBytes, sizeInBytes);
+template <typename T>
+static jint android_media_AudioTrack_writeArray(JNIEnv *env, jobject thiz,
+                                                T javaAudioData,
+                                                jint offsetInSamples, jint sizeInSamples,
+                                                jint javaAudioFormat,
+                                                jboolean isWriteBlocking) {
+    //ALOGV("android_media_AudioTrack_writeArray(offset=%d, sizeInSamples=%d) called",
+    //        offsetInSamples, sizeInSamples);
     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for write()");
-        return 0;
+        return (jint)AUDIO_JAVA_INVALID_OPERATION;
     }
 
-    // get the pointer for the audio data from the java array
+    if (javaAudioData == NULL) {
+        ALOGE("NULL java array of audio data to play");
+        return (jint)AUDIO_JAVA_BAD_VALUE;
+    }
+
     // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
     // a way that it becomes much more efficient. When doing so, we will have to prevent the
     // AudioSystem callback to be called while in critical section (in case of media server
     // process crash for instance)
-    jbyte* cAudioData = NULL;
-    if (javaAudioData) {
-        cAudioData = (jbyte *)env->GetByteArrayElements(javaAudioData, NULL);
-        if (cAudioData == NULL) {
-            ALOGE("Error retrieving source of audio data to play, can't play");
-            return 0; // out of memory or no data to load
-        }
-    } else {
-        ALOGE("NULL java array of audio data to play, can't play");
-        return 0;
+
+    // get the pointer for the audio data from the java array
+    auto cAudioData = envGetArrayElements(env, javaAudioData, NULL);
+    if (cAudioData == NULL) {
+        ALOGE("Error retrieving source of audio data to play");
+        return (jint)AUDIO_JAVA_BAD_VALUE; // out of memory or no data to load
     }
 
-    jint written = writeToTrack(lpTrack, javaAudioFormat, cAudioData, offsetInBytes, sizeInBytes,
-            isWriteBlocking == JNI_TRUE /* blocking */);
+    jint samplesWritten = writeToTrack(lpTrack, javaAudioFormat, cAudioData,
+            offsetInSamples, sizeInSamples, isWriteBlocking == JNI_TRUE /* blocking */);
 
-    env->ReleaseByteArrayElements(javaAudioData, cAudioData, 0);
+    envReleaseArrayElements(env, javaAudioData, cAudioData, 0);
 
-    //ALOGV("write wrote %d (tried %d) bytes in the native AudioTrack with offset %d",
-    //     (int)written, (int)(sizeInBytes), (int)offsetInBytes);
-    return written;
+    //ALOGV("write wrote %d (tried %d) samples in the native AudioTrack with offset %d",
+    //        (int)samplesWritten, (int)(sizeInSamples), (int)offsetInSamples);
+    return samplesWritten;
 }
 
-
 // ----------------------------------------------------------------------------
 static jint android_media_AudioTrack_write_native_bytes(JNIEnv *env,  jobject thiz,
         jbyteArray javaBytes, jint byteOffset, jint sizeInBytes,
@@ -586,7 +623,7 @@
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
                 "Unable to retrieve AudioTrack pointer for write()");
-        return 0;
+        return (jint)AUDIO_JAVA_INVALID_OPERATION;
     }
 
     ScopedBytesRO bytes(env, javaBytes);
@@ -602,90 +639,6 @@
 }
 
 // ----------------------------------------------------------------------------
-static jint android_media_AudioTrack_write_short(JNIEnv *env,  jobject thiz,
-                                                  jshortArray javaAudioData,
-                                                  jint offsetInShorts, jint sizeInShorts,
-                                                  jint javaAudioFormat) {
-
-    //ALOGV("android_media_AudioTrack_write_short(offset=%d, sizeInShorts=%d) called",
-    //    offsetInShorts, sizeInShorts);
-    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
-    if (lpTrack == NULL) {
-        jniThrowException(env, "java/lang/IllegalStateException",
-            "Unable to retrieve AudioTrack pointer for write()");
-        return 0;
-    }
-
-    // get the pointer for the audio data from the java array
-    // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
-    // a way that it becomes much more efficient. When doing so, we will have to prevent the
-    // AudioSystem callback to be called while in critical section (in case of media server
-    // process crash for instance)
-    jshort* cAudioData = NULL;
-    if (javaAudioData) {
-        cAudioData = (jshort *)env->GetShortArrayElements(javaAudioData, NULL);
-        if (cAudioData == NULL) {
-            ALOGE("Error retrieving source of audio data to play, can't play");
-            return 0; // out of memory or no data to load
-        }
-    } else {
-        ALOGE("NULL java array of audio data to play, can't play");
-        return 0;
-    }
-    jint written = writeToTrack(lpTrack, javaAudioFormat, (jbyte *)cAudioData,
-                                offsetInShorts * sizeof(short), sizeInShorts * sizeof(short),
-            true /*blocking write, legacy behavior*/);
-    env->ReleaseShortArrayElements(javaAudioData, cAudioData, 0);
-
-    if (written > 0) {
-        written /= sizeof(short);
-    }
-    //ALOGV("write wrote %d (tried %d) shorts in the native AudioTrack with offset %d",
-    //     (int)written, (int)(sizeInShorts), (int)offsetInShorts);
-
-    return written;
-}
-
-
-// ----------------------------------------------------------------------------
-static jint android_media_AudioTrack_write_float(JNIEnv *env,  jobject thiz,
-                                                  jfloatArray javaAudioData,
-                                                  jint offsetInFloats, jint sizeInFloats,
-                                                  jint javaAudioFormat,
-                                                  jboolean isWriteBlocking) {
-
-    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
-    if (lpTrack == NULL) {
-        jniThrowException(env, "java/lang/IllegalStateException",
-            "Unable to retrieve AudioTrack pointer for write()");
-        return 0;
-    }
-
-    jfloat* cAudioData = NULL;
-    if (javaAudioData) {
-        cAudioData = (jfloat *)env->GetFloatArrayElements(javaAudioData, NULL);
-        if (cAudioData == NULL) {
-            ALOGE("Error retrieving source of audio data to play, can't play");
-            return 0; // out of memory or no data to load
-        }
-    } else {
-        ALOGE("NULL java array of audio data to play, can't play");
-        return 0;
-    }
-    jint written = writeToTrack(lpTrack, javaAudioFormat, (jbyte *)cAudioData,
-                                offsetInFloats * sizeof(float), sizeInFloats * sizeof(float),
-                                isWriteBlocking == JNI_TRUE /* blocking */);
-    env->ReleaseFloatArrayElements(javaAudioData, cAudioData, 0);
-
-    if (written > 0) {
-        written /= sizeof(float);
-    }
-
-    return written;
-}
-
-
-// ----------------------------------------------------------------------------
 static jint android_media_AudioTrack_get_native_frame_count(JNIEnv *env,  jobject thiz) {
     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
     if (lpTrack == NULL) {
@@ -976,12 +929,12 @@
                                          (void *)android_media_AudioTrack_setup},
     {"native_finalize",      "()V",      (void *)android_media_AudioTrack_finalize},
     {"native_release",       "()V",      (void *)android_media_AudioTrack_release},
-    {"native_write_byte",    "([BIIIZ)I",(void *)android_media_AudioTrack_write_byte},
+    {"native_write_byte",    "([BIIIZ)I",(void *)android_media_AudioTrack_writeArray<jbyteArray>},
     {"native_write_native_bytes",
                              "(Ljava/lang/Object;IIIZ)I",
                                          (void *)android_media_AudioTrack_write_native_bytes},
-    {"native_write_short",   "([SIII)I", (void *)android_media_AudioTrack_write_short},
-    {"native_write_float",   "([FIIIZ)I",(void *)android_media_AudioTrack_write_float},
+    {"native_write_short",   "([SIIIZ)I",(void *)android_media_AudioTrack_writeArray<jshortArray>},
+    {"native_write_float",   "([FIIIZ)I",(void *)android_media_AudioTrack_writeArray<jfloatArray>},
     {"native_setVolume",     "(FF)V",    (void *)android_media_AudioTrack_set_volume},
     {"native_get_native_frame_count",
                              "()I",      (void *)android_media_AudioTrack_get_native_frame_count},
diff --git a/core/jni/android_view_DisplayListCanvas.cpp b/core/jni/android_view_DisplayListCanvas.cpp
index f42c89c..f2e6c4b 100644
--- a/core/jni/android_view_DisplayListCanvas.cpp
+++ b/core/jni/android_view_DisplayListCanvas.cpp
@@ -133,10 +133,10 @@
 // ----------------------------------------------------------------------------
 
 static void android_view_DisplayListCanvas_drawPatch(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jobject jbitmap, jlong patchPtr,
+        jlong rendererPtr, jlong bitmapPtr, jlong patchPtr,
         float left, float top, float right, float bottom, jlong paintPtr) {
-    SkBitmap bitmap;
-    GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapPtr);
+
     DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     Res_png_9patch* patch = reinterpret_cast<Res_png_9patch*>(patchPtr);
     Paint* paint = reinterpret_cast<Paint*>(paintPtr);
@@ -276,7 +276,7 @@
 
     { "nCallDrawGLFunction", "(JJ)V",          (void*) android_view_DisplayListCanvas_callDrawGLFunction },
 
-    { "nDrawPatch",         "(JLandroid/graphics/Bitmap;JFFFFJ)V",     (void*) android_view_DisplayListCanvas_drawPatch },
+    { "nDrawPatch",         "(JJJFFFFJ)V",     (void*) android_view_DisplayListCanvas_drawPatch },
 
     { "nDrawRects",         "(JJJ)V",          (void*) android_view_DisplayListCanvas_drawRegionAsRects },
     { "nDrawRoundRect",     "(JJJJJJJJ)V",     (void*) android_view_DisplayListCanvas_drawRoundRectProps },
diff --git a/core/jni/android_view_GraphicBuffer.cpp b/core/jni/android_view_GraphicBuffer.cpp
index aa79d70..a12629f 100644
--- a/core/jni/android_view_GraphicBuffer.cpp
+++ b/core/jni/android_view_GraphicBuffer.cpp
@@ -67,6 +67,11 @@
     jfieldID bottom;
 } gRectClassInfo;
 
+static struct {
+    jfieldID mSurfaceFormat;
+    jmethodID setNativeBitmap;
+} gCanvasClassInfo;
+
 #define GET_INT(object, field) \
     env->GetIntField(object, field)
 
@@ -191,9 +196,13 @@
         bitmap.setPixels(NULL);
     }
 
-    Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvas);
-    nativeCanvas->setBitmap(bitmap);
-    nativeCanvas->clipRect(rect.left, rect.top, rect.right, rect.bottom);
+    SET_INT(canvas, gCanvasClassInfo.mSurfaceFormat, buffer->getPixelFormat());
+    INVOKEV(canvas, gCanvasClassInfo.setNativeBitmap, reinterpret_cast<jlong>(&bitmap));
+
+    SkRect clipRect;
+    clipRect.set(rect.left, rect.top, rect.right, rect.bottom);
+    SkCanvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvas);
+    nativeCanvas->clipRect(clipRect);
 
     if (dirtyRect) {
         INVOKEV(dirtyRect, gRectClassInfo.set,
@@ -208,8 +217,7 @@
 
     GraphicBufferWrapper* wrapper =
                 reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
-    Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvas);
-    nativeCanvas->setBitmap(SkBitmap());
+    INVOKEV(canvas, gCanvasClassInfo.setNativeBitmap, (jlong)0);
 
     if (wrapper) {
         status_t status = wrapper->buffer->unlock();
@@ -294,6 +302,10 @@
     gRectClassInfo.right = GetFieldIDOrDie(env, clazz, "right", "I");
     gRectClassInfo.bottom = GetFieldIDOrDie(env, clazz, "bottom", "I");
 
+    clazz = FindClassOrDie(env, "android/graphics/Canvas");
+    gCanvasClassInfo.mSurfaceFormat = GetFieldIDOrDie(env, clazz, "mSurfaceFormat", "I");
+    gCanvasClassInfo.setNativeBitmap = GetMethodIDOrDie(env, clazz, "setNativeBitmap", "(J)V");
+
     return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
 }
 
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 06d1e85..f1c90ea 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -74,6 +74,11 @@
     jfieldID bottom;
 } gRectClassInfo;
 
+static struct {
+    jfieldID mSurfaceFormat;
+    jmethodID setNativeBitmap;
+} gCanvasClassInfo;
+
 // ----------------------------------------------------------------------------
 
 // this is just a pointer we use to pass to inc/decStrong
@@ -314,6 +319,9 @@
         return 0;
     }
 
+    // Associate a SkCanvas object to this surface
+    env->SetIntField(canvasObj, gCanvasClassInfo.mSurfaceFormat, outBuffer.format);
+
     SkImageInfo info = SkImageInfo::Make(outBuffer.width, outBuffer.height,
                                          convertPixelFormat(outBuffer.format),
                                          kPremul_SkAlphaType);
@@ -331,12 +339,12 @@
         bitmap.setPixels(NULL);
     }
 
-    Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvasObj);
-    nativeCanvas->setBitmap(bitmap);
+    env->CallVoidMethod(canvasObj, gCanvasClassInfo.setNativeBitmap,
+                        reinterpret_cast<jlong>(&bitmap));
 
     if (dirtyRectPtr) {
-        nativeCanvas->clipRect(dirtyRect.left, dirtyRect.top,
-                dirtyRect.right, dirtyRect.bottom);
+        SkCanvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvasObj);
+        nativeCanvas->clipRect( SkRect::Make(reinterpret_cast<const SkIRect&>(dirtyRect)) );
     }
 
     if (dirtyRectObj) {
@@ -362,8 +370,7 @@
     }
 
     // detach the canvas from the surface
-    Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvasObj);
-    nativeCanvas->setBitmap(SkBitmap());
+    env->CallVoidMethod(canvasObj, gCanvasClassInfo.setNativeBitmap, (jlong)0);
 
     // unlock surface
     status_t err = surface->unlockAndPost();
@@ -558,6 +565,10 @@
             gSurfaceClassInfo.clazz, "mLock", "Ljava/lang/Object;");
     gSurfaceClassInfo.ctor = GetMethodIDOrDie(env, gSurfaceClassInfo.clazz, "<init>", "(J)V");
 
+    clazz = FindClassOrDie(env, "android/graphics/Canvas");
+    gCanvasClassInfo.mSurfaceFormat = GetFieldIDOrDie(env, clazz, "mSurfaceFormat", "I");
+    gCanvasClassInfo.setNativeBitmap = GetMethodIDOrDie(env, clazz, "setNativeBitmap", "(J)V");
+
     clazz = FindClassOrDie(env, "android/graphics/Rect");
     gRectClassInfo.left = GetFieldIDOrDie(env, clazz, "left", "I");
     gRectClassInfo.top = GetFieldIDOrDie(env, clazz, "top", "I");
diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp
index 7e05793..c2bd0b3c4 100644
--- a/core/jni/android_view_TextureView.cpp
+++ b/core/jni/android_view_TextureView.cpp
@@ -48,6 +48,11 @@
 } gRectClassInfo;
 
 static struct {
+    jfieldID mSurfaceFormat;
+    jmethodID setNativeBitmap;
+} gCanvasClassInfo;
+
+static struct {
     jfieldID nativeWindow;
 } gTextureViewClassInfo;
 
@@ -167,9 +172,13 @@
         bitmap.setPixels(NULL);
     }
 
-    Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvas);
-    nativeCanvas->setBitmap(bitmap);
-    nativeCanvas->clipRect(rect.left, rect.top, rect.right, rect.bottom);
+    SET_INT(canvas, gCanvasClassInfo.mSurfaceFormat, buffer.format);
+    INVOKEV(canvas, gCanvasClassInfo.setNativeBitmap, reinterpret_cast<jlong>(&bitmap));
+
+    SkRect clipRect;
+    clipRect.set(rect.left, rect.top, rect.right, rect.bottom);
+    SkCanvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvas);
+    nativeCanvas->clipRect(clipRect);
 
     if (dirtyRect) {
         INVOKEV(dirtyRect, gRectClassInfo.set,
@@ -182,8 +191,7 @@
 static void android_view_TextureView_unlockCanvasAndPost(JNIEnv* env, jobject,
         jlong nativeWindow, jobject canvas) {
 
-    Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvas);
-    nativeCanvas->setBitmap(SkBitmap());
+    INVOKEV(canvas, gCanvasClassInfo.setNativeBitmap, (jlong)0);
 
     if (nativeWindow) {
         sp<ANativeWindow> window((ANativeWindow*) nativeWindow);
@@ -217,6 +225,10 @@
     gRectClassInfo.right = GetFieldIDOrDie(env, clazz, "right", "I");
     gRectClassInfo.bottom = GetFieldIDOrDie(env, clazz, "bottom", "I");
 
+    clazz = FindClassOrDie(env, "android/graphics/Canvas");
+    gCanvasClassInfo.mSurfaceFormat = GetFieldIDOrDie(env, clazz, "mSurfaceFormat", "I");
+    gCanvasClassInfo.setNativeBitmap = GetMethodIDOrDie(env, clazz, "setNativeBitmap", "(J)V");
+
     clazz = FindClassOrDie(env, "android/view/TextureView");
     gTextureViewClassInfo.nativeWindow = GetFieldIDOrDie(env, clazz, "mNativeWindow", "J");
 
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 4ccbb41..11b3805 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -21,7 +21,6 @@
 #include "jni.h"
 #include <nativehelper/JNIHelp.h>
 #include "core_jni_helpers.h"
-#include <GraphicsJNI.h>
 #include <ScopedPrimitiveArray.h>
 
 #include <EGL/egl.h>
@@ -348,11 +347,10 @@
 }
 
 static jboolean android_view_ThreadedRenderer_copyLayerInto(JNIEnv* env, jobject clazz,
-        jlong proxyPtr, jlong layerPtr, jobject jbitmap) {
+        jlong proxyPtr, jlong layerPtr, jlong bitmapPtr) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
-    SkBitmap bitmap;
-    GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapPtr);
     return proxy->copyLayerInto(layer, bitmap);
 }
 
@@ -460,7 +458,7 @@
     { "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
     { "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer },
     { "nBuildLayer", "(JJ)V", (void*) android_view_ThreadedRenderer_buildLayer },
-    { "nCopyLayerInto", "(JJLandroid/graphics/Bitmap;)Z", (void*) android_view_ThreadedRenderer_copyLayerInto },
+    { "nCopyLayerInto", "(JJJ)Z", (void*) android_view_ThreadedRenderer_copyLayerInto },
     { "nPushLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_pushLayerUpdate },
     { "nCancelLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_cancelLayerUpdate },
     { "nDetachSurfaceTexture", "(JJ)V", (void*) android_view_ThreadedRenderer_detachSurfaceTexture },
diff --git a/core/res/res/layout/date_picker_header_material.xml b/core/res/res/layout/date_picker_header_material.xml
index bda7de9..8125544 100644
--- a/core/res/res/layout/date_picker_header_material.xml
+++ b/core/res/res/layout/date_picker_header_material.xml
@@ -45,6 +45,7 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:textAppearance="@style/TextAppearance.Material.DatePicker.DateLabel"
+        android:gravity="start"
         android:maxLines="2"
         android:ellipsize="none"
         tools:text="Thu, Sep 30"
diff --git a/core/res/res/layout/day_picker_content_material.xml b/core/res/res/layout/day_picker_content_material.xml
new file mode 100644
index 0000000..1852bfa
--- /dev/null
+++ b/core/res/res/layout/day_picker_content_material.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+             android:layout_width="match_parent"
+             android:layout_height="match_parent">
+
+    <android.widget.DayPickerViewPager
+        android:id="@+id/day_picker_view_pager"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+    <ImageButton
+        android:id="@+id/prev"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:minWidth="48dp"
+        android:minHeight="48dp"
+        android:src="@drawable/ic_chevron_left"
+        android:background="?attr/selectableItemBackgroundBorderless"
+        android:contentDescription="@string/date_picker_prev_month_button"
+        android:visibility="invisible" />
+
+    <ImageButton
+        android:id="@+id/next"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:minWidth="48dp"
+        android:minHeight="48dp"
+        android:src="@drawable/ic_chevron_right"
+        android:background="?attr/selectableItemBackgroundBorderless"
+        android:contentDescription="@string/date_picker_next_month_button"
+        android:visibility="invisible" />
+
+</FrameLayout>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 180b415..98c1b8f 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2242,4 +2242,6 @@
   <java-symbol type="layout" name="chooser_grid" />
   <java-symbol type="layout" name="resolve_grid_item" />
   <java-symbol type="id" name="title_icon" />
+  <java-symbol type="id" name="day_picker_view_pager" />
+  <java-symbol type="layout" name="day_picker_content_material" />
 </resources>
diff --git a/core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.mk b/core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.mk
index 5fa2405..6ee6ffa 100644
--- a/core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.mk
+++ b/core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.mk
@@ -5,7 +5,6 @@
 
 LOCAL_PACKAGE_NAME := install_jni_lib_open_from_apk
 
-LOCAL_JNI_SHARED_LIBRARIES_ZIP_OPTIONS := -0
 LOCAL_PAGE_ALIGN_JNI_SHARED_LIBRARIES := true
 
 include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/docs/html/images/tools/hierarchicalviewer-icon.png b/docs/html/images/tools/hierarchicalviewer-icon.png
new file mode 100644
index 0000000..061f952
--- /dev/null
+++ b/docs/html/images/tools/hierarchicalviewer-icon.png
Binary files differ
diff --git a/docs/html/images/tools/studio-DDMS-open-perspective-icon.png b/docs/html/images/tools/studio-DDMS-open-perspective-icon.png
new file mode 100644
index 0000000..f8e6d1a
--- /dev/null
+++ b/docs/html/images/tools/studio-DDMS-open-perspective-icon.png
Binary files differ
diff --git a/docs/html/images/tools/studio-gradle-panel.png b/docs/html/images/tools/studio-gradle-panel.png
deleted file mode 100644
index 4a76a8d..0000000
--- a/docs/html/images/tools/studio-gradle-panel.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/tools/studio-gradle-tab.png b/docs/html/images/tools/studio-gradle-tab.png
deleted file mode 100644
index b0f302c..0000000
--- a/docs/html/images/tools/studio-gradle-tab.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/tools/building/building-studio.jd b/docs/html/tools/building/building-studio.jd
index 68800da..4431194 100644
--- a/docs/html/tools/building/building-studio.jd
+++ b/docs/html/tools/building/building-studio.jd
@@ -67,26 +67,13 @@
 <a href="{@docRoot}sdk/installing/studio-build.html">Build System</a> guide.</p>
 
 <p>To view the list of all available build tasks in Android Studio, click <strong>Gradle</strong>
-on the right side of the IDE window. The <em>Gradle tasks</em> panel appears as shown in
-figure 2. Double-click any build task to run it in Android Studio. To hide the <em>Gradle tasks</em>
-panel, click <strong>Gradle</strong> again.</p>
+on the right side of the IDE window. The <em>Gradle tasks</em> panel appears.</p>
 
-<img src="{@docRoot}images/tools/studio-gradle-panel.png" alt="" />
-<p class="img-caption"><strong>Figure 2.</strong> The list of build tasks in Android Studio.</p>
 
 <h3 id="buildRelease">Build a release version</h3>
 
-<p>You can now build the release version of your application for distribution. To build it from Android
-Studio:</p>
-
-<ol>
-    <li>Click <strong>Gradle</strong> on the right side of the IDE window.</li>
-    <li>On the <em>All tasks</em> section of the sidebar that appears, expand
-        <strong>BuildSystemExample</strong>.</li>
-    <li>Expand <strong>:app</strong> and double-click <strong>assembleRelease</strong>.</li>
-</ol>
-
-<p>You can use this procedure to invoke any build task from Android Studio.</p>
+<p>You can now use the <strong>Build</strong> menu options to build the release version of your
+application for distribution. </p>
 
 <p>The build generates an APK for each build variant:
 the <code>app/build/apk/</code> directory contains packages named
diff --git a/docs/html/tools/building/configuring-gradle.jd b/docs/html/tools/building/configuring-gradle.jd
index 8379508..7cca5b4 100644
--- a/docs/html/tools/building/configuring-gradle.jd
+++ b/docs/html/tools/building/configuring-gradle.jd
@@ -470,7 +470,11 @@
 <li>fullRelease</li>
 </ul>
 
-<p>To build this example, invoke the <code>assemble</code> task from Android Studio or from the
-command line.</p>
+<p>To build this example, click the <strong>Build</strong> menu option in Android Studio or invoke
+the <code>assemble</code> task from the command line. </p>
+
+<p class="note"><strong>Note:</strong> The <strong>Build &gt; Make Project</strong> option compiles
+all the source files in the entire project that have been modified since the last compilation. The
+<strong>Build &gt; Rebuild Project</strong> option recomplies all the source files in the project.</p>
 
 <p>Separate output folders are created for each build variant. </p>
diff --git a/docs/html/tools/building/plugin-for-gradle.jd b/docs/html/tools/building/plugin-for-gradle.jd
index 54a03fd..a497c1b 100644
--- a/docs/html/tools/building/plugin-for-gradle.jd
+++ b/docs/html/tools/building/plugin-for-gradle.jd
@@ -15,7 +15,7 @@
 <li><a href="{@docRoot}sdk/installing/studio-build.html">
 Build System Overview</a></li>
 <li><a href="{@docRoot}tools/building/index.html">
-Buidling and Running</a></li>
+Building and Running</a></li>
 <li><a href="{@docRoot}tools/building/building-studio.html">
 Building and Running from Android Studio</a></li>
 </ul>
@@ -273,16 +273,9 @@
    <dd><p>Performs the clean.</p></dd>
 </dl>
 
-<p>The Android plugin provides additional tasks for <em>connectedCheck</em> and <em>deviceCheck</em>
+<p>The Android plugin provides the <em>connectedCheck</em> and <em>deviceCheck</em> tasks
 for checks run on connected, emulated, and remote devices. Gradle tasks can be viewed by clicking
-the Gradle tab</a> in the right margin.
-<img src="{@docRoot}images/tools/studio-gradle-tab.png"></p>
-<p class="img-caption"><strong>Figure 1:</strong> Gradle tab</p>
-
-<p>Running a top-level task, runs all the dependent tasks. For example, the <em>assemble</em> task
-has dependent tasks for <em>assembleDebug</em> and <em>assembleRelease</em> to make the debug and
-release APKs. The <em>assemble</em> task depends on these tasks so calling it builds both APKs.
-These tasks can also be called independently to build the debug or release APK separately. </p>
+the Gradle tab</a> in the right margin.</p>
 
 <p>You can view the list of available tasks and invoke any task from Android Studio and from
 the command line, as described in
diff --git a/docs/html/tools/help/hierarchy-viewer.jd b/docs/html/tools/help/hierarchy-viewer.jd
index 4a346e0..da4cc1e 100644
--- a/docs/html/tools/help/hierarchy-viewer.jd
+++ b/docs/html/tools/help/hierarchy-viewer.jd
@@ -3,16 +3,27 @@
 parent.link=index.html
 @jd:body
 
-<p>Hierarchy Viewer allows you to debug and optimize your user 
-interface. It provides a visual representation of the layout's View hierarchy 
-(the Layout View) and a magnified inspector of the display (the Pixel Perfect View). 
+<p>The Hierarchy Viewer allows you to debug and optimize your user
+interface. It provides a visual representation of the layout's View hierarchy
+(the Layout View) and a magnified inspector of the display (the Pixel Perfect View). </p>
+
+<p>To start the Hierarchy Viewer, do one of the following: </p>
+
+<ul>
+<li> From Android Studio, choose <strong>Tools &gt; Android Device Monitor</strong> or click the
+Android Device Monitor icon
+<img src="{@docRoot}images/tools/hierarchicalviewer-icon.png" alt=""/>. Click the Open Perspectives
+icon <img src="{@docRoot}images/tools/studio-DDMS-open-perspective-icon.png" alt=""/> and select
+<strong>Hierarchy View</strong>. </li>
+<li>From the SDK <code>tools/</code> directory, enter:
+  <pre>monitor</pre> </li>
+</ul>
+
+<p>For more information on how to use the Hierarchy Viewer, see
+<a href="{@docRoot}tools/debugging/debugging-ui.html">Optimizing Your UI</a>.
 </p>
 
-<p>To start Hierarchy Viewer, enter the following command from the SDK <code>tools/</code> directory:</p>
-  <pre>hierarchyviewer</pre>
-</ol>
+<p class="note"><strong>Note:</strong> The command line version of Hierarchy Viewer has been
+deprecated. </p>
 
-<p>For more information on how to use Hierarchy Viewer, see 
-<a href="{@docRoot}tools/debugging/debugging-ui.html">Debugging and Profiling UIs</a>
-</p>
 
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index be5c52b..e2f7799 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -1568,13 +1568,9 @@
         nativePrepareToDraw(mSkBitmapPtr);
     }
 
-    /**
-     * Refs the underlying SkPixelRef and returns a pointer to it.
-     *
-     * @hide
-     * */
-    public final long refSkPixelRef() {
-        return nativeRefPixelRef(mSkBitmapPtr);
+    /** @hide */
+    public final long getSkBitmap() {
+        return mSkBitmapPtr;
     }
 
     private static class BitmapFinalizer {
@@ -1665,5 +1661,4 @@
     private static native boolean nativeHasMipMap(long nativeBitmap);
     private static native void nativeSetHasMipMap(long nativeBitmap, boolean hasMipMap);
     private static native boolean nativeSameAs(long nativeBitmap0, long nativeBitmap1);
-    private static native long nativeRefPixelRef(long nativeBitmap);
 }
diff --git a/graphics/java/android/graphics/BitmapShader.java b/graphics/java/android/graphics/BitmapShader.java
index bd74bc8..f2f890e 100644
--- a/graphics/java/android/graphics/BitmapShader.java
+++ b/graphics/java/android/graphics/BitmapShader.java
@@ -42,7 +42,8 @@
         mBitmap = bitmap;
         mTileX = tileX;
         mTileY = tileY;
-        init(nativeCreate(bitmap, tileX.nativeInt, tileY.nativeInt));
+        final long b = bitmap.getSkBitmap();
+        init(nativeCreate(b, tileX.nativeInt, tileY.nativeInt));
     }
 
     /**
@@ -55,6 +56,6 @@
         return copy;
     }
 
-    private static native long nativeCreate(Bitmap bitmap, int shaderTileModeX,
+    private static native long nativeCreate(long native_bitmap, int shaderTileModeX,
             int shaderTileModeY);
 }
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 1c56884..48afcbf 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -81,6 +81,10 @@
      */
     protected int mScreenDensity = Bitmap.DENSITY_NONE;
 
+    // Used by native code
+    @SuppressWarnings("UnusedDeclaration")
+    private int mSurfaceFormat;
+
     /**
      * Flag for drawTextRun indicating left-to-right run direction.
      * @hide
@@ -133,7 +137,7 @@
     public Canvas() {
         if (!isHardwareAccelerated()) {
             // 0 means no native bitmap
-            mNativeCanvasWrapper = initRaster(null);
+            mNativeCanvasWrapper = initRaster(0);
             mFinalizer = new CanvasFinalizer(mNativeCanvasWrapper);
         } else {
             mFinalizer = null;
@@ -154,7 +158,7 @@
             throw new IllegalStateException("Immutable bitmap passed to Canvas constructor");
         }
         throwIfCannotDraw(bitmap);
-        mNativeCanvasWrapper = initRaster(bitmap);
+        mNativeCanvasWrapper = initRaster(bitmap.getSkBitmap());
         mFinalizer = new CanvasFinalizer(mNativeCanvasWrapper);
         mBitmap = bitmap;
         mDensity = bitmap.mDensity;
@@ -211,7 +215,7 @@
         }
 
         if (bitmap == null) {
-            native_setBitmap(mNativeCanvasWrapper, null);
+            native_setBitmap(mNativeCanvasWrapper, 0, false);
             mDensity = Bitmap.DENSITY_NONE;
         } else {
             if (!bitmap.isMutable()) {
@@ -219,7 +223,7 @@
             }
             throwIfCannotDraw(bitmap);
 
-            native_setBitmap(mNativeCanvasWrapper, bitmap);
+            native_setBitmap(mNativeCanvasWrapper, bitmap.getSkBitmap(), true);
             mDensity = bitmap.mDensity;
         }
 
@@ -227,6 +231,13 @@
     }
 
     /**
+     * setBitmap() variant for native callers with a raw bitmap handle.
+     */
+    private void setNativeBitmap(long bitmapHandle) {
+        native_setBitmap(mNativeCanvasWrapper, bitmapHandle, false);
+    }
+
+    /**
      * Set the viewport dimensions if this canvas is GL based. If it is not,
      * this method is ignored and no exception is thrown.
      *
@@ -1335,7 +1346,7 @@
      */
     public void drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint) {
         throwIfCannotDraw(bitmap);
-        native_drawBitmap(mNativeCanvasWrapper, bitmap, left, top,
+        native_drawBitmap(mNativeCanvasWrapper, bitmap.getSkBitmap(), left, top,
                 paint != null ? paint.getNativeInstance() : 0, mDensity, mScreenDensity, bitmap.mDensity);
     }
 
@@ -1381,7 +1392,7 @@
           bottom = src.bottom;
       }
 
-      native_drawBitmap(mNativeCanvasWrapper, bitmap, left, top, right, bottom,
+      native_drawBitmap(mNativeCanvasWrapper, bitmap.getSkBitmap(), left, top, right, bottom,
               dst.left, dst.top, dst.right, dst.bottom, nativePaint, mScreenDensity,
               bitmap.mDensity);
   }
@@ -1428,7 +1439,7 @@
             bottom = src.bottom;
         }
 
-        native_drawBitmap(mNativeCanvasWrapper, bitmap, left, top, right, bottom,
+        native_drawBitmap(mNativeCanvasWrapper, bitmap.getSkBitmap(), left, top, right, bottom,
             dst.left, dst.top, dst.right, dst.bottom, nativePaint, mScreenDensity,
             bitmap.mDensity);
     }
@@ -1509,7 +1520,7 @@
      * @param paint  May be null. The paint used to draw the bitmap
      */
     public void drawBitmap(@NonNull Bitmap bitmap, @NonNull Matrix matrix, @Nullable Paint paint) {
-        nativeDrawBitmapMatrix(mNativeCanvasWrapper, bitmap, matrix.ni(),
+        nativeDrawBitmapMatrix(mNativeCanvasWrapper, bitmap.getSkBitmap(), matrix.ni(),
                 paint != null ? paint.getNativeInstance() : 0);
     }
 
@@ -1564,7 +1575,7 @@
             // no mul by 2, since we need only 1 color per vertex
             checkRange(colors.length, colorOffset, count);
         }
-        nativeDrawBitmapMesh(mNativeCanvasWrapper, bitmap, meshWidth, meshHeight,
+        nativeDrawBitmapMesh(mNativeCanvasWrapper, bitmap.getSkBitmap(), meshWidth, meshHeight,
                 verts, vertOffset, colors, colorOffset,
                 paint != null ? paint.getNativeInstance() : 0);
     }
@@ -1965,9 +1976,10 @@
      */
     public static native void freeTextLayoutCaches();
 
-    private static native long initRaster(Bitmap bitmap);
+    private static native long initRaster(long nativeBitmapOrZero);
     private static native void native_setBitmap(long canvasHandle,
-                                                Bitmap bitmap);
+                                                long bitmapHandle,
+                                                boolean copyState);
     private static native boolean native_isOpaque(long canvasHandle);
     private static native int native_getWidth(long canvasHandle);
     private static native int native_getHeight(long canvasHandle);
@@ -2052,13 +2064,13 @@
     private static native void native_drawPath(long nativeCanvas,
                                                long nativePath,
                                                long nativePaint);
-    private native void native_drawBitmap(long nativeCanvas, Bitmap bitmap,
+    private native void native_drawBitmap(long nativeCanvas, long nativeBitmap,
                                                  float left, float top,
                                                  long nativePaintOrZero,
                                                  int canvasDensity,
                                                  int screenDensity,
                                                  int bitmapDensity);
-    private native void native_drawBitmap(long nativeCanvas, Bitmap bitmap,
+    private native void native_drawBitmap(long nativeCanvas, long nativeBitmap,
             float srcLeft, float srcTop, float srcRight, float srcBottom,
             float dstLeft, float dstTop, float dstRight, float dstBottom,
             long nativePaintOrZero, int screenDensity, int bitmapDensity);
@@ -2068,11 +2080,11 @@
                                                  boolean hasAlpha,
                                                  long nativePaintOrZero);
     private static native void nativeDrawBitmapMatrix(long nativeCanvas,
-                                                      Bitmap bitmap,
+                                                      long nativeBitmap,
                                                       long nativeMatrix,
                                                       long nativePaint);
     private static native void nativeDrawBitmapMesh(long nativeCanvas,
-                                                    Bitmap bitmap,
+                                                    long nativeBitmap,
                                                     int meshWidth, int meshHeight,
                                                     float[] verts, int vertOffset,
                                                     int[] colors, int colorOffset,
diff --git a/graphics/java/android/graphics/NinePatch.java b/graphics/java/android/graphics/NinePatch.java
index 21a212a..9c4299a 100644
--- a/graphics/java/android/graphics/NinePatch.java
+++ b/graphics/java/android/graphics/NinePatch.java
@@ -98,7 +98,7 @@
     public NinePatch(Bitmap bitmap, byte[] chunk, String srcName) {
         mBitmap = bitmap;
         mSrcName = srcName;
-        mNativeChunk = validateNinePatchChunk(chunk);
+        mNativeChunk = validateNinePatchChunk(mBitmap.getSkBitmap(), chunk);
     }
 
     /**
@@ -199,12 +199,12 @@
     }
 
     void drawSoftware(Canvas canvas, RectF location, Paint paint) {
-        nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap, mNativeChunk,
+        nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap.getSkBitmap(), mNativeChunk,
                 paint != null ? paint.getNativeInstance() : 0, canvas.mDensity, mBitmap.mDensity);
     }
 
     void drawSoftware(Canvas canvas, Rect location, Paint paint) {
-        nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap, mNativeChunk,
+        nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap.getSkBitmap(), mNativeChunk,
                 paint != null ? paint.getNativeInstance() : 0, canvas.mDensity, mBitmap.mDensity);
     }
 
@@ -252,7 +252,7 @@
      * that are transparent.
      */
     public final Region getTransparentRegion(Rect bounds) {
-        long r = nativeGetTransparentRegion(mBitmap, mNativeChunk, bounds);
+        long r = nativeGetTransparentRegion(mBitmap.getSkBitmap(), mNativeChunk, bounds);
         return r != 0 ? new Region(r) : null;
     }
 
@@ -271,11 +271,11 @@
      * If validation is successful, this method returns a native Res_png_9patch*
      * object used by the renderers.
      */
-    private static native long validateNinePatchChunk(byte[] chunk);
+    private static native long validateNinePatchChunk(long bitmap, byte[] chunk);
     private static native void nativeFinalize(long chunk);
-    private static native void nativeDraw(long canvas_instance, RectF loc, Bitmap bitmap_instance,
+    private static native void nativeDraw(long canvas_instance, RectF loc, long bitmap_instance,
             long c, long paint_instance_or_null, int destDensity, int srcDensity);
-    private static native void nativeDraw(long canvas_instance, Rect loc, Bitmap bitmap_instance,
+    private static native void nativeDraw(long canvas_instance, Rect loc, long bitmap_instance,
             long c, long paint_instance_or_null, int destDensity, int srcDensity);
-    private static native long nativeGetTransparentRegion(Bitmap bitmap, long chunk, Rect location);
+    private static native long nativeGetTransparentRegion(long bitmap, long chunk, Rect location);
 }
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index e8b8c77..22ff3e74 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -572,7 +572,7 @@
      * Specifies a tint blending mode for this drawable.
      * <p>
      * Defines how this drawable's tint color should be blended into the drawable
-     * before it is drawn to screen. Default tint mode is {@link PorterDuff.Mode#MULTIPLY}.
+     * before it is drawn to screen. Default tint mode is {@link PorterDuff.Mode#SRC_IN}.
      * </p>
      * <p class="note"><strong>Note:</strong> Setting a color filter via
      * {@link #setColorFilter(ColorFilter)} or
diff --git a/libs/hwui/AssetAtlas.cpp b/libs/hwui/AssetAtlas.cpp
index 882826e..4d2e3a0 100644
--- a/libs/hwui/AssetAtlas.cpp
+++ b/libs/hwui/AssetAtlas.cpp
@@ -82,12 +82,12 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 AssetAtlas::Entry* AssetAtlas::getEntry(const SkBitmap* bitmap) const {
-    ssize_t index = mEntries.indexOfKey(bitmap->pixelRef());
+    ssize_t index = mEntries.indexOfKey(bitmap);
     return index >= 0 ? mEntries.valueAt(index) : nullptr;
 }
 
 Texture* AssetAtlas::getEntryTexture(const SkBitmap* bitmap) const {
-    ssize_t index = mEntries.indexOfKey(bitmap->pixelRef());
+    ssize_t index = mEntries.indexOfKey(bitmap);
     return index >= 0 ? mEntries.valueAt(index)->texture : nullptr;
 }
 
@@ -120,7 +120,7 @@
     const float height = float(mTexture->height);
 
     for (int i = 0; i < count; ) {
-        SkPixelRef* pixelRef = reinterpret_cast<SkPixelRef*>(map[i++]);
+        SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(map[i++]);
         // NOTE: We're converting from 64 bit signed values to 32 bit
         // signed values. This is guaranteed to be safe because the "x"
         // and "y" coordinate values are guaranteed to be representable
@@ -131,21 +131,21 @@
         bool rotated = map[i++] > 0;
 
         // Bitmaps should never be null, we're just extra paranoid
-        if (!pixelRef) continue;
+        if (!bitmap) continue;
 
         const UvMapper mapper(
-                x / width, (x + pixelRef->info().width()) / width,
-                y / height, (y + pixelRef->info().height()) / height);
+                x / width, (x + bitmap->width()) / width,
+                y / height, (y + bitmap->height()) / height);
 
         Texture* texture = new DelegateTexture(caches, mTexture);
-        texture->blend = !SkAlphaTypeIsOpaque(pixelRef->info().alphaType());
-        texture->width = pixelRef->info().width();
-        texture->height = pixelRef->info().height();
+        texture->blend = !bitmap->isOpaque();
+        texture->width = bitmap->width();
+        texture->height = bitmap->height();
 
-        Entry* entry = new Entry(pixelRef, x, y, rotated, texture, mapper, *this);
+        Entry* entry = new Entry(bitmap, x, y, rotated, texture, mapper, *this);
         texture->uvMapper = &entry->uvMapper;
 
-        mEntries.add(entry->pixelRef, entry);
+        mEntries.add(entry->bitmap, entry);
     }
 }
 
diff --git a/libs/hwui/AssetAtlas.h b/libs/hwui/AssetAtlas.h
index 17c5281..1772eff 100644
--- a/libs/hwui/AssetAtlas.h
+++ b/libs/hwui/AssetAtlas.h
@@ -48,8 +48,24 @@
      * Entry representing the position and rotation of a
      * bitmap inside the atlas.
      */
-    class Entry {
-    public:
+    struct Entry {
+        /**
+         * The bitmap that generated this atlas entry.
+         */
+        SkBitmap* bitmap;
+
+        /**
+         * Location of the bitmap inside the atlas, in pixels.
+         */
+        int x;
+        int y;
+
+        /**
+         * If set, the bitmap is rotated 90 degrees (clockwise)
+         * inside the atlas.
+         */
+        bool rotated;
+
         /*
          * A "virtual texture" object that represents the texture
          * this entry belongs to. This texture should never be
@@ -64,6 +80,11 @@
         const UvMapper uvMapper;
 
         /**
+         * Atlas this entry belongs to.
+         */
+        const AssetAtlas& atlas;
+
+        /**
          * Unique identifier used to merge bitmaps and 9-patches stored
          * in the atlas.
          */
@@ -72,37 +93,10 @@
         }
 
     private:
-        /**
-         * The pixel ref that generated this atlas entry.
-         */
-        SkPixelRef* pixelRef;
-
-        /**
-         * Location of the bitmap inside the atlas, in pixels.
-         */
-        int x;
-        int y;
-
-        /**
-         * If set, the bitmap is rotated 90 degrees (clockwise)
-         * inside the atlas.
-         */
-        bool rotated;
-
-        /**
-         * Atlas this entry belongs to.
-         */
-        const AssetAtlas& atlas;
-
-        Entry(SkPixelRef* pixelRef, int x, int y, bool rotated,
-                    Texture* texture, const UvMapper& mapper, const AssetAtlas& atlas)
-                : texture(texture)
-                , uvMapper(mapper)
-                , pixelRef(pixelRef)
-                , x(x)
-                , y(y)
-                , rotated(rotated)
-                , atlas(atlas) {
+        Entry(SkBitmap* bitmap, int x, int y, bool rotated,
+                Texture* texture, const UvMapper& mapper, const AssetAtlas& atlas):
+                bitmap(bitmap), x(x), y(y), rotated(rotated),
+                texture(texture), uvMapper(mapper), atlas(atlas) {
         }
 
         ~Entry() {
@@ -184,7 +178,7 @@
     const bool mBlendKey;
     const bool mOpaqueKey;
 
-    KeyedVector<const SkPixelRef*, Entry*> mEntries;
+    KeyedVector<const SkBitmap*, Entry*> mEntries;
 }; // class AssetAtlas
 
 }; // namespace uirenderer
diff --git a/libs/hwui/Canvas.h b/libs/hwui/Canvas.h
index aa24673..7ad0683 100644
--- a/libs/hwui/Canvas.h
+++ b/libs/hwui/Canvas.h
@@ -29,7 +29,7 @@
 public:
     virtual ~Canvas() {};
 
-    static Canvas* create_canvas(const SkBitmap& bitmap);
+    static Canvas* create_canvas(SkBitmap* bitmap);
 
     /**
      *  Create a new Canvas object which delegates to an SkCanvas.
@@ -52,7 +52,7 @@
      */
     virtual SkCanvas* asSkCanvas() = 0;
 
-    virtual void setBitmap(const SkBitmap& bitmap) = 0;
+    virtual void setBitmap(SkBitmap* bitmap, bool copyState) = 0;
 
     virtual bool isOpaque() = 0;
     virtual int width() = 0;
@@ -87,8 +87,7 @@
     virtual bool quickRejectRect(float left, float top, float right, float bottom) const = 0;
     virtual bool quickRejectPath(const SkPath& path) const = 0;
 
-    virtual bool clipRect(float left, float top, float right, float bottom,
-            SkRegion::Op op = SkRegion::kIntersect_Op) = 0;
+    virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op) = 0;
     virtual bool clipPath(const SkPath* path, SkRegion::Op op) = 0;
     virtual bool clipRegion(const SkRegion* region, SkRegion::Op op) = 0;
 
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 4d596fe..8757e15 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -220,7 +220,7 @@
 }
 
 void DisplayListRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
-    bitmap = refBitmap(*bitmap);
+    bitmap = refBitmap(bitmap);
     paint = refPaint(paint);
 
     addDrawOp(new (alloc()) DrawBitmapOp(bitmap, paint));
@@ -286,7 +286,7 @@
                 dstRight = srcRight - srcLeft;
                 dstBottom = srcBottom - srcTop;
 
-                addDrawOp(new (alloc()) DrawBitmapRectOp(refBitmap(bitmap),
+                addDrawOp(new (alloc()) DrawBitmapRectOp(refBitmap(&bitmap),
                         srcLeft, srcTop, srcRight, srcBottom,
                         dstLeft, dstTop, dstRight, dstBottom, paint));
                 restore();
@@ -294,7 +294,7 @@
             }
         }
 
-        addDrawOp(new (alloc()) DrawBitmapRectOp(refBitmap(bitmap),
+        addDrawOp(new (alloc()) DrawBitmapRectOp(refBitmap(&bitmap),
                 srcLeft, srcTop, srcRight, srcBottom,
                 dstLeft, dstTop, dstRight, dstBottom, paint));
     }
@@ -307,17 +307,17 @@
     paint = refPaint(paint);
     colors = refBuffer<int>(colors, vertexCount); // 1 color per vertex
 
-    addDrawOp(new (alloc()) DrawBitmapMeshOp(refBitmap(bitmap), meshWidth, meshHeight,
+    addDrawOp(new (alloc()) DrawBitmapMeshOp(refBitmap(&bitmap), meshWidth, meshHeight,
            vertices, colors, paint));
 }
 
-void DisplayListRenderer::drawPatch(const SkBitmap& bitmap, const Res_png_9patch* patch,
+void DisplayListRenderer::drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
         float left, float top, float right, float bottom, const SkPaint* paint) {
-    const SkBitmap* bitmapPtr = refBitmap(bitmap);
+    bitmap = refBitmap(bitmap);
     patch = refPatch(patch);
     paint = refPaint(paint);
 
-    addDrawOp(new (alloc()) DrawPatchOp(bitmapPtr, patch, left, top, right, bottom, paint));
+    addDrawOp(new (alloc()) DrawPatchOp(bitmap, patch, left, top, right, bottom, paint));
 }
 
 void DisplayListRenderer::drawColor(int color, SkXfermode::Mode mode) {
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 44cf546..53fd1ad 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -100,7 +100,7 @@
     // Bitmap-based
     void drawBitmap(const SkBitmap* bitmap, const SkPaint* paint);
     // TODO: move drawPatch() to Canvas.h
-    void drawPatch(const SkBitmap& bitmap, const Res_png_9patch* patch,
+    void drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
             float left, float top, float right, float bottom, const SkPaint* paint);
 
     // Shapes
@@ -138,7 +138,7 @@
 // ----------------------------------------------------------------------------
     virtual SkCanvas* asSkCanvas() override;
 
-    virtual void setBitmap(const SkBitmap& bitmap) override {
+    virtual void setBitmap(SkBitmap* bitmap, bool copyState) override {
         LOG_ALWAYS_FATAL("DisplayListRenderer is not backed by a bitmap.");
     }
 
@@ -347,7 +347,7 @@
         return cachedRegion;
     }
 
-    inline const SkBitmap* refBitmap(const SkBitmap& bitmap) {
+    inline const SkBitmap* refBitmap(const SkBitmap* bitmap) {
         // Note that this assumes the bitmap is immutable. There are cases this won't handle
         // correctly, such as creating the bitmap from scratch, drawing with it, changing its
         // contents, and drawing again. The only fix would be to always copy it the first time,
diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp
index 454fedc..d3b8d70 100644
--- a/libs/hwui/ResourceCache.cpp
+++ b/libs/hwui/ResourceCache.cpp
@@ -59,13 +59,13 @@
     mLock.unlock();
 }
 
-const SkBitmap* ResourceCache::insert(const SkBitmap& bitmapResource) {
+const SkBitmap* ResourceCache::insert(const SkBitmap* bitmapResource) {
     Mutex::Autolock _l(mLock);
 
     BitmapKey bitmapKey(bitmapResource);
     ssize_t index = mBitmapCache.indexOfKey(bitmapKey);
     if (index == NAME_NOT_FOUND) {
-        SkBitmap* cachedBitmap = new SkBitmap(bitmapResource);
+        SkBitmap* cachedBitmap = new SkBitmap(*bitmapResource);
         index = mBitmapCache.add(bitmapKey, cachedBitmap);
         return cachedBitmap;
     }
@@ -121,7 +121,7 @@
 }
 
 void ResourceCache::decrementRefcountLocked(const SkBitmap* bitmapResource) {
-    BitmapKey bitmapKey(*bitmapResource);
+    BitmapKey bitmapKey(bitmapResource);
     ssize_t index = mBitmapCache.indexOfKey(bitmapKey);
 
     LOG_ALWAYS_FATAL_IF(index == NAME_NOT_FOUND,
diff --git a/libs/hwui/ResourceCache.h b/libs/hwui/ResourceCache.h
index 6c483fa..fae55d1 100644
--- a/libs/hwui/ResourceCache.h
+++ b/libs/hwui/ResourceCache.h
@@ -53,11 +53,11 @@
 
 class BitmapKey {
 public:
-    BitmapKey(const SkBitmap& bitmap)
+    BitmapKey(const SkBitmap* bitmap)
         : mRefCount(1)
-        , mBitmapDimensions(bitmap.dimensions())
-        , mPixelRefOrigin(bitmap.pixelRefOrigin())
-        , mPixelRefStableID(bitmap.pixelRef()->getStableID()) { }
+        , mBitmapDimensions(bitmap->dimensions())
+        , mPixelRefOrigin(bitmap->pixelRefOrigin())
+        , mPixelRefStableID(bitmap->pixelRef()->getStableID()) { }
 
     void operator=(const BitmapKey& other);
     bool operator==(const BitmapKey& other) const;
@@ -101,7 +101,7 @@
      * The cache stores a copy of the provided resource or refs an existing resource
      * if the bitmap has previously been inserted and returns the cached copy.
      */
-    const SkBitmap* insert(const SkBitmap& resource);
+    const SkBitmap* insert(const SkBitmap* resource);
 
     void incrementRefcount(const Res_png_9patch* resource);
 
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index a323065..8b11757 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -31,7 +31,7 @@
 // Holds an SkCanvas reference plus additional native data.
 class SkiaCanvas : public Canvas {
 public:
-    explicit SkiaCanvas(const SkBitmap& bitmap);
+    explicit SkiaCanvas(SkBitmap* bitmap);
 
     /**
      *  Create a new SkiaCanvas.
@@ -49,7 +49,7 @@
         return mCanvas.get();
     }
 
-    virtual void setBitmap(const SkBitmap& bitmap) override;
+    virtual void setBitmap(SkBitmap* bitmap, bool copyState) override;
 
     virtual bool isOpaque() override;
     virtual int width() override;
@@ -145,7 +145,19 @@
     SkAutoTDelete<SkDeque> mSaveStack; // lazily allocated, tracks partial saves.
 };
 
-Canvas* Canvas::create_canvas(const SkBitmap& bitmap) {
+// Construct an SkCanvas from the bitmap.
+static SkCanvas* createCanvas(SkBitmap* bitmap) {
+    if (bitmap) {
+        return SkNEW_ARGS(SkCanvas, (*bitmap));
+    }
+
+    // Create an empty bitmap device to prevent callers from crashing
+    // if they attempt to draw into this canvas.
+    SkBitmap emptyBitmap;
+    return new SkCanvas(emptyBitmap);
+}
+
+Canvas* Canvas::create_canvas(SkBitmap* bitmap) {
     return new SkiaCanvas(bitmap);
 }
 
@@ -153,8 +165,8 @@
     return new SkiaCanvas(skiaCanvas);
 }
 
-SkiaCanvas::SkiaCanvas(const SkBitmap& bitmap) {
-    mCanvas.reset(new SkCanvas(bitmap));
+SkiaCanvas::SkiaCanvas(SkBitmap* bitmap) {
+    mCanvas.reset(createCanvas(bitmap));
 }
 
 // ----------------------------------------------------------------------------
@@ -179,11 +191,11 @@
     SkCanvas* m_dstCanvas;
 };
 
-void SkiaCanvas::setBitmap(const SkBitmap& bitmap) {
-    SkCanvas* newCanvas = new SkCanvas(bitmap);
+void SkiaCanvas::setBitmap(SkBitmap* bitmap, bool copyState) {
+    SkCanvas* newCanvas = createCanvas(bitmap);
     SkASSERT(newCanvas);
 
-    if (!bitmap.isNull()) {
+    if (copyState) {
         // Copy the canvas matrix & clip state.
         newCanvas->setMatrix(mCanvas->getTotalMatrix());
         if (NULL != mCanvas->getDevice() && NULL != newCanvas->getDevice()) {
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index d15fa39..cc87241 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -293,11 +293,11 @@
     return (void*) success;
 }
 
-bool RenderProxy::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap& bitmap) {
+bool RenderProxy::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
     SETUP_TASK(copyLayerInto);
     args->context = mContext;
     args->layer = layer;
-    args->bitmap = &bitmap;
+    args->bitmap = bitmap;
     return (bool) postAndWait(task);
 }
 
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index cc475fa..29c6f08 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -83,7 +83,7 @@
 
     ANDROID_API DeferredLayerUpdater* createTextureLayer();
     ANDROID_API void buildLayer(RenderNode* node);
-    ANDROID_API bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap& bitmap);
+    ANDROID_API bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
     ANDROID_API void pushLayerUpdate(DeferredLayerUpdater* layer);
     ANDROID_API void cancelLayerUpdate(DeferredLayerUpdater* layer);
     ANDROID_API void detachSurfaceTexture(DeferredLayerUpdater* layer);
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 9e1e055..3e771f4 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -901,21 +901,48 @@
      *    the parameters don't resolve to valid data and indexes.
      *    The number of bytes will not exceed sizeInBytes.
      */
-    public int read(byte[] audioData, int offsetInBytes, int sizeInBytes) {
-        if (mState != STATE_INITIALIZED) {
+    public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes) {
+        return read(audioData, offsetInBytes, sizeInBytes, READ_BLOCKING);
+    }
+
+    /**
+     * Reads audio data from the audio hardware for recording into a byte array.
+     * The format specified in the AudioRecord constructor should be
+     * {@link AudioFormat#ENCODING_PCM_8BIT} to correspond to the data in the array.
+     * @param audioData the array to which the recorded audio data is written.
+     * @param offsetInBytes index in audioData from which the data is written expressed in bytes.
+     * @param sizeInBytes the number of requested bytes.
+     * @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}.
+     *     <br>With {@link #READ_BLOCKING}, the read will block until all the requested data
+     *     is read.
+     *     <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after
+     *     reading as much audio data as possible without blocking.
+     * @return the number of bytes that were read or {@link #ERROR_INVALID_OPERATION}
+     *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
+     *    the parameters don't resolve to valid data and indexes.
+     *    The number of bytes will not exceed sizeInBytes.
+     */
+    public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes,
+            @ReadMode int readMode) {
+        if (mState != STATE_INITIALIZED  || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
             return ERROR_INVALID_OPERATION;
         }
 
+        if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) {
+            Log.e(TAG, "AudioRecord.read() called with invalid blocking mode");
+            return ERROR_BAD_VALUE;
+        }
+
         if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0)
                 || (offsetInBytes + sizeInBytes < 0)  // detect integer overflow
                 || (offsetInBytes + sizeInBytes > audioData.length)) {
             return ERROR_BAD_VALUE;
         }
 
-        return native_read_in_byte_array(audioData, offsetInBytes, sizeInBytes);
+        return native_read_in_byte_array(audioData, offsetInBytes, sizeInBytes,
+                readMode == READ_BLOCKING);
     }
 
-
     /**
      * Reads audio data from the audio hardware for recording into a short array.
      * The format specified in the AudioRecord constructor should be
@@ -928,18 +955,46 @@
      *    the parameters don't resolve to valid data and indexes.
      *    The number of shorts will not exceed sizeInShorts.
      */
-    public int read(short[] audioData, int offsetInShorts, int sizeInShorts) {
-        if (mState != STATE_INITIALIZED) {
+    public int read(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts) {
+        return read(audioData, offsetInShorts, sizeInShorts, READ_BLOCKING);
+    }
+
+    /**
+     * Reads audio data from the audio hardware for recording into a short array.
+     * The format specified in the AudioRecord constructor should be
+     * {@link AudioFormat#ENCODING_PCM_16BIT} to correspond to the data in the array.
+     * @param audioData the array to which the recorded audio data is written.
+     * @param offsetInShorts index in audioData from which the data is written expressed in shorts.
+     * @param sizeInShorts the number of requested shorts.
+     * @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}.
+     *     <br>With {@link #READ_BLOCKING}, the read will block until all the requested data
+     *     is read.
+     *     <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after
+     *     reading as much audio data as possible without blocking.
+     * @return the number of shorts that were read or {@link #ERROR_INVALID_OPERATION}
+     *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
+     *    the parameters don't resolve to valid data and indexes.
+     *    The number of shorts will not exceed sizeInShorts.
+     */
+    public int read(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts,
+            @ReadMode int readMode) {
+        if (mState != STATE_INITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
             return ERROR_INVALID_OPERATION;
         }
 
+        if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) {
+            Log.e(TAG, "AudioRecord.read() called with invalid blocking mode");
+            return ERROR_BAD_VALUE;
+        }
+
         if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0)
                 || (offsetInShorts + sizeInShorts < 0)  // detect integer overflow
                 || (offsetInShorts + sizeInShorts > audioData.length)) {
             return ERROR_BAD_VALUE;
         }
 
-        return native_read_in_short_array(audioData, offsetInShorts, sizeInShorts);
+        return native_read_in_short_array(audioData, offsetInShorts, sizeInShorts,
+                readMode == READ_BLOCKING);
     }
 
     /**
@@ -950,22 +1005,33 @@
      * @param offsetInFloats index in audioData from which the data is written.
      * @param sizeInFloats the number of requested floats.
      * @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}.
-     *     <BR>With {@link #READ_BLOCKING}, the read will block until all the requested data
+     *     <br>With {@link #READ_BLOCKING}, the read will block until all the requested data
      *     is read.
-     *     <BR>With {@link #READ_NON_BLOCKING}, the read will return immediately after
+     *     <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after
      *     reading as much audio data as possible without blocking.
      * @return the number of floats that were read or {@link #ERROR_INVALID_OPERATION}
      *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
      *    the parameters don't resolve to valid data and indexes.
      *    The number of floats will not exceed sizeInFloats.
      */
-    public int read(float[] audioData, int offsetInFloats, int sizeInFloats,
+    public int read(@NonNull float[] audioData, int offsetInFloats, int sizeInFloats,
             @ReadMode int readMode) {
-        if (mState != STATE_INITIALIZED) {
+        if (mState == STATE_UNINITIALIZED) {
+            Log.e(TAG, "AudioRecord.read() called in invalid state STATE_UNINITIALIZED");
             return ERROR_INVALID_OPERATION;
         }
 
-        if ( (audioData == null) || (offsetInFloats < 0 ) || (sizeInFloats < 0)
+        if (mAudioFormat != AudioFormat.ENCODING_PCM_FLOAT) {
+            Log.e(TAG, "AudioRecord.read(float[] ...) requires format ENCODING_PCM_FLOAT");
+            return ERROR_INVALID_OPERATION;
+        }
+
+        if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) {
+            Log.e(TAG, "AudioRecord.read() called with invalid blocking mode");
+            return ERROR_BAD_VALUE;
+        }
+
+        if ((audioData == null) || (offsetInFloats < 0) || (sizeInFloats < 0)
                 || (offsetInFloats + sizeInFloats < 0)  // detect integer overflow
                 || (offsetInFloats + sizeInFloats > audioData.length)) {
             return ERROR_BAD_VALUE;
@@ -992,19 +1058,49 @@
      *    The number of bytes will not exceed sizeInBytes.
      *    The number of bytes read will truncated to be a multiple of the frame size.
      */
-    public int read(ByteBuffer audioBuffer, int sizeInBytes) {
+    public int read(@NonNull ByteBuffer audioBuffer, int sizeInBytes) {
+        return read(audioBuffer, sizeInBytes, READ_BLOCKING);
+    }
+
+    /**
+     * Reads audio data from the audio hardware for recording into a direct buffer. If this buffer
+     * is not a direct buffer, this method will always return 0.
+     * Note that the value returned by {@link java.nio.Buffer#position()} on this buffer is
+     * unchanged after a call to this method.
+     * The representation of the data in the buffer will depend on the format specified in
+     * the AudioRecord constructor, and will be native endian.
+     * @param audioBuffer the direct buffer to which the recorded audio data is written.
+     * @param sizeInBytes the number of requested bytes. It is recommended but not enforced
+     *    that the number of bytes requested be a multiple of the frame size (sample size in
+     *    bytes multiplied by the channel count).
+     * @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}.
+     *     <br>With {@link #READ_BLOCKING}, the read will block until all the requested data
+     *     is read.
+     *     <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after
+     *     reading as much audio data as possible without blocking.
+     * @return the number of bytes that were read or {@link #ERROR_INVALID_OPERATION}
+     *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
+     *    the parameters don't resolve to valid data and indexes.
+     *    The number of bytes will not exceed sizeInBytes.
+     *    The number of bytes read will truncated to be a multiple of the frame size.
+     */
+    public int read(@NonNull ByteBuffer audioBuffer, int sizeInBytes, @ReadMode int readMode) {
         if (mState != STATE_INITIALIZED) {
             return ERROR_INVALID_OPERATION;
         }
 
+        if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) {
+            Log.e(TAG, "AudioRecord.read() called with invalid blocking mode");
+            return ERROR_BAD_VALUE;
+        }
+
         if ( (audioBuffer == null) || (sizeInBytes < 0) ) {
             return ERROR_BAD_VALUE;
         }
 
-        return native_read_in_direct_buffer(audioBuffer, sizeInBytes);
+        return native_read_in_direct_buffer(audioBuffer, sizeInBytes, readMode == READ_BLOCKING);
     }
 
-
     //--------------------------------------------------------------------------
     // Initialization / configuration
     //--------------------
@@ -1186,15 +1282,16 @@
     private native final void native_stop();
 
     private native final int native_read_in_byte_array(byte[] audioData,
-            int offsetInBytes, int sizeInBytes);
+            int offsetInBytes, int sizeInBytes, boolean isBlocking);
 
     private native final int native_read_in_short_array(short[] audioData,
-            int offsetInShorts, int sizeInShorts);
+            int offsetInShorts, int sizeInShorts, boolean isBlocking);
 
     private native final int native_read_in_float_array(float[] audioData,
             int offsetInFloats, int sizeInFloats, boolean isBlocking);
 
-    private native final int native_read_in_direct_buffer(Object jBuffer, int sizeInBytes);
+    private native final int native_read_in_direct_buffer(Object jBuffer,
+            int sizeInBytes, boolean isBlocking);
 
     private native final int native_get_native_frame_count();
 
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 6c41a2a..44455fa 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -1540,6 +1540,8 @@
     /**
      * Writes the audio data to the audio sink for playback (streaming mode),
      * or copies audio data for later playback (static buffer mode).
+     * The format specified in the AudioTrack constructor should be
+     * {@link AudioFormat#ENCODING_PCM_8BIT} to correspond to the data in the array.
      * In streaming mode, will block until all data has been written to the audio sink.
      * In static buffer mode, copies the data to the buffer starting at offset 0.
      * Note that the actual playback of this data might occur after this function
@@ -1556,13 +1558,49 @@
      *    {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
      *    needs to be recreated.
      */
+    public int write(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes) {
+        return write(audioData, offsetInBytes, sizeInBytes, WRITE_BLOCKING);
+    }
 
-    public int write(byte[] audioData, int offsetInBytes, int sizeInBytes) {
+    /**
+     * Writes the audio data to the audio sink for playback (streaming mode),
+     * or copies audio data for later playback (static buffer mode).
+     * The format specified in the AudioTrack constructor should be
+     * {@link AudioFormat#ENCODING_PCM_8BIT} to correspond to the data in the array.
+     * In streaming mode, will block until all data has been written to the audio sink.
+     * In static buffer mode, copies the data to the buffer starting at offset 0.
+     * Note that the actual playback of this data might occur after this function
+     * returns. This function is thread safe with respect to {@link #stop} calls,
+     * in which case all of the specified data might not be written to the audio sink.
+     *
+     * @param audioData the array that holds the data to play.
+     * @param offsetInBytes the offset expressed in bytes in audioData where the data to play
+     *    starts.
+     * @param sizeInBytes the number of bytes to read in audioData after the offset.
+     * @param writeMode one of {@link #WRITE_BLOCKING}, {@link #WRITE_NON_BLOCKING}. It has no
+     *     effect in static mode.
+     *     <br>With {@link #WRITE_BLOCKING}, the write will block until all data has been written
+     *         to the audio sink.
+     *     <br>With {@link #WRITE_NON_BLOCKING}, the write will return immediately after
+     *     queuing as much audio data for playback as possible without blocking.
+     * @return the number of bytes that were written or {@link #ERROR_INVALID_OPERATION}
+     *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
+     *    the parameters don't resolve to valid data and indexes, or
+     *    {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
+     *    needs to be recreated.
+     */
+    public int write(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes,
+            @WriteMode int writeMode) {
 
         if (mState == STATE_UNINITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
             return ERROR_INVALID_OPERATION;
         }
 
+        if ((writeMode != WRITE_BLOCKING) && (writeMode != WRITE_NON_BLOCKING)) {
+            Log.e(TAG, "AudioTrack.write() called with invalid blocking mode");
+            return ERROR_BAD_VALUE;
+        }
+
         if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0)
                 || (offsetInBytes + sizeInBytes < 0)    // detect integer overflow
                 || (offsetInBytes + sizeInBytes > audioData.length)) {
@@ -1570,7 +1608,7 @@
         }
 
         int ret = native_write_byte(audioData, offsetInBytes, sizeInBytes, mAudioFormat,
-                true /*isBlocking*/);
+                writeMode == WRITE_BLOCKING);
 
         if ((mDataLoadMode == MODE_STATIC)
                 && (mState == STATE_NO_STATIC_DATA)
@@ -1582,10 +1620,11 @@
         return ret;
     }
 
-
     /**
      * Writes the audio data to the audio sink for playback (streaming mode),
      * or copies audio data for later playback (static buffer mode).
+     * The format specified in the AudioTrack constructor should be
+     * {@link AudioFormat#ENCODING_PCM_16BIT} to correspond to the data in the array.
      * In streaming mode, will block until all data has been written to the audio sink.
      * In static buffer mode, copies the data to the buffer starting at offset 0.
      * Note that the actual playback of this data might occur after this function
@@ -1602,20 +1641,57 @@
      *    {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
      *    needs to be recreated.
      */
+    public int write(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts) {
+        return write(audioData, offsetInShorts, sizeInShorts, WRITE_BLOCKING);
+    }
 
-    public int write(short[] audioData, int offsetInShorts, int sizeInShorts) {
+    /**
+     * Writes the audio data to the audio sink for playback (streaming mode),
+     * or copies audio data for later playback (static buffer mode).
+     * The format specified in the AudioTrack constructor should be
+     * {@link AudioFormat#ENCODING_PCM_16BIT} to correspond to the data in the array.
+     * In streaming mode, will block until all data has been written to the audio sink.
+     * In static buffer mode, copies the data to the buffer starting at offset 0.
+     * Note that the actual playback of this data might occur after this function
+     * returns. This function is thread safe with respect to {@link #stop} calls,
+     * in which case all of the specified data might not be written to the audio sink.
+     *
+     * @param audioData the array that holds the data to play.
+     * @param offsetInShorts the offset expressed in shorts in audioData where the data to play
+     *     starts.
+     * @param sizeInShorts the number of shorts to read in audioData after the offset.
+     * @param writeMode one of {@link #WRITE_BLOCKING}, {@link #WRITE_NON_BLOCKING}. It has no
+     *     effect in static mode.
+     *     <br>With {@link #WRITE_BLOCKING}, the write will block until all data has been written
+     *         to the audio sink.
+     *     <br>With {@link #WRITE_NON_BLOCKING}, the write will return immediately after
+     *     queuing as much audio data for playback as possible without blocking.
+     * @return the number of shorts that were written or {@link #ERROR_INVALID_OPERATION}
+     *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
+     *    the parameters don't resolve to valid data and indexes, or
+     *    {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
+     *    needs to be recreated.
+     */
+    public int write(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts,
+            @WriteMode int writeMode) {
 
         if (mState == STATE_UNINITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
             return ERROR_INVALID_OPERATION;
         }
 
+        if ((writeMode != WRITE_BLOCKING) && (writeMode != WRITE_NON_BLOCKING)) {
+            Log.e(TAG, "AudioTrack.write() called with invalid blocking mode");
+            return ERROR_BAD_VALUE;
+        }
+
         if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0)
                 || (offsetInShorts + sizeInShorts < 0)  // detect integer overflow
                 || (offsetInShorts + sizeInShorts > audioData.length)) {
             return ERROR_BAD_VALUE;
         }
 
-        int ret = native_write_short(audioData, offsetInShorts, sizeInShorts, mAudioFormat);
+        int ret = native_write_short(audioData, offsetInShorts, sizeInShorts, mAudioFormat,
+                writeMode == WRITE_BLOCKING);
 
         if ((mDataLoadMode == MODE_STATIC)
                 && (mState == STATE_NO_STATIC_DATA)
@@ -1627,10 +1703,11 @@
         return ret;
     }
 
-
     /**
      * Writes the audio data to the audio sink for playback (streaming mode),
      * or copies audio data for later playback (static buffer mode).
+     * The format specified in the AudioTrack constructor should be
+     * {@link AudioFormat#ENCODING_PCM_FLOAT} to correspond to the data in the array.
      * In static buffer mode, copies the data to the buffer starting at offset 0,
      * and the write mode is ignored.
      * In streaming mode, the blocking behavior will depend on the write mode.
@@ -1654,9 +1731,9 @@
      * @param sizeInFloats the number of floats to read in audioData after the offset.
      * @param writeMode one of {@link #WRITE_BLOCKING}, {@link #WRITE_NON_BLOCKING}. It has no
      *     effect in static mode.
-     *     <BR>With {@link #WRITE_BLOCKING}, the write will block until all data has been written
+     *     <br>With {@link #WRITE_BLOCKING}, the write will block until all data has been written
      *         to the audio sink.
-     *     <BR>With {@link #WRITE_NON_BLOCKING}, the write will return immediately after
+     *     <br>With {@link #WRITE_NON_BLOCKING}, the write will return immediately after
      *     queuing as much audio data for playback as possible without blocking.
      * @return the number of floats that were written, or {@link #ERROR_INVALID_OPERATION}
      *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
@@ -1664,7 +1741,7 @@
      *    {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
      *    needs to be recreated.
      */
-    public int write(float[] audioData, int offsetInFloats, int sizeInFloats,
+    public int write(@NonNull float[] audioData, int offsetInFloats, int sizeInFloats,
             @WriteMode int writeMode) {
 
         if (mState == STATE_UNINITIALIZED) {
@@ -1727,7 +1804,7 @@
      *     {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
      *     needs to be recreated.
      */
-    public int write(ByteBuffer audioData, int sizeInBytes,
+    public int write(@NonNull ByteBuffer audioData, int sizeInBytes,
             @WriteMode int writeMode) {
 
         if (mState == STATE_UNINITIALIZED) {
@@ -2017,7 +2094,8 @@
                                                boolean isBlocking);
 
     private native final int native_write_short(short[] audioData,
-                                                int offsetInShorts, int sizeInShorts, int format);
+                                                int offsetInShorts, int sizeInShorts, int format,
+                                                boolean isBlocking);
 
     private native final int native_write_float(float[] audioData,
                                                 int offsetInFloats, int sizeInFloats, int format,
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index c8464c7..8cf9874 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -43,7 +43,7 @@
     libusbhost \
     libjhead \
     libexif \
-    libstagefright_amrnb_common
+    libstagefright_amrnb_common \
 
 LOCAL_REQUIRED_MODULES := \
     libjhead_jni
@@ -55,7 +55,6 @@
     external/libexif/ \
     external/tremor/Tremor \
     frameworks/base/core/jni \
-    frameworks/base/libs/hwui \
     frameworks/av/media/libmedia \
     frameworks/av/media/libstagefright \
     frameworks/av/media/libstagefright/codecs/amrnb/enc/src \
diff --git a/native/graphics/jni/Android.mk b/native/graphics/jni/Android.mk
index f89a5af..91c9ac6 100644
--- a/native/graphics/jni/Android.mk
+++ b/native/graphics/jni/Android.mk
@@ -24,8 +24,7 @@
 
 LOCAL_C_INCLUDES += \
     frameworks/base/native/include \
-    frameworks/base/core/jni/android/graphics \
-    frameworks/base/libs/hwui
+    frameworks/base/core/jni/android/graphics
 
 LOCAL_MODULE:= libjnigraphics
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index f16fb5c..b828e78 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -171,6 +171,11 @@
      */
     private static final String KEYGUARD_ANALYTICS_SETTING = "keyguard_analytics";
 
+    /**
+     * How much faster we collapse the lockscreen when authenticating with fingerprint.
+     */
+    private static final float FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR = 1.3f;
+
     /** The stream type that the lock sounds are tied to. */
     private int mUiSoundsStreamType;
 
@@ -441,7 +446,8 @@
             if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
                 mViewMediatorCallback.keyguardDone(true);
             } else {
-                mStatusBarKeyguardViewManager.animateCollapsePanels();
+                mStatusBarKeyguardViewManager.animateCollapsePanels(
+                        FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR);
             }
         };
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 9f86475..de4874f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -687,13 +687,7 @@
         setHeadsUpUser(newUserId);
     }
 
-    private void setHeadsUpUser(int newUserId) {
-        mHeadsUpManager.setUser(newUserId);
-    }
-
-    public boolean isHeadsUp(String key) {
-      return mHeadsUpManager.isHeadsUp(key);
-    }
+    protected abstract void setHeadsUpUser(int newUserId);
 
     @Override  // NotificationData.Environment
     public boolean isNotificationForCurrentProfiles(StatusBarNotification n) {
@@ -1578,7 +1572,7 @@
                             mCurrentUserId);
             dismissKeyguardThenExecute(new OnDismissAction() {
                 public boolean onDismiss() {
-                    if (mHeadsUpManager.isHeadsUp(mNotificationKey)) {
+                    if (mHeadsUpManager != null && mHeadsUpManager.isHeadsUp(mNotificationKey)) {
                         // Release the HUN notification to the shade.
                         //
                         // In most cases, when FLAG_AUTO_CANCEL is set, the notification will
@@ -1941,20 +1935,8 @@
         setAreThereNotifications();
     }
 
-    private void updateHeadsUp(String key, Entry entry, boolean shouldInterrupt,
-            boolean alertAgain) {
-        final boolean wasHeadsUp = isHeadsUp(key);
-        if (wasHeadsUp) {
-            mHeadsUpManager.updateNotification(entry, alertAgain);
-            if (!shouldInterrupt) {
-                // We don't want this to be interrupting anymore, lets remove it
-                mHeadsUpManager.removeNotification(key);
-            }
-        } else if (shouldInterrupt && alertAgain) {
-            // This notification was updated to be a heads-up, show it!
-            mHeadsUpManager.showNotification(entry);
-        }
-    }
+    protected abstract void updateHeadsUp(String key, Entry entry, boolean shouldInterrupt,
+            boolean alertAgain);
 
     private void logUpdate(Entry oldEntry, Notification n) {
         StatusBarNotification oldNotification = oldEntry.notification;
@@ -2075,7 +2057,7 @@
             return false;
         }
 
-        if (mHeadsUpManager.isSnoozed(sbn.getPackageName())) {
+        if (isSnoozedPackage(sbn)) {
             return false;
         }
 
@@ -2109,6 +2091,8 @@
         return interrupt;
     }
 
+    protected abstract boolean isSnoozedPackage(StatusBarNotification sbn);
+
     public void setInteracting(int barWindow, boolean interacting) {
         // hook for subclasses
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index c266467..96e9543 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -511,9 +511,10 @@
     }
 
     @Override
-    protected void flingToHeight(float vel, boolean expand, float target) {
+    protected void flingToHeight(float vel, boolean expand, float target,
+            float collapseSpeedUpFactor) {
         mHeadsUpTouchHelper.notifyFling(!expand);
-        super.flingToHeight(vel, expand, target);
+        super.flingToHeight(vel, expand, target, collapseSpeedUpFactor);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index 240438a7..f3d4c7f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -140,7 +140,7 @@
         mPanelHolder.setSelectedPanel(mTouchingPanel);
         for (PanelView pv : mPanels) {
             if (pv != panel) {
-                pv.collapse(false /* delayed */);
+                pv.collapse(false /* delayed */, 1.0f /* speedUpFactor */);
             }
         }
     }
@@ -186,11 +186,11 @@
                 (fullyOpenedPanel!=null)?" fullyOpened":"", fullyClosed?" fullyClosed":"");
     }
 
-    public void collapseAllPanels(boolean animate, boolean delayed) {
+    public void collapseAllPanels(boolean animate, boolean delayed, float speedUpFactor) {
         boolean waiting = false;
         for (PanelView pv : mPanels) {
             if (animate && !pv.isFullyCollapsed()) {
-                pv.collapse(delayed);
+                pv.collapse(delayed, speedUpFactor);
                 waiting = true;
             } else {
                 pv.resetViews();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index ddce9d5..3a30429 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -101,6 +101,12 @@
 
     private boolean mPeekPending;
     private boolean mCollapseAfterPeek;
+
+    /**
+     * Speed-up factor to be used when {@link #mFlingCollapseRunnable} runs the next time.
+     */
+    private float mNextCollapseSpeedUpFactor = 1.0f;
+
     private boolean mExpanding;
     private boolean mGestureWaitForTouchSlop;
     private Runnable mPeekRunnable = new Runnable() {
@@ -164,7 +170,7 @@
                     postOnAnimation(new Runnable() {
                         @Override
                         public void run() {
-                            collapse(false /* delayed */);
+                            collapse(false /* delayed */, 1.0f /* speedUpFactor */);
                         }
                     });
                 }
@@ -563,12 +569,17 @@
     }
 
     protected void fling(float vel, boolean expand) {
-        cancelPeek();
-        float target = expand ? getMaxPanelHeight() : 0.0f;
-        flingToHeight(vel, expand, target);
+        fling(vel, expand, 1.0f /* collapseSpeedUpFactor */);
     }
 
-    protected void flingToHeight(float vel, boolean expand, float target) {
+    protected void fling(float vel, boolean expand, float collapseSpeedUpFactor) {
+        cancelPeek();
+        float target = expand ? getMaxPanelHeight() : 0.0f;
+        flingToHeight(vel, expand, target, collapseSpeedUpFactor);
+    }
+
+    protected void flingToHeight(float vel, boolean expand, float target,
+            float collapseSpeedUpFactor) {
         // Hack to make the expand transition look nice when clear all button is visible - we make
         // the animation only to the last notification, and then jump to the maximum panel height so
         // clear all just fades in and the decelerating motion is towards the last notification.
@@ -600,7 +611,8 @@
             // Make it shorter if we run a canned animation
             if (vel == 0) {
                 animator.setDuration((long)
-                        (animator.getDuration() * getCannedFlingDurationFactor()));
+                        (animator.getDuration() * getCannedFlingDurationFactor()
+                                / collapseSpeedUpFactor));
             }
         }
         animator.addListener(new AnimatorListenerAdapter() {
@@ -745,7 +757,7 @@
         mBar = panelBar;
     }
 
-    public void collapse(boolean delayed) {
+    public void collapse(boolean delayed, float speedUpFactor) {
         if (DEBUG) logf("collapse: " + this);
         if (mPeekPending || mPeekAnimator != null) {
             mCollapseAfterPeek = true;
@@ -761,9 +773,10 @@
             mClosing = true;
             notifyExpandingStarted();
             if (delayed) {
+                mNextCollapseSpeedUpFactor = speedUpFactor;
                 postDelayed(mFlingCollapseRunnable, 120);
             } else {
-                fling(0, false /* expand */);
+                fling(0, false /* expand */, speedUpFactor);
             }
         }
     }
@@ -771,7 +784,7 @@
     private final Runnable mFlingCollapseRunnable = new Runnable() {
         @Override
         public void run() {
-            fling(0, false /* expand */);
+            fling(0, false /* expand */, mNextCollapseSpeedUpFactor);
         }
     };
 
@@ -975,7 +988,7 @@
     protected final Runnable mPostCollapseRunnable = new Runnable() {
         @Override
         public void run() {
-            collapse(false /* delayed */);
+            collapse(false /* delayed */, 1.0f /* speedUpFactor */);
         }
     };
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index a5dad92..b6dbfce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1867,6 +1867,35 @@
 
     }
 
+    protected void updateHeadsUp(String key, Entry entry, boolean shouldInterrupt,
+            boolean alertAgain) {
+        final boolean wasHeadsUp = isHeadsUp(key);
+        if (wasHeadsUp) {
+            mHeadsUpManager.updateNotification(entry, alertAgain);
+            if (!shouldInterrupt) {
+                // We don't want this to be interrupting anymore, lets remove it
+                mHeadsUpManager.removeNotification(key);
+            }
+        } else if (shouldInterrupt && alertAgain) {
+            // This notification was updated to be a heads-up, show it!
+            mHeadsUpManager.showNotification(entry);
+        }
+    }
+
+    protected void setHeadsUpUser(int newUserId) {
+        if (mHeadsUpManager != null) {
+            mHeadsUpManager.setUser(newUserId);
+        }
+    }
+
+    public boolean isHeadsUp(String key) {
+        return mHeadsUpManager.isHeadsUp(key);
+    }
+
+    protected boolean isSnoozedPackage(StatusBarNotification sbn) {
+        return mHeadsUpManager.isSnoozed(sbn.getPackageName());
+    }
+
     /**
      * All changes to the status bar and notifications funnel through here and are batched.
      */
@@ -1952,14 +1981,20 @@
     }
 
     public void animateCollapsePanels(int flags) {
-        animateCollapsePanels(flags, false /* force */, false /* delayed */);
+        animateCollapsePanels(flags, false /* force */, false /* delayed */,
+                1.0f /* speedUpFactor */);
     }
 
     public void animateCollapsePanels(int flags, boolean force) {
-        animateCollapsePanels(flags, force, false /* delayed*/);
+        animateCollapsePanels(flags, force, false /* delayed */, 1.0f /* speedUpFactor */);
     }
 
     public void animateCollapsePanels(int flags, boolean force, boolean delayed) {
+        animateCollapsePanels(flags, force, delayed, 1.0f /* speedUpFactor */);
+    }
+
+    public void animateCollapsePanels(int flags, boolean force, boolean delayed,
+            float speedUpFactor) {
         if (!force &&
                 (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)) {
             runPostCollapseRunnables();
@@ -1983,7 +2018,7 @@
             mStatusBarWindowManager.setStatusBarFocusable(false);
 
             mStatusBarWindow.cancelExpandHelper();
-            mStatusBarView.collapseAllPanels(true /* animate */, delayed);
+            mStatusBarView.collapseAllPanels(true /* animate */, delayed, speedUpFactor);
         }
     }
 
@@ -2026,7 +2061,7 @@
 
     public void animateCollapseQuickSettings() {
         if (mState == StatusBarState.SHADE) {
-            mStatusBarView.collapseAllPanels(true, false /* delayed */);
+            mStatusBarView.collapseAllPanels(true, false /* delayed */, 1.0f /* speedUpFactor */);
         }
     }
 
@@ -2039,7 +2074,8 @@
         }
 
         // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868)
-        mStatusBarView.collapseAllPanels(/*animate=*/ false, false /* delayed*/);
+        mStatusBarView.collapseAllPanels(/*animate=*/ false, false /* delayed*/,
+                1.0f /* speedUpFactor */);
 
         mNotificationPanel.closeQs();
 
@@ -2129,7 +2165,8 @@
             mStatusBarWindowState = state;
             if (DEBUG_WINDOW_STATE) Log.d(TAG, "Status bar " + windowStateToString(state));
             if (!showing && mState == StatusBarState.SHADE) {
-                mStatusBarView.collapseAllPanels(false /* animate */, false /* delayed */);
+                mStatusBarView.collapseAllPanels(false /* animate */, false /* delayed */,
+                        1.0f /* speedUpFactor */);
             }
         }
         if (mNavigationBarView != null
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 6369d5e..194a19a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -441,7 +441,8 @@
         mPhoneStatusBar.keyguardGoingAway();
     }
 
-    public void animateCollapsePanels() {
-        mPhoneStatusBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */);
+    public void animateCollapsePanels(float speedUpFactor) {
+        mPhoneStatusBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */,
+                false /* delayed */, speedUpFactor);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index 78122d6..dce695d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -20,8 +20,6 @@
 import android.service.notification.NotificationListenerService.RankingMap;
 import android.service.notification.StatusBarNotification;
 import android.view.View;
-import android.view.ViewGroup.LayoutParams;
-import android.view.WindowManager;
 
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.systemui.statusbar.ActivatableNotificationView;
@@ -166,4 +164,17 @@
     @Override
     public void appTransitionStarting(long startTime, long duration) {
     }
+
+    @Override
+    protected void updateHeadsUp(String key, NotificationData.Entry entry, boolean shouldInterrupt,
+            boolean alertAgain) {
+    }
+
+    @Override
+    protected void setHeadsUpUser(int newUserId) {
+    }
+
+    protected boolean isSnoozedPackage(StatusBarNotification sbn) {
+        return false;
+    }
 }
diff --git a/rs/jni/Android.mk b/rs/jni/Android.mk
index 0658620..94f0859 100644
--- a/rs/jni/Android.mk
+++ b/rs/jni/Android.mk
@@ -25,7 +25,6 @@
     $(JNI_H_INCLUDE) \
     frameworks/rs \
     frameworks/base/core/jni \
-    frameworks/base/libs/hwui \
     $(rs_generated_include_dir)
 
 LOCAL_CFLAGS += -Wno-unused-parameter -std=c++11
diff --git a/services/core/java/com/android/server/AssetAtlasService.java b/services/core/java/com/android/server/AssetAtlasService.java
index 26f4232..66cc29a 100644
--- a/services/core/java/com/android/server/AssetAtlasService.java
+++ b/services/core/java/com/android/server/AssetAtlasService.java
@@ -199,6 +199,11 @@
         private final ArrayList<Bitmap> mBitmaps;
         private final int mPixelCount;
 
+        private long mNativeBitmap;
+
+        // Used for debugging only
+        private Bitmap mAtlasBitmap;
+
         Renderer(ArrayList<Bitmap> bitmaps, int pixelCount) {
             mBitmaps = bitmaps;
             mPixelCount = pixelCount;
@@ -253,9 +258,8 @@
 
             // We always render the atlas into a bitmap. This bitmap is then
             // uploaded into the GraphicBuffer using OpenGL to swizzle the content
-            final Bitmap atlasBitmap = Bitmap.createBitmap(
-                    buffer.getWidth(), buffer.getHeight(), Bitmap.Config.ARGB_8888);
-            final Canvas canvas = new Canvas(atlasBitmap);
+            final Canvas canvas = acquireCanvas(buffer.getWidth(), buffer.getHeight());
+            if (canvas == null) return false;
 
             final Atlas.Entry entry = new Atlas.Entry();
 
@@ -264,78 +268,108 @@
             int mapIndex = 0;
 
             boolean result = false;
-            final long startRender = System.nanoTime();
-            final int count = mBitmaps.size();
+            try {
+                final long startRender = System.nanoTime();
+                final int count = mBitmaps.size();
 
-            for (int i = 0; i < count; i++) {
-                final Bitmap bitmap = mBitmaps.get(i);
-                if (atlas.pack(bitmap.getWidth(), bitmap.getHeight(), entry) != null) {
-                    // We have more bitmaps to pack than the current configuration
-                    // says, we were most likely not able to detect a change in the
-                    // list of preloaded drawables, abort and delete the configuration
-                    if (mapIndex >= mAtlasMap.length) {
-                        deleteDataFile();
-                        break;
-                    }
+                for (int i = 0; i < count; i++) {
+                    final Bitmap bitmap = mBitmaps.get(i);
+                    if (atlas.pack(bitmap.getWidth(), bitmap.getHeight(), entry) != null) {
+                        // We have more bitmaps to pack than the current configuration
+                        // says, we were most likely not able to detect a change in the
+                        // list of preloaded drawables, abort and delete the configuration
+                        if (mapIndex >= mAtlasMap.length) {
+                            deleteDataFile();
+                            break;
+                        }
 
-                    canvas.save();
-                    canvas.translate(entry.x, entry.y);
-                    if (entry.rotated) {
-                        canvas.translate(bitmap.getHeight(), 0.0f);
-                        canvas.rotate(90.0f);
+                        canvas.save();
+                        canvas.translate(entry.x, entry.y);
+                        if (entry.rotated) {
+                            canvas.translate(bitmap.getHeight(), 0.0f);
+                            canvas.rotate(90.0f);
+                        }
+                        canvas.drawBitmap(bitmap, 0.0f, 0.0f, null);
+                        canvas.restore();
+                        atlasMap[mapIndex++] = bitmap.getSkBitmap();
+                        atlasMap[mapIndex++] = entry.x;
+                        atlasMap[mapIndex++] = entry.y;
+                        atlasMap[mapIndex++] = entry.rotated ? 1 : 0;
                     }
-                    canvas.drawBitmap(bitmap, 0.0f, 0.0f, null);
-                    canvas.restore();
-                    atlasMap[mapIndex++] = bitmap.refSkPixelRef();
-                    atlasMap[mapIndex++] = entry.x;
-                    atlasMap[mapIndex++] = entry.y;
-                    atlasMap[mapIndex++] = entry.rotated ? 1 : 0;
                 }
-            }
 
-            final long endRender = System.nanoTime();
-            releaseCanvas(canvas, atlasBitmap);
-            result = nUploadAtlas(buffer, atlasBitmap);
-            atlasBitmap.recycle();
-            final long endUpload = System.nanoTime();
+                final long endRender = System.nanoTime();
+                if (mNativeBitmap != 0) {
+                    result = nUploadAtlas(buffer, mNativeBitmap);
+                }
 
-            if (DEBUG_ATLAS) {
-                float renderDuration = (endRender - startRender) / 1000.0f / 1000.0f;
-                float uploadDuration = (endUpload - endRender) / 1000.0f / 1000.0f;
-                Log.d(LOG_TAG, String.format("Rendered atlas in %.2fms (%.2f+%.2fms)",
-                        renderDuration + uploadDuration, renderDuration, uploadDuration));
+                final long endUpload = System.nanoTime();
+                if (DEBUG_ATLAS) {
+                    float renderDuration = (endRender - startRender) / 1000.0f / 1000.0f;
+                    float uploadDuration = (endUpload - endRender) / 1000.0f / 1000.0f;
+                    Log.d(LOG_TAG, String.format("Rendered atlas in %.2fms (%.2f+%.2fms)",
+                            renderDuration + uploadDuration, renderDuration, uploadDuration));
+                }
+
+            } finally {
+                releaseCanvas(canvas);
             }
 
             return result;
         }
 
         /**
+         * Returns a Canvas for the specified buffer. If {@link #DEBUG_ATLAS_TEXTURE}
+         * is turned on, the returned Canvas will render into a local bitmap that
+         * will then be saved out to disk for debugging purposes.
+         * @param width
+         * @param height
+         */
+        private Canvas acquireCanvas(int width, int height) {
+            if (DEBUG_ATLAS_TEXTURE) {
+                mAtlasBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+                return new Canvas(mAtlasBitmap);
+            } else {
+                Canvas canvas = new Canvas();
+                mNativeBitmap = nAcquireAtlasCanvas(canvas, width, height);
+                return canvas;
+            }
+        }
+
+        /**
          * Releases the canvas used to render into the buffer. Calling this method
          * will release any resource previously acquired. If {@link #DEBUG_ATLAS_TEXTURE}
          * is turend on, calling this method will write the content of the atlas
          * to disk in /data/system/atlas.png for debugging.
          */
-        private void releaseCanvas(Canvas canvas, Bitmap atlasBitmap) {
-            canvas.setBitmap(null);
+        private void releaseCanvas(Canvas canvas) {
             if (DEBUG_ATLAS_TEXTURE) {
+                canvas.setBitmap(null);
 
                 File systemDirectory = new File(Environment.getDataDirectory(), "system");
                 File dataFile = new File(systemDirectory, "atlas.png");
 
                 try {
                     FileOutputStream out = new FileOutputStream(dataFile);
-                    atlasBitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
+                    mAtlasBitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
                     out.close();
                 } catch (FileNotFoundException e) {
                     // Ignore
                 } catch (IOException e) {
                     // Ignore
                 }
+
+                mAtlasBitmap.recycle();
+                mAtlasBitmap = null;
+            } else {
+                nReleaseAtlasCanvas(canvas, mNativeBitmap);
             }
         }
     }
 
-    private static native boolean nUploadAtlas(GraphicBuffer buffer, Bitmap bitmap);
+    private static native long nAcquireAtlasCanvas(Canvas canvas, int width, int height);
+    private static native void nReleaseAtlasCanvas(Canvas canvas, long bitmap);
+    private static native boolean nUploadAtlas(GraphicBuffer buffer, long bitmap);
 
     @Override
     public boolean isCompatible(int ppid) {
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 16689ee..a31a1a7 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -134,7 +134,11 @@
 
     public void systemReady() {
         migrateOldData();
-        getGateKeeperService();
+        try {
+            getGateKeeperService();
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Failure retrieving IGateKeeperService", e);
+        }
         mStorage.prefetchUser(UserHandle.USER_OWNER);
     }
 
@@ -695,7 +699,16 @@
         return null;
     }
 
-    private synchronized IGateKeeperService getGateKeeperService() {
+    private class GateKeeperDiedRecipient implements IBinder.DeathRecipient {
+        @Override
+        public void binderDied() {
+            mGateKeeperService.asBinder().unlinkToDeath(this, 0);
+            mGateKeeperService = null;
+        }
+    }
+
+    private synchronized IGateKeeperService getGateKeeperService()
+            throws RemoteException {
         if (mGateKeeperService != null) {
             return mGateKeeperService;
         }
@@ -703,6 +716,7 @@
         final IBinder service =
             ServiceManager.getService("android.service.gatekeeper.IGateKeeperService");
         if (service != null) {
+            service.linkToDeath(new GateKeeperDiedRecipient(), 0);
             mGateKeeperService = IGateKeeperService.Stub.asInterface(service);
             return mGateKeeperService;
         }
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 4c937f7..7e4df58 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -61,6 +61,7 @@
 import android.os.storage.StorageVolume;
 import android.os.storage.VolumeInfo;
 import android.text.TextUtils;
+import android.text.format.DateUtils;
 import android.util.ArrayMap;
 import android.util.AtomicFile;
 import android.util.DebugUtils;
@@ -533,7 +534,11 @@
                     break;
                 }
                 case H_FSTRIM: {
-                    waitForReady();
+                    if (!isReady()) {
+                        Slog.i(TAG, "fstrim requested, but no daemon connection yet; trying again");
+                        sendMessageDelayed(obtainMessage(H_FSTRIM), DateUtils.SECOND_IN_MILLIS);
+                    }
+
                     Slog.i(TAG, "Running fstrim idle maintenance");
 
                     // Remember when we kicked it off
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 908ee22..4ee6657 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -17,6 +17,7 @@
 package com.android.server;
 
 import android.app.ActivityManager;
+import android.app.AppOpsManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -84,7 +85,7 @@
     private static final boolean VDBG = false; // STOPSHIP if true
 
     private static class Record {
-        String pkgForDebug;
+        String callingPackage;
 
         IBinder binder;
 
@@ -109,7 +110,8 @@
 
         @Override
         public String toString() {
-            return "{pkgForDebug=" + pkgForDebug + " binder=" + binder + " callback=" + callback
+            return "{callingPackage=" + callingPackage + " binder=" + binder
+                    + " callback=" + callback
                     + " onSubscriptionsChangedListenererCallback="
                                             + onSubscriptionsChangedListenerCallback
                     + " callerUid=" + callerUid + " subId=" + subId + " phoneId=" + phoneId
@@ -125,6 +127,8 @@
 
     private final IBatteryStats mBatteryStats;
 
+    private final AppOpsManager mAppOps;
+
     private boolean hasNotifySubscriptionInfoChangedOccurred = false;
 
     private int mNumPhones;
@@ -327,6 +331,8 @@
             }
         }
         mConnectedApns = new ArrayList<String>();
+
+        mAppOps = mContext.getSystemService(AppOpsManager.class);
     }
 
     public void systemRunning() {
@@ -340,18 +346,24 @@
     }
 
     @Override
-    public void addOnSubscriptionsChangedListener(String pkgForDebug,
+    public void addOnSubscriptionsChangedListener(String callingPackage,
             IOnSubscriptionsChangedListener callback) {
         int callerUid = UserHandle.getCallingUserId();
         int myUid = UserHandle.myUserId();
         if (VDBG) {
-            log("listen oscl: E pkg=" + pkgForDebug + " myUid=" + myUid
+            log("listen oscl: E pkg=" + callingPackage + " myUid=" + myUid
                 + " callerUid="  + callerUid + " callback=" + callback
                 + " callback.asBinder=" + callback.asBinder());
         }
 
-        /* Checks permission and throws Security exception */
-        checkOnSubscriptionsChangedListenerPermission();
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.READ_PHONE_STATE, null);
+
+        if (mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(),
+                callingPackage) != AppOpsManager.MODE_ALLOWED) {
+            return;
+        }
+
         Record r = null;
 
         synchronized (mRecords) {
@@ -372,7 +384,7 @@
             }
 
             r.onSubscriptionsChangedListenerCallback = callback;
-            r.pkgForDebug = pkgForDebug;
+            r.callingPackage = callingPackage;
             r.callerUid = callerUid;
             r.events = 0;
             if (DBG) {
@@ -401,12 +413,6 @@
         remove(callback.asBinder());
     }
 
-    private void checkOnSubscriptionsChangedListenerPermission() {
-        mContext.enforceCallingOrSelfPermission(
-                SubscriptionManager.OnSubscriptionsChangedListener
-                    .PERMISSION_ON_SUBSCRIPTIONS_CHANGED, null);
-    }
-
     @Override
     public void notifySubscriptionInfoChanged() {
         if (VDBG) log("notifySubscriptionInfoChanged:");
@@ -446,12 +452,12 @@
         listen(pkgForDebug, callback, events, notifyNow, subId);
     }
 
-    private void listen(String pkgForDebug, IPhoneStateListener callback, int events,
+    private void listen(String callingPackage, IPhoneStateListener callback, int events,
             boolean notifyNow, int subId) {
         int callerUid = UserHandle.getCallingUserId();
         int myUid = UserHandle.myUserId();
         if (VDBG) {
-            log("listen: E pkg=" + pkgForDebug + " events=0x" + Integer.toHexString(events)
+            log("listen: E pkg=" + callingPackage + " events=0x" + Integer.toHexString(events)
                 + " notifyNow=" + notifyNow + " subId=" + subId + " myUid=" + myUid
                 + " callerUid=" + callerUid);
         }
@@ -459,6 +465,14 @@
         if (events != PhoneStateListener.LISTEN_NONE) {
             /* Checks permission and throws Security exception */
             checkListenerPermission(events);
+
+            if ((events & PHONE_STATE_PERMISSION_MASK) != 0) {
+                if (mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(),
+                        callingPackage) != AppOpsManager.MODE_ALLOWED) {
+                    return;
+                }
+            }
+
             synchronized (mRecords) {
                 // register
                 Record r = null;
@@ -478,7 +492,7 @@
                 }
 
                 r.callback = callback;
-                r.pkgForDebug = pkgForDebug;
+                r.callingPackage = callingPackage;
                 r.callerUid = callerUid;
                 // Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID,
                 // force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID
@@ -631,7 +645,7 @@
                 if (mRecords.get(i).binder == binder) {
                     if (DBG) {
                         Record r = mRecords.get(i);
-                        log("remove: binder=" + binder + "r.pkgForDebug" + r.pkgForDebug
+                        log("remove: binder=" + binder + "r.callingPackage" + r.callingPackage
                                 + "r.callback" + r.callback);
                     }
                     mRecords.remove(i);
@@ -1380,7 +1394,8 @@
         }
         intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
         mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
-                android.Manifest.permission.READ_PHONE_STATE);
+                android.Manifest.permission.READ_PHONE_STATE,
+                AppOpsManager.OP_READ_PHONE_STATE);
     }
 
     private void broadcastDataConnectionStateChanged(int state,
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 0ca0c0e..770df82 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -143,75 +143,67 @@
                     + ", mAuthClients = " + mAuthClient + ", mEnrollClient = " + mEnrollClient);
         if (mEnrollClient != null) {
             final IBinder token = mEnrollClient.token;
-            if (doNotify(mEnrollClient, type, arg1, arg2, arg3)) {
-                stopEnrollment(token);
+            if (dispatchNotify(mEnrollClient, type, arg1, arg2, arg3)) {
+                stopEnrollment(token, false);
+                removeClient(mEnrollClient);
             }
         }
         if (mAuthClient != null) {
             final IBinder token = mAuthClient.token;
-            if (doNotify(mAuthClient, type, arg1, arg2, arg3)) {
-                stopAuthentication(token);
+            if (dispatchNotify(mAuthClient, type, arg1, arg2, arg3)) {
+                stopAuthentication(token, false);
+                removeClient(mAuthClient);
             }
         }
         if (mRemoveClient != null) {
-            if (doNotify(mRemoveClient, type, arg1, arg2, arg3)) {
+            if (dispatchNotify(mRemoveClient, type, arg1, arg2, arg3)) {
                 removeClient(mRemoveClient);
             }
         }
     }
 
-    // Returns true if the operation is done, i.e. authentication completed
-    boolean doNotify(ClientMonitor clientMonitor, int type, int arg1, int arg2, int arg3) {
+    /*
+     * Dispatch notify events to clients.
+     *
+     * @return true if the operation is done, i.e. authentication completed
+     */
+    boolean dispatchNotify(ClientMonitor clientMonitor, int type, int arg1, int arg2, int arg3) {
         ContentResolver contentResolver = mContext.getContentResolver();
         boolean operationCompleted = false;
+        int fpId;
+        int groupId;
+        int remaining;
+        int acquireInfo;
         switch (type) {
             case FINGERPRINT_ERROR:
-                {
-                    final int error = arg1;
-                    clientMonitor.sendError(error);
-                    removeClient(clientMonitor);
-                    operationCompleted = true; // any error means the operation is done
-                }
+                fpId = arg1;
+                operationCompleted = clientMonitor.sendError(fpId);
                 break;
             case FINGERPRINT_ACQUIRED:
-                clientMonitor.sendAcquired(arg1 /* acquireInfo */);
+                acquireInfo = arg1;
+                operationCompleted = clientMonitor.sendAcquired(acquireInfo);
                 break;
             case FINGERPRINT_AUTHENTICATED:
-                {
-                    final int fpId = arg1;
-                    final int groupId = arg2;
-                    clientMonitor.sendAuthenticated(fpId, groupId);
-                    if (fpId == 0) {
-                        if (clientMonitor == mAuthClient) {
-                            operationCompleted = handleFailedAttempt(clientMonitor);
-                        }
-                    } else {
-                        mLockoutReset.run(); // a valid fingerprint resets lockout
-                    }
-                }
+                fpId = arg1;
+                groupId = arg2;
+                operationCompleted = clientMonitor.sendAuthenticated(fpId, groupId);
                 break;
             case FINGERPRINT_TEMPLATE_ENROLLING:
-                {
-                    final int fpId = arg1;
-                    final int groupId = arg2;
-                    final int remaining = arg3;
-                    clientMonitor.sendEnrollResult(fpId, groupId, remaining);
-                    if (remaining == 0) {
-                        addTemplateForUser(clientMonitor, contentResolver, fpId);
-                        operationCompleted = true; // enroll completed
-                    }
+                fpId = arg1;
+                groupId = arg2;
+                remaining = arg3;
+                operationCompleted = clientMonitor.sendEnrollResult(fpId, groupId, remaining);
+                if (remaining == 0) {
+                    addTemplateForUser(clientMonitor, contentResolver, fpId);
+                    operationCompleted = true; // enroll completed
                 }
                 break;
             case FINGERPRINT_TEMPLATE_REMOVED:
-                {
-                    final int fingerId = arg1;
-                    final int groupId = arg2;
-                    removeTemplateForUser(clientMonitor, contentResolver, fingerId);
-                    if (fingerId == 0) {
-                        operationCompleted = true; // remove completed
-                    } else {
-                        clientMonitor.sendRemoved(fingerId, groupId);
-                    }
+                fpId = arg1;
+                groupId = arg2;
+                operationCompleted = clientMonitor.sendRemoved(fpId, groupId);
+                if (fpId != 0) {
+                    removeTemplateForUser(clientMonitor, contentResolver, fpId);
                 }
                 break;
         }
@@ -235,7 +227,9 @@
     }
 
     private void resetFailedAttempts() {
-        if (DEBUG) Slog.v(TAG, "Reset fingerprint lockout");
+        if (DEBUG && inLockoutMode()) {
+            Slog.v(TAG, "Reset fingerprint lockout");
+        }
         mFailedAttempts = 0;
     }
 
@@ -283,19 +277,21 @@
 
     private void stopPendingOperations() {
         if (mEnrollClient != null) {
-            stopEnrollment(mEnrollClient.token);
+            stopEnrollment(mEnrollClient.token, true);
         }
         if (mAuthClient != null) {
-            stopAuthentication(mAuthClient.token);
+            stopAuthentication(mAuthClient.token, true);
         }
         // mRemoveClient is allowed to continue
     }
 
-    void stopEnrollment(IBinder token) {
+    void stopEnrollment(IBinder token, boolean notify) {
         final ClientMonitor client = mEnrollClient;
         if (client == null || client.token != token) return;
         int result = nativeStopEnrollment();
-        client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED);
+        if (notify) {
+            client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED);
+        }
         removeClient(mEnrollClient);
         if (result != 0) {
             Slog.w(TAG, "startEnrollCancel failed, result=" + result);
@@ -321,11 +317,13 @@
         }
     }
 
-    void stopAuthentication(IBinder token) {
+    void stopAuthentication(IBinder token, boolean notify) {
         final ClientMonitor client = mAuthClient;
         if (client == null || client.token != token) return;
         int result = nativeStopAuthentication();
-        client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED);
+        if (notify) {
+            client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED);
+        }
         removeClient(mAuthClient);
         if (result != 0) {
             Slog.w(TAG, "stopAuthentication failed, result=" + result);
@@ -408,74 +406,89 @@
             }
         }
 
+        /*
+         * @return true if we're done.
+         */
         private boolean sendRemoved(int fingerId, int groupId) {
             IFingerprintServiceReceiver rx = receiver.get();
-            if (rx != null) {
-                try {
-                    rx.onRemoved(mHalDeviceId, fingerId, groupId);
-                    return true;
-                } catch (RemoteException e) {
-                    if (DEBUG) Slog.v(TAG, "Failed to invoke sendRemoved:", e);
-                }
+            if (rx == null) return true; // client not listening
+            try {
+                rx.onRemoved(mHalDeviceId, fingerId, groupId);
+                return fingerId == 0;
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Failed to notify Removed:", e);
             }
-            removeClient(this);
             return false;
         }
 
+        /*
+         * @return true if we're done.
+         */
         private boolean sendEnrollResult(int fpId, int groupId, int remaining) {
             IFingerprintServiceReceiver rx = receiver.get();
-            if (rx != null) {
-                try {
-                    rx.onEnrollResult(mHalDeviceId, fpId, groupId, remaining);
-                    return true;
-                } catch (RemoteException e) {
-                    if (DEBUG) Slog.v(TAG, "Failed to invoke sendEnrollResult:", e);
-                }
+            if (rx == null) return true; // client not listening
+            try {
+                rx.onEnrollResult(mHalDeviceId, fpId, groupId, remaining);
+                return remaining == 0;
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Failed to notify EnrollResult:", e);
+                return true;
             }
-            removeClient(this);
-            return false;
         }
 
+        /*
+         * @return true if we're done.
+         */
         private boolean sendAuthenticated(int fpId, int groupId) {
             IFingerprintServiceReceiver rx = receiver.get();
+            boolean result = false;
             if (rx != null) {
                 try {
                     rx.onAuthenticated(mHalDeviceId, fpId, groupId);
-                    return true;
                 } catch (RemoteException e) {
-                    if (DEBUG) Slog.v(TAG, "Failed to invoke sendProcessed:", e);
+                    Slog.w(TAG, "Failed to notify Authenticated:", e);
+                    result = true; // client failed
                 }
+            } else {
+                result = true; // client not listening
             }
-            removeClient(this);
-            return false;
+            if (fpId <= 0) {
+                result |= handleFailedAttempt(this);
+            } else {
+                result |= true; // we have a valid fingerprint
+                mLockoutReset.run();
+            }
+            return result;
         }
 
+        /*
+         * @return true if we're done.
+         */
         private boolean sendAcquired(int acquiredInfo) {
             IFingerprintServiceReceiver rx = receiver.get();
-            if (rx != null) {
-                try {
-                    rx.onAcquired(mHalDeviceId, acquiredInfo);
-                    return true;
-                } catch (RemoteException e) {
-                    if (DEBUG) Slog.v(TAG, "Failed to invoke sendAcquired:", e);
-                }
+            if (rx == null) return true; // client not listening
+            try {
+                rx.onAcquired(mHalDeviceId, acquiredInfo);
+                return false; // acquisition continues...
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Failed to invoke sendAcquired:", e);
+                return true; // client failed
             }
-            removeClient(this);
-            return false;
         }
 
+        /*
+         * @return true if we're done.
+         */
         private boolean sendError(int error) {
             IFingerprintServiceReceiver rx = receiver.get();
             if (rx != null) {
                 try {
                     rx.onError(mHalDeviceId, error);
-                    return true;
                 } catch (RemoteException e) {
-                    if (DEBUG) Slog.v(TAG, "Failed to invoke sendError:", e);
+                    Slog.w(TAG, "Failed to invoke sendError:", e);
                 }
             }
-            removeClient(this);
-            return false;
+            return true; // errors always terminate progress
         }
     }
 
@@ -507,7 +520,7 @@
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    stopEnrollment(token);
+                    stopEnrollment(token, true);
                 }
             });
         }
@@ -533,7 +546,7 @@
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    stopAuthentication(token);
+                    stopAuthentication(token, true);
                 }
             });
         }
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 5de7d42..4e90f97 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -74,6 +74,7 @@
 import android.Manifest;
 import android.app.ActivityManager;
 import android.app.AppGlobals;
+import android.app.AppOpsManager;
 import android.app.IActivityManager;
 import android.app.INotificationManager;
 import android.app.IProcessObserver;
@@ -136,6 +137,7 @@
 import android.util.TrustedTime;
 import android.util.Xml;
 
+import com.android.server.AppOpsService;
 import libcore.io.IoUtils;
 
 import com.android.internal.R;
@@ -292,6 +294,8 @@
 
     private final AtomicFile mPolicyFile;
 
+    private final AppOpsManager mAppOps;
+
     // TODO: keep whitelist of system-critical services that should never have
     // rules enforced, such as system, phone, and radio UIDs.
 
@@ -326,6 +330,8 @@
         mSuppressDefaultPolicy = suppressDefaultPolicy;
 
         mPolicyFile = new AtomicFile(new File(systemDir, "netpolicy.xml"));
+
+        mAppOps = context.getSystemService(AppOpsManager.class);
     }
 
     public void bindConnectivityManager(IConnectivityManager connManager) {
@@ -1593,16 +1599,21 @@
     }
 
     void addNetworkPolicyLocked(NetworkPolicy policy) {
-        NetworkPolicy[] policies = getNetworkPolicies();
+        NetworkPolicy[] policies = getNetworkPolicies(mContext.getOpPackageName());
         policies = ArrayUtils.appendElement(NetworkPolicy.class, policies, policy);
         setNetworkPolicies(policies);
     }
 
     @Override
-    public NetworkPolicy[] getNetworkPolicies() {
+    public NetworkPolicy[] getNetworkPolicies(String callingPackage) {
         mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
         mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, TAG);
 
+        if (mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(),
+                callingPackage) != AppOpsManager.MODE_ALLOWED) {
+            return new NetworkPolicy[0];
+        }
+
         synchronized (mRulesLock) {
             final int size = mNetworkPolicy.size();
             final NetworkPolicy[] policies = new NetworkPolicy[size];
@@ -1614,7 +1625,7 @@
     }
 
     private void normalizePoliciesLocked() {
-        normalizePoliciesLocked(getNetworkPolicies());
+        normalizePoliciesLocked(getNetworkPolicies(mContext.getOpPackageName()));
     }
 
     private void normalizePoliciesLocked(NetworkPolicy[] policies) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 964dcc2..f29d524 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -709,6 +709,11 @@
     private WindowContentFrameStats mTempWindowRenderStats;
 
     final class DragInputEventReceiver extends InputEventReceiver {
+        // Set, if stylus button was down at the start of the drag.
+        private boolean mStylusButtonDownAtStart;
+        // Indicates the first event to check for button state.
+        private boolean mIsStartEvent = true;
+
         public DragInputEventReceiver(InputChannel inputChannel, Looper looper) {
             super(inputChannel, looper);
         }
@@ -724,6 +729,18 @@
                     boolean endDrag = false;
                     final float newX = motionEvent.getRawX();
                     final float newY = motionEvent.getRawY();
+                    final boolean isStylusButtonDown =
+                            (motionEvent.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS)
+                            && (motionEvent.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0;
+
+                    if (mIsStartEvent) {
+                        if (isStylusButtonDown) {
+                            // First event and the button was down, check for the button being
+                            // lifted in the future, if that happens we'll drop the item.
+                            mStylusButtonDownAtStart = true;
+                        }
+                        mIsStartEvent = false;
+                    }
 
                     switch (motionEvent.getAction()) {
                     case MotionEvent.ACTION_DOWN: {
@@ -733,9 +750,17 @@
                     } break;
 
                     case MotionEvent.ACTION_MOVE: {
-                        synchronized (mWindowMap) {
-                            // move the surface and tell the involved window(s) where we are
-                            mDragState.notifyMoveLw(newX, newY);
+                        if (mStylusButtonDownAtStart && !isStylusButtonDown) {
+                            if (DEBUG_DRAG) Slog.d(TAG, "Button no longer pressed; dropping at "
+                                    + newX + "," + newY);
+                            synchronized (mWindowMap) {
+                                endDrag = mDragState.notifyDropLw(newX, newY);
+                            }
+                        } else {
+                            synchronized (mWindowMap) {
+                                // move the surface and tell the involved window(s) where we are
+                                mDragState.notifyMoveLw(newX, newY);
+                            }
                         }
                     } break;
 
@@ -759,6 +784,8 @@
                         synchronized (mWindowMap) {
                             mDragState.endDragLw();
                         }
+                        mStylusButtonDownAtStart = false;
+                        mIsStartEvent = true;
                     }
 
                     handled = true;
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index a5546cf..19ca2b4 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -33,7 +33,6 @@
     $(JNI_H_INCLUDE) \
     frameworks/base/services \
     frameworks/base/libs \
-    frameworks/base/libs/hwui \
     frameworks/base/core/jni \
     frameworks/native/services \
     libcore/include \
diff --git a/services/core/jni/com_android_server_AssetAtlasService.cpp b/services/core/jni/com_android_server_AssetAtlasService.cpp
index 8f4fb51..e4f242e 100644
--- a/services/core/jni/com_android_server_AssetAtlasService.cpp
+++ b/services/core/jni/com_android_server_AssetAtlasService.cpp
@@ -47,9 +47,40 @@
 #define FENCE_TIMEOUT 2000000000
 
 // ----------------------------------------------------------------------------
+// JNI Helpers
+// ----------------------------------------------------------------------------
+
+static struct {
+    jmethodID setNativeBitmap;
+} gCanvasClassInfo;
+
+#define INVOKEV(object, method, ...) \
+    env->CallVoidMethod(object, method, __VA_ARGS__)
+
+// ----------------------------------------------------------------------------
 // Canvas management
 // ----------------------------------------------------------------------------
 
+static jlong com_android_server_AssetAtlasService_acquireCanvas(JNIEnv* env, jobject,
+        jobject canvas, jint width, jint height) {
+
+    SkBitmap* bitmap = new SkBitmap;
+    bitmap->allocN32Pixels(width, height);
+    bitmap->eraseColor(0);
+    INVOKEV(canvas, gCanvasClassInfo.setNativeBitmap, reinterpret_cast<jlong>(bitmap));
+
+    return reinterpret_cast<jlong>(bitmap);
+}
+
+static void com_android_server_AssetAtlasService_releaseCanvas(JNIEnv* env, jobject,
+        jobject canvas, jlong bitmapHandle) {
+
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    INVOKEV(canvas, gCanvasClassInfo.setNativeBitmap, (jlong)0);
+
+    delete bitmap;
+}
+
 #define CLEANUP_GL_AND_RETURN(result) \
     if (fence != EGL_NO_SYNC_KHR) eglDestroySyncKHR(display, fence); \
     if (image) eglDestroyImageKHR(display, image); \
@@ -62,12 +93,9 @@
     return result;
 
 static jboolean com_android_server_AssetAtlasService_upload(JNIEnv* env, jobject,
-        jobject graphicBuffer, jobject bitmapHandle) {
+        jobject graphicBuffer, jlong bitmapHandle) {
 
-    SkBitmap bitmap;
-    GraphicsJNI::getSkBitmap(env, bitmapHandle, &bitmap);
-    SkAutoLockPixels alp(bitmap);
-
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
     // The goal of this method is to copy the bitmap into the GraphicBuffer
     // using the GPU to swizzle the texture content
     sp<GraphicBuffer> buffer(graphicBufferForJavaObject(env, graphicBuffer));
@@ -158,9 +186,9 @@
         }
 
         // Upload the content of the bitmap in the GraphicBuffer
-        glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap.bytesPerPixel());
-        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(),
-                GL_RGBA, GL_UNSIGNED_BYTE, bitmap.getPixels());
+        glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
+        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap->width(), bitmap->height(),
+                GL_RGBA, GL_UNSIGNED_BYTE, bitmap->getPixels());
         if (glGetError() != GL_NO_ERROR) {
             ALOGW("Could not upload to texture");
             CLEANUP_GL_AND_RETURN(JNI_FALSE);
@@ -205,11 +233,20 @@
 const char* const kClassPathName = "com/android/server/AssetAtlasService";
 
 static JNINativeMethod gMethods[] = {
-    { "nUploadAtlas", "(Landroid/view/GraphicBuffer;Landroid/graphics/Bitmap;)Z",
+    { "nAcquireAtlasCanvas", "(Landroid/graphics/Canvas;II)J",
+            (void*) com_android_server_AssetAtlasService_acquireCanvas },
+    { "nReleaseAtlasCanvas", "(Landroid/graphics/Canvas;J)V",
+            (void*) com_android_server_AssetAtlasService_releaseCanvas },
+    { "nUploadAtlas", "(Landroid/view/GraphicBuffer;J)Z",
             (void*) com_android_server_AssetAtlasService_upload },
 };
 
 int register_android_server_AssetAtlasService(JNIEnv* env) {
+    jclass clazz;
+
+    FIND_CLASS(clazz, "android/graphics/Canvas");
+    GET_METHOD_ID(gCanvasClassInfo.setNativeBitmap, clazz, "setNativeBitmap", "(J)V");
+
     return jniRegisterNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
 }
 
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 5abbb50..a72172c 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -359,7 +359,8 @@
     public PhoneAccountHandle getDefaultOutgoingPhoneAccount(String uriScheme) {
         try {
             if (isServiceConnected()) {
-                return getTelecomService().getDefaultOutgoingPhoneAccount(uriScheme);
+                return getTelecomService().getDefaultOutgoingPhoneAccount(uriScheme,
+                        mContext.getOpPackageName());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelecomService#getDefaultOutgoingPhoneAccount", e);
@@ -443,7 +444,7 @@
     public List<PhoneAccountHandle> getSimCallManagers() {
         try {
             if (isServiceConnected()) {
-                return getTelecomService().getSimCallManagers();
+                return getTelecomService().getSimCallManagers(mContext.getOpPackageName());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelecomService#getSimCallManagers");
@@ -491,7 +492,8 @@
     public List<PhoneAccountHandle> getPhoneAccountsSupportingScheme(String uriScheme) {
         try {
             if (isServiceConnected()) {
-                return getTelecomService().getPhoneAccountsSupportingScheme(uriScheme);
+                return getTelecomService().getPhoneAccountsSupportingScheme(uriScheme,
+                        mContext.getOpPackageName());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelecomService#getPhoneAccountsSupportingScheme", e);
@@ -511,7 +513,7 @@
     public List<PhoneAccountHandle> getCallCapablePhoneAccounts() {
         try {
             if (isServiceConnected()) {
-                return getTelecomService().getCallCapablePhoneAccounts();
+                return getTelecomService().getCallCapablePhoneAccounts(mContext.getOpPackageName());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelecomService#getCallCapablePhoneAccounts", e);
@@ -711,7 +713,8 @@
     public boolean isVoiceMailNumber(PhoneAccountHandle accountHandle, String number) {
         try {
             if (isServiceConnected()) {
-                return getTelecomService().isVoiceMailNumber(accountHandle, number);
+                return getTelecomService().isVoiceMailNumber(accountHandle, number,
+                        mContext.getOpPackageName());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException calling ITelecomService#isVoiceMailNumber.", e);
@@ -729,7 +732,8 @@
     public String getVoiceMailNumber(PhoneAccountHandle accountHandle) {
         try {
             if (isServiceConnected()) {
-                return getTelecomService().getVoiceMailNumber(accountHandle);
+                return getTelecomService().getVoiceMailNumber(accountHandle,
+                        mContext.getOpPackageName());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException calling ITelecomService#hasVoiceMailNumber.", e);
@@ -746,7 +750,8 @@
     public String getLine1Number(PhoneAccountHandle accountHandle) {
         try {
             if (isServiceConnected()) {
-                return getTelecomService().getLine1Number(accountHandle);
+                return getTelecomService().getLine1Number(accountHandle,
+                        mContext.getOpPackageName());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException calling ITelecomService#getLine1Number.", e);
@@ -764,7 +769,7 @@
     public boolean isInCall() {
         try {
             if (isServiceConnected()) {
-                return getTelecomService().isInCall();
+                return getTelecomService().isInCall(mContext.getOpPackageName());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException calling isInCall().", e);
@@ -806,7 +811,7 @@
     public boolean isRinging() {
         try {
             if (isServiceConnected()) {
-                return getTelecomService().isRinging();
+                return getTelecomService().isRinging(mContext.getOpPackageName());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException attempting to get ringing state of phone app.", e);
@@ -872,7 +877,7 @@
     public boolean isTtySupported() {
         try {
             if (isServiceConnected()) {
-                return getTelecomService().isTtySupported();
+                return getTelecomService().isTtySupported(mContext.getOpPackageName());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException attempting to get TTY supported state.", e);
@@ -893,7 +898,7 @@
     public int getCurrentTtyMode() {
         try {
             if (isServiceConnected()) {
-                return getTelecomService().getCurrentTtyMode();
+                return getTelecomService().getCurrentTtyMode(mContext.getOpPackageName());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException attempting to get the current TTY mode.", e);
@@ -1045,7 +1050,7 @@
         ITelecomService service = getTelecomService();
         if (service != null) {
             try {
-                service.showInCallScreen(showDialpad);
+                service.showInCallScreen(showDialpad, mContext.getOpPackageName());
             } catch (RemoteException e) {
                 Log.e(TAG, "Error calling ITelecomService#showCallScreen", e);
             }
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 35db97f..727fd4bb 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -33,12 +33,12 @@
      *
      * @param showDialpad if true, make the dialpad visible initially.
      */
-    void showInCallScreen(boolean showDialpad);
+    void showInCallScreen(boolean showDialpad, String callingPackage);
 
     /**
      * @see TelecomServiceImpl#getDefaultOutgoingPhoneAccount
      */
-    PhoneAccountHandle getDefaultOutgoingPhoneAccount(in String uriScheme);
+    PhoneAccountHandle getDefaultOutgoingPhoneAccount(in String uriScheme, String callingPackage);
 
     /**
      * @see TelecomServiceImpl#getUserSelectedOutgoingPhoneAccount
@@ -53,12 +53,13 @@
     /**
      * @see TelecomServiceImpl#getCallCapablePhoneAccounts
      */
-    List<PhoneAccountHandle> getCallCapablePhoneAccounts();
+    List<PhoneAccountHandle> getCallCapablePhoneAccounts(String callingPackage);
 
     /**
      * @see TelecomManager#getPhoneAccountsSupportingScheme
      */
-    List<PhoneAccountHandle> getPhoneAccountsSupportingScheme(in String uriScheme);
+    List<PhoneAccountHandle> getPhoneAccountsSupportingScheme(in String uriScheme,
+            String callingPackage);
 
     /**
      * @see TelecomManager#getPhoneAccountsForPackage
@@ -98,7 +99,7 @@
     /**
      * @see TelecomServiceImpl#getSimCallManagers
      */
-    List<PhoneAccountHandle> getSimCallManagers();
+    List<PhoneAccountHandle> getSimCallManagers(String callingPackage);
 
     /**
      * @see TelecomServiceImpl#registerPhoneAccount
@@ -118,17 +119,18 @@
     /**
      * @see TelecomServiceImpl#isVoiceMailNumber
      */
-    boolean isVoiceMailNumber(in PhoneAccountHandle accountHandle, String number);
+    boolean isVoiceMailNumber(in PhoneAccountHandle accountHandle, String number,
+            String callingPackage);
 
     /**
      * @see TelecomServiceImpl#getVoiceMailNumber
      */
-    String getVoiceMailNumber(in PhoneAccountHandle accountHandle);
+    String getVoiceMailNumber(in PhoneAccountHandle accountHandle, String callingPackage);
 
     /**
      * @see TelecomServiceImpl#getLine1Number
      */
-    String getLine1Number(in PhoneAccountHandle accountHandle);
+    String getLine1Number(in PhoneAccountHandle accountHandle, String callingPackage);
 
     /**
      * @see TelecomServiceImpl#getDefaultPhoneApp
@@ -147,12 +149,12 @@
     /**
      * @see TelecomServiceImpl#isInCall
      */
-    boolean isInCall();
+    boolean isInCall(String callingPackage);
 
     /**
      * @see TelecomServiceImpl#isRinging
      */
-    boolean isRinging();
+    boolean isRinging(String callingPackage);
 
     /**
      * @see TelecomServiceImpl#getCallState
@@ -192,12 +194,12 @@
     /**
      * @see TelecomServiceImpl#isTtySupported
      */
-    boolean isTtySupported();
+    boolean isTtySupported(String callingPackage);
 
     /**
      * @see TelecomServiceImpl#getCurrentTtyMode
      */
-    int getCurrentTtyMode();
+    int getCurrentTtyMode(String callingPackage);
 
     /**
      * @see TelecomServiceImpl#addNewIncomingCall
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index b1fb3a6..d103fbf 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -85,7 +85,6 @@
      *
      *  @hide
      */
-    @SystemApi
     public static final String STRING_VVM_DESTINATION_NUMBER = "string_vvm_destination_number";
 
     /**
@@ -93,15 +92,13 @@
      *
      * @hide
      */
-    @SystemApi
-    public static final String SHORT_VVM_PORT_NUMBER = "string_vvm_port_number";
+    public static final String INT_VVM_PORT_NUMBER = "int_vvm_port_number";
 
     /**
      * The type of visual voicemail protocol the carrier adheres to (see below).
      *
      * @hide
      */
-    @SystemApi
     public static final String STRING_VVM_TYPE = "string_vvm_type";
 
     /* Visual voicemail protocols */
@@ -111,7 +108,6 @@
      *
      * @hide
      */
-    @SystemApi
     public static final String VVM_TYPE_OMTP = "vvm_type_omtp";
 
     private final static String TAG = "CarrierConfigManager";
@@ -127,6 +123,10 @@
         sDefaults.putBoolean(BOOL_SHOW_APN_SETTING_CDMA, false);
 
         sDefaults.putInt(INT_VOLTE_REPLACEMENT_RAT, 0);
+
+        sDefaults.putString(STRING_VVM_DESTINATION_NUMBER, "");
+        sDefaults.putString(STRING_VVM_TYPE, "");
+        sDefaults.putInt(INT_VVM_PORT_NUMBER, 0);
     }
 
     /**
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 08aec08..3ecf5ac 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -272,10 +272,6 @@
      * for #onSubscriptionsChanged to be invoked.
      */
     public static class OnSubscriptionsChangedListener {
-        /** @hide */
-        public static final String PERMISSION_ON_SUBSCRIPTIONS_CHANGED =
-                android.Manifest.permission.READ_PHONE_STATE;
-
         private final Handler mHandler  = new Handler() {
             @Override
             public void handleMessage(Message msg) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 128f6e3..cd3f636 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -664,7 +664,7 @@
             ITelephony telephony = getITelephony();
             if (telephony == null)
                 return null;
-            return telephony.getDeviceId();
+            return telephony.getDeviceId(mContext.getOpPackageName());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -1975,7 +1975,7 @@
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
-                number = telephony.getLine1NumberForDisplay(subId);
+                number = telephony.getLine1NumberForDisplay(subId, mContext.getOpPackageName());
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
@@ -2096,7 +2096,8 @@
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
-                alphaTag = telephony.getLine1AlphaTagForDisplay(subId);
+                alphaTag = telephony.getLine1AlphaTagForDisplay(subId,
+                        mContext.getOpPackageName());
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
@@ -3342,7 +3343,7 @@
             ITelephony telephony = getITelephony();
             if (telephony == null)
                 return new String[0];
-            return telephony.getPcscfAddress(apnType);
+            return telephony.getPcscfAddress(apnType, mContext.getOpPackageName());
         } catch (RemoteException e) {
             return new String[0];
         }
@@ -3759,7 +3760,7 @@
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
-                return telephony.isSimPinEnabled();
+                return telephony.isSimPinEnabled(mContext.getOpPackageName());
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#isSimPinEnabled", e);
         }
@@ -4026,7 +4027,7 @@
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
-                return telephony.isVideoCallingEnabled();
+                return telephony.isVideoCallingEnabled(mContext.getOpPackageName());
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#isVideoCallingEnabled", e);
         }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index a24859b..4fe88c4 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -45,6 +45,7 @@
 
     /**
      * Place a call to the specified number.
+     * @param callingPackage The package making the call.
      * @param number the number to be called.
      */
     void call(String callingPackage, String number);
@@ -169,8 +170,9 @@
     /**
      * Check if the SIM pin lock is enabled.
      * @return true if the SIM pin lock is enabled.
+     * @param callingPackage The package making the call.
      */
-    boolean isSimPinEnabled();
+    boolean isSimPinEnabled(String callingPackage);
 
     /**
      * Supply a pin to unlock the SIM.  Blocks until a result is determined.
@@ -644,10 +646,11 @@
     /*
      * Get the calculated preferred network type.
      * Used for device configuration by some CDMA operators.
+     * @param callingPackage The package making the call.
      *
      * @return the calculated preferred network type, defined in RILConstants.java.
      */
-    int getCalculatedPreferredNetworkType();
+    int getCalculatedPreferredNetworkType(String callingPackage);
 
     /*
      * Get the preferred network type.
@@ -701,8 +704,9 @@
     /**
      * Get P-CSCF address from PCO after data connection is established or modified.
      * @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN
+     * @param callingPackage The package making the call.
      */
-    String[] getPcscfAddress(String apnType);
+    String[] getPcscfAddress(String apnType, String callingPackage);
 
     /**
      * Set IMS registration state
@@ -768,19 +772,21 @@
      * {@link #setLine1NumberForDisplay}. Otherwise returns null.
      *
      * @param subId whose dialing number for line 1 is returned.
+     * @param callingPackage The package making the call.
      * @return the displayed dialing number if set, or null if not set.
      */
-    String getLine1NumberForDisplay(int subId);
+    String getLine1NumberForDisplay(int subId, String callingPackage);
 
     /**
      * Returns the displayed alphatag of the dialing number if it was set
      * previously via {@link #setLine1NumberForDisplay}. Otherwise returns null.
      *
      * @param subId whose alphatag associated with line 1 is returned.
+     * @param callingPackage The package making the call.
      * @return the displayed alphatag of the dialing number if set, or null if
      *         not set.
      */
-    String getLine1AlphaTagForDisplay(int subId);
+    String getLine1AlphaTagForDisplay(int subId, String callingPackage);
 
     String[] getMergedSubscriberIds();
 
@@ -872,9 +878,10 @@
     /**
      * Whether video calling has been enabled by the user.
      *
+     * @param callingPackage The package making the call.
      * @return {@code true} if the user has enabled video calling, {@code false} otherwise.
      */
-    boolean isVideoCallingEnabled();
+    boolean isVideoCallingEnabled(String callingPackage);
 
     /**
      * Whether the DTMF tone length can be changed.
@@ -925,10 +932,11 @@
       * Returns the unique device ID of phone, for example, the IMEI for
       * GSM and the MEID for CDMA phones. Return null if device ID is not available.
       *
+      * @param callingPackage The package making the call.
       * <p>Requires Permission:
       *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
       */
-    String getDeviceId();
+    String getDeviceId(String callingPackage);
 
     /**
      * Returns the subscription ID associated with the specified PhoneAccount.
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index b265d47..04ded9d 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -354,6 +354,13 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @hide */
+    @Override
+    public void sendBroadcastAsUser(Intent intent, UserHandle user,
+            String receiverPermission, int appOp) {
+        throw new UnsupportedOperationException();
+    }
+
     @Override
     public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
             String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,