Merge "Uses a notification to request auto-fill."
diff --git a/Android.mk b/Android.mk
index f6e4b0a..cd738e7 100644
--- a/Android.mk
+++ b/Android.mk
@@ -488,7 +488,7 @@
 	../../system/update_engine/binder_bindings/android/os/IUpdateEngine.aidl \
 	../../system/update_engine/binder_bindings/android/os/IUpdateEngineCallback.aidl \
 
-LOCAL_SRC_FILES +=  \
+LOCAL_SRC_FILES += \
 	../../system/netd/server/binder/android/net/INetd.aidl \
 
 LOCAL_AIDL_INCLUDES += system/update_engine/binder_bindings
@@ -520,6 +520,7 @@
 LOCAL_STATIC_JAVA_LIBRARIES :=                          \
     framework-protos                                    \
     android.hardware.thermal@1.0-java-constants         \
+    android.hardware.health@1.0-java-constants          \
 
 LOCAL_MODULE := framework
 
diff --git a/api/current.txt b/api/current.txt
index 8a68076..fede9cf 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4954,9 +4954,9 @@
     ctor public Notification(android.os.Parcel);
     method public android.app.Notification clone();
     method public int describeContents();
+    method public java.lang.String getChannel();
     method public java.lang.String getGroup();
     method public android.graphics.drawable.Icon getLargeIcon();
-    method public java.lang.String getNotificationChannel();
     method public android.graphics.drawable.Icon getSmallIcon();
     method public java.lang.String getSortKey();
     method public void writeToParcel(android.os.Parcel, int);
@@ -5983,6 +5983,7 @@
     method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
     method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
     method public void addUserRestriction(android.content.ComponentName, java.lang.String);
+    method public boolean bindDeviceAdminServiceAsUser(android.content.ComponentName, android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle);
     method public void clearCrossProfileIntentFilters(android.content.ComponentName);
     method public void clearDeviceOwnerApp(java.lang.String);
     method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
@@ -37266,8 +37267,12 @@
     method public int describeContents();
     method public boolean equals(java.lang.Object);
     method public int getAsuLevel();
+    method public int getCqi();
     method public int getDbm();
     method public int getLevel();
+    method public int getRsrp();
+    method public int getRsrq();
+    method public int getRssnr();
     method public int getTimingAdvance();
     method public int hashCode();
     method public void writeToParcel(android.os.Parcel, int);
@@ -45109,6 +45114,7 @@
     field public static final int IME_FLAG_NO_ENTER_ACTION = 1073741824; // 0x40000000
     field public static final int IME_FLAG_NO_EXTRACT_UI = 268435456; // 0x10000000
     field public static final int IME_FLAG_NO_FULLSCREEN = 33554432; // 0x2000000
+    field public static final int IME_FLAG_NO_PERSONALIZED_LEARNING = 16777216; // 0x1000000
     field public static final int IME_MASK_ACTION = 255; // 0xff
     field public static final int IME_NULL = 0; // 0x0
     field public int actionId;
diff --git a/api/system-current.txt b/api/system-current.txt
index a8cee67..b5b7441 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5107,9 +5107,9 @@
     ctor public Notification(android.os.Parcel);
     method public android.app.Notification clone();
     method public int describeContents();
+    method public java.lang.String getChannel();
     method public java.lang.String getGroup();
     method public android.graphics.drawable.Icon getLargeIcon();
-    method public java.lang.String getNotificationChannel();
     method public android.graphics.drawable.Icon getSmallIcon();
     method public java.lang.String getSortKey();
     method public void writeToParcel(android.os.Parcel, int);
@@ -6154,6 +6154,7 @@
     method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
     method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
     method public void addUserRestriction(android.content.ComponentName, java.lang.String);
+    method public boolean bindDeviceAdminServiceAsUser(android.content.ComponentName, android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle);
     method public void clearCrossProfileIntentFilters(android.content.ComponentName);
     method public void clearDeviceOwnerApp(java.lang.String);
     method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
@@ -40344,8 +40345,12 @@
     method public int describeContents();
     method public boolean equals(java.lang.Object);
     method public int getAsuLevel();
+    method public int getCqi();
     method public int getDbm();
     method public int getLevel();
+    method public int getRsrp();
+    method public int getRsrq();
+    method public int getRssnr();
     method public int getTimingAdvance();
     method public int hashCode();
     method public void writeToParcel(android.os.Parcel, int);
@@ -48279,6 +48284,7 @@
     field public static final int IME_FLAG_NO_ENTER_ACTION = 1073741824; // 0x40000000
     field public static final int IME_FLAG_NO_EXTRACT_UI = 268435456; // 0x10000000
     field public static final int IME_FLAG_NO_FULLSCREEN = 33554432; // 0x2000000
+    field public static final int IME_FLAG_NO_PERSONALIZED_LEARNING = 16777216; // 0x1000000
     field public static final int IME_MASK_ACTION = 255; // 0xff
     field public static final int IME_NULL = 0; // 0x0
     field public int actionId;
diff --git a/api/test-current.txt b/api/test-current.txt
index 56da49c..918400e 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -4964,9 +4964,9 @@
     ctor public Notification(android.os.Parcel);
     method public android.app.Notification clone();
     method public int describeContents();
+    method public java.lang.String getChannel();
     method public java.lang.String getGroup();
     method public android.graphics.drawable.Icon getLargeIcon();
-    method public java.lang.String getNotificationChannel();
     method public android.graphics.drawable.Icon getSmallIcon();
     method public java.lang.String getSortKey();
     method public void writeToParcel(android.os.Parcel, int);
@@ -5999,6 +5999,7 @@
     method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
     method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
     method public void addUserRestriction(android.content.ComponentName, java.lang.String);
+    method public boolean bindDeviceAdminServiceAsUser(android.content.ComponentName, android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle);
     method public void clearCrossProfileIntentFilters(android.content.ComponentName);
     method public void clearDeviceOwnerApp(java.lang.String);
     method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
@@ -37356,8 +37357,12 @@
     method public int describeContents();
     method public boolean equals(java.lang.Object);
     method public int getAsuLevel();
+    method public int getCqi();
     method public int getDbm();
     method public int getLevel();
+    method public int getRsrp();
+    method public int getRsrq();
+    method public int getRssnr();
     method public int getTimingAdvance();
     method public int hashCode();
     method public void writeToParcel(android.os.Parcel, int);
@@ -45356,6 +45361,7 @@
     field public static final int IME_FLAG_NO_ENTER_ACTION = 1073741824; // 0x40000000
     field public static final int IME_FLAG_NO_EXTRACT_UI = 268435456; // 0x10000000
     field public static final int IME_FLAG_NO_FULLSCREEN = 33554432; // 0x2000000
+    field public static final int IME_FLAG_NO_PERSONALIZED_LEARNING = 16777216; // 0x1000000
     field public static final int IME_MASK_ACTION = 255; // 0xff
     field public static final int IME_NULL = 0; // 0x0
     field public int actionId;
diff --git a/core/java/android/annotation/HalfFloat.java b/core/java/android/annotation/HalfFloat.java
new file mode 100644
index 0000000..d3e9f08
--- /dev/null
+++ b/core/java/android/annotation/HalfFloat.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2016 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.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * <p>Denotes that the annotated element represents a half-precision floating point
+ * value. Such values are stored in short data types and can be manipulated with
+ * the {@link android.util.Half} class. If applied to an array of short, every
+ * element in the array represents a half-precision float.</p>
+ *
+ * <p>Example:</p>
+ *
+ * <pre>{@code
+ * public abstract void setPosition(@HalfFloat short x, @HalfFloat short y, @HalfFloat short z);
+ * }</pre>
+ *
+ * @see android.util.Half
+ * @see android.util.Half#valueOf(float)
+ * @see android.util.Half#toFloat(short)
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({PARAMETER, METHOD, LOCAL_VARIABLE, FIELD})
+public @interface HalfFloat {
+}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index d41a7e8..8dd4c9c 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -5859,6 +5859,7 @@
                     case BlockedNumberContract.AUTHORITY:
                     case CalendarContract.AUTHORITY:
                     case Downloads.Impl.AUTHORITY:
+                    case "telephony":
                         Binder.allowBlocking(provider.asBinder());
                 }
             }
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index cf794c5..6b16e8f 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -349,7 +349,9 @@
 
     public BackStackRecord(FragmentManagerImpl manager) {
         mManager = manager;
-        mAllowOptimization = Build.isAtLeastO();
+        int targetSdkVersion = manager.mHost.getContext().getApplicationInfo().targetSdkVersion;
+        // TODO: make the check N_MR1 or O
+        mAllowOptimization = targetSdkVersion > Build.VERSION_CODES.N;
     }
 
     public int getId() {
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index f1d0e10..c5180fd 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentProvider;
@@ -1457,8 +1458,22 @@
         return bindServiceCommon(service, conn, flags, handler, user);
     }
 
+    /** @hide */
+    @Override
+    public IServiceConnection getServiceDispatcher(ServiceConnection conn, Handler handler,
+            int flags) {
+        return mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
+    }
+
+    /** @hide */
+    @Override
+    public IApplicationThread getIApplicationThread() {
+        return mMainThread.getApplicationThread();
+    }
+
     private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
             handler, UserHandle user) {
+        // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
         IServiceConnection sd;
         if (conn == null) {
             throw new IllegalArgumentException("connection is null");
@@ -2141,7 +2156,8 @@
         return mOuterContext;
     }
 
-    final IBinder getActivityToken() {
+    @Override
+    public IBinder getActivityToken() {
         return mActivityToken;
     }
 
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index bdb2685..261fde2 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2239,7 +2239,7 @@
     /**
      * Returns the id of the channel this notification posts to.
      */
-    public String getNotificationChannel() {
+    public String getChannel() {
         return mChannelId;
     }
 
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index 360087c..cbd5a6d 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -285,6 +285,27 @@
             = "android.app.action.NETWORK_LOGS_AVAILABLE";
 
     /**
+     * A {@code long} containing a token of the current batch of network logs, that has to be used
+     * to retrieve the batch of logs by the device owner.
+     *
+     * @see #ACTION_NETWORK_LOGS_AVAILABLE
+     * @see DevicePolicyManager#retrieveNetworkLogs
+     * @hide
+     */
+    public static final String EXTRA_NETWORK_LOGS_TOKEN =
+            "android.app.extra.EXTRA_NETWORK_LOGS_TOKEN";
+
+    /**
+     * An {@code int} count representing a total count of network logs inside the current batch of
+     * network logs.
+     *
+     * @see #ACTION_NETWORK_LOGS_AVAILABLE
+     * @hide
+     */
+    public static final String EXTRA_NETWORK_LOGS_COUNT =
+            "android.app.extra.EXTRA_NETWORK_LOGS_COUNT";
+
+    /**
      * A string containing the SHA-256 hash of the bugreport file.
      *
      * @see #ACTION_BUGREPORT_SHARE
@@ -644,19 +665,22 @@
     }
 
     /**
-     * Called when a new batch of network logs can be retrieved. This callback method will only ever
-     * be called when network logging is enabled. The logs can only be retrieved while network
+     * Called each time a new batch of network logs can be retrieved. This callback method will only
+     * ever be called when network logging is enabled. The logs can only be retrieved while network
      * logging is enabled.
      *
      * <p>This callback is only applicable to device owners.
      *
      * @param context The running context as per {@link #onReceive}.
      * @param intent The received intent as per {@link #onReceive}.
+     * @param batchToken The token representing the current batch of network logs.
+     * @param networkLogsCount The total count of events in the current batch of network logs.
      * @see DevicePolicyManager#retrieveNetworkLogs(ComponentName)
      *
      * @hide
      */
-    public void onNetworkLogsAvailable(Context context, Intent intent) {
+    public void onNetworkLogsAvailable(Context context, Intent intent, long batchToken,
+            int networkLogsCount) {
     }
 
     /**
@@ -714,7 +738,9 @@
         } else if (ACTION_SECURITY_LOGS_AVAILABLE.equals(action)) {
             onSecurityLogsAvailable(context, intent);
         } else if (ACTION_NETWORK_LOGS_AVAILABLE.equals(action)) {
-            onNetworkLogsAvailable(context, intent);
+            long batchToken = intent.getLongExtra(EXTRA_NETWORK_LOGS_TOKEN, -1);
+            int networkLogsCount = intent.getIntExtra(EXTRA_NETWORK_LOGS_COUNT, 0);
+            onNetworkLogsAvailable(context, intent, batchToken, networkLogsCount);
         }
     }
 }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 538e52b..5ca39b0 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -20,19 +20,21 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
 import android.annotation.UserIdInt;
 import android.annotation.WorkerThread;
 import android.app.Activity;
-import android.app.admin.NetworkEvent;
 import android.app.admin.PasswordMetrics;
+import android.app.IServiceConnection;
 import android.app.admin.SecurityLog.SecurityEvent;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ParceledListSlice;
@@ -45,10 +47,8 @@
 import android.os.Process;
 import android.os.RemoteCallback;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.os.ServiceManager.ServiceNotFoundException;
 import android.provider.ContactsContract.Directory;
 import android.provider.Settings;
 import android.security.Credentials;
@@ -6649,8 +6649,6 @@
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param enabled whether network logging should be enabled or not.
      * @throws {@link SecurityException} if {@code admin} is not a device owner.
-     * @throws {@link RemoteException} if network logging could not be enabled or disabled due to
-     *         the logging service not being available
      * @see #retrieveNetworkLogs
      *
      * @hide
@@ -6683,7 +6681,10 @@
     }
 
     /**
-     * Called by device owner to retrieve a new batch of network logging events.
+     * Called by device owner to retrieve the most recent batch of network logging events.
+     * A device owner has to provide a batchToken provided as part of
+     * {@link DeviceAdminReceiver#onNetworkLogsAvailable} callback. If the token doesn't match the
+     * token of the most recent available batch of logs, {@code null} will be returned.
      *
      * <p> {@link NetworkEvent} can be one of {@link DnsEvent} or {@link ConnectEvent}.
      *
@@ -6694,16 +6695,56 @@
      * {@link DeviceAdminReceiver#onNetworkLogsAvailable}.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param batchToken A token of the batch to retrieve
      * @return A new batch of network logs which is a list of {@link NetworkEvent}. Returns
-     * {@code null} if there's no batch currently awaiting for retrieval or if logging is disabled.
+     *        {@code null} if the batch represented by batchToken is no longer available or if
+     *        logging is disabled.
      * @throws {@link SecurityException} if {@code admin} is not a device owner.
+     * @see DeviceAdminReceiver#onNetworkLogsAvailable
      *
      * @hide
      */
-    public List<NetworkEvent> retrieveNetworkLogs(@NonNull ComponentName admin) {
+    public @Nullable List<NetworkEvent> retrieveNetworkLogs(@NonNull ComponentName admin,
+            long batchToken) {
         throwIfParentInstance("retrieveNetworkLogs");
         try {
-            return mService.retrieveNetworkLogs(admin);
+            return mService.retrieveNetworkLogs(admin, batchToken);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Called by device owner/ profile owner in managed profile to bind the service with each other.
+     * The service must be unexported. Note that the {@link Context} used to obtain this
+     * {@link DevicePolicyManager} instance via {@link Context#getSystemService(Class)} will be used
+     * to bind to the {@link android.app.Service}.
+     * STOPSHIP (b/31952368): Update the javadoc after we policy to control which packages can talk.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param serviceIntent Identifies the service to connect to.  The Intent must specify either an
+     *        explicit component name or a package name to match an
+     *        {@link IntentFilter} published by a service.
+     * @param conn Receives information as the service is started and stopped. This must be a
+     *        valid {@link ServiceConnection} object; it must not be {@code null}.
+     * @param flags Operation options for the binding operation. See
+     *        {@link Context#bindService(Intent, ServiceConnection, int)}.
+     * @param targetUser Which user to bind to.
+     * @return If you have successfully bound to the service, {@code true} is returned;
+     *         {@code false} is returned if the connection is not made and you will not
+     *         receive the service object.
+     * @see Context#bindService(Intent, ServiceConnection, int)
+     */
+    public boolean bindDeviceAdminServiceAsUser(
+            @NonNull ComponentName admin,  Intent serviceIntent, @NonNull ServiceConnection conn,
+            @Context.BindServiceFlags int flags, @NonNull UserHandle targetUser) {
+        throwIfParentInstance("bindDeviceAdminServiceAsUser");
+        // Keep this in sync with ContextImpl.bindServiceCommon.
+        try {
+            final IServiceConnection sd = mContext.getServiceDispatcher(conn, null, flags);
+            serviceIntent.prepareToLeaveProcess(mContext);
+            return mService.bindDeviceAdminServiceAsUser(admin,
+                    mContext.getIApplicationThread(), mContext.getActivityToken(), serviceIntent,
+                    sd, flags, targetUser.getIdentifier());
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index b0aec8c..a2546c0 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -18,6 +18,8 @@
 package android.app.admin;
 
 import android.app.admin.NetworkEvent;
+import android.app.IApplicationThread;
+import android.app.IServiceConnection;
 import android.app.admin.SystemUpdatePolicy;
 import android.app.admin.PasswordMetrics;
 import android.content.ComponentName;
@@ -318,5 +320,9 @@
 
     void setNetworkLoggingEnabled(in ComponentName admin, boolean enabled);
     boolean isNetworkLoggingEnabled(in ComponentName admin);
-    List<NetworkEvent> retrieveNetworkLogs(in ComponentName admin);
+    List<NetworkEvent> retrieveNetworkLogs(in ComponentName admin, long batchToken);
+
+    boolean bindDeviceAdminServiceAsUser(in ComponentName admin,
+        IApplicationThread caller, IBinder token, in Intent service,
+        IServiceConnection connection, int flags, int targetUserId);
 }
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index bb344a6..b0e27a4 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -604,10 +604,6 @@
      */
     public BluetoothLeAdvertiser getBluetoothLeAdvertiser() {
         if (!getLeAccess()) return null;
-        if (!isMultipleAdvertisementSupported() && !isPeripheralModeSupported()) {
-            Log.e(TAG, "Bluetooth LE advertising not supported");
-            return null;
-        }
         synchronized(mLock) {
             if (sBluetoothLeAdvertiser == null) {
                 sBluetoothLeAdvertiser = new BluetoothLeAdvertiser(mManagerService);
@@ -1357,24 +1353,6 @@
     }
 
     /**
-     * Returns whether peripheral mode is supported.
-     *
-     * @hide
-     */
-    public boolean isPeripheralModeSupported() {
-        if (getState() != STATE_ON) return false;
-        try {
-            mServiceLock.readLock().lock();
-            if (mService != null) return mService.isPeripheralModeSupported();
-        } catch (RemoteException e) {
-            Log.e(TAG, "failed to get peripheral mode capability: ", e);
-        } finally {
-            mServiceLock.readLock().unlock();
-        }
-        return false;
-    }
-
-    /**
      * Return true if offloaded filters are supported
      *
      * @return true if chipset supports on-chip filtering
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index 96a1ae8..7c5458b 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -100,7 +100,6 @@
     boolean factoryReset();
 
     boolean isMultiAdvertisementSupported();
-    boolean isPeripheralModeSupported();
     boolean isOffloadedFilteringSupported();
     boolean isOffloadedScanBatchingSupported();
     boolean isActivityAndEnergyReportingSupported();
diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index 26f2dea..5d27662 100644
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -111,12 +111,6 @@
             if (callback == null) {
                 throw new IllegalArgumentException("callback cannot be null");
             }
-            if (!mBluetoothAdapter.isMultipleAdvertisementSupported() &&
-                    !mBluetoothAdapter.isPeripheralModeSupported()) {
-                postStartFailure(callback,
-                        AdvertiseCallback.ADVERTISE_FAILED_FEATURE_UNSUPPORTED);
-                return;
-            }
             boolean isConnectable = settings.isConnectable();
             if (totalBytes(advertiseData, isConnectable) > MAX_ADVERTISING_DATA_BYTES ||
                     totalBytes(scanResponse, false) > MAX_ADVERTISING_DATA_BYTES) {
@@ -236,9 +230,9 @@
         private final AdvertiseSettings mSettings;
         private final IBluetoothGatt mBluetoothGatt;
 
-        // mAdvertiserId 0: not registered
-        // -1: advertise stopped or registration timeout
-        // >0: registered and advertising started
+        // mAdvertiserId -1: not registered
+        // -2: advertise stopped or registration timeout
+        // >=0: registered and advertising started
         private int mAdvertiserId;
         private boolean mIsAdvertising = false;
 
@@ -251,12 +245,12 @@
             mScanResponse = scanResponse;
             mSettings = settings;
             mBluetoothGatt = bluetoothGatt;
-            mAdvertiserId = 0;
+            mAdvertiserId = -1;
         }
 
         public void startRegisteration() {
             synchronized (this) {
-                if (mAdvertiserId == -1) return;
+                if (mAdvertiserId == -2) return;
 
                 try {
                     mBluetoothGatt.registerAdvertiser(this);
@@ -264,13 +258,13 @@
                 } catch (InterruptedException | RemoteException e) {
                     Log.e(TAG, "Failed to start registeration", e);
                 }
-                if (mAdvertiserId > 0 && mIsAdvertising) {
+                if (mAdvertiserId >= 0 && mIsAdvertising) {
                     mLeAdvertisers.put(mAdvertiseCallback, this);
-                } else if (mAdvertiserId <= 0) {
+                } else if (mAdvertiserId < 0) {
 
                     // Registration timeout, reset mClientIf to -1 so no subsequent operations can
                     // proceed.
-                    if (mAdvertiserId == 0) mAdvertiserId = -1;
+                    if (mAdvertiserId == 0) mAdvertiserId = -2;
                     // Post internal error if registration failed.
                     postStartFailure(mAdvertiseCallback,
                             AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR);
@@ -278,7 +272,7 @@
                     // Unregister application if it's already registered but advertise failed.
                     try {
                         mBluetoothGatt.unregisterAdvertiser(mAdvertiserId);
-                        mAdvertiserId = -1;
+                        mAdvertiserId = -2;
                     } catch (RemoteException e) {
                         Log.e(TAG, "remote exception when unregistering", e);
                     }
@@ -312,7 +306,7 @@
             synchronized (this) {
                 if (status == BluetoothGatt.GATT_SUCCESS) {
                     try {
-                        if (mAdvertiserId == -1) {
+                        if (mAdvertiserId == -2) {
                             // Registration succeeds after timeout, unregister advertiser.
                             mBluetoothGatt.unregisterAdvertiser(advertiserId);
                         } else {
@@ -326,7 +320,7 @@
                     }
                 }
                 // Registration failed.
-                mAdvertiserId = -1;
+                mAdvertiserId = -2;
                 notifyAll();
             }
         }
@@ -348,7 +342,7 @@
                     // unregister advertiser for stop.
                     try {
                         mBluetoothGatt.unregisterAdvertiser(mAdvertiserId);
-                        mAdvertiserId = -1;
+                        mAdvertiserId = -2;
                         mIsAdvertising = false;
                         mLeAdvertisers.remove(mAdvertiseCallback);
                     } catch (RemoteException e) {
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 1e6424e..49b5853 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -42,6 +42,7 @@
 import android.os.OperationCanceledException;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.Log;
@@ -463,6 +464,23 @@
             }
         }
 
+        @Override
+        public boolean refresh(String callingPkg, Uri uri, Bundle args,
+                ICancellationSignal cancellationSignal) throws RemoteException {
+            validateIncomingUri(uri);
+            uri = getUriWithoutUserId(uri);
+            if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
+                return false;
+            }
+            final String original = setCallingPackage(callingPkg);
+            try {
+                return ContentProvider.this.refresh(uri, args,
+                        CancellationSignal.fromTransport(cancellationSignal));
+            } finally {
+                setCallingPackage(original);
+            }
+        }
+
         private void enforceFilePermission(String callingPkg, Uri uri, String mode,
                 IBinder callerToken) throws FileNotFoundException, SecurityException {
             if (mode != null && mode.indexOf('w') != -1) {
@@ -1093,6 +1111,34 @@
     }
 
     /**
+     * Implement this to support refresh of content identified by {@code uri}. By default, this
+     * method returns false; providers who wish to implement this should return true to signal the
+     * client that the provider has tried refreshing with its own implementation.
+     * <p>
+     * This allows clients to request an explicit refresh of content identified by {@code uri}.
+     * <p>
+     * Client code should only invoke this method when there is a strong indication (such as a user
+     * initiated pull to refresh gesture) that the content is stale.
+     * <p>
+     * Remember to send {@link ContentResolver#notifyChange(Uri, android.database.ContentObserver)}
+     * notifications when content changes.
+     *
+     * @param uri The Uri identifying the data to refresh.
+     * @param args Additional options from the client. The definitions of these are specific to the
+     *            content provider being called.
+     * @param cancellationSignal A signal to cancel the operation in progress, or {@code null} if
+     *            none. For example, if you called refresh on a particular uri, you should call
+     *            {@link CancellationSignal#throwIfCanceled()} to check whether the client has
+     *            canceled the refresh request.
+     * @return true if the provider actually tried refreshing.
+     * @hide
+     */
+    public boolean refresh(Uri uri, @Nullable Bundle args,
+            @Nullable CancellationSignal cancellationSignal) {
+        return false;
+    }
+
+    /**
      * @hide
      * Implementation when a caller has performed an insert on the content
      * provider, but that call has been rejected for the operation given
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index 9221fbb..857610d 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -234,6 +234,30 @@
         }
     }
 
+    /** @hide */
+    public boolean refresh(Uri url, @Nullable Bundle args,
+            @Nullable CancellationSignal cancellationSignal) throws RemoteException {
+        Preconditions.checkNotNull(url, "url");
+
+        beforeRemote();
+        try {
+            ICancellationSignal remoteCancellationSignal = null;
+            if (cancellationSignal != null) {
+                cancellationSignal.throwIfCanceled();
+                remoteCancellationSignal = mContentProvider.createCancellationSignal();
+                cancellationSignal.setRemote(remoteCancellationSignal);
+            }
+            return mContentProvider.refresh(mPackageName, url, args, remoteCancellationSignal);
+        } catch (DeadObjectException e) {
+            if (!mStable) {
+                mContentResolver.unstableProviderDied(mContentProvider);
+            }
+            throw e;
+        } finally {
+            afterRemote();
+        }
+    }
+
     /** See {@link ContentProvider#insert ContentProvider.insert} */
     public @Nullable Uri insert(@NonNull Uri url, @Nullable ContentValues initialValues)
             throws RemoteException {
diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java
index 439e1ff..eadc013 100644
--- a/core/java/android/content/ContentProviderNative.java
+++ b/core/java/android/content/ContentProviderNative.java
@@ -355,6 +355,20 @@
                     Uri.writeToParcel(reply, out);
                     return true;
                 }
+
+                case REFRESH_TRANSACTION: {
+                    data.enforceInterface(IContentProvider.descriptor);
+                    String callingPkg = data.readString();
+                    Uri url = Uri.CREATOR.createFromParcel(data);
+                    Bundle args = data.readBundle();
+                    ICancellationSignal signal = ICancellationSignal.Stub.asInterface(
+                            data.readStrongBinder());
+
+                    boolean out = refresh(callingPkg, url, args, signal);
+                    reply.writeNoException();
+                    reply.writeInt(out ? 0 : -1);
+                    return true;
+                }
             }
         } catch (Exception e) {
             DatabaseUtils.writeExceptionToParcel(reply, e);
@@ -761,5 +775,28 @@
         }
     }
 
+    public boolean refresh(String callingPkg, Uri url, Bundle args, ICancellationSignal signal)
+            throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        try {
+            data.writeInterfaceToken(IContentProvider.descriptor);
+
+            data.writeString(callingPkg);
+            url.writeToParcel(data, 0);
+            data.writeBundle(args);
+            data.writeStrongBinder(signal != null ? signal.asBinder() : null);
+
+            mRemote.transact(IContentProvider.REFRESH_TRANSACTION, data, reply, 0);
+
+            DatabaseUtils.readExceptionFromParcel(reply);
+            int success = reply.readInt();
+            return (success == 0);
+        } finally {
+            data.recycle();
+            reply.recycle();
+        }
+    }
+
     private IBinder mRemote;
 }
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index daa1b93..705c091 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -194,6 +194,15 @@
     public static final String EXTRA_SIZE = "android.content.extra.SIZE";
 
     /**
+     * An extra boolean describing whether a particular provider supports refresh
+     * or not. If a provider supports refresh, it should include this key in its
+     * returned Cursor as part of its query call.
+     *
+     * @hide
+     */
+    public static final String EXTRA_REFRESH_SUPPORTED = "android.content.extra.REFRESH_SUPPORTED";
+
+    /**
      * This is the Android platform's base MIME type for a content: URI
      * containing a Cursor of a single item.  Applications should use this
      * as the base type along with their own sub-type of their content: URIs
@@ -664,6 +673,54 @@
     }
 
     /**
+     * Implement this to support refresh of content identified by {@code uri}. By default, this
+     * method returns false; providers who wish to implement this should return true to signal the
+     * client that the provider has tried refreshing with its own implementation.
+     * <p>
+     * This allows clients to request an explicit refresh of content identified by {@code uri}.
+     * <p>
+     * Client code should only invoke this method when there is a strong indication (such as a user
+     * initiated pull to refresh gesture) that the content is stale.
+     * <p>
+     * Remember to send {@link ContentResolver#notifyChange(Uri, android.database.ContentObserver)}
+     * notifications when content changes.
+     *
+     * @param uri The Uri identifying the data to refresh.
+     * @param args Additional options from the client. The definitions of these are specific to the
+     *            content provider being called.
+     * @param cancellationSignal A signal to cancel the operation in progress, or {@code null} if
+     *            none. For example, if you called refresh on a particular uri, you should call
+     *            {@link CancellationSignal#throwIfCanceled()} to check whether the client has
+     *            canceled the refresh request.
+     * @return true if the provider actually tried refreshing.
+     * @hide
+     */
+    public final boolean refresh(@NonNull Uri url, @Nullable Bundle args,
+            @Nullable CancellationSignal cancellationSignal) {
+        Preconditions.checkNotNull(url, "url");
+        IContentProvider provider = acquireProvider(url);
+        if (provider == null) {
+            return false;
+        }
+
+        try {
+            ICancellationSignal remoteCancellationSignal = null;
+            if (cancellationSignal != null) {
+                cancellationSignal.throwIfCanceled();
+                remoteCancellationSignal = provider.createCancellationSignal();
+                cancellationSignal.setRemote(remoteCancellationSignal);
+            }
+            return provider.refresh(mPackageName, url, args, remoteCancellationSignal);
+        } catch (RemoteException e) {
+            // Arbitrary and not worth documenting, as Activity
+            // Manager will kill this process shortly anyway.
+            return false;
+        } finally {
+            releaseProvider(provider);
+        }
+    }
+
+    /**
      * Open a stream on to the content associated with a content URI.  If there
      * is no data associated with the URI, FileNotFoundException is thrown.
      *
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 3964e0a..821b0f8 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -32,6 +32,10 @@
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.annotation.UserIdInt;
+import android.app.IApplicationThread;
+import android.app.IServiceConnection;
+import android.app.LoadedApk;
+import android.app.admin.DevicePolicyManager;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.AssetManager;
@@ -4363,4 +4367,27 @@
     public boolean isCredentialEncryptedStorage() {
         return isCredentialProtectedStorage();
     }
+
+    /**
+     * @hide
+     */
+    public IBinder getActivityToken() {
+        throw new RuntimeException("Not implemented. Must override in a subclass.");
+    }
+
+    /**
+     * @hide
+     */
+    @Nullable
+    public IServiceConnection getServiceDispatcher(ServiceConnection conn, Handler handler,
+            int flags) {
+        throw new RuntimeException("Not implemented. Must override in a subclass.");
+    }
+
+    /**
+     * @hide
+     */
+    public IApplicationThread getIApplicationThread() {
+        throw new RuntimeException("Not implemented. Must override in a subclass.");
+    }
 }
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index edc8d82..7533655 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -16,7 +16,10 @@
 
 package android.content;
 
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.app.IApplicationThread;
+import android.app.IServiceConnection;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.AssetManager;
@@ -857,4 +860,29 @@
     public boolean isCredentialProtectedStorage() {
         return mBase.isCredentialProtectedStorage();
     }
+
+    /**
+     * @hide
+     */
+    @Override
+    public IBinder getActivityToken() {
+        return mBase.getActivityToken();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public IServiceConnection getServiceDispatcher(ServiceConnection conn, Handler handler,
+            int flags) {
+        return mBase.getServiceDispatcher(conn, handler, flags);
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public IApplicationThread getIApplicationThread() {
+        return mBase.getIApplicationThread();
+    }
 }
diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java
index 4afe38b..ee8a22f 100644
--- a/core/java/android/content/IContentProvider.java
+++ b/core/java/android/content/IContentProvider.java
@@ -65,6 +65,9 @@
     public Uri canonicalize(String callingPkg, Uri uri) throws RemoteException;
     public Uri uncanonicalize(String callingPkg, Uri uri) throws RemoteException;
 
+    public boolean refresh(String callingPkg, Uri url, @Nullable Bundle args,
+            ICancellationSignal cancellationSignal) throws RemoteException;
+
     // Data interchange.
     public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException;
     public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri url, String mimeType,
@@ -88,4 +91,5 @@
     static final int CREATE_CANCELATION_SIGNAL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 23;
     static final int CANONICALIZE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 24;
     static final int UNCANONICALIZE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 25;
+    static final int REFRESH_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 26;
 }
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index a93870e..f7c4d59 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -193,7 +193,11 @@
  * The following list includes descriptions for the different attributes within a static shortcut:
  * <dl>
  *   <dt>{@code android:shortcutId}</dt>
- *   <dd>Mandatory shortcut ID</dd>
+ *   <dd>Mandatory shortcut ID.
+ *   <p>
+ *   This must be a string literal.
+ *   A resource string, such as <code>@string/foo</code>, cannot be used.
+ *   </dd>
  *
  *   <dt>{@code android:enabled}</dt>
  *   <dd>Default is {@code true}.  Can be set to {@code false} in order
@@ -206,15 +210,24 @@
  *
  *   <dt>{@code android:shortcutShortLabel}</dt>
  *   <dd>Mandatory shortcut short label.
- *   See {@link ShortcutInfo.Builder#setShortLabel(CharSequence)}.</dd>
+ *   See {@link ShortcutInfo.Builder#setShortLabel(CharSequence)}.
+ *   <p>
+ *   This must be a resource string, such as <code>@string/shortcut_label</code>.
+ *   </dd>
  *
  *   <dt>{@code android:shortcutLongLabel}</dt>
  *   <dd>Shortcut long label.
- *   See {@link ShortcutInfo.Builder#setLongLabel(CharSequence)}.</dd>
+ *   See {@link ShortcutInfo.Builder#setLongLabel(CharSequence)}.
+ *   <p>
+ *   This must be a resource string, such as <code>@string/shortcut_long_label</code>.
+ *   </dd>
  *
  *   <dt>{@code android:shortcutDisabledMessage}</dt>
  *   <dd>When {@code android:enabled} is set to
- *   {@code false}, this attribute is used to display a custom disabled message.</dd>
+ *   {@code false}, this attribute is used to display a custom disabled message.
+ *   <p>
+ *   This must be a resource string, such as <code>@string/shortcut_disabled_message</code>.
+ *   </dd>
  *
  *   <dt>{@code intent}</dt>
  *   <dd>Intent to launch when the user selects the shortcut.
diff --git a/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl b/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl
index c99cb0c..a7dd035 100644
--- a/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl
+++ b/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl
@@ -24,7 +24,7 @@
  *
  * @hide
  */
-interface IFusedLocationHardwareSink {
+oneway interface IFusedLocationHardwareSink {
     /**
      * Event generated when a batch of location information is available.
      *
@@ -50,4 +50,4 @@
      * changes (location is successful/unsuccessful).
      */
     void onStatusChanged(int status) = 3;
-}
\ No newline at end of file
+}
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index 252385f..263750a 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.hardware.health.V1_0.Constants;
 import com.android.internal.app.IBatteryStats;
 
 /**
@@ -118,20 +119,20 @@
      public static final String EXTRA_CHARGE_COUNTER = "charge_counter";
 
     // values for "status" field in the ACTION_BATTERY_CHANGED Intent
-    public static final int BATTERY_STATUS_UNKNOWN = 1;
-    public static final int BATTERY_STATUS_CHARGING = 2;
-    public static final int BATTERY_STATUS_DISCHARGING = 3;
-    public static final int BATTERY_STATUS_NOT_CHARGING = 4;
-    public static final int BATTERY_STATUS_FULL = 5;
+    public static final int BATTERY_STATUS_UNKNOWN = Constants.BATTERY_STATUS_UNKNOWN;
+    public static final int BATTERY_STATUS_CHARGING = Constants.BATTERY_STATUS_CHARGING;
+    public static final int BATTERY_STATUS_DISCHARGING = Constants.BATTERY_STATUS_DISCHARGING;
+    public static final int BATTERY_STATUS_NOT_CHARGING = Constants.BATTERY_STATUS_NOT_CHARGING;
+    public static final int BATTERY_STATUS_FULL = Constants.BATTERY_STATUS_FULL;
 
     // values for "health" field in the ACTION_BATTERY_CHANGED Intent
-    public static final int BATTERY_HEALTH_UNKNOWN = 1;
-    public static final int BATTERY_HEALTH_GOOD = 2;
-    public static final int BATTERY_HEALTH_OVERHEAT = 3;
-    public static final int BATTERY_HEALTH_DEAD = 4;
-    public static final int BATTERY_HEALTH_OVER_VOLTAGE = 5;
-    public static final int BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6;
-    public static final int BATTERY_HEALTH_COLD = 7;
+    public static final int BATTERY_HEALTH_UNKNOWN = Constants.BATTERY_HEALTH_UNKNOWN;
+    public static final int BATTERY_HEALTH_GOOD = Constants.BATTERY_HEALTH_GOOD;
+    public static final int BATTERY_HEALTH_OVERHEAT = Constants.BATTERY_HEALTH_OVERHEAT;
+    public static final int BATTERY_HEALTH_DEAD = Constants.BATTERY_HEALTH_DEAD;
+    public static final int BATTERY_HEALTH_OVER_VOLTAGE = Constants.BATTERY_HEALTH_OVER_VOLTAGE;
+    public static final int BATTERY_HEALTH_UNSPECIFIED_FAILURE = Constants.BATTERY_HEALTH_UNSPECIFIED_FAILURE;
+    public static final int BATTERY_HEALTH_COLD = Constants.BATTERY_HEALTH_COLD;
 
     // values of the "plugged" field in the ACTION_BATTERY_CHANGED intent.
     // These must be powers of 2.
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index e5832c8..0d6d369 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -924,16 +924,4 @@
             return -1;
         }
     }
-
-    /**
-     * Check if the device is running on the Android O release or newer.
-     *
-     * @return {@code true} if O APIs are available for use
-     *
-     * @hide
-     */
-    public static boolean isAtLeastO() {
-        return !"REL".equals(VERSION.CODENAME)
-                && "O".compareTo(VERSION.CODENAME) <= 0;
-    }
 }
diff --git a/core/java/android/text/Editable.java b/core/java/android/text/Editable.java
index b3f2c2a..c0948a6 100644
--- a/core/java/android/text/Editable.java
+++ b/core/java/android/text/Editable.java
@@ -121,8 +121,10 @@
     public InputFilter[] getFilters();
 
     /**
-     * Factory used by TextView to create new Editables.  You can subclass
-     * it to provide something other than SpannableStringBuilder.
+     * Factory used by TextView to create new {@link Editable Editables}. You can subclass
+     * it to provide something other than {@link SpannableStringBuilder}.
+     *
+     * @see android.widget.TextView#setEditableFactory(Factory)
      */
     public static class Factory {
         private static Editable.Factory sInstance = new Editable.Factory();
diff --git a/core/java/android/text/Spannable.java b/core/java/android/text/Spannable.java
index ae5d356..39b78eb 100644
--- a/core/java/android/text/Spannable.java
+++ b/core/java/android/text/Spannable.java
@@ -46,15 +46,17 @@
     public void removeSpan(Object what);
 
     /**
-     * Factory used by TextView to create new Spannables.  You can subclass
-     * it to provide something other than SpannableString.
+     * Factory used by TextView to create new {@link Spannable Spannables}. You can subclass
+     * it to provide something other than {@link SpannableString}.
+     *
+     * @see android.widget.TextView#setSpannableFactory(Factory)
      */
     public static class Factory {
         private static Spannable.Factory sInstance = new Spannable.Factory();
 
         /**
          * Returns the standard Spannable Factory.
-         */ 
+         */
         public static Spannable.Factory getInstance() {
             return sInstance;
         }
diff --git a/core/java/android/util/Half.java b/core/java/android/util/Half.java
index 08fb948..1abc10d 100644
--- a/core/java/android/util/Half.java
+++ b/core/java/android/util/Half.java
@@ -16,12 +16,15 @@
 
 package android.util;
 
+import android.annotation.HalfFloat;
+
 /**
  * <p>Half is a utility class to manipulate half-precision 16-bit
  * <a href="https://en.wikipedia.org/wiki/Half-precision_floating-point_format">IEEE 754</a>
- * floating point data types (also called fp16 or binary16). A half-precision
- * float is stored in a short data type. A half-precision float can be
- * created from or converted to single-precision floats.</p>
+ * floating point data types (also called fp16 or binary16). A half-precision float can be
+ * created from or converted to single-precision floats, and is stored in a short data type.
+ * To distinguish short values holding half-precision floats from regular short values,
+ * it is recommended to use the <code>@HalfFloat</code> annotation.</p>
  *
  * <p>The IEEE 754 standard specifies an fp16 as having the following format:</p>
  * <ul>
@@ -95,51 +98,53 @@
      * Epsilon is the difference between 1.0 and the next value representable
      * by a half-precision floating-point.
      */
-    public static final short EPSILON            = (short) 0x1400;
-    /**
-     * Smallest negative value a half-precision float may have.
-     */
-    public static final short LOWEST_VALUE       = (short) 0xfbff;
+    public static final @HalfFloat short EPSILON = (short) 0x1400;
+
     /**
      * Maximum exponent a finite half-precision float may have.
      */
-    public static final int MAX_EXPONENT         = 15;
-    /**
-     * Maximum positive finite value a half-precision float may have.
-     */
-    public static final short MAX_VALUE          = (short) 0x7bff;
+    public static final int MAX_EXPONENT = 15;
     /**
      * Minimum exponent a normalized half-precision float may have.
      */
-    public static final int MIN_EXPONENT         = -14;
+    public static final int MIN_EXPONENT = -14;
+
+    /**
+     * Smallest negative value a half-precision float may have.
+     */
+    public static final @HalfFloat short LOWEST_VALUE = (short) 0xfbff;
+    /**
+     * Maximum positive finite value a half-precision float may have.
+     */
+    public static final @HalfFloat short MAX_VALUE = (short) 0x7bff;
     /**
      * Smallest positive normal value a half-precision float may have.
      */
-    public static final short MIN_NORMAL         = (short) 0x0400;
+    public static final @HalfFloat short MIN_NORMAL = (short) 0x0400;
     /**
      * Smallest positive non-zero value a half-precision float may have.
      */
-    public static final short MIN_VALUE          = (short) 0x0001;
+    public static final @HalfFloat short MIN_VALUE = (short) 0x0001;
     /**
      * A Not-a-Number representation of a half-precision float.
      */
-    public static final short NaN                = (short) 0x7e00;
+    public static final @HalfFloat short NaN = (short) 0x7e00;
     /**
      * Negative infinity of type half-precision float.
      */
-    public static final short NEGATIVE_INFINITY  = (short) 0xfc00;
+    public static final @HalfFloat short NEGATIVE_INFINITY = (short) 0xfc00;
     /**
      * Negative 0 of type half-precision float.
      */
-    public static final short NEGATIVE_ZERO      = (short) 0x8000;
+    public static final @HalfFloat short NEGATIVE_ZERO = (short) 0x8000;
     /**
      * Positive infinity of type half-precision float.
      */
-    public static final short POSITIVE_INFINITY  = (short) 0x7c00;
+    public static final @HalfFloat short POSITIVE_INFINITY = (short) 0x7c00;
     /**
      * Positive 0 of type half-precision float.
      */
-    public static final short POSITIVE_ZERO      = (short) 0x0000;
+    public static final @HalfFloat short POSITIVE_ZERO = (short) 0x0000;
 
     private static final int FP16_SIGN_SHIFT        = 15;
     private static final int FP16_SIGN_MASK         = 0x8000;
@@ -171,7 +176,7 @@
      * @return A value with the magnitude of the first parameter and the sign
      *         of the second parameter
      */
-    public static short copySign(short magnitude, short sign) {
+    public static @HalfFloat short copySign(@HalfFloat short magnitude, @HalfFloat short sign) {
         return (short) ((sign & FP16_SIGN_MASK) | (magnitude & FP16_COMBINED));
     }
 
@@ -189,7 +194,7 @@
      * @param h A half-precision float value
      * @return The absolute value of the specified half-precision float
      */
-    public static short abs(short h) {
+    public static @HalfFloat short abs(@HalfFloat short h) {
         return (short) (h & FP16_COMBINED);
     }
 
@@ -209,7 +214,7 @@
      * @return The value of the specified half-precision float rounded to the nearest
      *         half-precision float value
      */
-    public static short round(short h) {
+    public static @HalfFloat short round(@HalfFloat short h) {
         int bits = h & 0xffff;
         int e = bits & 0x7fff;
         int result = bits;
@@ -243,7 +248,7 @@
      * @return The smallest half-precision float value toward negative infinity
      *         greater than or equal to the specified half-precision float value
      */
-    public static short ceil(short h) {
+    public static @HalfFloat short ceil(@HalfFloat short h) {
         int bits = h & 0xffff;
         int e = bits & 0x7fff;
         int result = bits;
@@ -277,7 +282,7 @@
      * @return The largest half-precision float value toward positive infinity
      *         less than or equal to the specified half-precision float value
      */
-    public static short floor(short h) {
+    public static @HalfFloat short floor(@HalfFloat short h) {
         int bits = h & 0xffff;
         int e = bits & 0x7fff;
         int result = bits;
@@ -310,7 +315,7 @@
      * @return The truncated half-precision float value of the specified
      *         half-precision float value
      */
-    public static short trunc(short h) {
+    public static @HalfFloat short trunc(@HalfFloat short h) {
         int bits = h & 0xffff;
         int e = bits & 0x7fff;
         int result = bits;
@@ -338,7 +343,7 @@
      * @param y The second half-precision value
      * @return The smaller of the two specified half-precision values
      */
-    public static short min(short x, short y) {
+    public static @HalfFloat short min(@HalfFloat short x, @HalfFloat short y) {
         if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return NaN;
         if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return NaN;
 
@@ -363,7 +368,7 @@
      *
      * @return The larger of the two specified half-precision values
      */
-    public static short max(short x, short y) {
+    public static @HalfFloat short max(@HalfFloat short x, @HalfFloat short y) {
         if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return NaN;
         if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return NaN;
 
@@ -385,7 +390,7 @@
      *
      * @return True if x is less than y, false otherwise
      */
-    public static boolean less(short x, short y) {
+    public static boolean less(@HalfFloat short x, @HalfFloat short y) {
         if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
         if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
 
@@ -403,7 +408,7 @@
      *
      * @return True if x is less than or equal to y, false otherwise
      */
-    public static boolean lessEquals(short x, short y) {
+    public static boolean lessEquals(@HalfFloat short x, @HalfFloat short y) {
         if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
         if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
 
@@ -421,7 +426,7 @@
      *
      * @return True if x is greater than y, false otherwise
      */
-    public static boolean greater(short x, short y) {
+    public static boolean greater(@HalfFloat short x, @HalfFloat short y) {
         if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
         if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
 
@@ -439,7 +444,7 @@
      *
      * @return True if x is greater than y, false otherwise
      */
-    public static boolean greaterEquals(short x, short y) {
+    public static boolean greaterEquals(@HalfFloat short x, @HalfFloat short y) {
         if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
         if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
 
@@ -457,7 +462,7 @@
      *
      * @return True if x is equal to y, false otherwise
      */
-    public static boolean equals(short x, short y) {
+    public static boolean equals(@HalfFloat short x, @HalfFloat short y) {
         if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
         if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
 
@@ -470,7 +475,7 @@
      * @param h A half-precision float value
      * @return 1 if the value is positive, -1 if the value is negative
      */
-    public static int getSign(short h) {
+    public static int getSign(@HalfFloat short h) {
         return (h & FP16_SIGN_MASK) == 0 ? 1 : -1;
     }
 
@@ -484,7 +489,7 @@
      * @param h A half-precision float value
      * @return The unbiased exponent of the specified value
      */
-    public static int getExponent(short h) {
+    public static int getExponent(@HalfFloat short h) {
         return ((h >>> FP16_EXPONENT_SHIFT) & FP16_EXPONENT_MASK) - FP16_EXPONENT_BIAS;
     }
 
@@ -495,7 +500,7 @@
      * @param h A half-precision float value
      * @return The significand, or significand, of the specified vlaue
      */
-    public static int getSignificand(short h) {
+    public static int getSignificand(@HalfFloat short h) {
         return h & FP16_SIGNIFICAND_MASK;
     }
 
@@ -507,7 +512,7 @@
      * @return true if the value is positive infinity or negative infinity,
      *         false otherwise
      */
-    public static boolean isInfinite(short h) {
+    public static boolean isInfinite(@HalfFloat short h) {
         return (h & FP16_COMBINED) == FP16_EXPONENT_MAX;
     }
 
@@ -518,7 +523,7 @@
      * @param h A half-precision float value
      * @return true if the value is a NaN, false otherwise
      */
-    public static boolean isNaN(short h) {
+    public static boolean isNaN(@HalfFloat short h) {
         return (h & FP16_COMBINED) > FP16_EXPONENT_MAX;
     }
 
@@ -532,7 +537,7 @@
      * @param h A half-precision float value
      * @return true if the value is normalized, false otherwise
      */
-    public static boolean isNormalized(short h) {
+    public static boolean isNormalized(@HalfFloat short h) {
         return (h & FP16_EXPONENT_MAX) != 0 && (h & FP16_EXPONENT_MAX) != FP16_EXPONENT_MAX;
     }
 
@@ -551,7 +556,7 @@
      * @param h The half-precision float value to convert to single-precision
      * @return A normalized single-precision float value
      */
-    public static float toFloat(short h) {
+    public static float toFloat(@HalfFloat short h) {
         int bits = h & 0xffff;
         int s = bits & FP16_SIGN_MASK;
         int e = (bits >>> FP16_EXPONENT_SHIFT) & FP16_EXPONENT_MASK;
@@ -603,7 +608,7 @@
      * @return A half-precision float value
      */
     @SuppressWarnings("StatementWithEmptyBody")
-    public static short valueOf(float f) {
+    public static @HalfFloat short valueOf(float f) {
         int bits = Float.floatToRawIntBits(f);
         int s = (bits >>> FP32_SIGN_SHIFT    );
         int e = (bits >>> FP32_EXPONENT_SHIFT) & FP32_EXPONENT_MASK;
@@ -653,7 +658,7 @@
      * @param h A half-precision float value
      * @return A string representation of the specified value
      */
-    public static String toString(short h) {
+    public static String toString(@HalfFloat short h) {
         return Float.toString(toFloat(h));
     }
 
@@ -683,7 +688,7 @@
      * @param h A half-precision float value
      * @return A hexadecimal string representation of the specified value
      */
-    public static String toHexString(short h) {
+    public static String toHexString(@HalfFloat short h) {
         StringBuilder o = new StringBuilder();
 
         int bits = h & 0xffff;
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index 8038089..2f12e9b 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -34,6 +34,54 @@
  */
 public class EditorInfo implements InputType, Parcelable {
     /**
+     * Masks for {@link inputType}
+     *
+     * <pre>
+     * |-------|-------|-------|-------|
+     *                              1111 TYPE_MASK_CLASS
+     *                      11111111     TYPE_MASK_VARIATION
+     *          111111111111             TYPE_MASK_FLAGS
+     * |-------|-------|-------|-------|
+     *                                   TYPE_NULL
+     * |-------|-------|-------|-------|
+     *                                 1 TYPE_CLASS_TEXT
+     *                             1     TYPE_TEXT_VARIATION_URI
+     *                            1      TYPE_TEXT_VARIATION_EMAIL_ADDRESS
+     *                            11     TYPE_TEXT_VARIATION_EMAIL_SUBJECT
+     *                           1       TYPE_TEXT_VARIATION_SHORT_MESSAGE
+     *                           1 1     TYPE_TEXT_VARIATION_LONG_MESSAGE
+     *                           11      TYPE_TEXT_VARIATION_PERSON_NAME
+     *                           111     TYPE_TEXT_VARIATION_POSTAL_ADDRESS
+     *                          1        TYPE_TEXT_VARIATION_PASSWORD
+     *                          1  1     TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
+     *                          1 1      TYPE_TEXT_VARIATION_WEB_EDIT_TEXT
+     *                          1 11     TYPE_TEXT_VARIATION_FILTER
+     *                          11       TYPE_TEXT_VARIATION_PHONETIC
+     *                          11 1     TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS
+     *                          111      TYPE_TEXT_VARIATION_WEB_PASSWORD
+     *                     1             TYPE_TEXT_FLAG_CAP_CHARACTERS
+     *                    1              TYPE_TEXT_FLAG_CAP_WORDS
+     *                   1               TYPE_TEXT_FLAG_CAP_SENTENCES
+     *                  1                TYPE_TEXT_FLAG_AUTO_CORRECT
+     *                 1                 TYPE_TEXT_FLAG_AUTO_COMPLETE
+     *                1                  TYPE_TEXT_FLAG_MULTI_LINE
+     *               1                   TYPE_TEXT_FLAG_IME_MULTI_LINE
+     *              1                    TYPE_TEXT_FLAG_NO_SUGGESTIONS
+     * |-------|-------|-------|-------|
+     *                                1  TYPE_CLASS_NUMBER
+     *                             1     TYPE_NUMBER_VARIATION_PASSWORD
+     *                     1             TYPE_NUMBER_FLAG_SIGNED
+     *                    1              TYPE_NUMBER_FLAG_DECIMAL
+     * |-------|-------|-------|-------|
+     *                                11 TYPE_CLASS_PHONE
+     * |-------|-------|-------|-------|
+     *                               1   TYPE_CLASS_DATETIME
+     *                             1     TYPE_DATETIME_VARIATION_DATE
+     *                            1      TYPE_DATETIME_VARIATION_TIME
+     * |-------|-------|-------|-------|</pre>
+     */
+
+    /**
      * The content type of the text box, whose bits are defined by
      * {@link InputType}.
      *
@@ -107,6 +155,26 @@
     public static final int IME_ACTION_PREVIOUS = 0x00000007;
 
     /**
+     * Flag of {@link #imeOptions}: used to request that the IME does not update any personalized
+     * data such as typing history and personalized language model based on what the user typed on
+     * this text editing object.  Typical use cases are:
+     * <ul>
+     *     <li>When the application is in a special mode, where user's activities are expected to be
+     *     not recorded in the application's history.  Some web browsers and chat applications may
+     *     have this kind of modes.</li>
+     *     <li>When storing typing history does not make much sense.  Specifying this flag in typing
+     *     games may help to avoid typing history from being filled up with words that the user is
+     *     less likely to type in their daily life.  Another example is that when the application
+     *     already knows that the expected input is not a valid word (e.g. a promotion code that is
+     *     not a valid word in any natural language).</li>
+     * </ul>
+     *
+     * <p>Applications need to be aware that the flag is not a guarantee, and some IMEs may not
+     * respect it.</p>
+     */
+    public static final int IME_FLAG_NO_PERSONALIZED_LEARNING = 0x1000000;
+
+    /**
      * Flag of {@link #imeOptions}: used to request that the IME never go
      * into fullscreen mode.
      * By default, IMEs may go into full screen mode when they think
@@ -208,6 +276,32 @@
     public static final int IME_NULL = 0x00000000;
 
     /**
+     * Masks for {@link imeOptions}
+     *
+     * <pre>
+     * |-------|-------|-------|-------|
+     *                              1111 IME_MASK_ACTION
+     * |-------|-------|-------|-------|
+     *                                   IME_ACTION_UNSPECIFIED
+     *                                 1 IME_ACTION_NONE
+     *                                1  IME_ACTION_GO
+     *                                11 IME_ACTION_SEARCH
+     *                               1   IME_ACTION_SEND
+     *                               1 1 IME_ACTION_NEXT
+     *                               11  IME_ACTION_DONE
+     *                               111 IME_ACTION_PREVIOUS
+     *         1                         IME_FLAG_NO_PERSONALIZED_LEARNING
+     *        1                          IME_FLAG_NO_FULLSCREEN
+     *       1                           IME_FLAG_NAVIGATE_PREVIOUS
+     *      1                            IME_FLAG_NAVIGATE_NEXT
+     *     1                             IME_FLAG_NO_EXTRACT_UI
+     *    1                              IME_FLAG_NO_ACCESSORY_ACTION
+     *   1                               IME_FLAG_NO_ENTER_ACTION
+     *  1                                IME_FLAG_FORCE_ASCII
+     * |-------|-------|-------|-------|</pre>
+     */
+
+    /**
      * Extended type information for the editor, to help the IME better
      * integrate with it.
      */
diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java
index 9d228cf..bbc50da 100644
--- a/core/java/android/widget/ArrayAdapter.java
+++ b/core/java/android/widget/ArrayAdapter.java
@@ -312,10 +312,10 @@
     }
 
     /**
-     * Control whether methods that change the list ({@link #add},
-     * {@link #insert}, {@link #remove}, {@link #clear}) automatically call
-     * {@link #notifyDataSetChanged}.  If set to false, caller must
-     * manually call notifyDataSetChanged() to have the changes
+     * Control whether methods that change the list ({@link #add}, {@link #addAll(Collection)},
+     * {@link #addAll(Object[])}, {@link #insert}, {@link #remove}, {@link #clear},
+     * {@link #sort(Comparator)}) automatically call {@link #notifyDataSetChanged}.  If set to
+     * false, caller must manually call notifyDataSetChanged() to have the changes
      * reflected in the attached view.
      *
      * The default is true, and calling notifyDataSetChanged()
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 73af755..5426a37 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -1683,12 +1683,13 @@
     }
 
     /**
-     * Return the text the TextView is displaying. If setText() was called with
-     * an argument of BufferType.SPANNABLE or BufferType.EDITABLE, you can cast
+     * Return the text that TextView is displaying. If {@link #setText(CharSequence)} was called
+     * with an argument of {@link android.widget.TextView.BufferType#SPANNABLE BufferType.SPANNABLE}
+     * or {@link android.widget.TextView.BufferType#EDITABLE BufferType.EDITABLE}, you can cast
      * the return value from this method to Spannable or Editable, respectively.
-     *
-     * Note: The content of the return value should not be modified. If you want
-     * a modifiable one, you should make your own copy first.
+     * <p/>
+     * The content of the return value should not be modified. If you want a modifiable one, you
+     * should make your own copy first.
      *
      * @attr ref android.R.styleable#TextView_text
      */
@@ -1705,8 +1706,8 @@
     }
 
     /**
-     * Return the text the TextView is displaying as an Editable object.  If
-     * the text is not editable, null is returned.
+     * Return the text that TextView is displaying as an Editable object. If the text is not
+     * editable, null is returned.
      *
      * @see #getText
      */
@@ -4148,18 +4149,26 @@
     }
 
     /**
-     * Convenience method: Append the specified text to the TextView's
-     * display buffer, upgrading it to BufferType.EDITABLE if it was
-     * not already editable.
+     * Convenience method to append the specified text to the TextView's
+     * display buffer, upgrading it to {@link android.widget.TextView.BufferType#EDITABLE}
+     * if it was not already editable.
+     *
+     * @param text text to be appended to the already displayed text
      */
     public final void append(CharSequence text) {
         append(text, 0, text.length());
     }
 
     /**
-     * Convenience method: Append the specified text slice to the TextView's
-     * display buffer, upgrading it to BufferType.EDITABLE if it was
-     * not already editable.
+     * Convenience method to append the specified text slice to the TextView's
+     * display buffer, upgrading it to {@link android.widget.TextView.BufferType#EDITABLE}
+     * if it was not already editable.
+     *
+     * @param text text to be appended to the already displayed text
+     * @param start the index of the first character in the {@code text}
+     * @param end the index of the character following the last character in the {@code text}
+     *
+     * @see Appendable#append(CharSequence, int, int)
      */
     public void append(CharSequence text, int start, int end) {
         if (!(mText instanceof Editable)) {
@@ -4403,7 +4412,12 @@
     ///////////////////////////////////////////////////////////////////////////
 
     /**
-     * Sets the Factory used to create new Editables.
+     * Sets the Factory used to create new {@link Editable Editables}.
+     *
+     * @param factory {@link android.text.Editable.Factory Editable.Factory} to be used
+     *
+     * @see android.text.Editable.Factory
+     * @see android.widget.TextView.BufferType#EDITABLE
      */
     public final void setEditableFactory(Editable.Factory factory) {
         mEditableFactory = factory;
@@ -4411,7 +4425,12 @@
     }
 
     /**
-     * Sets the Factory used to create new Spannables.
+     * Sets the Factory used to create new {@link Spannable Spannables}.
+     *
+     * @param factory {@link android.text.Spannable.Factory Spannable.Factory} to be used
+     *
+     * @see android.text.Spannable.Factory
+     * @see android.widget.TextView.BufferType#SPANNABLE
      */
     public final void setSpannableFactory(Spannable.Factory factory) {
         mSpannableFactory = factory;
@@ -4419,13 +4438,20 @@
     }
 
     /**
-     * Sets the string value of the TextView. TextView <em>does not</em> accept
+     * Sets the text to be displayed. TextView <em>does not</em> accept
      * HTML-like formatting, which you can do with text strings in XML resource files.
      * To style your strings, attach android.text.style.* objects to a
-     * {@link android.text.SpannableString SpannableString}, or see the
+     * {@link android.text.SpannableString}, or see the
      * <a href="{@docRoot}guide/topics/resources/available-resources.html#stringresources">
      * Available Resource Types</a> documentation for an example of setting
      * formatted text in the XML resource file.
+     * <p/>
+     * When required, TextView will use {@link android.text.Spannable.Factory} to create final or
+     * intermediate {@link Spannable Spannables}. Likewise it will use
+     * {@link android.text.Editable.Factory} to create final or intermediate
+     * {@link Editable Editables}.
+     *
+     * @param text text to be displayed
      *
      * @attr ref android.R.styleable#TextView_text
      */
@@ -4435,10 +4461,16 @@
     }
 
     /**
-     * Like {@link #setText(CharSequence)},
-     * except that the cursor position (if any) is retained in the new text.
+     * Sets the text to be displayed but retains the cursor position. Same as
+     * {@link #setText(CharSequence)} except that the cursor position (if any) is retained in the
+     * new text.
+     * <p/>
+     * When required, TextView will use {@link android.text.Spannable.Factory} to create final or
+     * intermediate {@link Spannable Spannables}. Likewise it will use
+     * {@link android.text.Editable.Factory} to create final or intermediate
+     * {@link Editable Editables}.
      *
-     * @param text The new text to place in the text view.
+     * @param text text to be displayed
      *
      * @see #setText(CharSequence)
      */
@@ -4448,9 +4480,21 @@
     }
 
     /**
-     * Sets the text that this TextView is to display (see
-     * {@link #setText(CharSequence)}) and also sets whether it is stored
-     * in a styleable/spannable buffer and whether it is editable.
+     * Sets the text to be displayed and the {@link android.widget.TextView.BufferType}.
+     * <p/>
+     * When required, TextView will use {@link android.text.Spannable.Factory} to create final or
+     * intermediate {@link Spannable Spannables}. Likewise it will use
+     * {@link android.text.Editable.Factory} to create final or intermediate
+     * {@link Editable Editables}.
+     *
+     * @param text text to be displayed
+     * @param type a {@link android.widget.TextView.BufferType} which defines whether the text is
+     *              stored as a static text, styleable/spannable text, or editable text
+     *
+     * @see #setText(CharSequence)
+     * @see android.widget.TextView.BufferType
+     * @see #setSpannableFactory(Spannable.Factory)
+     * @see #setEditableFactory(Editable.Factory)
      *
      * @attr ref android.R.styleable#TextView_text
      * @attr ref android.R.styleable#TextView_bufferType
@@ -4617,10 +4661,14 @@
 
     /**
      * Sets the TextView to display the specified slice of the specified
-     * char array.  You must promise that you will not change the contents
+     * char array. You must promise that you will not change the contents
      * of the array except for right before another call to setText(),
      * since the TextView has no way to know that the text
      * has changed and that it needs to invalidate and re-layout.
+     *
+     * @param text char array to be displayed
+     * @param start start index in the char array
+     * @param len length of char count after {@code start}
      */
     public final void setText(char[] text, int start, int len) {
         int oldlen = 0;
@@ -4651,8 +4699,19 @@
     }
 
     /**
-     * Like {@link #setText(CharSequence, android.widget.TextView.BufferType)},
-     * except that the cursor position (if any) is retained in the new text.
+     * Sets the text to be displayed and the {@link android.widget.TextView.BufferType} but retains
+     * the cursor position. Same as
+     * {@link #setText(CharSequence, android.widget.TextView.BufferType)} except that the cursor
+     * position (if any) is retained in the new text.
+     * <p/>
+     * When required, TextView will use {@link android.text.Spannable.Factory} to create final or
+     * intermediate {@link Spannable Spannables}. Likewise it will use
+     * {@link android.text.Editable.Factory} to create final or intermediate
+     * {@link Editable Editables}.
+     *
+     * @param text text to be displayed
+     * @param type a {@link android.widget.TextView.BufferType} which defines whether the text is
+     *              stored as a static text, styleable/spannable text, or editable text
      *
      * @see #setText(CharSequence, android.widget.TextView.BufferType)
      */
@@ -4672,11 +4731,42 @@
         }
     }
 
+    /**
+     * Sets the text to be displayed using a string resource identifier.
+     *
+     * @param resid the resource identifier of the string resource to be displayed
+     *
+     * @see #setText(CharSequence)
+     *
+     * @attr ref android.R.styleable#TextView_text
+     */
     @android.view.RemotableViewMethod
     public final void setText(@StringRes int resid) {
         setText(getContext().getResources().getText(resid));
     }
 
+    /**
+     * Sets the text to be displayed using a string resource identifier and the
+     * {@link android.widget.TextView.BufferType}.
+     * <p/>
+     * When required, TextView will use {@link android.text.Spannable.Factory} to create final or
+     * intermediate {@link Spannable Spannables}. Likewise it will use
+     * {@link android.text.Editable.Factory} to create final or intermediate
+     * {@link Editable Editables}.
+     *
+     * @param resid the resource identifier of the string resource to be displayed
+     * @param type a {@link android.widget.TextView.BufferType} which defines whether the text is
+     *              stored as a static text, styleable/spannable text, or editable text
+     *
+     * @see #setText(int)
+     * @see #setText(CharSequence)
+     * @see android.widget.TextView.BufferType
+     * @see #setSpannableFactory(Spannable.Factory)
+     * @see #setEditableFactory(Editable.Factory)
+     *
+     * @attr ref android.R.styleable#TextView_text
+     * @attr ref android.R.styleable#TextView_bufferType
+     */
     public final void setText(@StringRes int resid, BufferType type) {
         setText(getContext().getResources().getText(resid), type);
     }
@@ -5110,7 +5200,7 @@
      * Set the extra input data of the text, which is the
      * {@link EditorInfo#extras TextBoxAttribute.extras}
      * Bundle that will be filled in when creating an input connection.  The
-     * given integer is the resource ID of an XML resource holding an
+     * given integer is the resource identifier of an XML resource holding an
      * {@link android.R.styleable#InputExtras &lt;input-extras&gt;} XML tree.
      *
      * @see #getInputExtras(boolean)
@@ -8832,8 +8922,12 @@
         }
     }
 
+    /**
+     * Type of the text buffer that defines the characteristics of the text such as static,
+     * styleable, or editable.
+     */
     public enum BufferType {
-        NORMAL, SPANNABLE, EDITABLE,
+        NORMAL, SPANNABLE, EDITABLE
     }
 
     /**
diff --git a/core/java/com/android/internal/policy/PipSnapAlgorithm.java b/core/java/com/android/internal/policy/PipSnapAlgorithm.java
index 1e2a53b..62d506f 100644
--- a/core/java/com/android/internal/policy/PipSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/PipSnapAlgorithm.java
@@ -41,8 +41,12 @@
     // Allows snapping to anywhere along the edge of the screen
     private static final int SNAP_MODE_EDGE = 2;
 
+    // The friction multiplier to control how slippery the PIP is when flung
     private static final float SCROLL_FRICTION_MULTIPLIER = 8f;
 
+    // The fraction of the stack width to show when minimized
+    private static final float MINIMIZED_VISIBLE_FRACTION = 0.25f;
+
     private final Context mContext;
 
     private final ArrayList<Integer> mSnapGravities = new ArrayList<>();
@@ -122,6 +126,18 @@
     }
 
     /**
+     * Applies the offset to the {@param stackBounds} to adjust it to a minimized state.
+     */
+    public void applyMinimizedOffset(Rect stackBounds, Rect movementBounds, Point displaySize) {
+        int visibleWidth = (int) (MINIMIZED_VISIBLE_FRACTION * stackBounds.width());
+        if (stackBounds.left <= movementBounds.centerX()) {
+            stackBounds.offsetTo(-stackBounds.width() + visibleWidth, stackBounds.top);
+        } else {
+            stackBounds.offsetTo(displaySize.x - visibleWidth, stackBounds.top);
+        }
+    }
+
+    /**
      * @return returns a fraction that describes where along the {@param movementBounds} the
      *         {@param stackBounds} are. If the {@param stackBounds} are not currently on the
      *         {@param movementBounds} exactly, then they will be snapped to the movement bounds.
diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp
index 886c0e6..f909580 100644
--- a/core/jni/android_os_HwParcel.cpp
+++ b/core/jni/android_os_HwParcel.cpp
@@ -267,9 +267,9 @@
 
     const jchar *interfaceName = env->GetStringCritical(interfaceNameObj, NULL);
     if (interfaceName) {
-        String16 nameCopy(
+        String8 nameCopy = String8(String16(
                 reinterpret_cast<const char16_t *>(interfaceName),
-                env->GetStringLength(interfaceNameObj));
+                env->GetStringLength(interfaceNameObj)));
 
         env->ReleaseStringCritical(interfaceNameObj, interfaceName);
         interfaceName = NULL;
@@ -277,7 +277,7 @@
         hardware::Parcel *parcel =
             JHwParcel::GetNativeContext(env, thiz)->getParcel();
 
-        status_t err = parcel->writeInterfaceToken(nameCopy);
+        status_t err = parcel->writeInterfaceToken(nameCopy.string());
         signalExceptionForError(env, err);
     }
 }
@@ -294,9 +294,9 @@
 
     const jchar *interfaceName = env->GetStringCritical(interfaceNameObj, NULL);
     if (interfaceName) {
-        String16 interfaceNameCopy(
+        String8 interfaceNameCopy = String8(String16(
                 reinterpret_cast<const char16_t *>(interfaceName),
-                env->GetStringLength(interfaceNameObj));
+                env->GetStringLength(interfaceNameObj)));
 
         env->ReleaseStringCritical(interfaceNameObj, interfaceName);
         interfaceName = NULL;
@@ -304,7 +304,7 @@
         hardware::Parcel *parcel =
             JHwParcel::GetNativeContext(env, thiz)->getParcel();
 
-        bool valid = parcel->enforceInterface(interfaceNameCopy);
+        bool valid = parcel->enforceInterface(interfaceNameCopy.string());
 
         if (!valid) {
             jniThrowException(
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 38078c1..da059e3 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -326,7 +326,7 @@
         storageSource = "/mnt/runtime/read";
     } else if (mount_mode == MOUNT_EXTERNAL_WRITE) {
         storageSource = "/mnt/runtime/write";
-    } else {
+    } else if (!force_mount_namespace) {
         // Sane default of no storage visible
         return true;
     }
diff --git a/core/jni/fd_utils-inl.h b/core/jni/fd_utils-inl.h
index 2babe44..e270911 100644
--- a/core/jni/fd_utils-inl.h
+++ b/core/jni/fd_utils-inl.h
@@ -241,6 +241,18 @@
     is_sock(false) {
   }
 
+  static bool StartsWith(const std::string& str, const std::string& prefix) {
+    return str.compare(0, prefix.size(), prefix) == 0;
+  }
+
+  static bool EndsWith(const std::string& str, const std::string& suffix) {
+    if (suffix.size() > str.size()) {
+      return false;
+    }
+
+    return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
+  }
+
   // Returns true iff. a given path is whitelisted. A path is whitelisted
   // if it belongs to the whitelist (see kPathWhitelist) or if it's a path
   // under /system/framework that ends with ".jar" or if it is a system
@@ -252,31 +264,42 @@
       }
     }
 
-    static const char* kFrameworksPrefix = "/system/framework/";
-    static const char* kJarSuffix = ".jar";
-    if (android::base::StartsWith(path, kFrameworksPrefix)
-        && android::base::EndsWith(path, kJarSuffix)) {
+    static const std::string kFrameworksPrefix = "/system/framework/";
+    static const std::string kJarSuffix = ".jar";
+    if (StartsWith(path, kFrameworksPrefix) && EndsWith(path, kJarSuffix)) {
       return true;
     }
 
     // Whitelist files needed for Runtime Resource Overlay, like these:
+    // /system/vendor/overlay/framework-res.apk
+    // /system/vendor/overlay-subdir/pg/framework-res.apk
     // /vendor/overlay/framework-res.apk
     // /vendor/overlay/PG/android-framework-runtime-resource-overlay.apk
     // /data/resource-cache/system@vendor@overlay@framework-res.apk@idmap
-    // /data/resource-cache/system@vendor@overlay@PG@framework-res.apk@idmap
-    static const char* kOverlayDir = "/vendor/overlay/";
-    static const char* kApkSuffix = ".apk";
+    // /data/resource-cache/system@vendor@overlay-subdir@pg@framework-res.apk@idmap
+    // See AssetManager.cpp for more details on overlay-subdir.
+    static const std::string kOverlayDir = "/system/vendor/overlay/";
+    static const std::string kVendorOverlayDir = "/vendor/overlay";
+    static const std::string kOverlaySubdir = "/system/vendor/overlay-subdir/";
+    static const std::string kApkSuffix = ".apk";
 
-    if (android::base::StartsWith(path, kOverlayDir)
-        && android::base::EndsWith(path, kApkSuffix)
+    if ((StartsWith(path, kOverlayDir) || StartsWith(path, kOverlaySubdir)
+         || StartsWith(path, kVendorOverlayDir))
+        && EndsWith(path, kApkSuffix)
         && path.find("/../") == std::string::npos) {
       return true;
     }
 
-    static const char* kOverlayIdmapPrefix = "/data/resource-cache/";
-    static const char* kOverlayIdmapSuffix = ".apk@idmap";
-    if (android::base::StartsWith(path, kOverlayIdmapPrefix)
-        && android::base::EndsWith(path, kOverlayIdmapSuffix)) {
+    static const std::string kOverlayIdmapPrefix = "/data/resource-cache/";
+    static const std::string kOverlayIdmapSuffix = ".apk@idmap";
+    if (StartsWith(path, kOverlayIdmapPrefix) && EndsWith(path, kOverlayIdmapSuffix)
+        && path.find("/../") == std::string::npos) {
+      return true;
+    }
+
+    // All regular files that are placed under this path are whitelisted automatically.
+    static const std::string kZygoteWhitelistPath = "/vendor/zygote_whitelist/";
+    if (StartsWith(path, kZygoteWhitelistPath) && path.find("/../") == std::string::npos) {
       return true;
     }
 
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 13218b7..9c26340 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1333,7 +1333,7 @@
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Tik voor gebruik en instellingen"</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Gegevenslimiet van 2G-3G bereikt"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Gegevenslimiet van 4G bereikt"</string>
-    <string name="data_usage_mobile_limit_title" msgid="557158376602636112">"Mobiele gegevenslimiet bereikt"</string>
+    <string name="data_usage_mobile_limit_title" msgid="557158376602636112">"Mobiele datalimiet bereikt"</string>
     <string name="data_usage_wifi_limit_title" msgid="5803363779034792676">"Wifi-gegevenslimiet bereikt"</string>
     <string name="data_usage_limit_body" msgid="291731708279614081">"Gegev. onderbr. voor rest cyclus"</string>
     <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"Gegevenslimiet 2G-3G overschreden"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 7005afe..996fd55 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2492,11 +2492,11 @@
 
     <!-- Default insets [LEFT/RIGHTxTOP/BOTTOM] from the screen edge for picture-in-picture windows.
          These values are in DPs and will be converted to pixel sizes internally. -->
-    <string translatable="false" name="config_defaultPictureInPictureScreenEdgeInsets">10x10</string>
+    <string translatable="false" name="config_defaultPictureInPictureScreenEdgeInsets">8x8</string>
 
     <!-- Max default size [WIDTHxHEIGHT] on screen for picture-in-picture windows to fit inside.
          These values are in DPs and will be converted to pixel sizes internally. -->
-    <string translatable="false" name="config_defaultPictureInPictureSize">216x135</string>
+    <string translatable="false" name="config_defaultPictureInPictureSize">192x120</string>
 
     <!-- The default gravity for the picture-in-picture window.
          Currently, this maps to Gravity.BOTTOM | Gravity.RIGHT -->
diff --git a/core/tests/coretests/src/android/net/IpPrefixTest.java b/core/tests/coretests/src/android/net/IpPrefixTest.java
index fcc6389..4f2387d 100644
--- a/core/tests/coretests/src/android/net/IpPrefixTest.java
+++ b/core/tests/coretests/src/android/net/IpPrefixTest.java
@@ -18,14 +18,14 @@
 
 import android.net.IpPrefix;
 import android.os.Parcel;
-import static android.test.MoreAsserts.assertNotEqual;
 import android.test.suitebuilder.annotation.SmallTest;
-
-import static org.junit.Assert.assertArrayEquals;
 import java.net.InetAddress;
 import java.util.Random;
 import junit.framework.TestCase;
 
+import static android.test.MoreAsserts.assertNotEqual;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
 
 public class IpPrefixTest extends TestCase {
 
@@ -242,25 +242,42 @@
 
     @SmallTest
     public void testHashCode() {
-        IpPrefix p;
-        int oldCode = -1;
+        IpPrefix p = new IpPrefix(new byte[4], 0);
         Random random = new Random();
         for (int i = 0; i < 100; i++) {
+            final IpPrefix oldP = p;
             if (random.nextBoolean()) {
                 // IPv4.
                 byte[] b = new byte[4];
                 random.nextBytes(b);
                 p = new IpPrefix(b, random.nextInt(33));
-                assertNotEqual(oldCode, p.hashCode());
-                oldCode = p.hashCode();
             } else {
                 // IPv6.
                 byte[] b = new byte[16];
                 random.nextBytes(b);
                 p = new IpPrefix(b, random.nextInt(129));
-                assertNotEqual(oldCode, p.hashCode());
-                oldCode = p.hashCode();
             }
+            if (p.equals(oldP)) {
+              assertEquals(p.hashCode(), oldP.hashCode());
+            }
+            if (p.hashCode() != oldP.hashCode()) {
+              assertNotEqual(p, oldP);
+            }
+        }
+    }
+
+    @SmallTest
+    public void testHashCodeIsNotConstant() {
+        IpPrefix[] prefixes = {
+            new IpPrefix("2001:db8:f00::ace:d00d/127"),
+            new IpPrefix("192.0.2.0/23"),
+            new IpPrefix("::/0"),
+            new IpPrefix("0.0.0.0/0"),
+        };
+        for (int i = 0; i < prefixes.length; i++) {
+          for (int j = i + 1; j < prefixes.length; j++) {
+            assertNotEqual(prefixes[i].hashCode(), prefixes[j].hashCode());
+          }
         }
     }
 
diff --git a/docs/html/guide/topics/ui/settings.jd b/docs/html/guide/topics/ui/settings.jd
index 619fd26..b51e6d9 100644
--- a/docs/html/guide/topics/ui/settings.jd
+++ b/docs/html/guide/topics/ui/settings.jd
@@ -390,7 +390,9 @@
     <dd>The package part of the component name, as per the {@link
 android.content.Intent#setComponent setComponent()} method.</dd>
 </dl>
-
+<p class="note"><strong>Note: </strong>You must use string literals as the values for these
+intent attributes. You cannot use resource strings, such as <code>@string/foo</code>, to define the attributes.
+</p>
 
 
 <h2 id="Activity">Creating a Preference Activity</h2>
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 8dc502a..4722050 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -40,6 +40,7 @@
     renderthread/OpenGLPipeline.cpp \
     renderthread/DrawFrameTask.cpp \
     renderthread/EglManager.cpp \
+    renderthread/VulkanManager.cpp \
     renderthread/RenderProxy.cpp \
     renderthread/RenderTask.cpp \
     renderthread/RenderThread.cpp \
diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp
index 50bc6c3..59b1185 100644
--- a/libs/hwui/hwui/Typeface.cpp
+++ b/libs/hwui/hwui/Typeface.cpp
@@ -49,10 +49,60 @@
 }
 
 Typeface* gDefaultTypeface = NULL;
+pthread_once_t gDefaultTypefaceOnce = PTHREAD_ONCE_INIT;
+
+// This installs a default typeface (from a hardcoded path) that allows
+// layouts to work (not crash on null pointer) before the default
+// typeface is set. This happens if HWUI is used outside of zygote/app_process.
+static minikin::FontCollection *makeFontCollection() {
+    std::vector<minikin::FontFamily *>typefaces;
+    const char *fns[] = {
+        "/system/fonts/Roboto-Regular.ttf",
+    };
+
+    minikin::FontFamily *family = new minikin::FontFamily();
+    for (size_t i = 0; i < sizeof(fns)/sizeof(fns[0]); i++) {
+        const char *fn = fns[i];
+        ALOGD("makeFontCollection adding %s", fn);
+        sk_sp<SkTypeface> skFace = SkTypeface::MakeFromFile(fn);
+        if (skFace != NULL) {
+            // TODO: might be a nice optimization to get access to the underlying font
+            // data, but would require us opening the file ourselves and passing that
+            // to the appropriate Create method of SkTypeface.
+            minikin::MinikinFont *font = new MinikinFontSkia(std::move(skFace), NULL, 0, 0);
+            family->addFont(font);
+            font->Unref();
+        } else {
+            ALOGE("failed to create font %s", fn);
+        }
+    }
+    typefaces.push_back(family);
+
+    minikin::FontCollection *result = new minikin::FontCollection(typefaces);
+    family->Unref();
+    return result;
+}
+
+static void getDefaultTypefaceOnce() {
+  minikin::Layout::init();
+    if (gDefaultTypeface == NULL) {
+        // We expect the client to set a default typeface, but provide a
+        // default so we can make progress before that happens.
+        gDefaultTypeface = new Typeface;
+        gDefaultTypeface->fFontCollection = makeFontCollection();
+        gDefaultTypeface->fSkiaStyle = SkTypeface::kNormal;
+        gDefaultTypeface->fBaseWeight = 400;
+        resolveStyle(gDefaultTypeface);
+    }
+}
 
 Typeface* Typeface::resolveDefault(Typeface* src) {
-    LOG_ALWAYS_FATAL_IF(gDefaultTypeface == nullptr);
-    return src == nullptr ? gDefaultTypeface : src;
+    if (src == NULL) {
+        pthread_once(&gDefaultTypefaceOnce, getDefaultTypefaceOnce);
+        return gDefaultTypeface;
+    } else {
+        return src;
+    }
 }
 
 Typeface* Typeface::createFromTypeface(Typeface* src, SkTypeface::Style style) {
diff --git a/libs/hwui/hwui_static_deps.mk b/libs/hwui/hwui_static_deps.mk
index dca78b3..37126a6 100644
--- a/libs/hwui/hwui_static_deps.mk
+++ b/libs/hwui/hwui_static_deps.mk
@@ -18,6 +18,7 @@
     libutils \
     libEGL \
     libGLESv2 \
+    libvulkan \
     libskia \
     libui \
     libgui \
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index ba13ca5..ca394b2 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -23,37 +23,43 @@
 #include "SkiaPipeline.h"
 #include "SkiaProfileRenderer.h"
 
+#include <SkSurface.h>
 #include <SkTypes.h>
-#include <WindowContextFactory_android.h>
-#include <VulkanWindowContext.h>
+
+#include <GrContext.h>
+#include <GrTypes.h>
+#include <vk/GrVkTypes.h>
 
 #include <android/native_window.h>
 #include <cutils/properties.h>
 #include <strings.h>
 
 using namespace android::uirenderer::renderthread;
-using namespace sk_app;
 
 namespace android {
 namespace uirenderer {
 namespace skiapipeline {
 
+SkiaVulkanPipeline::SkiaVulkanPipeline(renderthread::RenderThread& thread)
+        : SkiaPipeline(thread)
+        , mVkManager(thread.vulkanManager()) {}
+
 MakeCurrentResult SkiaVulkanPipeline::makeCurrent() {
-    return (mWindowContext != nullptr) ?
-        MakeCurrentResult::AlreadyCurrent : MakeCurrentResult::Failed;
+    return MakeCurrentResult::AlreadyCurrent;
 }
 
 Frame SkiaVulkanPipeline::getFrame() {
-    LOG_ALWAYS_FATAL_IF(mWindowContext == nullptr, "Tried to draw into null vulkan context!");
-    mBackbuffer = mWindowContext->getBackbufferSurface();
-    if (mBackbuffer.get() == nullptr) {
-        // try recreating the context?
+    LOG_ALWAYS_FATAL_IF(mVkSurface == nullptr,
+                "drawRenderNode called on a context with no surface!");
+
+    SkSurface* backBuffer = mVkManager.getBackbufferSurface(mVkSurface);
+    if (backBuffer == nullptr) {
         SkDebugf("failed to get backbuffer");
         return Frame(-1, -1, 0);
     }
 
     // TODO: support buffer age if Vulkan API can do it
-    Frame frame(mBackbuffer->width(), mBackbuffer->height(), 0);
+    Frame frame(backBuffer->width(), backBuffer->height(), 0);
     return frame;
 }
 
@@ -66,16 +72,18 @@
         const std::vector<sp<RenderNode>>& renderNodes,
         FrameInfoVisualizer* profiler) {
 
-    if (mBackbuffer.get() == nullptr) {
+    sk_sp<SkSurface> backBuffer = mVkSurface->getBackBufferSurface();
+    if (backBuffer.get() == nullptr) {
         return false;
     }
-    renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, mBackbuffer);
+    SkiaPipeline::updateLighting(lightGeometry, lightInfo);
+    renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, backBuffer);
     layerUpdateQueue->clear();
 
     // Draw visual debugging features
     if (CC_UNLIKELY(Properties::showDirtyRegions
             || ProfileType::None != Properties::getProfileType())) {
-        SkCanvas* profileCanvas = mBackbuffer->getCanvas();
+        SkCanvas* profileCanvas = backBuffer->getCanvas();
         SkiaProfileRenderer profileRenderer(profileCanvas);
         profiler->draw(profileRenderer);
         profileCanvas->flush();
@@ -99,11 +107,9 @@
     currentFrameInfo->markSwapBuffers();
 
     if (*requireSwap) {
-        mWindowContext->swapBuffers();
+        mVkManager.swapBuffers(mVkSurface);
     }
 
-    mBackbuffer.reset();
-
     return *requireSwap;
 }
 
@@ -113,6 +119,7 @@
 }
 
 DeferredLayerUpdater* SkiaVulkanPipeline::createTextureLayer() {
+    mVkManager.initialize();
     Layer* layer = new Layer(mRenderThread.renderState(), 0, 0);
     return new DeferredLayerUpdater(layer);
 }
@@ -121,33 +128,24 @@
 }
 
 bool SkiaVulkanPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior) {
-
-    if (mWindowContext) {
-        delete mWindowContext;
-        mWindowContext = nullptr;
+    if (mVkSurface) {
+        mVkManager.destroySurface(mVkSurface);
+        mVkSurface = nullptr;
     }
 
     if (surface) {
-        DisplayParams displayParams;
-        mWindowContext = window_context_factory::NewVulkanForAndroid(surface, displayParams);
-        if (mWindowContext) {
-            DeviceInfo::initialize(mWindowContext->getGrContext()->caps()->maxRenderTargetSize());
-        }
+        mVkSurface = mVkManager.createSurface(surface);
     }
 
-
-    // this doesn't work for if there is more than one CanvasContext available at one time!
-    mRenderThread.setGrContext(mWindowContext ? mWindowContext->getGrContext() : nullptr);
-
-    return mWindowContext != nullptr;
+    return mVkSurface != nullptr;
 }
 
 bool SkiaVulkanPipeline::isSurfaceReady() {
-    return CC_LIKELY(mWindowContext != nullptr) && mWindowContext->isValid();
+    return CC_UNLIKELY(mVkSurface != nullptr);
 }
 
 bool SkiaVulkanPipeline::isContextReady() {
-    return CC_LIKELY(mWindowContext != nullptr);
+    return CC_LIKELY(mVkManager.hasVkContext());
 }
 
 void SkiaVulkanPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) {
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index cdc8692..aab1d7a 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -17,11 +17,7 @@
 #pragma once
 
 #include "SkiaPipeline.h"
-#include <SkSurface.h>
-
-namespace sk_app {
-class WindowContext;
-}
+#include "renderthread/VulkanManager.h"
 
 namespace android {
 namespace uirenderer {
@@ -29,7 +25,7 @@
 
 class SkiaVulkanPipeline : public SkiaPipeline {
 public:
-    SkiaVulkanPipeline(renderthread::RenderThread& thread) : SkiaPipeline(thread) {}
+    SkiaVulkanPipeline(renderthread::RenderThread& thread);
     virtual ~SkiaVulkanPipeline() {}
 
     renderthread::MakeCurrentResult makeCurrent() override;
@@ -53,8 +49,8 @@
     static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor);
 
 private:
-    sk_app::WindowContext* mWindowContext = nullptr;
-    sk_sp<SkSurface> mBackbuffer;
+    renderthread::VulkanManager& mVkManager;
+    renderthread::VulkanSurface* mVkSurface = nullptr;
 };
 
 } /* namespace skiapipeline */
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 9688340..f3789c8 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -20,6 +20,7 @@
 #include "CanvasContext.h"
 #include "EglManager.h"
 #include "RenderProxy.h"
+#include "VulkanManager.h"
 
 #include <gui/DisplayEventReceiver.h>
 #include <gui/ISurfaceComposer.h>
@@ -157,7 +158,8 @@
         , mFrameCallbackTaskPending(false)
         , mFrameCallbackTask(nullptr)
         , mRenderState(nullptr)
-        , mEglManager(nullptr) {
+        , mEglManager(nullptr)
+        , mVkManager(nullptr) {
     Properties::load();
     mFrameCallbackTask = new DispatchFrameCallbacks(this);
     mLooper = new Looper(false);
@@ -191,6 +193,7 @@
     mEglManager = new EglManager(*this);
     mRenderState = new RenderState(*this);
     mJankTracker = new JankTracker(mDisplayInfo);
+    mVkManager = new VulkanManager(*this);
 }
 
 int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index d8677e13..12050dd 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -46,6 +46,7 @@
 class DispatchFrameCallbacks;
 class EglManager;
 class RenderProxy;
+class VulkanManager;
 
 class TaskQueue {
 public:
@@ -98,6 +99,8 @@
     GrContext* getGrContext() const { return mGrContext.get(); }
     void setGrContext(GrContext* cxt) { mGrContext.reset(cxt); }
 
+    VulkanManager& vulkanManager() { return *mVkManager; }
+
 protected:
     virtual bool threadLoop() override;
 
@@ -150,6 +153,7 @@
     JankTracker* mJankTracker = nullptr;
 
     sk_sp<GrContext> mGrContext;
+    VulkanManager* mVkManager;
 };
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
new file mode 100644
index 0000000..4d239bc
--- /dev/null
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -0,0 +1,675 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include "VulkanManager.h"
+
+#include "DeviceInfo.h"
+#include "RenderThread.h"
+
+#include <GrContext.h>
+#include <GrTypes.h>
+#include <vk/GrVkTypes.h>
+
+namespace android {
+namespace uirenderer {
+namespace renderthread {
+
+#define GET_PROC(F) m ## F = (PFN_vk ## F) vkGetInstanceProcAddr(instance, "vk" #F)
+#define GET_DEV_PROC(F) m ## F = (PFN_vk ## F) vkGetDeviceProcAddr(device, "vk" #F)
+
+VulkanManager::VulkanManager(RenderThread& thread) : mRenderThread(thread) {
+}
+
+void VulkanManager::destroy() {
+    if (!hasVkContext()) return;
+
+    if (VK_NULL_HANDLE != mCommandPool) {
+        mDestroyCommandPool(mBackendContext->fDevice, mCommandPool, nullptr);
+        mCommandPool = VK_NULL_HANDLE;
+    }
+}
+
+void VulkanManager::initialize() {
+    if (hasVkContext()) { return; }
+
+    auto canPresent = [](VkInstance, VkPhysicalDevice, uint32_t) { return true; };
+
+    mBackendContext.reset(GrVkBackendContext::Create(&mPresentQueueIndex, canPresent));
+
+    // Get all the addresses of needed vulkan functions
+    VkInstance instance = mBackendContext->fInstance;
+    VkDevice device = mBackendContext->fDevice;
+    GET_PROC(CreateAndroidSurfaceKHR);
+    GET_PROC(DestroySurfaceKHR);
+    GET_PROC(GetPhysicalDeviceSurfaceSupportKHR);
+    GET_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR);
+    GET_PROC(GetPhysicalDeviceSurfaceFormatsKHR);
+    GET_PROC(GetPhysicalDeviceSurfacePresentModesKHR);
+    GET_DEV_PROC(CreateSwapchainKHR);
+    GET_DEV_PROC(DestroySwapchainKHR);
+    GET_DEV_PROC(GetSwapchainImagesKHR);
+    GET_DEV_PROC(AcquireNextImageKHR);
+    GET_DEV_PROC(QueuePresentKHR);
+    GET_DEV_PROC(CreateCommandPool);
+    GET_DEV_PROC(DestroyCommandPool);
+    GET_DEV_PROC(AllocateCommandBuffers);
+    GET_DEV_PROC(FreeCommandBuffers);
+    GET_DEV_PROC(ResetCommandBuffer);
+    GET_DEV_PROC(BeginCommandBuffer);
+    GET_DEV_PROC(EndCommandBuffer);
+    GET_DEV_PROC(CmdPipelineBarrier);
+    GET_DEV_PROC(GetDeviceQueue);
+    GET_DEV_PROC(QueueSubmit);
+    GET_DEV_PROC(QueueWaitIdle);
+    GET_DEV_PROC(DeviceWaitIdle);
+    GET_DEV_PROC(CreateSemaphore);
+    GET_DEV_PROC(DestroySemaphore);
+    GET_DEV_PROC(CreateFence);
+    GET_DEV_PROC(DestroyFence);
+    GET_DEV_PROC(WaitForFences);
+    GET_DEV_PROC(ResetFences);
+
+    // create the command pool for the command buffers
+    if (VK_NULL_HANDLE == mCommandPool) {
+        VkCommandPoolCreateInfo commandPoolInfo;
+        memset(&commandPoolInfo, 0, sizeof(VkCommandPoolCreateInfo));
+        commandPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
+        // this needs to be on the render queue
+        commandPoolInfo.queueFamilyIndex = mBackendContext->fGraphicsQueueIndex;
+        commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
+        SkDEBUGCODE(VkResult res =) mCreateCommandPool(mBackendContext->fDevice,
+                &commandPoolInfo, nullptr, &mCommandPool);
+        SkASSERT(VK_SUCCESS == res);
+    }
+
+    mGetDeviceQueue(mBackendContext->fDevice, mPresentQueueIndex, 0, &mPresentQueue);
+
+    mRenderThread.setGrContext(GrContext::Create(kVulkan_GrBackend,
+            (GrBackendContext) mBackendContext.get()));
+    DeviceInfo::initialize(mRenderThread.getGrContext()->caps()->maxRenderTargetSize());
+}
+
+// Returns the next BackbufferInfo to use for the next draw. The function will make sure all
+// previous uses have finished before returning.
+VulkanSurface::BackbufferInfo* VulkanManager::getAvailableBackbuffer(VulkanSurface* surface) {
+    SkASSERT(surface->mBackbuffers);
+
+    ++surface->mCurrentBackbufferIndex;
+    if (surface->mCurrentBackbufferIndex > surface->mImageCount) {
+        surface->mCurrentBackbufferIndex = 0;
+    }
+
+    VulkanSurface::BackbufferInfo* backbuffer = surface->mBackbuffers +
+            surface->mCurrentBackbufferIndex;
+
+    // Before we reuse a backbuffer, make sure its fences have all signaled so that we can safely
+    // reuse its commands buffers.
+    VkResult res = mWaitForFences(mBackendContext->fDevice, 2, backbuffer->mUsageFences,
+            true, UINT64_MAX);
+    if (res != VK_SUCCESS) {
+        return nullptr;
+    }
+
+    return backbuffer;
+}
+
+
+SkSurface* VulkanManager::getBackbufferSurface(VulkanSurface* surface) {
+    VulkanSurface::BackbufferInfo* backbuffer = getAvailableBackbuffer(surface);
+    SkASSERT(backbuffer);
+
+    VkResult res;
+
+    res = mResetFences(mBackendContext->fDevice, 2, backbuffer->mUsageFences);
+    SkASSERT(VK_SUCCESS == res);
+
+    // The acquire will signal the attached mAcquireSemaphore. We use this to know the image has
+    // finished presenting and that it is safe to begin sending new commands to the returned image.
+    res = mAcquireNextImageKHR(mBackendContext->fDevice, surface->mSwapchain, UINT64_MAX,
+            backbuffer->mAcquireSemaphore, VK_NULL_HANDLE, &backbuffer->mImageIndex);
+
+    if (VK_ERROR_SURFACE_LOST_KHR == res) {
+        // need to figure out how to create a new vkSurface without the platformData*
+        // maybe use attach somehow? but need a Window
+        return nullptr;
+    }
+    if (VK_ERROR_OUT_OF_DATE_KHR == res) {
+        // tear swapchain down and try again
+        if (!createSwapchain(surface)) {
+            return nullptr;
+        }
+
+        // acquire the image
+        res = mAcquireNextImageKHR(mBackendContext->fDevice, surface->mSwapchain, UINT64_MAX,
+                backbuffer->mAcquireSemaphore, VK_NULL_HANDLE, &backbuffer->mImageIndex);
+
+        if (VK_SUCCESS != res) {
+            return nullptr;
+        }
+    }
+
+    // set up layout transfer from initial to color attachment
+    VkImageLayout layout = surface->mImageLayouts[backbuffer->mImageIndex];
+    SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout || VK_IMAGE_LAYOUT_PRESENT_SRC_KHR == layout);
+    VkPipelineStageFlags srcStageMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout) ?
+                                        VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT :
+                                        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+    VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+    VkAccessFlags srcAccessMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout) ?
+                                  0 : VK_ACCESS_MEMORY_READ_BIT;
+    VkAccessFlags dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+
+    VkImageMemoryBarrier imageMemoryBarrier = {
+        VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,    // sType
+        NULL,                                      // pNext
+        srcAccessMask,                             // outputMask
+        dstAccessMask,                             // inputMask
+        layout,                                    // oldLayout
+        VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,  // newLayout
+        mPresentQueueIndex,                        // srcQueueFamilyIndex
+        mBackendContext->fGraphicsQueueIndex,      // dstQueueFamilyIndex
+        surface->mImages[backbuffer->mImageIndex], // image
+        { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }  // subresourceRange
+    };
+    mResetCommandBuffer(backbuffer->mTransitionCmdBuffers[0], 0);
+
+    VkCommandBufferBeginInfo info;
+    memset(&info, 0, sizeof(VkCommandBufferBeginInfo));
+    info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+    info.flags = 0;
+    mBeginCommandBuffer(backbuffer->mTransitionCmdBuffers[0], &info);
+
+    mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[0], srcStageMask, dstStageMask, 0,
+            0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
+
+    mEndCommandBuffer(backbuffer->mTransitionCmdBuffers[0]);
+
+    VkPipelineStageFlags waitDstStageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+    // insert the layout transfer into the queue and wait on the acquire
+    VkSubmitInfo submitInfo;
+    memset(&submitInfo, 0, sizeof(VkSubmitInfo));
+    submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+    submitInfo.waitSemaphoreCount = 1;
+    // Wait to make sure aquire semaphore set above has signaled.
+    submitInfo.pWaitSemaphores = &backbuffer->mAcquireSemaphore;
+    submitInfo.pWaitDstStageMask = &waitDstStageFlags;
+    submitInfo.commandBufferCount = 1;
+    submitInfo.pCommandBuffers = &backbuffer->mTransitionCmdBuffers[0];
+    submitInfo.signalSemaphoreCount = 0;
+
+    // Attach first fence to submission here so we can track when the command buffer finishes.
+    mQueueSubmit(mBackendContext->fQueue, 1, &submitInfo, backbuffer->mUsageFences[0]);
+
+    // We need to notify Skia that we changed the layout of the wrapped VkImage
+    GrVkImageInfo* imageInfo;
+    sk_sp<SkSurface> skSurface = surface->mSurfaces[backbuffer->mImageIndex];
+    skSurface->getRenderTargetHandle((GrBackendObject*)&imageInfo,
+            SkSurface::kFlushRead_BackendHandleAccess);
+    imageInfo->updateImageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+
+    surface->mBackbuffer = std::move(skSurface);
+    return surface->mBackbuffer.get();
+}
+
+void VulkanManager::destroyBuffers(VulkanSurface* surface) {
+    if (surface->mBackbuffers) {
+        for (uint32_t i = 0; i < surface->mImageCount + 1; ++i) {
+            mWaitForFences(mBackendContext->fDevice, 2, surface->mBackbuffers[i].mUsageFences, true,
+                    UINT64_MAX);
+            surface->mBackbuffers[i].mImageIndex = -1;
+            mDestroySemaphore(mBackendContext->fDevice, surface->mBackbuffers[i].mAcquireSemaphore,
+                    nullptr);
+            mDestroySemaphore(mBackendContext->fDevice, surface->mBackbuffers[i].mRenderSemaphore,
+                    nullptr);
+            mFreeCommandBuffers(mBackendContext->fDevice, mCommandPool, 2,
+                    surface->mBackbuffers[i].mTransitionCmdBuffers);
+            mDestroyFence(mBackendContext->fDevice, surface->mBackbuffers[i].mUsageFences[0], 0);
+            mDestroyFence(mBackendContext->fDevice, surface->mBackbuffers[i].mUsageFences[1], 0);
+        }
+    }
+
+    delete[] surface->mBackbuffers;
+    surface->mBackbuffers = nullptr;
+    delete[] surface->mSurfaces;
+    surface->mSurfaces = nullptr;
+    delete[] surface->mImageLayouts;
+    surface->mImageLayouts = nullptr;
+    delete[] surface->mImages;
+    surface->mImages = nullptr;
+}
+
+void VulkanManager::destroySurface(VulkanSurface* surface) {
+    // Make sure all submit commands have finished before starting to destroy objects.
+    if (VK_NULL_HANDLE != mPresentQueue) {
+        mQueueWaitIdle(mPresentQueue);
+    }
+    mDeviceWaitIdle(mBackendContext->fDevice);
+
+    destroyBuffers(surface);
+
+    if (VK_NULL_HANDLE != surface->mSwapchain) {
+        mDestroySwapchainKHR(mBackendContext->fDevice, surface->mSwapchain, nullptr);
+        surface->mSwapchain = VK_NULL_HANDLE;
+    }
+
+    if (VK_NULL_HANDLE != surface->mVkSurface) {
+        mDestroySurfaceKHR(mBackendContext->fInstance, surface->mVkSurface, nullptr);
+        surface->mVkSurface = VK_NULL_HANDLE;
+    }
+    delete surface;
+}
+
+void VulkanManager::createBuffers(VulkanSurface* surface, VkFormat format, VkExtent2D extent) {
+    mGetSwapchainImagesKHR(mBackendContext->fDevice, surface->mSwapchain, &surface->mImageCount,
+            nullptr);
+    SkASSERT(surface->mImageCount);
+    surface->mImages = new VkImage[surface->mImageCount];
+    mGetSwapchainImagesKHR(mBackendContext->fDevice, surface->mSwapchain,
+            &surface->mImageCount, surface->mImages);
+
+    SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
+
+    bool wantSRGB = VK_FORMAT_R8G8B8A8_SRGB == format;
+    GrPixelConfig config = wantSRGB ? kSRGBA_8888_GrPixelConfig : kRGBA_8888_GrPixelConfig;
+
+    // set up initial image layouts and create surfaces
+    surface->mImageLayouts = new VkImageLayout[surface->mImageCount];
+    surface->mSurfaces = new sk_sp<SkSurface>[surface->mImageCount];
+    for (uint32_t i = 0; i < surface->mImageCount; ++i) {
+        GrBackendRenderTargetDesc desc;
+        GrVkImageInfo info;
+        info.fImage = surface->mImages[i];
+        info.fAlloc = { VK_NULL_HANDLE, 0, 0, 0 };
+        info.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+        info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
+        info.fFormat = format;
+        info.fLevelCount = 1;
+
+        desc.fWidth = extent.width;
+        desc.fHeight = extent.height;
+        desc.fConfig = config;
+        desc.fOrigin = kTopLeft_GrSurfaceOrigin;
+        desc.fSampleCnt = 0;
+        desc.fStencilBits = 0;
+        desc.fRenderTargetHandle = (GrBackendObject) &info;
+
+        surface->mSurfaces[i] = SkSurface::MakeFromBackendRenderTarget(mRenderThread.getGrContext(),
+                desc, &props);
+        surface->mImageLayouts[i] = VK_IMAGE_LAYOUT_UNDEFINED;
+    }
+
+    SkASSERT(mCommandPool != VK_NULL_HANDLE);
+
+    // set up the backbuffers
+    VkSemaphoreCreateInfo semaphoreInfo;
+    memset(&semaphoreInfo, 0, sizeof(VkSemaphoreCreateInfo));
+    semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+    semaphoreInfo.pNext = nullptr;
+    semaphoreInfo.flags = 0;
+    VkCommandBufferAllocateInfo commandBuffersInfo;
+    memset(&commandBuffersInfo, 0, sizeof(VkCommandBufferAllocateInfo));
+    commandBuffersInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+    commandBuffersInfo.pNext = nullptr;
+    commandBuffersInfo.commandPool = mCommandPool;
+    commandBuffersInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+    commandBuffersInfo.commandBufferCount = 2;
+    VkFenceCreateInfo fenceInfo;
+    memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo));
+    fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
+    fenceInfo.pNext = nullptr;
+    fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
+
+    // we create one additional backbuffer structure here, because we want to
+    // give the command buffers they contain a chance to finish before we cycle back
+    surface->mBackbuffers = new VulkanSurface::BackbufferInfo[surface->mImageCount + 1];
+    for (uint32_t i = 0; i < surface->mImageCount + 1; ++i) {
+        SkDEBUGCODE(VkResult res);
+        surface->mBackbuffers[i].mImageIndex = -1;
+        SkDEBUGCODE(res = ) mCreateSemaphore(mBackendContext->fDevice, &semaphoreInfo, nullptr,
+                &surface->mBackbuffers[i].mAcquireSemaphore);
+        SkDEBUGCODE(res = ) mCreateSemaphore(mBackendContext->fDevice, &semaphoreInfo, nullptr,
+                &surface->mBackbuffers[i].mRenderSemaphore);
+        SkDEBUGCODE(res = ) mAllocateCommandBuffers(mBackendContext->fDevice, &commandBuffersInfo,
+                surface->mBackbuffers[i].mTransitionCmdBuffers);
+        SkDEBUGCODE(res = ) mCreateFence(mBackendContext->fDevice, &fenceInfo, nullptr,
+                &surface->mBackbuffers[i].mUsageFences[0]);
+        SkDEBUGCODE(res = ) mCreateFence(mBackendContext->fDevice, &fenceInfo, nullptr,
+                &surface->mBackbuffers[i].mUsageFences[1]);
+        SkASSERT(VK_SUCCESS == res);
+    }
+    surface->mCurrentBackbufferIndex = surface->mImageCount;
+}
+
+bool VulkanManager::createSwapchain(VulkanSurface* surface) {
+    // check for capabilities
+    VkSurfaceCapabilitiesKHR caps;
+    VkResult res = mGetPhysicalDeviceSurfaceCapabilitiesKHR(mBackendContext->fPhysicalDevice,
+            surface->mVkSurface, &caps);
+    if (VK_SUCCESS != res) {
+        return false;
+    }
+
+    uint32_t surfaceFormatCount;
+    res = mGetPhysicalDeviceSurfaceFormatsKHR(mBackendContext->fPhysicalDevice, surface->mVkSurface,
+            &surfaceFormatCount, nullptr);
+    if (VK_SUCCESS != res) {
+        return false;
+    }
+
+    SkAutoMalloc surfaceFormatAlloc(surfaceFormatCount * sizeof(VkSurfaceFormatKHR));
+    VkSurfaceFormatKHR* surfaceFormats = (VkSurfaceFormatKHR*)surfaceFormatAlloc.get();
+    res = mGetPhysicalDeviceSurfaceFormatsKHR(mBackendContext->fPhysicalDevice, surface->mVkSurface,
+            &surfaceFormatCount, surfaceFormats);
+    if (VK_SUCCESS != res) {
+        return false;
+    }
+
+    uint32_t presentModeCount;
+    res = mGetPhysicalDeviceSurfacePresentModesKHR(mBackendContext->fPhysicalDevice,
+            surface->mVkSurface, &presentModeCount, nullptr);
+    if (VK_SUCCESS != res) {
+        return false;
+    }
+
+    SkAutoMalloc presentModeAlloc(presentModeCount * sizeof(VkPresentModeKHR));
+    VkPresentModeKHR* presentModes = (VkPresentModeKHR*)presentModeAlloc.get();
+    res = mGetPhysicalDeviceSurfacePresentModesKHR(mBackendContext->fPhysicalDevice,
+            surface->mVkSurface, &presentModeCount, presentModes);
+    if (VK_SUCCESS != res) {
+        return false;
+    }
+
+    VkExtent2D extent = caps.currentExtent;
+    // clamp width; to handle currentExtent of -1 and  protect us from broken hints
+    if (extent.width < caps.minImageExtent.width) {
+        extent.width = caps.minImageExtent.width;
+    }
+    SkASSERT(extent.width <= caps.maxImageExtent.width);
+    // clamp height
+    if (extent.height < caps.minImageExtent.height) {
+        extent.height = caps.minImageExtent.height;
+    }
+    SkASSERT(extent.height <= caps.maxImageExtent.height);
+
+    uint32_t imageCount = caps.minImageCount + 2;
+    if (caps.maxImageCount > 0 && imageCount > caps.maxImageCount) {
+        // Application must settle for fewer images than desired:
+        imageCount = caps.maxImageCount;
+    }
+
+    // Currently Skia requires the images to be color attchments and support all transfer
+    // operations.
+    VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
+                                   VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
+                                   VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+    SkASSERT((caps.supportedUsageFlags & usageFlags) == usageFlags);
+    SkASSERT(caps.supportedTransforms & caps.currentTransform);
+    SkASSERT(caps.supportedCompositeAlpha & (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR |
+                                             VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR));
+    VkCompositeAlphaFlagBitsKHR composite_alpha =
+        (caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) ?
+                                        VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR :
+                                        VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
+
+    // Pick our surface format. For now, just make sure it matches our sRGB request:
+    VkFormat surfaceFormat = VK_FORMAT_UNDEFINED;
+    VkColorSpaceKHR colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
+
+    bool wantSRGB = false;
+#ifdef ANDROID_ENABLE_LINEAR_BLENDING
+    wantSRGB = true;
+#endif
+    for (uint32_t i = 0; i < surfaceFormatCount; ++i) {
+        // We are assuming we can get either R8G8B8A8_UNORM or R8G8B8A8_SRGB
+        VkFormat desiredFormat = wantSRGB ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM;
+        if (desiredFormat == surfaceFormats[i].format) {
+            surfaceFormat = surfaceFormats[i].format;
+            colorSpace = surfaceFormats[i].colorSpace;
+        }
+    }
+
+    if (VK_FORMAT_UNDEFINED == surfaceFormat) {
+        return false;
+    }
+
+    // If mailbox mode is available, use it, as it is the lowest-latency non-
+    // tearing mode. If not, fall back to FIFO which is always available.
+    VkPresentModeKHR mode = VK_PRESENT_MODE_FIFO_KHR;
+    for (uint32_t i = 0; i < presentModeCount; ++i) {
+        // use mailbox
+        if (VK_PRESENT_MODE_MAILBOX_KHR == presentModes[i]) {
+            mode = presentModes[i];
+            break;
+        }
+    }
+
+    VkSwapchainCreateInfoKHR swapchainCreateInfo;
+    memset(&swapchainCreateInfo, 0, sizeof(VkSwapchainCreateInfoKHR));
+    swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
+    swapchainCreateInfo.surface = surface->mVkSurface;
+    swapchainCreateInfo.minImageCount = imageCount;
+    swapchainCreateInfo.imageFormat = surfaceFormat;
+    swapchainCreateInfo.imageColorSpace = colorSpace;
+    swapchainCreateInfo.imageExtent = extent;
+    swapchainCreateInfo.imageArrayLayers = 1;
+    swapchainCreateInfo.imageUsage = usageFlags;
+
+    uint32_t queueFamilies[] = { mBackendContext->fGraphicsQueueIndex, mPresentQueueIndex };
+    if (mBackendContext->fGraphicsQueueIndex != mPresentQueueIndex) {
+        swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
+        swapchainCreateInfo.queueFamilyIndexCount = 2;
+        swapchainCreateInfo.pQueueFamilyIndices = queueFamilies;
+    } else {
+        swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
+        swapchainCreateInfo.queueFamilyIndexCount = 0;
+        swapchainCreateInfo.pQueueFamilyIndices = nullptr;
+    }
+
+    swapchainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
+    swapchainCreateInfo.compositeAlpha = composite_alpha;
+    swapchainCreateInfo.presentMode = mode;
+    swapchainCreateInfo.clipped = true;
+    swapchainCreateInfo.oldSwapchain = surface->mSwapchain;
+
+    res = mCreateSwapchainKHR(mBackendContext->fDevice, &swapchainCreateInfo, nullptr,
+            &surface->mSwapchain);
+    if (VK_SUCCESS != res) {
+        return false;
+    }
+
+    // destroy the old swapchain
+    if (swapchainCreateInfo.oldSwapchain != VK_NULL_HANDLE) {
+        mDeviceWaitIdle(mBackendContext->fDevice);
+
+        destroyBuffers(surface);
+
+        mDestroySwapchainKHR(mBackendContext->fDevice, swapchainCreateInfo.oldSwapchain, nullptr);
+    }
+
+    createBuffers(surface, surfaceFormat, extent);
+
+    return true;
+}
+
+
+VulkanSurface* VulkanManager::createSurface(ANativeWindow* window) {
+    initialize();
+
+    if (!window) {
+        return nullptr;
+    }
+
+    VulkanSurface* surface = new VulkanSurface();
+
+    VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo;
+    memset(&surfaceCreateInfo, 0, sizeof(VkAndroidSurfaceCreateInfoKHR));
+    surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
+    surfaceCreateInfo.pNext = nullptr;
+    surfaceCreateInfo.flags = 0;
+    surfaceCreateInfo.window = window;
+
+    VkResult res = mCreateAndroidSurfaceKHR(mBackendContext->fInstance, &surfaceCreateInfo,
+            nullptr, &surface->mVkSurface);
+    if (VK_SUCCESS != res) {
+        delete surface;
+        return nullptr;
+    }
+
+SkDEBUGCODE(
+    VkBool32 supported;
+    res = mGetPhysicalDeviceSurfaceSupportKHR(mBackendContext->fPhysicalDevice,
+            mPresentQueueIndex, surface->mVkSurface, &supported);
+    // All physical devices and queue families on Android must be capable of presentation with any
+    // native window.
+    SkASSERT(VK_SUCCESS == res && supported);
+);
+
+    if (!createSwapchain(surface)) {
+        destroySurface(surface);
+        return nullptr;
+    }
+
+    return surface;
+}
+
+// Helper to know which src stage flags we need to set when transitioning to the present layout
+static VkPipelineStageFlags layoutToPipelineStageFlags(const VkImageLayout layout) {
+    if (VK_IMAGE_LAYOUT_GENERAL == layout) {
+        return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
+    } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout ||
+               VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) {
+        return VK_PIPELINE_STAGE_TRANSFER_BIT;
+    } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout ||
+               VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL == layout ||
+               VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL == layout ||
+               VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout) {
+        return VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
+    } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
+        return VK_PIPELINE_STAGE_HOST_BIT;
+    }
+
+    SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout);
+    return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
+}
+
+// Helper to know which src access mask we need to set when transitioning to the present layout
+static VkAccessFlags layoutToSrcAccessMask(const VkImageLayout layout) {
+    VkAccessFlags flags = 0;
+    if (VK_IMAGE_LAYOUT_GENERAL == layout) {
+        flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
+                VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
+                VK_ACCESS_TRANSFER_WRITE_BIT |
+                VK_ACCESS_TRANSFER_READ_BIT |
+                VK_ACCESS_SHADER_READ_BIT |
+                VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_HOST_READ_BIT;
+    } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
+        flags = VK_ACCESS_HOST_WRITE_BIT;
+    } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout) {
+        flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+    } else if (VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL == layout) {
+        flags = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
+    } else if (VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) {
+        flags = VK_ACCESS_TRANSFER_WRITE_BIT;
+    } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout) {
+        flags = VK_ACCESS_TRANSFER_READ_BIT;
+    } else if (VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout) {
+        flags = VK_ACCESS_SHADER_READ_BIT;
+    }
+    return flags;
+}
+
+void VulkanManager::swapBuffers(VulkanSurface* surface) {
+    VulkanSurface::BackbufferInfo* backbuffer = surface->mBackbuffers +
+            surface->mCurrentBackbufferIndex;
+    GrVkImageInfo* imageInfo;
+    SkSurface* skSurface = surface->mSurfaces[backbuffer->mImageIndex].get();
+    skSurface->getRenderTargetHandle((GrBackendObject*)&imageInfo,
+            SkSurface::kFlushRead_BackendHandleAccess);
+    // Check to make sure we never change the actually wrapped image
+    SkASSERT(imageInfo->fImage == surface->mImages[backbuffer->mImageIndex]);
+
+    // We need to transition the image to VK_IMAGE_LAYOUT_PRESENT_SRC_KHR and make sure that all
+    // previous work is complete for before presenting. So we first add the necessary barrier here.
+    VkImageLayout layout = imageInfo->fImageLayout;
+    VkPipelineStageFlags srcStageMask = layoutToPipelineStageFlags(layout);
+    VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
+    VkAccessFlags srcAccessMask = layoutToSrcAccessMask(layout);
+    VkAccessFlags dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
+
+    VkImageMemoryBarrier imageMemoryBarrier = {
+        VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,    // sType
+        NULL,                                      // pNext
+        srcAccessMask,                             // outputMask
+        dstAccessMask,                             // inputMask
+        layout,                                    // oldLayout
+        VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,           // newLayout
+        mBackendContext->fGraphicsQueueIndex,      // srcQueueFamilyIndex
+        mPresentQueueIndex,                        // dstQueueFamilyIndex
+        surface->mImages[backbuffer->mImageIndex], // image
+        { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }  // subresourceRange
+    };
+
+    mResetCommandBuffer(backbuffer->mTransitionCmdBuffers[1], 0);
+    VkCommandBufferBeginInfo info;
+    memset(&info, 0, sizeof(VkCommandBufferBeginInfo));
+    info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+    info.flags = 0;
+    mBeginCommandBuffer(backbuffer->mTransitionCmdBuffers[1], &info);
+    mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[1], srcStageMask, dstStageMask, 0,
+            0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
+    mEndCommandBuffer(backbuffer->mTransitionCmdBuffers[1]);
+
+    surface->mImageLayouts[backbuffer->mImageIndex] = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+
+    // insert the layout transfer into the queue and wait on the acquire
+    VkSubmitInfo submitInfo;
+    memset(&submitInfo, 0, sizeof(VkSubmitInfo));
+    submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+    submitInfo.waitSemaphoreCount = 0;
+    submitInfo.pWaitDstStageMask = 0;
+    submitInfo.commandBufferCount = 1;
+    submitInfo.pCommandBuffers = &backbuffer->mTransitionCmdBuffers[1];
+    submitInfo.signalSemaphoreCount = 1;
+    // When this command buffer finishes we will signal this semaphore so that we know it is now
+    // safe to present the image to the screen.
+    submitInfo.pSignalSemaphores = &backbuffer->mRenderSemaphore;
+
+    // Attach second fence to submission here so we can track when the command buffer finishes.
+    mQueueSubmit(mBackendContext->fQueue, 1, &submitInfo, backbuffer->mUsageFences[1]);
+
+    // Submit present operation to present queue. We use a semaphore here to make sure all rendering
+    // to the image is complete and that the layout has been change to present on the graphics
+    // queue.
+    const VkPresentInfoKHR presentInfo =
+    {
+        VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, // sType
+        NULL, // pNext
+        1, // waitSemaphoreCount
+        &backbuffer->mRenderSemaphore, // pWaitSemaphores
+        1, // swapchainCount
+        &surface->mSwapchain, // pSwapchains
+        &backbuffer->mImageIndex, // pImageIndices
+        NULL // pResults
+    };
+
+    mQueuePresentKHR(mPresentQueue, &presentInfo);
+
+    surface->mBackbuffer.reset();
+}
+
+} /* namespace renderthread */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
new file mode 100644
index 0000000..f0e3320
--- /dev/null
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef VULKANMANAGER_H
+#define VULKANMANAGER_H
+
+#include <SkSurface.h>
+#include <vk/GrVkBackendContext.h>
+
+#include <vulkan/vulkan.h>
+
+namespace android {
+namespace uirenderer {
+namespace renderthread {
+
+class RenderThread;
+
+class VulkanSurface {
+public:
+    VulkanSurface() {}
+
+    sk_sp<SkSurface> getBackBufferSurface() { return mBackbuffer; }
+
+private:
+    friend class VulkanManager;
+    struct BackbufferInfo {
+        uint32_t        mImageIndex;          // image this is associated with
+        VkSemaphore     mAcquireSemaphore;    // we signal on this for acquisition of image
+        VkSemaphore     mRenderSemaphore;     // we wait on this for rendering to be done
+        VkCommandBuffer mTransitionCmdBuffers[2]; // to transition layout between present and render
+        // We use these fences to make sure the above Command buffers have finished their work
+        // before attempting to reuse them or destroy them.
+        VkFence         mUsageFences[2];
+    };
+
+    sk_sp<SkSurface> mBackbuffer;
+
+    VkSurfaceKHR mVkSurface = VK_NULL_HANDLE;
+    VkSwapchainKHR mSwapchain = VK_NULL_HANDLE;
+
+    BackbufferInfo* mBackbuffers;
+    uint32_t mCurrentBackbufferIndex;
+
+    uint32_t mImageCount;
+    VkImage* mImages;
+    VkImageLayout* mImageLayouts;
+    sk_sp<SkSurface>* mSurfaces;
+};
+
+// This class contains the shared global Vulkan objects, such as VkInstance, VkDevice and VkQueue,
+// which are re-used by CanvasContext. This class is created once and should be used by all vulkan
+// windowing contexts. The VulkanManager must be initialized before use.
+class VulkanManager {
+public:
+    // Sets up the vulkan context that is shared amonst all clients of the VulkanManager. This must
+    // be call once before use of the VulkanManager. Multiple calls after the first will simiply
+    // return.
+    void initialize();
+
+    // Quick check to see if the VulkanManager has been initialized.
+    bool hasVkContext() { return mBackendContext.get() != nullptr; }
+
+    // Given a window this creates a new VkSurfaceKHR and VkSwapchain and stores them inside a new
+    // VulkanSurface object which is returned.
+    VulkanSurface* createSurface(ANativeWindow* window);
+
+    // Destroy the VulkanSurface and all associated vulkan objects.
+    void destroySurface(VulkanSurface* surface);
+
+    // Cleans up all the global state in the VulkanManger.
+    void destroy();
+
+    // No work is needed to make a VulkanSurface current, and all functions require that a
+    // VulkanSurface is passed into them so we just return true here.
+    bool isCurrent(VulkanSurface* surface) { return true; }
+
+    // Returns an SkSurface which wraps the next image returned from vkAcquireNextImageKHR. It also
+    // will transition the VkImage from a present layout to color attachment so that it can be used
+    // by the client for drawing.
+    SkSurface* getBackbufferSurface(VulkanSurface* surface);
+
+    // Presents the current VkImage.
+    void swapBuffers(VulkanSurface* surface);
+
+private:
+    friend class RenderThread;
+
+    explicit VulkanManager(RenderThread& thread);
+    ~VulkanManager() { destroy(); }
+
+    void destroyBuffers(VulkanSurface* surface);
+
+    bool createSwapchain(VulkanSurface* surface);
+    void createBuffers(VulkanSurface* surface, VkFormat format, VkExtent2D extent);
+
+    VulkanSurface::BackbufferInfo* getAvailableBackbuffer(VulkanSurface* surface);
+
+    // simple wrapper class that exists only to initialize a pointer to NULL
+    template <typename FNPTR_TYPE> class VkPtr {
+    public:
+        VkPtr() : fPtr(NULL) {}
+        VkPtr operator=(FNPTR_TYPE ptr) { fPtr = ptr; return *this; }
+        operator FNPTR_TYPE() const { return fPtr; }
+    private:
+        FNPTR_TYPE fPtr;
+    };
+
+    // WSI interface functions
+    VkPtr<PFN_vkCreateAndroidSurfaceKHR> mCreateAndroidSurfaceKHR;
+    VkPtr<PFN_vkDestroySurfaceKHR> mDestroySurfaceKHR;
+    VkPtr<PFN_vkGetPhysicalDeviceSurfaceSupportKHR> mGetPhysicalDeviceSurfaceSupportKHR;
+    VkPtr<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR> mGetPhysicalDeviceSurfaceCapabilitiesKHR;
+    VkPtr<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR> mGetPhysicalDeviceSurfaceFormatsKHR;
+    VkPtr<PFN_vkGetPhysicalDeviceSurfacePresentModesKHR> mGetPhysicalDeviceSurfacePresentModesKHR;
+
+    VkPtr<PFN_vkCreateSwapchainKHR> mCreateSwapchainKHR;
+    VkPtr<PFN_vkDestroySwapchainKHR> mDestroySwapchainKHR;
+    VkPtr<PFN_vkGetSwapchainImagesKHR> mGetSwapchainImagesKHR;
+    VkPtr<PFN_vkAcquireNextImageKHR> mAcquireNextImageKHR;
+    VkPtr<PFN_vkQueuePresentKHR> mQueuePresentKHR;
+    VkPtr<PFN_vkCreateSharedSwapchainsKHR> mCreateSharedSwapchainsKHR;
+
+    // Additional vulkan functions
+    VkPtr<PFN_vkCreateCommandPool> mCreateCommandPool;
+    VkPtr<PFN_vkDestroyCommandPool> mDestroyCommandPool;
+    VkPtr<PFN_vkAllocateCommandBuffers> mAllocateCommandBuffers;
+    VkPtr<PFN_vkFreeCommandBuffers> mFreeCommandBuffers;
+    VkPtr<PFN_vkResetCommandBuffer> mResetCommandBuffer;
+    VkPtr<PFN_vkBeginCommandBuffer> mBeginCommandBuffer;
+    VkPtr<PFN_vkEndCommandBuffer> mEndCommandBuffer;
+    VkPtr<PFN_vkCmdPipelineBarrier> mCmdPipelineBarrier;
+
+    VkPtr<PFN_vkGetDeviceQueue> mGetDeviceQueue;
+    VkPtr<PFN_vkQueueSubmit> mQueueSubmit;
+    VkPtr<PFN_vkQueueWaitIdle> mQueueWaitIdle;
+    VkPtr<PFN_vkDeviceWaitIdle> mDeviceWaitIdle;
+
+    VkPtr<PFN_vkCreateSemaphore> mCreateSemaphore;
+    VkPtr<PFN_vkDestroySemaphore> mDestroySemaphore;
+    VkPtr<PFN_vkCreateFence> mCreateFence;
+    VkPtr<PFN_vkDestroyFence> mDestroyFence;
+    VkPtr<PFN_vkWaitForFences> mWaitForFences;
+    VkPtr<PFN_vkResetFences> mResetFences;
+
+    RenderThread& mRenderThread;
+
+    sk_sp<const GrVkBackendContext> mBackendContext;
+    uint32_t mPresentQueueIndex;
+    VkQueue mPresentQueue = VK_NULL_HANDLE;
+    VkCommandPool mCommandPool = VK_NULL_HANDLE;
+};
+
+} /* namespace renderthread */
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* VULKANMANAGER_H */
+
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 5dcad7a..3b84313 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -168,7 +168,7 @@
     <string name="wifi_verbose_logging" msgid="4203729756047242344">"Uitgebreide wifi-logregistratie insch."</string>
     <string name="wifi_aggressive_handover" msgid="9194078645887480917">"Agressieve handover van wifi naar mobiel"</string>
     <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Altijd roamingscans voor wifi toestaan"</string>
-    <string name="mobile_data_always_on" msgid="7745605759775320362">"Mobiele gegevens altijd actief"</string>
+    <string name="mobile_data_always_on" msgid="7745605759775320362">"Mobiele data altijd actief"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Absoluut volume uitschakelen"</string>
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Opties weergeven voor certificering van draadloze weergave"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Logniveau voor wifi verhogen, weergeven per SSID RSSI in wifi-kiezer"</string>
diff --git a/packages/Shell/Android.mk b/packages/Shell/Android.mk
index 2170cc1..935d09b 100644
--- a/packages/Shell/Android.mk
+++ b/packages/Shell/Android.mk
@@ -5,6 +5,13 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
+LOCAL_SRC_FILES += \
+        ../../../native/cmds/dumpstate/binder/android/os/IDumpstate.aidl \
+        ../../../native/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl \
+        ../../../native/cmds/dumpstate/binder/android/os/IDumpstateToken.aidl
+
+LOCAL_AIDL_INCLUDES = frameworks/native/cmds/dumpstate/binder
+
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
 
 LOCAL_PACKAGE_NAME := Shell
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index dedb9ac..47abd4f 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -31,6 +31,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.nio.charset.StandardCharsets;
 import java.text.NumberFormat;
 import java.util.ArrayList;
@@ -45,6 +46,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.util.FastPrintWriter;
 
 import com.google.android.collect.Lists;
 
@@ -69,10 +71,16 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
+import android.os.IDumpstate;
+import android.os.IDumpstateListener;
+import android.os.IDumpstateToken;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.os.Vibrator;
 import android.support.v4.content.FileProvider;
@@ -146,10 +154,9 @@
     static final String EXTRA_INFO = "android.intent.extra.INFO";
 
     private static final int MSG_SERVICE_COMMAND = 1;
-    private static final int MSG_POLL = 2;
-    private static final int MSG_DELAYED_SCREENSHOT = 3;
-    private static final int MSG_SCREENSHOT_REQUEST = 4;
-    private static final int MSG_SCREENSHOT_RESPONSE = 5;
+    private static final int MSG_DELAYED_SCREENSHOT = 2;
+    private static final int MSG_SCREENSHOT_REQUEST = 3;
+    private static final int MSG_SCREENSHOT_RESPONSE = 4;
 
     // Passed to Message.obtain() when msg.arg2 is not used.
     private static final int UNUSED_ARG2 = -2;
@@ -165,16 +172,9 @@
      */
     static final int SCREENSHOT_DELAY_SECONDS = 3;
 
-    /** Polling frequency, in milliseconds. */
-    static final long POLLING_FREQUENCY = 2 * DateUtils.SECOND_IN_MILLIS;
-
-    /** How long (in ms) a dumpstate process will be monitored if it didn't show progress. */
-    private static final long INACTIVITY_TIMEOUT = 10 * DateUtils.MINUTE_IN_MILLIS;
-
-    /** System properties used for monitoring progress. */
+    // TODO: will be gone once fully migrated to Binder
+    /** System properties used to communicate with dumpstate progress. */
     private static final String DUMPSTATE_PREFIX = "dumpstate.";
-    private static final String PROGRESS_SUFFIX = ".progress";
-    private static final String MAX_SUFFIX = ".max";
     private static final String NAME_SUFFIX = ".name";
 
     /** System property (and value) used to stop dumpstate. */
@@ -190,7 +190,7 @@
     private static final String SCREENSHOT_DIR = "bugreports";
 
     /** Managed dumpstate processes (keyed by id) */
-    private final SparseArray<BugreportInfo> mProcesses = new SparseArray<>();
+    private final SparseArray<DumpstateListener> mProcesses = new SparseArray<>();
 
     private Context mContext;
     private ServiceHandler mMainHandler;
@@ -267,14 +267,16 @@
     protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
         final int size = mProcesses.size();
         if (size == 0) {
-            writer.printf("No monitored processes");
+            writer.println("No monitored processes");
             return;
         }
-        writer.printf("Foreground id: %d\n\n", mForegroundId);
-        writer.printf("Monitored dumpstate processes\n");
-        writer.printf("-----------------------------\n");
+        writer.print("Foreground id: "); writer.println(mForegroundId);
+        writer.println("\n");
+        writer.println("Monitored dumpstate processes");
+        writer.println("-----------------------------");
         for (int i = 0; i < size; i++) {
-            writer.printf("%s\n", mProcesses.valueAt(i));
+            writer.print("#"); writer.println(i + 1);
+            writer.println(mProcesses.valueAt(i).info);
         }
     }
 
@@ -288,11 +290,6 @@
 
         @Override
         public void handleMessage(Message msg) {
-            if (msg.what == MSG_POLL) {
-                poll();
-                return;
-            }
-
             if (msg.what == MSG_DELAYED_SCREENSHOT) {
                 takeScreenshot(msg.arg1, msg.arg2);
                 return;
@@ -339,7 +336,6 @@
                         stopSelfWhenDone();
                         return;
                     }
-                    poll();
                     break;
                 case INTENT_BUGREPORT_FINISHED:
                     if (id == 0) {
@@ -367,15 +363,6 @@
             return;
 
         }
-
-        private void poll() {
-            if (pollProgress()) {
-                // Keep polling...
-                sendEmptyMessageDelayed(MSG_POLL, POLLING_FREQUENCY);
-            } else {
-                Log.i(TAG, "Stopped polling");
-            }
-        }
     }
 
     /**
@@ -397,11 +384,12 @@
     }
 
     private BugreportInfo getInfo(int id) {
-        final BugreportInfo info = mProcesses.get(id);
-        if (info == null) {
+        final DumpstateListener listener = mProcesses.get(id);
+        if (listener == null) {
             Log.w(TAG, "Not monitoring process with ID " + id);
+            return null;
         }
-        return info;
+        return listener.info;
     }
 
     /**
@@ -433,9 +421,15 @@
             Log.w(TAG, "ID " + id + " already watched");
             return true;
         }
-        mProcesses.put(info.id, info);
-        updateProgress(info);
-        return true;
+        final DumpstateListener listener = new DumpstateListener(info);
+        mProcesses.put(info.id, listener);
+        if (listener.connect()) {
+            updateProgress(info);
+            return true;
+        } else {
+            Log.w(TAG, "not updating progress because it could not connect to dumpstate");
+            return false;
+        }
     }
 
     /**
@@ -504,10 +498,7 @@
                 .setActions(infoAction, screenshotAction, cancelAction);
         }
 
-        if (DEBUG) {
-            Log.d(TAG, "Sending 'Progress' notification for id " + info.id + " (pid " + info.pid
-                    + "): " + percentageText);
-        }
+        Log.d(TAG, "Sending 'Progress' notification for id " + info.id + ": " + percentageText);
         sendForegroundabledNotification(info.id, builder.build());
     }
 
@@ -567,96 +558,11 @@
     }
 
     /**
-     * Poll {@link SystemProperties} to get the progress on each monitored process.
-     *
-     * @return whether it should keep polling.
-     */
-    private boolean pollProgress() {
-        final int total = mProcesses.size();
-        if (total == 0) {
-            Log.d(TAG, "No process to poll progress.");
-        }
-        int activeProcesses = 0;
-        for (int i = 0; i < total; i++) {
-            final BugreportInfo info = mProcesses.valueAt(i);
-            if (info == null) {
-                Log.wtf(TAG, "pollProgress(): null info at index " + i + "(ID = "
-                        + mProcesses.keyAt(i) + ")");
-                continue;
-            }
-
-            final int pid = info.pid;
-            final int id = info.id;
-            if (info.finished) {
-                if (DEBUG) Log.v(TAG, "Skipping finished process " + pid + " (id: " + id + ")");
-                continue;
-            }
-            activeProcesses++;
-            final String progressKey = DUMPSTATE_PREFIX + pid + PROGRESS_SUFFIX;
-            info.realProgress = SystemProperties.getInt(progressKey, 0);
-            if (info.realProgress == 0) {
-                Log.v(TAG, "System property " + progressKey + " is not set yet");
-            }
-            final String maxKey = DUMPSTATE_PREFIX + pid + MAX_SUFFIX;
-            info.realMax = SystemProperties.getInt(maxKey, info.max);
-            if (info.realMax <= 0 ) {
-                Log.w(TAG, "Property " + maxKey + " is not positive: " + info.max);
-                continue;
-            }
-            /*
-             * Checks whether the progress changed in a way that should be displayed to the user:
-             * - info.progress / info.max represents the displayed progress
-             * - info.realProgress / info.realMax represents the real progress
-             * - since the real progress can decrease, the displayed progress is only updated if it
-             *   increases
-             * - the displayed progress is capped at a maximum (like 99%)
-             */
-            final int oldPercentage = (CAPPED_MAX * info.progress) / info.max;
-            int newPercentage = (CAPPED_MAX * info.realProgress) / info.realMax;
-            int max = info.realMax;
-            int progress = info.realProgress;
-
-            if (newPercentage > CAPPED_PROGRESS) {
-                progress = newPercentage = CAPPED_PROGRESS;
-                max = CAPPED_MAX;
-            }
-
-            if (newPercentage > oldPercentage) {
-                if (DEBUG) {
-                    if (progress != info.progress) {
-                        Log.v(TAG, "Updating progress for PID " + pid + "(id: " + id + ") from "
-                                + info.progress + " to " + progress);
-                    }
-                    if (max != info.max) {
-                        Log.v(TAG, "Updating max progress for PID " + pid + "(id: " + id + ") from "
-                                + info.max + " to " + max);
-                    }
-                }
-                info.progress = progress;
-                info.max = max;
-                info.lastUpdate = System.currentTimeMillis();
-                updateProgress(info);
-            } else {
-                long inactiveTime = System.currentTimeMillis() - info.lastUpdate;
-                if (inactiveTime >= INACTIVITY_TIMEOUT) {
-                    Log.w(TAG, "No progress update for PID " + pid + " since "
-                            + info.getFormattedLastUpdate());
-                    stopProgress(info.id);
-                }
-            }
-        }
-        if (DEBUG) Log.v(TAG, "pollProgress() total=" + total + ", actives=" + activeProcesses);
-        return activeProcesses > 0;
-    }
-
-    /**
      * Fetches a {@link BugreportInfo} for a given process and launches a dialog where the user can
      * change its values.
      */
     private void launchBugreportInfoDialog(int id) {
         MetricsLogger.action(this, MetricsEvent.ACTION_BUGREPORT_NOTIFICATION_ACTION_DETAILS);
-        // Copy values so it doesn't lock mProcesses while UI is being updated
-        final String name, title, description;
         final BugreportInfo info = getInfo(id);
         if (info == null) {
             // Most likely am killed Shell before user tapped the notification. Since system might
@@ -737,7 +643,7 @@
         synchronized (BugreportProgressService.this) {
             mTakingScreenshot = flag;
             for (int i = 0; i < mProcesses.size(); i++) {
-                final BugreportInfo info = mProcesses.valueAt(i);
+                final BugreportInfo info = mProcesses.valueAt(i).info;
                 if (info.finished) {
                     Log.d(TAG, "Not updating progress for " + info.id + " while taking screenshot"
                             + " because share notification was already sent");
@@ -809,7 +715,7 @@
         final int total = mProcesses.size();
         if (total > 0) {
             for (int i = 0; i < total; i++) {
-                final BugreportInfo info = mProcesses.valueAt(i);
+                final BugreportInfo info = mProcesses.valueAt(i).info;
                 if (!info.finished) {
                     updateProgress(info);
                     break;
@@ -848,13 +754,13 @@
             Log.wtf(TAG, "Missing " + EXTRA_BUGREPORT + " on intent " + intent);
             return;
         }
-        mInfoDialog.onBugreportFinished(id);
+        mInfoDialog.onBugreportFinished();
         BugreportInfo info = getInfo(id);
         if (info == null) {
             // Happens when BUGREPORT_FINISHED was received without a BUGREPORT_STARTED first.
             Log.v(TAG, "Creating info for untracked ID " + id);
             info = new BugreportInfo(mContext, id);
-            mProcesses.put(id, info);
+            mProcesses.put(id, new DumpstateListener(info));
         }
         info.renameScreenshots(mScreenshotsDir);
         info.bugreportFile = bugreportFile;
@@ -1363,7 +1269,6 @@
         if (bitmap == null) {
             return false;
         }
-        boolean status;
         try (final FileOutputStream fos = new FileOutputStream(path)) {
             if (bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos)) {
                 ((Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE)).vibrate(150);
@@ -1570,7 +1475,7 @@
          * <p>Once the bugreport is finished dumpstate has already generated the final files, so
          * changing the name would have no effect.
          */
-        void onBugreportFinished(int id) {
+        void onBugreportFinished() {
             if (mInfoName != null) {
                 mInfoName.setEnabled(false);
                 mInfoName.setText(mSavedName);
@@ -1684,7 +1589,7 @@
             this.id = id;
             this.pid = pid;
             this.name = name;
-            this.max = max;
+            this.max = this.realMax = max;
         }
 
         /**
@@ -1750,14 +1655,17 @@
         public String toString() {
             final float percent = ((float) progress * 100 / max);
             final float realPercent = ((float) realProgress * 100 / realMax);
-            return "id: " + id + ", pid: " + pid + ", name: " + name + ", finished: " + finished
-                    + "\n\ttitle: " + title + "\n\tdescription: " + description
-                    + "\n\tfile: " + bugreportFile + "\n\tscreenshots: " + screenshotFiles
+            return "\tid: " + id + ", pid: " + pid + ", name: " + name + ", finished: " + finished
+                    + "\n\ttitle: " + title
+                    + "\n\tdescription: " + description
+                    + "\n\tfile: " + bugreportFile
+                    + "\n\tscreenshots: " + screenshotFiles
                     + "\n\tprogress: " + progress + "/" + max + " (" + percent + ")"
-                    + "\n\treal progress: " + realProgress + "/" + realMax + " (" + realPercent + ")"
+                    + "\n\treal progress: " + realProgress + "/" + realMax + " (" + realPercent
+                    + ")"
                     + "\n\tlast_update: " + getFormattedLastUpdate()
-                    + "\naddingDetailsToZip: " + addingDetailsToZip
-                    + " addedDetailsToZip: " + addedDetailsToZip;
+                    + "\n\taddingDetailsToZip: " + addingDetailsToZip + " addedDetailsToZip: "
+                    + addedDetailsToZip;
         }
 
         // Parcelable contract
@@ -1823,16 +1731,118 @@
             return path == null ? null : new File(path);
         }
 
+        @SuppressWarnings("unused")
         public static final Parcelable.Creator<BugreportInfo> CREATOR =
                 new Parcelable.Creator<BugreportInfo>() {
+            @Override
             public BugreportInfo createFromParcel(Parcel source) {
                 return new BugreportInfo(source);
             }
 
+            @Override
             public BugreportInfo[] newArray(int size) {
                 return new BugreportInfo[size];
             }
         };
 
     }
+
+    private final class DumpstateListener extends IDumpstateListener.Stub
+        implements DeathRecipient {
+
+        private final BugreportInfo info;
+        private IDumpstateToken token;
+
+        DumpstateListener(BugreportInfo info) {
+            this.info = info;
+        }
+
+        /**
+         * Connects to the {@code dumpstate} binder to receive updates.
+         */
+        boolean connect() {
+            if (token != null) {
+                Log.d(TAG, "connect(): " + info.id + " already connected");
+                return true;
+            }
+            final IBinder service = ServiceManager.getService("dumpstate");
+            if (service == null) {
+                Log.d(TAG, "dumpstate service not bound yet");
+                return true;
+            }
+            final IDumpstate dumpstate = IDumpstate.Stub.asInterface(service);
+            try {
+                token = dumpstate.setListener("Shell", this);
+                if (token != null) {
+                    token.asBinder().linkToDeath(this, 0);
+                }
+            } catch (Exception e) {
+                Log.e(TAG, "Could not set dumpstate listener: " + e);
+            }
+            return token != null;
+        }
+
+        @Override
+        public void binderDied() {
+            if (!info.finished) {
+                // TODO: linkToDeath() might be called BEFORE Shell received the
+                // BUGREPORT_FINISHED broadcast, in which case the statements below
+                // spam logcat (but are harmless).
+                // The right, long-term solution is to provide an onFinished() callback
+                // on IDumpstateListener and call it instead of using a broadcast.
+                Log.w(TAG, "Dumpstate process died:\n" + info);
+                stopProgress(info.id);
+            }
+            token.asBinder().unlinkToDeath(this, 0);
+        }
+
+        @Override
+        public void onProgressUpdated(int progress) throws RemoteException {
+            /*
+             * Checks whether the progress changed in a way that should be displayed to the user:
+             * - info.progress / info.max represents the displayed progress
+             * - info.realProgress / info.realMax represents the real progress
+             * - since the real progress can decrease, the displayed progress is only updated if it
+             *   increases
+             * - the displayed progress is capped at a maximum (like 99%)
+             */
+            info.realProgress = progress;
+            final int oldPercentage = (CAPPED_MAX * info.progress) / info.max;
+            int newPercentage = (CAPPED_MAX * info.realProgress) / info.realMax;
+            int max = info.realMax;
+
+            if (newPercentage > CAPPED_PROGRESS) {
+                progress = newPercentage = CAPPED_PROGRESS;
+                max = CAPPED_MAX;
+            }
+
+            if (newPercentage > oldPercentage) {
+                if (DEBUG) {
+                    if (progress != info.progress) {
+                        Log.v(TAG, "Updating progress for PID " + info.pid + "(id: " + info.id
+                                + ") from " + info.progress + " to " + progress);
+                    }
+                    if (max != info.max) {
+                        Log.v(TAG, "Updating max progress for PID " + info.pid + "(id: " + info.id
+                                + ") from " + info.max + " to " + max);
+                    }
+                }
+                info.progress = progress;
+                info.max = max;
+                info.lastUpdate = System.currentTimeMillis();
+
+                updateProgress(info);
+            }
+        }
+
+        @Override
+        public void onMaxProgressUpdated(int maxProgress) throws RemoteException {
+            Log.d(TAG, "onMaxProgressUpdated: " + maxProgress);
+            info.realMax = maxProgress;
+        }
+
+        public void dump(String prefix, PrintWriter pw) {
+            pw.print(prefix); pw.print("token: "); pw.println(token);
+        }
+    }
 }
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index b4bfb01..4e3744a 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -33,7 +33,6 @@
 import static com.android.shell.BugreportProgressService.EXTRA_SCREENSHOT;
 import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_FINISHED;
 import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_STARTED;
-import static com.android.shell.BugreportProgressService.POLLING_FREQUENCY;
 import static com.android.shell.BugreportProgressService.SCREENSHOT_DELAY_SECONDS;
 
 import static org.junit.Assert.assertEquals;
@@ -65,6 +64,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TestName;
@@ -116,7 +116,7 @@
     private static final String TAG = "BugreportReceiverTest";
 
     // Timeout for UI operations, in milliseconds.
-    private static final int TIMEOUT = (int) POLLING_FREQUENCY * 4;
+    private static final int TIMEOUT = (int) (5 * DateUtils.SECOND_IN_MILLIS);
 
     // Timeout for when waiting for a screenshot to finish.
     private static final int SAFE_SCREENSHOT_DELAY = SCREENSHOT_DELAY_SECONDS + 10;
@@ -209,6 +209,12 @@
         }
     }
 
+    /*
+     * TODO: this test is incomplete because:
+     * - the assertProgressNotification() is not really asserting the progress because the
+     *   UI automation API doesn't provide a way to check the notification progress bar value
+     * - it should use the binder object instead of SystemProperties to update progress
+     */
     @Test
     public void testProgress() throws Exception {
         resetProperties();
@@ -227,7 +233,6 @@
 
         // Make sure progress never goes back...
         SystemProperties.set(MAX_PROPERTY, "2000");
-        sleep(POLLING_FREQUENCY + DateUtils.SECOND_IN_MILLIS);
         assertProgressNotification(NAME, 95.00f);
 
         SystemProperties.set(PROGRESS_PROPERTY, "1000");
diff --git a/packages/SystemUI/res/layout-sw600dp/recents_grid.xml b/packages/SystemUI/res/layout-sw600dp/recents_grid.xml
index c8b4fd0..cff770a 100644
--- a/packages/SystemUI/res/layout-sw600dp/recents_grid.xml
+++ b/packages/SystemUI/res/layout-sw600dp/recents_grid.xml
@@ -16,8 +16,11 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:paddingTop="24dp"
+    android:paddingBottom="54dp"
     android:orientation="vertical"
-    android:id="@+id/recents_container">
+    android:id="@+id/recents_container"
+    android:background="#99000000">
     <include layout="@layout/recents_stack_action_button" />
     <FrameLayout
         android:layout_width="match_parent"
@@ -26,7 +29,6 @@
         android:layout_marginLeft="12dp"
         android:layout_marginTop="10dp"
         android:layout_marginRight="12dp"
-        android:layout_marginBottom="5dp"
         android:gravity="center">
     </FrameLayout>
 </LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index 2f5358e..07966cf 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -421,7 +421,7 @@
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Սարքը կմնա արգելափակված՝ մինչև ձեռքով չբացեք"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Ավելի արագ ստացեք ծանուցումները"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"Տեսեք դրանք մինչև ապակողպելը"</string>
-    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"Ոչ, շնորհակալություն"</string>
+    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"Ոչ"</string>
     <string name="hidden_notifications_setup" msgid="41079514801976810">"Կարգավորել"</string>
     <string name="zen_mode_and_condition" msgid="4462471036429759903">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
     <string name="volume_zen_end_now" msgid="3179845345429841822">"Ավարտել"</string>
@@ -430,7 +430,7 @@
     <string name="screen_pinning_title" msgid="3273740381976175811">"Էկրանն ամրացված է"</string>
     <string name="screen_pinning_description" msgid="7238941806855968768">"Էկրանը կմնա տեսադաշտում, մինչև այն ապամրացնեք: Ապամրացնելու համար հպեք և պահեք Հետ կոճակը:"</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Եղավ"</string>
-    <string name="screen_pinning_negative" msgid="3741602308343880268">"Ոչ, շնորհակալություն"</string>
+    <string name="screen_pinning_negative" msgid="3741602308343880268">"Ոչ"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Թաքցնե՞լ <xliff:g id="TILE_LABEL">%1$s</xliff:g>-ը:"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Այն դարձյալ կհայտնվի, երբ նորից միացնեք կարգավորումներում:"</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Թաքցնել"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 7c12b5fd..8217ee5 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -235,7 +235,7 @@
     <string name="accessibility_brightness" msgid="8003681285547803095">"Helderheid van het scherm"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G/3G-data zijn onderbroken"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data zijn onderbroken"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobiele gegevens zijn onderbroken"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobiele data zijn onderbroken"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Gegevens zijn onderbroken"</string>
     <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"De ingestelde datalimiet is bereikt. Je gebruikt geen mobiele data meer.\n\nAls je hervat, kunnen er kosten voor datagebruik in rekening worden gebracht."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Hervatten"</string>
@@ -310,7 +310,7 @@
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Meldingen"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Zaklamp"</string>
-    <string name="quick_settings_cellular_detail_title" msgid="8575062783675171695">"Mobiele gegevens"</string>
+    <string name="quick_settings_cellular_detail_title" msgid="8575062783675171695">"Mobiele data"</string>
     <string name="quick_settings_cellular_detail_data_usage" msgid="1964260360259312002">"Datagebruik"</string>
     <string name="quick_settings_cellular_detail_remaining_data" msgid="722715415543541249">"Resterende gegevens"</string>
     <string name="quick_settings_cellular_detail_over_limit" msgid="967669665390990427">"Limiet overschreden"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index cc5b693..78c6102 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -652,6 +652,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otwórz ustawienia: <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edytuj kolejność ustawień."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Strona <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string>
-    <!-- no translation found for pip_phone_expand (5889780005575693909) -->
-    <skip />
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Rozwiń"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index ef07edc..0dbdcb9 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -650,6 +650,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir configurações de <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar ordem das configurações."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
-    <!-- no translation found for pip_phone_expand (5889780005575693909) -->
-    <skip />
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Expandir"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index ef07edc..0dbdcb9 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -650,6 +650,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir configurações de <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar ordem das configurações."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
-    <!-- no translation found for pip_phone_expand (5889780005575693909) -->
-    <skip />
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Expandir"</string>
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index b24d199..c6dde46 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -71,8 +71,6 @@
     private static final int EXPAND_STACK_DURATION = 225;
     private static final int MINIMIZE_STACK_MAX_DURATION = 200;
 
-    // The fraction of the stack width to show when minimized
-    private static final float MINIMIZED_VISIBLE_FRACTION = 0.25f;
     // The fraction of the stack width that the user has to drag offscreen to minimize the PIP
     private static final float MINIMIZE_OFFSCREEN_FRACTION = 0.15f;
     // The fraction of the stack width that the user has to move when flinging to dismiss the PIP
@@ -396,6 +394,8 @@
      * Flings the minimized PIP to the closest minimized snap target.
      */
     private void flingToMinimizedSnapTarget(float velocityY) {
+        // We currently only allow flinging the minimized stack up and down, so just lock the
+        // movement bounds to the current stack bounds horizontally
         Rect movementBounds = new Rect(mPinnedStackBounds.left, mBoundedPinnedStackBounds.top,
                 mPinnedStackBounds.left, mBoundedPinnedStackBounds.bottom);
         Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mPinnedStackBounds,
@@ -414,16 +414,11 @@
      * Animates the PIP to the minimized state, slightly offscreen.
      */
     private void animateToClosestMinimizedTarget() {
-        Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(mBoundedPinnedStackBounds,
-                mPinnedStackBounds);
         Point displaySize = new Point();
         mContext.getDisplay().getRealSize(displaySize);
-        int visibleWidth = (int) (MINIMIZED_VISIBLE_FRACTION * mPinnedStackBounds.width());
-        if (mPinnedStackBounds.left < 0) {
-            toBounds.offsetTo(-toBounds.width() + visibleWidth, toBounds.top);
-        } else if (mPinnedStackBounds.right > displaySize.x) {
-            toBounds.offsetTo(displaySize.x - visibleWidth, toBounds.top);
-        }
+        Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(mBoundedPinnedStackBounds,
+                mPinnedStackBounds);
+        mSnapAlgorithm.applyMinimizedOffset(toBounds, mBoundedPinnedStackBounds, displaySize);
         mPinnedStackBoundsAnimator = mMotionHelper.createAnimationToBounds(mPinnedStackBounds,
                 toBounds, MINIMIZE_STACK_MAX_DURATION, LINEAR_OUT_SLOW_IN,
                 mUpdatePinnedStackBoundsListener);
@@ -635,7 +630,7 @@
                     setMinimizedState(false);
                 }
 
-                if (isDraggingOffscreen) {
+                if (touchState.allowDraggingOffscreen() && isDraggingOffscreen) {
                     // Move the pinned stack, but ignore the vertical movement
                     float left = mPinnedStackBounds.left + touchState.getLastTouchDelta().x;
                     mTmpBounds.set(mPinnedStackBounds);
@@ -685,7 +680,7 @@
                     setMinimizedState(false);
                 }
 
-                if (isDraggingOffscreen) {
+                if (touchState.allowDraggingOffscreen() && isDraggingOffscreen) {
                     // Move the pinned stack, but ignore the vertical movement
                     float left = mPinnedStackBounds.left + touchState.getLastTouchDelta().x;
                     mTmpBounds.set(mPinnedStackBounds);
@@ -769,6 +764,12 @@
     private PipTouchGesture mDefaultMovementGesture = new PipTouchGesture() {
         @Override
         boolean onMove(PipTouchState touchState) {
+            if (touchState.startedDragging()) {
+                // For now, once the user has started a drag that the other gestures have not
+                // intercepted, disallow those gestures from intercepting again to drag offscreen
+                touchState.setDisallowDraggingOffscreen();
+            }
+
             if (touchState.isDragging()) {
                 // Move the pinned stack freely
                 PointF lastDelta = touchState.getLastTouchDelta();
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java
index 80af5a6..17d9864 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java
@@ -40,6 +40,7 @@
     private final PointF mVelocity = new PointF();
     private boolean mIsDragging = false;
     private boolean mStartedDragging = false;
+    private boolean mAllowDraggingOffscreen = false;
     private int mActivePointerId;
 
     public PipTouchState(ViewConfiguration viewConfig) {
@@ -59,6 +60,7 @@
                 mDownTouch.set(mLastTouch);
                 mIsDragging = false;
                 mStartedDragging = false;
+                mAllowDraggingOffscreen = true;
                 break;
             }
             case MotionEvent.ACTION_MOVE: {
@@ -159,6 +161,20 @@
         return mStartedDragging;
     }
 
+    /**
+     * Disallows dragging offscreen for the duration of the current gesture.
+     */
+    public void setDisallowDraggingOffscreen() {
+        mAllowDraggingOffscreen = false;
+    }
+
+    /**
+     * @return whether dragging offscreen is allowed during this gesture.
+     */
+    public boolean allowDraggingOffscreen() {
+        return mAllowDraggingOffscreen;
+    }
+
     private void initOrResetVelocityTracker() {
         if (mVelocityTracker == null) {
             mVelocityTracker = VelocityTracker.obtain();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/grid/RecentsGridActivity.java b/packages/SystemUI/src/com/android/systemui/recents/grid/RecentsGridActivity.java
index 9ed4924..e1e654d5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/grid/RecentsGridActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/grid/RecentsGridActivity.java
@@ -27,6 +27,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
+import android.view.WindowManager;
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 import android.widget.TextView;
@@ -60,7 +61,6 @@
 import com.android.systemui.recents.views.TaskView;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 
 /**
@@ -95,6 +95,11 @@
         mTouchExplorationEnabled = ssp.isTouchExplorationEnabled();
 
         mRecentsView = (FrameLayout) findViewById(R.id.recents_view);
+        mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
+                View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
+                View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
+        getWindow().getAttributes().privateFlags |=
+                WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
         LinearLayout recentsContainer = (LinearLayout) findViewById(R.id.recents_container);
         mEmptyView = (TextView) mInflater.inflate(R.layout.recents_empty, recentsContainer, false);
         mClearAllButton = findViewById(R.id.button);
@@ -177,9 +182,7 @@
         loadOpts.numVisibleTaskThumbnails = numVisibleTasks;
         loader.loadTasks(this, plan, loadOpts);
 
-        List<Task> stackTasks = mTaskStack.getStackTasks();
-        Collections.reverse(stackTasks);
-        mTasks = stackTasks;
+        mTasks = mTaskStack.getStackTasks();
 
         updateControlVisibility();
 
@@ -255,7 +258,10 @@
         removeTaskViews();
         for (int i = 0; i < rects.size(); i++) {
             Rect rect = rects.get(i);
-            View taskView = mTaskViews.get(i);
+            // We keep the same ordering in the model as other Recents flavors (older tasks are
+            // first in the stack) so that the logic can be similar, but we reverse the order
+            // when placing views on the screen so that most recent tasks are displayed first.
+            View taskView = mTaskViews.get(rects.size() - 1 - i);
             taskView.setLayoutParams(new FrameLayout.LayoutParams(rect.width(), rect.height()));
             taskView.setTranslationX(rect.left);
             taskView.setTranslationY(rect.top);
@@ -302,6 +308,9 @@
             dismissRecentsToLaunchTargetTaskOrHome();
         } else if (event.triggeredFromHomeKey) {
             dismissRecentsToHome();
+        } else {
+            // Fall through tap on the background view but not on any of the tasks.
+            dismissRecentsToHome();
         }
     }
 
@@ -365,10 +374,7 @@
 
     public final void onBusEvent(LaunchNextTaskRequestEvent event) {
         if (mTaskStack.getTaskCount() > 0) {
-            // The task to launch is the second most recent, which is at index 1 given our ordering.
-            // If there is only one task, launch that one instead.
-            int launchTaskIndex = (mTaskStack.getStackTaskCount() > 1) ? 1 : 0;
-            Task launchTask = mTaskStack.getStackTasks().get(launchTaskIndex);
+            Task launchTask = mTaskStack.getNextLaunchTarget();
             TaskView launchTaskView = getChildViewForTask(launchTask);
             if (launchTaskView != null) {
                 EventBus.getDefault().send(new LaunchTaskEvent(launchTaskView,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index 745f5a5..178cb9f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -849,6 +849,24 @@
         return null;
     }
 
+    /**
+     * Returns the task in stack tasks which should be launched next if Recents are toggled
+     * again, or null if there is no task to be launched.
+     */
+    public Task getNextLaunchTarget() {
+        int taskCount = getTaskCount();
+        if (taskCount == 0) {
+            return null;
+        }
+        int launchTaskIndex = indexOfStackTask(getLaunchTarget());
+        if (launchTaskIndex != -1) {
+            launchTaskIndex = Math.max(0, launchTaskIndex - 1);
+        } else {
+            launchTaskIndex = getTaskCount() - 1;
+        }
+        return getStackTasks().get(launchTaskIndex);
+    }
+
     /** Returns the index of this task in this current task stack */
     public int indexOfStackTask(Task t) {
         return mStackTaskList.indexOf(t);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 77c61f8..8c94c35 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -1683,17 +1683,11 @@
             return;
         }
 
-        int launchTaskIndex = mStack.indexOfStackTask(mStack.getLaunchTarget());
-        if (launchTaskIndex != -1) {
-            launchTaskIndex = Math.max(0, launchTaskIndex - 1);
-        } else {
-            launchTaskIndex = mStack.getTaskCount() - 1;
-        }
-        if (launchTaskIndex != -1) {
+        final Task launchTask = mStack.getNextLaunchTarget();
+        if (launchTask != null) {
             // Stop all animations
             cancelAllTaskViewAnimations();
 
-            final Task launchTask = mStack.getStackTasks().get(launchTaskIndex);
             float curScroll = mStackScroller.getStackScroll();
             float targetScroll = mLayoutAlgorithm.getStackScrollForTaskAtInitialOffset(launchTask);
             float absScrollDiff = Math.abs(targetScroll - curScroll);
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 48bc27e..5cf74c7 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -2627,6 +2627,11 @@
     // ACTION: Logs the end to end time taken by all provisioning tasks.
     PROVISIONING_TOTAL_TASK_TIME_MS = 627;
 
+    // OPEN: Settings > Privacy
+    // CATEGORY: SETTINGS
+    // OS: O
+    ENTERPRISE_PRIVACY_SETTINGS = 628;
+
     // ---- End O Constants, all O constants go above this line ----
 
     // Add new aosp constants above this line.
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 9b3fac3..f7068cf 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -59,6 +59,7 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -118,7 +119,6 @@
     private static final int SERVICE_IBLUETOOTHGATT = 2;
 
     private final Context mContext;
-    private static int mBleAppCount = 0;
 
     // Locks are not provided for mName and mAddress.
     // They are accessed in handler or broadcast receiver, same thread context.
@@ -212,10 +212,7 @@
 
                     if (isAirplaneModeOn()) {
                         // Clear registered LE apps to force shut-off
-                        synchronized (this) {
-                            mBleAppCount = 0;
-                            mBleApps.clear();
-                        }
+                        clearBleApps();
                         if (st == BluetoothAdapter.STATE_BLE_ON) {
                             //if state is BLE_ON make sure you trigger disableBLE part
                             try {
@@ -460,28 +457,28 @@
     class ClientDeathRecipient implements IBinder.DeathRecipient {
         public void binderDied() {
             if (DBG) Slog.d(TAG, "Binder is dead - unregister Ble App");
-            if (mBleAppCount > 0) --mBleAppCount;
-
-            if (mBleAppCount == 0) {
-                if (DBG) Slog.d(TAG, "Disabling LE only mode after application crash");
-                try {
-                    mBluetoothLock.readLock().lock();
-                    if (mBluetooth != null &&
-                        mBluetooth.getState() == BluetoothAdapter.STATE_BLE_ON) {
-                        mEnable = false;
-                        mBluetooth.onBrEdrDown();
-                    }
-                } catch (RemoteException e) {
-                     Slog.e(TAG,"Unable to call onBrEdrDown", e);
-                } finally {
-                    mBluetoothLock.readLock().unlock();
+            if (isBleAppPresent()) {
+              // Nothing to do, another app is here.
+              return;
+            }
+            if (DBG) Slog.d(TAG, "Disabling LE only mode after application crash");
+            try {
+                mBluetoothLock.readLock().lock();
+                if (mBluetooth != null &&
+                    mBluetooth.getState() == BluetoothAdapter.STATE_BLE_ON) {
+                    mEnable = false;
+                    mBluetooth.onBrEdrDown();
                 }
+            } catch (RemoteException e) {
+                 Slog.e(TAG,"Unable to call onBrEdrDown", e);
+            } finally {
+                mBluetoothLock.readLock().unlock();
             }
         }
     }
 
     /** Internal death rec list */
-    Map<IBinder, ClientDeathRecipient> mBleApps = new HashMap<IBinder, ClientDeathRecipient>();
+    Map<IBinder, ClientDeathRecipient> mBleApps = new ConcurrentHashMap<IBinder, ClientDeathRecipient>();
 
     @Override
     public boolean isBleScanAlwaysAvailable() {
@@ -501,17 +498,20 @@
         ContentObserver contentObserver = new ContentObserver(null) {
             @Override
             public void onChange(boolean selfChange) {
-                if (!isBleScanAlwaysAvailable()) {
-                    disableBleScanMode();
-                    clearBleApps();
-                    try {
-                        mBluetoothLock.readLock().lock();
-                        if (mBluetooth != null) mBluetooth.onBrEdrDown();
-                    } catch (RemoteException e) {
-                        Slog.e(TAG, "error when disabling bluetooth", e);
-                    } finally {
-                        mBluetoothLock.readLock().unlock();
-                    }
+                if (isBleScanAlwaysAvailable()) {
+                  // Nothing to do
+                  return;
+                }
+                // BLE scan is not available.
+                disableBleScanMode();
+                clearBleApps();
+                try {
+                    mBluetoothLock.readLock().lock();
+                    if (mBluetooth != null) mBluetooth.onBrEdrDown();
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "error when disabling bluetooth", e);
+                } finally {
+                    mBluetoothLock.readLock().unlock();
                 }
             }
         };
@@ -547,9 +547,6 @@
                     throw new IllegalArgumentException("Wake lock is already dead.");
                 }
                 mBleApps.put(token, deathRec);
-                synchronized (this) {
-                    ++mBleAppCount;
-                }
                 if (DBG) Slog.d(TAG, "Registered for death Notification");
             }
 
@@ -559,31 +556,26 @@
                 // Unregister death recipient as the app goes away.
                 token.unlinkToDeath(r, 0);
                 mBleApps.remove(token);
-                synchronized (this) {
-                    if (mBleAppCount > 0) --mBleAppCount;
-                }
                 if (DBG) Slog.d(TAG, "Unregistered for death Notification");
             }
         }
-        if (DBG) Slog.d(TAG, "Updated BleAppCount" + mBleAppCount);
-        if (mBleAppCount == 0 && mEnable) {
+        int appCount = mBleApps.size();
+        if (DBG) Slog.d(TAG, appCount + " registered Ble Apps");
+        if (appCount == 0 && mEnable) {
             disableBleScanMode();
         }
-        return mBleAppCount;
+        return appCount;
     }
 
     // Clear all apps using BLE scan only mode.
     private void clearBleApps() {
-        synchronized (this) {
-            mBleApps.clear();
-            mBleAppCount = 0;
-        }
+        mBleApps.clear();
     }
 
     /** @hide*/
     public boolean isBleAppPresent() {
-        if (DBG) Slog.d(TAG, "isBleAppPresent() count: " + mBleAppCount);
-        return (mBleAppCount > 0);
+        if (DBG) Slog.d(TAG, "isBleAppPresent() count: " + mBleApps.size());
+        return mBleApps.size() > 0;
     }
 
     /**
@@ -1449,12 +1441,12 @@
                     if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_ON) &&
                             (newState == BluetoothAdapter.STATE_OFF) &&
                             (mBluetooth != null) && mEnable) {
-                        recoverBluetoothServiceFromError();
+                        recoverBluetoothServiceFromError(false);
                     }
                     if ((prevState == BluetoothAdapter.STATE_TURNING_ON) &&
                             (newState == BluetoothAdapter.STATE_BLE_ON) &&
                             (mBluetooth != null) && mEnable) {
-                        recoverBluetoothServiceFromError();
+                        recoverBluetoothServiceFromError(true);
                     }
                     // If we tried to enable BT while BT was in the process of shutting down,
                     // wait for the BT process to fully tear down and then force a restart
@@ -1870,7 +1862,7 @@
                              quietMode ? 1 : 0, 0));
     }
 
-    private void recoverBluetoothServiceFromError() {
+    private void recoverBluetoothServiceFromError(boolean clearBle) {
         Slog.e(TAG,"recoverBluetoothServiceFromError");
         try {
             mBluetoothLock.readLock().lock();
@@ -1908,6 +1900,10 @@
         mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
         mState = BluetoothAdapter.STATE_OFF;
 
+        if (clearBle) {
+          clearBleApps();
+        }
+
         mEnable = false;
 
         if (mErrorRecoveryRetryCounter++ < MAX_ERROR_RESTART_RETRIES) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 8bb0e1a..282ec50 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -2120,6 +2120,14 @@
             final int size = tasks.size();
             if (onTop) {
                 for (int i = 0; i < size; i++) {
+                    final TaskRecord task = tasks.get(i);
+                    if (fromStackId == PINNED_STACK_ID) {
+                        // Update the return-to to reflect where the pinned stack task was moved
+                        // from so that we retain the stack that was previously visible if the
+                        // pinned stack is recreated. See moveActivityToPinnedStackLocked().
+                        task.setTaskToReturnTo(getFocusedStack().getStackId() == HOME_STACK_ID
+                                ? HOME_ACTIVITY_TYPE : APPLICATION_ACTIVITY_TYPE);
+                    }
                     moveTaskToStackLocked(tasks.get(i).taskId,
                             FULLSCREEN_WORKSPACE_STACK_ID, onTop, onTop /*forceFocus*/,
                             "moveTasksToFullscreenStack", ANIMATE, DEFER_RESUME);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index c7f4d6b..90ede6f 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2722,7 +2722,7 @@
                     + " id=" + id + " notification=" + notification);
         }
         final NotificationChannel channel =  mRankingHelper.getNotificationChannelWithFallback(pkg,
-                callingUid, notification.getNotificationChannel());
+                callingUid, notification.getChannel());
         final StatusBarNotification n = new StatusBarNotification(
                 pkg, opPkg, channel, id, tag, callingUid, callingPid, notification,
                 user, null, System.currentTimeMillis());
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 965257c..5eacba6 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -283,7 +283,7 @@
         pw.println(prefix + "  mVisibleSinceMs=" + mVisibleSinceMs);
         pw.println(prefix + "  mUpdateTimeMs=" + mUpdateTimeMs);
         pw.println(prefix + "  mSuppressedVisualEffects= " + mSuppressedVisualEffects);
-        pw.println(prefix + "  notificationChannel= " + notification.getNotificationChannel());
+        pw.println(prefix + "  notificationChannel= " + notification.getChannel());
     }
 
 
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 869e207..49ffa22 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -649,15 +649,12 @@
 
             private void populateWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
                 final DisplayContent dc = mWindowManagerService.getDefaultDisplayContentLocked();
-                final ReadOnlyWindowList windowList = dc.getReadOnlyWindowList();
-                final int windowCount = windowList.size();
-                for (int i = 0; i < windowCount; i++) {
-                    final WindowState windowState = windowList.get(i);
-                    if (windowState.isOnScreen() && windowState.isVisibleLw() &&
-                            !windowState.mWinAnimator.mEnterAnimationPending) {
-                        outWindows.put(windowState.mLayer, windowState);
+                dc.forAllWindows((w) -> {
+                    if (w.isOnScreen() && w.isVisibleLw()
+                            && !w.mWinAnimator.mEnterAnimationPending) {
+                        outWindows.put(w.mLayer, w);
                     }
-                }
+                }, false /* traverseTopToBottom */ );
             }
 
             private final class ViewportWindow {
@@ -1296,14 +1293,11 @@
 
         private void populateVisibleWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
             final DisplayContent dc = mWindowManagerService.getDefaultDisplayContentLocked();
-            final ReadOnlyWindowList windowList = dc.getReadOnlyWindowList();
-            final int windowCount = windowList.size();
-            for (int i = 0; i < windowCount; i++) {
-                final WindowState windowState = windowList.get(i);
-                if (windowState.isVisibleLw()) {
-                    outWindows.put(windowState.mLayer, windowState);
+            dc.forAllWindows((w) -> {
+                if (w.isVisibleLw()) {
+                    outWindows.put(w.mLayer, w);
                 }
-            }
+            }, false /* traverseTopToBottom */ );
         }
 
         private class MyHandler extends Handler {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 6a625f4..ff39853 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1400,14 +1400,14 @@
 
     /** Updates the layer assignment of windows on this display. */
     void assignWindowLayers(boolean setLayoutNeeded) {
-        mLayersController.assignWindowLayers(mWindows.getReadOnly());
+        mLayersController.assignWindowLayers(this);
         if (setLayoutNeeded) {
             setLayoutNeeded();
         }
     }
 
     void adjustWallpaperWindows() {
-        if (mWallpaperController.adjustWallpaperWindows(mWindows.getReadOnly())) {
+        if (mWallpaperController.adjustWallpaperWindows(mWindows)) {
             assignWindowLayers(true /*setLayoutNeeded*/);
         }
     }
@@ -2457,14 +2457,6 @@
         }
     }
 
-    ReadOnlyWindowList getReadOnlyWindowList() {
-        return mWindows.getReadOnly();
-    }
-
-    void getWindows(WindowList output) {
-        output.addAll(mWindows);
-    }
-
     // TODO: Super crazy long method that should be broken down...
     boolean applySurfaceChangesTransaction(boolean recoveringMemory) {
 
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 6326148..c56f6b8 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -266,10 +266,8 @@
     }
 
     private void resetDragResizingChangeReported() {
-        final ReadOnlyWindowList windowList = mDisplayContent.getReadOnlyWindowList();
-        for (int i = windowList.size() - 1; i >= 0; i--) {
-            windowList.get(i).resetDragResizingChangeReported();
-        }
+        mDisplayContent.forAllWindows(WindowState::resetDragResizingChangeReported,
+                true /* traverseTopToBottom */ );
     }
 
     void setWindow(WindowState window) {
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index d52168c..4d195e8 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -271,11 +271,8 @@
             Slog.d(TAG_WM, "broadcasting DRAG_STARTED at (" + touchX + ", " + touchY + ")");
         }
 
-        final ReadOnlyWindowList windows = mDisplayContent.getReadOnlyWindowList();
-        final int N = windows.size();
-        for (int i = 0; i < N; i++) {
-            sendDragStartedLw(windows.get(i), touchX, touchY, mDataDescription);
-        }
+        mDisplayContent.forAllWindows((w) -> sendDragStartedLw(w, touchX, touchY, mDataDescription),
+                false /* traverseTopToBottom */ );
     }
 
     /* helper - send a ACTION_DRAG_STARTED event, if the
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index c711b39..01a50b7 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -256,6 +256,12 @@
                     false /* adjustForIme */);
             mSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds,
                     snapFraction);
+            if (mIsMinimized) {
+                final Point displaySize = new Point(mDisplayInfo.logicalWidth,
+                        mDisplayInfo.logicalHeight);
+                mSnapAlgorithm.applyMinimizedOffset(postChangeStackBounds, postChangeMovementBounds,
+                        displaySize);
+            }
         }
         return postChangeStackBounds;
     }
@@ -285,7 +291,12 @@
             final Rect toBounds = new Rect(stackBounds);
             if (adjustedForIme) {
                 // IME visible
-                toBounds.offset(0, Math.min(0, movementBounds.bottom - stackBounds.top));
+                if (stackBounds.top == prevMovementBounds.bottom) {
+                    // If the PIP is resting on top of the IME, then adjust it with the hiding IME
+                    toBounds.offsetTo(toBounds.left, movementBounds.bottom);
+                } else {
+                    toBounds.offset(0, Math.min(0, movementBounds.bottom - stackBounds.top));
+                }
             } else {
                 // IME hidden
                 if (stackBounds.top == prevMovementBounds.bottom) {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 299fa05..88986e3 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -219,28 +219,6 @@
         return false;
     }
 
-    void getWindows(WindowList output) {
-        final int count = mChildren.size();
-        for (int i = 0; i < count; ++i) {
-            final DisplayContent dc = mChildren.get(i);
-            dc.getWindows(output);
-        }
-    }
-
-    void getWindows(WindowList output, boolean visibleOnly, boolean appsOnly) {
-        final int numDisplays = mChildren.size();
-        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final ReadOnlyWindowList windowList = mChildren.get(displayNdx).getReadOnlyWindowList();
-            for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
-                final WindowState w = windowList.get(winNdx);
-                if ((!visibleOnly || w.mWinAnimator.getShown())
-                        && (!appsOnly || w.mAppToken != null)) {
-                    output.add(w);
-                }
-            }
-        }
-    }
-
     void getWindowsByName(WindowList output, String name) {
         int objectId = 0;
         // See if this is an object ID.
@@ -249,36 +227,20 @@
             name = null;
         } catch (RuntimeException e) {
         }
-        final int numDisplays = mChildren.size();
-        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final ReadOnlyWindowList windowList = mChildren.get(displayNdx).getReadOnlyWindowList();
-            for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
-                final WindowState w = windowList.get(winNdx);
-                if (name != null) {
-                    if (w.mAttrs.getTitle().toString().contains(name)) {
-                        output.add(w);
-                    }
-                } else if (System.identityHashCode(w) == objectId) {
-                    output.add(w);
-                }
-            }
-        }
+
+        getWindowsByName(output, name, objectId);
     }
 
-    WindowState findWindow(int hashCode) {
-        final int numDisplays = mChildren.size();
-        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final ReadOnlyWindowList windows = mChildren.get(displayNdx).getReadOnlyWindowList();
-            final int numWindows = windows.size();
-            for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
-                final WindowState w = windows.get(winNdx);
-                if (System.identityHashCode(w) == hashCode) {
-                    return w;
+    private void getWindowsByName(WindowList output, String name, int objectId) {
+        forAllWindows((w) -> {
+            if (name != null) {
+                if (w.mAttrs.getTitle().toString().contains(name)) {
+                    output.add(w);
                 }
+            } else if (System.identityHashCode(w) == objectId) {
+                output.add(w);
             }
-        }
-
-        return null;
+        }, true /* traverseTopToBottom */);
     }
 
     /**
@@ -399,81 +361,50 @@
     }
 
     void setSecureSurfaceState(int userId, boolean disabled) {
-        for (int i = mChildren.size() - 1; i >= 0; --i) {
-            final ReadOnlyWindowList windows = mChildren.get(i).getReadOnlyWindowList();
-            for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
-                final WindowState win = windows.get(winNdx);
-                if (win.mHasSurface && userId == UserHandle.getUserId(win.mOwnerUid)) {
-                    win.mWinAnimator.setSecureLocked(disabled);
-                }
+        forAllWindows((w) -> {
+            if (w.mHasSurface && userId == UserHandle.getUserId(w.mOwnerUid)) {
+                w.mWinAnimator.setSecureLocked(disabled);
             }
-        }
+        }, true /* traverseTopToBottom */);
     }
 
     void updateAppOpsState() {
-        final int count = mChildren.size();
-        for (int i = 0; i < count; ++i) {
-            final ReadOnlyWindowList windows = mChildren.get(i).getReadOnlyWindowList();
-            final int numWindows = windows.size();
-            for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
-                final WindowState win = windows.get(winNdx);
-                if (win.mAppOp == OP_NONE) {
-                    continue;
-                }
-                final int mode = mService.mAppOps.checkOpNoThrow(win.mAppOp, win.getOwningUid(),
-                        win.getOwningPackage());
-                win.setAppOpVisibilityLw(mode == MODE_ALLOWED || mode == MODE_DEFAULT);
+        forAllWindows((w) -> {
+            if (w.mAppOp == OP_NONE) {
+                return;
             }
-        }
+            final int mode = mService.mAppOps.checkOpNoThrow(w.mAppOp, w.getOwningUid(),
+                    w.getOwningPackage());
+            w.setAppOpVisibilityLw(mode == MODE_ALLOWED || mode == MODE_DEFAULT);
+        }, false /* traverseTopToBottom */);
     }
 
     boolean canShowStrictModeViolation(int pid) {
-        final int count = mChildren.size();
-        for (int i = 0; i < count; ++i) {
-            final ReadOnlyWindowList windows = mChildren.get(i).getReadOnlyWindowList();
-            final int numWindows = windows.size();
-            for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
-                final WindowState ws = windows.get(winNdx);
-                if (ws.mSession.mPid == pid && ws.isVisibleLw()) {
-                    return true;
-                }
-            }
-        }
-        return false;
+        final WindowState win = getWindow((w) -> w.mSession.mPid == pid && w.isVisibleLw());
+        return win != null;
     }
 
     void closeSystemDialogs(String reason) {
-        final int count = mChildren.size();
-        for (int i = 0; i < count; ++i) {
-            final ReadOnlyWindowList windows = mChildren.get(i).getReadOnlyWindowList();
-            final int numWindows = windows.size();
-            for (int j = 0; j < numWindows; ++j) {
-                final WindowState w = windows.get(j);
-                if (w.mHasSurface) {
-                    try {
-                        w.mClient.closeSystemDialogs(reason);
-                    } catch (RemoteException e) {
-                    }
+        forAllWindows((w) -> {
+            if (w.mHasSurface) {
+                try {
+                    w.mClient.closeSystemDialogs(reason);
+                } catch (RemoteException e) {
                 }
             }
-        }
+        }, false /* traverseTopToBottom */);
     }
 
     void removeReplacedWindows() {
         if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION removeReplacedWindows");
         mService.openSurfaceTransaction();
         try {
-            for (int i = mChildren.size() - 1; i >= 0; i--) {
-                DisplayContent dc = mChildren.get(i);
-                final ReadOnlyWindowList windows = mChildren.get(i).getReadOnlyWindowList();
-                for (int j = windows.size() - 1; j >= 0; j--) {
-                    final WindowState win = windows.get(j);
-                    final AppWindowToken aToken = win.mAppToken;
-                    if (aToken != null) {
-                        aToken.removeReplacedWindowIfNeeded(win);
-                    }
+            forAllWindows((w) -> {
+                final AppWindowToken aToken = w.mAppToken;
+                if (aToken != null) {
+                    aToken.removeReplacedWindowIfNeeded(w);
                 }
-            }
+            }, true /* traverseTopToBottom */);
         } finally {
             mService.closeSurfaceTransaction();
             if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION removeReplacedWindows");
@@ -530,19 +461,15 @@
                 Slog.w(TAG_WM, "No leaked surfaces; killing applications!");
                 final SparseIntArray pidCandidates = new SparseIntArray();
                 for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-                    final ReadOnlyWindowList windows =
-                            mChildren.get(displayNdx).getReadOnlyWindowList();
-                    final int numWindows = windows.size();
-                    for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
-                        final WindowState ws = windows.get(winNdx);
-                        if (mService.mForceRemoves.contains(ws)) {
-                            continue;
+                    mChildren.get(displayNdx).forAllWindows((w) -> {
+                        if (mService.mForceRemoves.contains(w)) {
+                            return;
                         }
-                        final WindowStateAnimator wsa = ws.mWinAnimator;
+                        final WindowStateAnimator wsa = w.mWinAnimator;
                         if (wsa.mSurfaceController != null) {
                             pidCandidates.append(wsa.mSession.mPid, wsa.mSession.mPid);
                         }
-                    }
+                    }, false /* traverseTopToBottom */);
 
                     if (pidCandidates.size() > 0) {
                         int[] pids = new int[pidCandidates.size()];
@@ -1078,17 +1005,14 @@
     }
 
     void dumpWindowsNoHeader(PrintWriter pw, boolean dumpAll, ArrayList<WindowState> windows) {
-        final int numDisplays = mChildren.size();
-        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final ReadOnlyWindowList windowList = mChildren.get(displayNdx).getReadOnlyWindowList();
-            for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
-                final WindowState w = windowList.get(winNdx);
-                if (windows == null || windows.contains(w)) {
-                    pw.println("  Window #" + winNdx + " " + w + ":");
-                    w.dump(pw, "    ", dumpAll || windows != null);
-                }
+        final int[] index = new int[1];
+        forAllWindows((w) -> {
+            if (windows == null || windows.contains(w)) {
+                pw.println("  Window #" + index[0] + " " + w + ":");
+                w.dump(pw, "    ", dumpAll || windows != null);
+                index[0] = index[0] + 1;
             }
-        }
+        }, true /* traverseTopToBottom */);
     }
 
     void dumpTokens(PrintWriter pw, boolean dumpAll) {
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 178fbe7..d3e8e8e 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -388,7 +388,7 @@
         return mWallpaperAnimLayerAdjustment;
     }
 
-    private void findWallpaperTarget(ReadOnlyWindowList windows, FindWallpaperTargetResult result) {
+    private void findWallpaperTarget(WindowList windows, FindWallpaperTargetResult result) {
         final WindowAnimator winAnimator = mService.mAnimator;
         result.reset();
         WindowState w = null;
@@ -489,7 +489,7 @@
 
     /** Updates the target wallpaper if needed and returns true if an update happened. */
     private boolean updateWallpaperWindowsTarget(
-            ReadOnlyWindowList windows, FindWallpaperTargetResult result) {
+            WindowList windows, FindWallpaperTargetResult result) {
 
         WindowState wallpaperTarget = result.wallpaperTarget;
         int wallpaperTargetIndex = result.wallpaperTargetIndex;
@@ -590,7 +590,7 @@
         return true;
     }
 
-    private boolean updateWallpaperWindowsTargetByLayer(ReadOnlyWindowList windows,
+    private boolean updateWallpaperWindowsTargetByLayer(WindowList windows,
             FindWallpaperTargetResult result) {
 
         WindowState wallpaperTarget = result.wallpaperTarget;
@@ -641,7 +641,7 @@
         return visible;
     }
 
-    private boolean updateWallpaperWindowsPlacement(ReadOnlyWindowList windows,
+    private boolean updateWallpaperWindowsPlacement(WindowList windows,
             WindowState wallpaperTarget, int wallpaperTargetIndex, boolean visible) {
 
         // TODO(multidisplay): Wallpapers on main screen only.
@@ -660,7 +660,7 @@
         return changed;
     }
 
-    boolean adjustWallpaperWindows(ReadOnlyWindowList windows) {
+    boolean adjustWallpaperWindows(WindowList windows) {
         mService.mRoot.mWallpaperMayChange = false;
 
         // First find top-most window that has asked to be on top of the wallpaper;
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index fdefcfe..3a76cd4 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -119,7 +119,7 @@
         }
     }
 
-    boolean updateWallpaperWindowsPlacement(ReadOnlyWindowList windowList,
+    boolean updateWallpaperWindowsPlacement(WindowList windowList,
             WindowState wallpaperTarget, int wallpaperTargetIndex, boolean visible, int dw, int dh,
             int wallpaperAnimLayerAdj) {
 
@@ -193,7 +193,7 @@
      * @return The index in {@param windows} of the lowest window that is currently on screen and
      *         not hidden by the policy.
      */
-    private int findLowestWindowOnScreen(ReadOnlyWindowList windowList) {
+    private int findLowestWindowOnScreen(WindowList windowList) {
         final int size = windowList.size();
         for (int index = 0; index < size; index++) {
             final WindowState win = windowList.get(index);
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 62ad217..150160c 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -23,6 +23,7 @@
 import java.util.Comparator;
 import java.util.LinkedList;
 import java.util.function.Consumer;
+import java.util.function.Predicate;
 
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
@@ -508,6 +509,17 @@
         }
     }
 
+    WindowState getWindow(Predicate<WindowState> callback) {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowState w = mChildren.get(i).getWindow(callback);
+            if (w != null) {
+                return w;
+            }
+        }
+
+        return null;
+    }
+
     /**
      * Returns 1, 0, or -1 depending on if this container is greater than, equal to, or lesser than
      * the input container in terms of z-order.
diff --git a/services/core/java/com/android/server/wm/WindowLayersController.java b/services/core/java/com/android/server/wm/WindowLayersController.java
index d94094a..c06e5cc 100644
--- a/services/core/java/com/android/server/wm/WindowLayersController.java
+++ b/services/core/java/com/android/server/wm/WindowLayersController.java
@@ -60,33 +60,32 @@
     private ArrayDeque<WindowState> mOnTopLauncherWindows = new ArrayDeque<>();
     private WindowState mDockDivider = null;
     private ArrayDeque<WindowState> mReplacingWindows = new ArrayDeque<>();
+    private int mCurBaseLayer;
+    private int mCurLayer;
+    private boolean mAnyLayerChanged;
 
-    final void assignWindowLayers(ReadOnlyWindowList windows) {
-        if (DEBUG_LAYERS) Slog.v(TAG_WM, "Assigning layers based on windows=" + windows,
+    final void assignWindowLayers(DisplayContent dc) {
+        if (DEBUG_LAYERS) Slog.v(TAG_WM, "Assigning layers based",
                 new RuntimeException("here").fillInStackTrace());
 
         clear();
-        int curBaseLayer = 0;
-        int curLayer = 0;
-        boolean anyLayerChanged = false;
-        for (int i = 0, windowCount = windows.size(); i < windowCount; i++) {
-            final WindowState w = windows.get(i);
+        dc.forAllWindows((w) -> {
             boolean layerChanged = false;
 
             int oldLayer = w.mLayer;
-            if (w.mBaseLayer == curBaseLayer || w.mIsImWindow || (i > 0 && w.mIsWallpaper)) {
-                curLayer += WINDOW_LAYER_MULTIPLIER;
+            if (w.mBaseLayer == mCurBaseLayer || w.mIsImWindow) {
+                mCurLayer += WINDOW_LAYER_MULTIPLIER;
             } else {
-                curBaseLayer = curLayer = w.mBaseLayer;
+                mCurBaseLayer = mCurLayer = w.mBaseLayer;
             }
-            assignAnimLayer(w, curLayer);
+            assignAnimLayer(w, mCurLayer);
 
-            // TODO: Preserved old behavior of code here but not sure comparing
-            // oldLayer to mAnimLayer and mLayer makes sense...though the
-            // worst case would be unintentional layer reassignment.
+            // TODO: Preserved old behavior of code here but not sure comparing oldLayer to
+            // mAnimLayer and mLayer makes sense...though the worst case would be unintentional
+            // layer reassignment.
             if (w.mLayer != oldLayer || w.mWinAnimator.mAnimLayer != oldLayer) {
                 layerChanged = true;
-                anyLayerChanged = true;
+                mAnyLayerChanged = true;
             }
 
             if (w.mAppToken != null) {
@@ -98,28 +97,27 @@
             if (layerChanged) {
                 w.scheduleAnimationIfDimming();
             }
-        }
+        }, false /* traverseTopToBottom */);
 
         adjustSpecialWindows();
 
         //TODO (multidisplay): Magnification is supported only for the default display.
-        if (mService.mAccessibilityController != null && anyLayerChanged
-                && windows.get(windows.size() - 1).getDisplayId() == Display.DEFAULT_DISPLAY) {
+        if (mService.mAccessibilityController != null && mAnyLayerChanged
+                && dc.getDisplayId() == Display.DEFAULT_DISPLAY) {
             mService.mAccessibilityController.onWindowLayersChangedLocked();
         }
 
-        if (DEBUG_LAYERS) logDebugLayers(windows);
+        if (DEBUG_LAYERS) logDebugLayers(dc);
     }
 
-    private void logDebugLayers(ReadOnlyWindowList windows) {
-        for (int i = 0, n = windows.size(); i < n; i++) {
-            final WindowState w = windows.get(i);
+    private void logDebugLayers(DisplayContent dc) {
+        dc.forAllWindows((w) -> {
             final WindowStateAnimator winAnimator = w.mWinAnimator;
             Slog.v(TAG_WM, "Assign layer " + w + ": " + "mBase=" + w.mBaseLayer
                     + " mLayer=" + w.mLayer + (w.mAppToken == null
                     ? "" : " mAppLayer=" + w.mAppToken.mAppAnimator.animLayerAdjustment)
                     + " =mAnimLayer=" + winAnimator.mAnimLayer);
-        }
+        }, false /* traverseTopToBottom */);
     }
 
     private void clear() {
@@ -130,6 +128,10 @@
         mOnTopLauncherWindows.clear();
         mReplacingWindows.clear();
         mDockDivider = null;
+
+        mCurBaseLayer = 0;
+        mCurLayer = 0;
+        mAnyLayerChanged = false;
     }
 
     private void collectSpecialWindows(WindowState w) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 5c9dc10..c4c4bcd 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -4787,37 +4787,42 @@
             return false;
         }
 
-        final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
-        final ReadOnlyWindowList windows = displayContent.getReadOnlyWindowList();
+        final DisplayContent dc = mRoot.getDisplayContent(displayId);
 
         final int oldRotation = mRotation;
         int rotation = mPolicy.rotationForOrientationLw(mLastOrientation, mRotation);
-        boolean rotateSeamlessly = mPolicy.shouldRotateSeamlessly(oldRotation, rotation);
+        final boolean rotateSeamlessly;
 
-        if (rotateSeamlessly) {
-            for (int i = windows.size() - 1; i >= 0; i--) {
-                WindowState w = windows.get(i);
+        if (mPolicy.shouldRotateSeamlessly(oldRotation, rotation)) {
+            final WindowState seamlessRotated = dc.getWindow((w) -> w.mSeamlesslyRotated);
+            if (seamlessRotated != null) {
                 // We can't rotate (seamlessly or not) while waiting for the last seamless rotation
                 // to complete (that is, waiting for windows to redraw). It's tempting to check
-                // w.mSeamlessRotationCount but that could be incorrect in the case of window-removal.
-                if (w.mSeamlesslyRotated) {
-                    return false;
-                }
-                // In what can only be called an unfortunate workaround we require
-                // seamlessly rotated child windows to have the TRANSFORM_TO_DISPLAY_INVERSE
-                // flag. Due to limitations in the client API, there is no way for
-                // the client to set this flag in a race free fashion. If we seamlessly rotate
-                // a window which does not have this flag, but then gains it, we will get
-                // an incorrect visual result (rotated viewfinder). This means if we want to
-                // support seamlessly rotating windows which could gain this flag, we can't
-                // rotate windows without it. This limits seamless rotation in N to camera framework
-                // users, windows without children, and native code. This is unfortunate but
-                // having the camera work is our primary goal.
-                if (w.isChildWindow() & w.isVisibleNow() &&
-                        !w.mWinAnimator.mSurfaceController.getTransformToDisplayInverse()) {
-                    rotateSeamlessly = false;
-                }
+                // w.mSeamlessRotationCount but that could be incorrect in the case of
+                // window-removal.
+                return false;
             }
+
+            final WindowState cantSeamlesslyRotate = dc.getWindow((w) ->
+                    w.isChildWindow() && w.isVisibleNow()
+                            && !w.mWinAnimator.mSurfaceController.getTransformToDisplayInverse());
+            if (cantSeamlesslyRotate != null) {
+                // In what can only be called an unfortunate workaround we require seamlessly
+                // rotated child windows to have the TRANSFORM_TO_DISPLAY_INVERSE flag. Due to
+                // limitations in the client API, there is no way for the client to set this flag in
+                // a race free fashion. If we seamlessly rotate a window which does not have this
+                // flag, but then gains it, we will get an incorrect visual result
+                // (rotated viewfinder). This means if we want to support seamlessly rotating
+                // windows which could gain this flag, we can't rotate windows without it. This
+                // limits seamless rotation in N to camera framework users, windows without
+                // children, and native code. This is unfortunate but having the camera work is our
+                // primary goal.
+                rotateSeamlessly = false;
+            } else {
+                rotateSeamlessly = true;
+            }
+        } else {
+            rotateSeamlessly = false;
         }
 
         // TODO: Implement forced rotation changes.
@@ -4849,9 +4854,9 @@
         mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
         mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, WINDOW_FREEZE_TIMEOUT_DURATION);
         mWaitingForConfig = true;
-        displayContent.setLayoutNeeded();
+        dc.setLayoutNeeded();
         final int[] anim = new int[2];
-        if (displayContent.isDimming()) {
+        if (dc.isDimming()) {
             anim[0] = anim[1] = 0;
         } else {
             mPolicy.selectRotationAnimationLw(anim);
@@ -4860,8 +4865,7 @@
         if (!rotateSeamlessly) {
             startFreezingDisplayLocked(inTransaction, anim[0], anim[1]);
             // startFreezingDisplayLocked can reset the ScreenRotationAnimation.
-            screenRotationAnimation =
-                mAnimator.getScreenRotationAnimationLocked(displayId);
+            screenRotationAnimation = mAnimator.getScreenRotationAnimationLocked(displayId);
         } else {
             // The screen rotation animation uses a screenshot to freeze the screen
             // while windows resize underneath.
@@ -4879,9 +4883,9 @@
         // the top of the method, the caller is obligated to call computeNewConfigurationLocked().
         // By updating the Display info here it will be available to
         // computeScreenConfigurationLocked later.
-        updateDisplayAndOrientationLocked(displayContent.getConfiguration().uiMode, displayId);
+        updateDisplayAndOrientationLocked(dc.getConfiguration().uiMode, displayId);
 
-        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
+        final DisplayInfo displayInfo = dc.getDisplayInfo();
         if (!inTransaction) {
             if (SHOW_TRANSACTIONS) {
                 Slog.i(TAG_WM, ">>> OPEN TRANSACTION setRotationUnchecked");
@@ -4902,10 +4906,9 @@
             }
 
             if (rotateSeamlessly) {
-                for (int i = windows.size() - 1; i >= 0; i--) {
-                    WindowState w = windows.get(i);
-                    w.mWinAnimator.seamlesslyRotateWindow(oldRotation, mRotation);
-                }
+                dc.forAllWindows((w) ->
+                        w.mWinAnimator.seamlesslyRotateWindow(oldRotation, mRotation),
+                        true /* traverseTopToBottom */);
             }
 
             mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
@@ -4918,8 +4921,7 @@
             }
         }
 
-        for (int i = windows.size() - 1; i >= 0; i--) {
-            WindowState w = windows.get(i);
+        dc.forAllWindows((w) -> {
             // Discard surface after orientation change, these can't be reused.
             if (w.mAppToken != null) {
                 w.mAppToken.destroySavedSurfaces();
@@ -4930,7 +4932,8 @@
                 mRoot.mOrientationChangeComplete = false;
                 w.mLastFreezeDuration = 0;
             }
-        }
+
+        }, true /* traverseTopToBottom */);
 
         if (rotateSeamlessly) {
             mH.removeMessages(H.SEAMLESS_ROTATION_TIMEOUT);
@@ -4948,7 +4951,7 @@
         // Announce rotation only if we will not animate as we already have the
         // windows in final state. Otherwise, we make this call at the rotation end.
         if (screenRotationAnimation == null && mAccessibilityController != null
-                && displayContent.getDisplayId() == DEFAULT_DISPLAY) {
+                && dc.getDisplayId() == DEFAULT_DISPLAY) {
             mAccessibilityController.onRotationChangedLocked(getDefaultDisplayContentLocked(),
                     rotation);
         }
@@ -5181,7 +5184,7 @@
 
         final WindowList windows = new WindowList();
         synchronized (mWindowMap) {
-            mRoot.getWindows(windows);
+            mRoot.forAllWindows(windows::add, false /* traverseTopToBottom */);
         }
 
         BufferedWriter out = null;
@@ -5408,7 +5411,7 @@
         }
 
         synchronized (mWindowMap) {
-            return mRoot.findWindow(hashCode);
+            return mRoot.getWindow((w) -> System.identityHashCode(w) == hashCode);
         }
     }
 
@@ -8091,7 +8094,12 @@
                     mRoot.dumpDisplayContents(pw);
                 }
 
-                mRoot.getWindows(windows, visibleOnly, appsOnly);
+                mRoot.forAllWindows((w) -> {
+                    if ((!visibleOnly || w.mWinAnimator.getShown())
+                            && (!appsOnly || w.mAppToken != null)) {
+                        windows.add(w);
+                    }
+                }, true /* traverseTopToBottom */);
             }
         } else {
             synchronized(mWindowMap) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 1a56518..5e65aec 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -60,6 +60,7 @@
 import java.util.Comparator;
 import java.util.LinkedList;
 import java.util.function.Consumer;
+import java.util.function.Predicate;
 
 import static android.app.ActivityManager.StackId;
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
@@ -138,52 +139,6 @@
 import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
 
 class WindowList extends ArrayList<WindowState> {
-
-    /**
-     * Read-only interface for the window list that the creator of the window list can pass-out to
-     * other users to prevent them from modifying the window list.
-     */
-    private ReadOnlyWindowList mReadOnly;
-
-    WindowList() {
-        mReadOnly = new ReadOnlyWindowList(this);
-    }
-
-    /** Returns the read-only interface for this window list. */
-    ReadOnlyWindowList getReadOnly() {
-        return mReadOnly;
-    }
-}
-
-/**
- * Read-only interface for a list of windows. It is common for the owner of a list of windows to
- * want to provide a way for external classes to iterate of its windows, but prevent them from
- * modifying the list in any way. This call provides a way for them to do that by wrapping the
- * original window list and only exposing the read-only APIs.
- */
-final class ReadOnlyWindowList {
-    // List of windows this read-only class is tied to.
-    private final WindowList mWindows;
-
-    ReadOnlyWindowList(WindowList windows) {
-        mWindows = windows;
-    }
-
-    WindowState get(int index) {
-        return mWindows.get(index);
-    }
-
-    int indexOf(WindowState w) {
-        return mWindows.indexOf(w);
-    }
-
-    int size() {
-        return mWindows.size();
-    }
-
-    boolean isEmpty() {
-        return mWindows.isEmpty();
-    }
 }
 
 /** A window in the window manager. */
@@ -3949,6 +3904,13 @@
         }
     }
 
+    WindowState getWindow(Predicate<WindowState> callback) {
+        if (callback.test(this)) {
+            return this;
+        }
+        return super.getWindow(callback);
+    }
+
     boolean isWindowAnimationSet() {
         if (mWinAnimator.isWindowAnimationSet()) {
             return true;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 7f8b9b8..7e68447 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -42,6 +42,8 @@
 import android.app.AlarmManager;
 import android.app.AppGlobals;
 import android.app.IActivityManager;
+import android.app.IApplicationThread;
+import android.app.IServiceConnection;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -137,6 +139,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.JournaledFile;
 import com.android.internal.util.ParcelableString;
@@ -490,9 +493,12 @@
              * to listen for events.
              */
             if (Intent.ACTION_USER_STARTED.equals(action)
-                    && userHandle == mOwners.getDeviceOwnerUserId()
-                    && isNetworkLoggingEnabledInternal()) {
-                setNetworkLoggingActiveInternal(true);
+                    && userHandle == mOwners.getDeviceOwnerUserId()) {
+                synchronized (DevicePolicyManagerService.this) {
+                    if (isNetworkLoggingEnabledInternalLocked()) {
+                        setNetworkLoggingActiveInternal(true);
+                    }
+                }
             }
             if (Intent.ACTION_BOOT_COMPLETED.equals(action)
                     && userHandle == mOwners.getDeviceOwnerUserId()
@@ -1436,6 +1442,10 @@
                 ServiceManager.getService(IpConnectivityLog.SERVICE_NAME));
         }
 
+        PackageManager getPackageManager() {
+            return mContext.getPackageManager();
+        }
+
         PowerManagerInternal getPowerManagerInternal() {
             return LocalServices.getService(PowerManagerInternal.class);
         }
@@ -5904,6 +5914,10 @@
         }
     }
 
+    boolean isDeviceOwner(ActiveAdmin admin) {
+        return isDeviceOwner(admin.info.getComponent(), admin.getUserHandle().getIdentifier());
+    }
+
     public boolean isDeviceOwner(ComponentName who, int userId) {
         synchronized (this) {
             return mOwners.hasDeviceOwner()
@@ -9425,6 +9439,77 @@
         }
     }
 
+    @Override
+    public boolean bindDeviceAdminServiceAsUser(
+            @NonNull ComponentName admin, @NonNull IApplicationThread caller,
+            @Nullable IBinder activtiyToken, @NonNull Intent serviceIntent,
+            @NonNull IServiceConnection connection, int flags, @UserIdInt int targetUserId) {
+        if (!mHasFeature) {
+            return false;
+        }
+        Preconditions.checkNotNull(admin);
+        Preconditions.checkNotNull(caller);
+        Preconditions.checkNotNull(serviceIntent);
+        Preconditions.checkNotNull(connection);
+        final int callingUserId = mInjector.userHandleGetCallingUserId();
+        Preconditions.checkArgument(callingUserId != targetUserId,
+                "target user id must be different from the calling user id");
+
+        synchronized (this) {
+            final ActiveAdmin callingAdmin = getActiveAdminForCallerLocked(admin,
+                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+            // Ensure the target user is valid.
+            if (isDeviceOwner(callingAdmin)) {
+                enforceManagedProfile(targetUserId, "Target user must be a managed profile");
+            } else {
+                // Further lock down to profile owner in managed profile.
+                enforceManagedProfile(callingUserId,
+                        "Only support profile owner in managed profile.");
+                if (mOwners.getDeviceOwnerUserId() != targetUserId) {
+                    throw new SecurityException("Target user must be a device owner.");
+                }
+            }
+        }
+        final long callingIdentity = mInjector.binderClearCallingIdentity();
+        try {
+            if (!mUserManager.isSameProfileGroup(callingUserId, targetUserId)) {
+                throw new SecurityException(
+                        "Can only bind service across users under the same profile group");
+            }
+            final String targetPackage;
+            synchronized (this) {
+                targetPackage = getOwnerPackageNameForUserLocked(targetUserId);
+            }
+            // STOPSHIP(b/31952368): Add policy to control which packages can talk.
+            if (TextUtils.isEmpty(targetPackage) || !targetPackage.equals(admin.getPackageName())) {
+                throw new SecurityException("Device owner and profile owner must be the same " +
+                        "package in order to communicate.");
+            }
+            // Validate and sanitize the incoming service intent.
+            final Intent sanitizedIntent =
+                    createCrossUserServiceIntent(serviceIntent, targetPackage);
+            if (sanitizedIntent == null) {
+                // Fail, cannot lookup the target service.
+                throw new SecurityException("Invalid intent or failed to look up the service");
+            }
+            // Ask ActivityManager to bind it. Notice that we are binding the service with the
+            // caller app instead of DevicePolicyManagerService.
+            try {
+                return mInjector.getIActivityManager().bindService(
+                        caller, activtiyToken, serviceIntent,
+                        serviceIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
+                        connection, flags, mContext.getOpPackageName(),
+                        targetUserId) != 0;
+            } catch (RemoteException ex) {
+                // Same process, should not happen.
+            }
+        } finally {
+            mInjector.binderRestoreCallingIdentity(callingIdentity);
+        }
+        // Fail to bind.
+        return false;
+    }
+
     /**
      * Return true if a given user has any accounts that'll prevent installing a device or profile
      * owner {@code owner}.
@@ -9515,7 +9600,7 @@
         Preconditions.checkNotNull(admin);
         ensureDeviceOwnerManagingSingleUser(admin);
 
-        if (enabled == isNetworkLoggingEnabledInternal()) {
+        if (enabled == isNetworkLoggingEnabledInternalLocked()) {
             // already in the requested state
             return;
         }
@@ -9556,11 +9641,11 @@
         Preconditions.checkNotNull(admin);
         synchronized (this) {
             getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
-            return isNetworkLoggingEnabledInternal();
+            return isNetworkLoggingEnabledInternalLocked();
         }
     }
 
-    private synchronized boolean isNetworkLoggingEnabledInternal() {
+    private boolean isNetworkLoggingEnabledInternalLocked() {
         ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
         return (deviceOwner != null) && deviceOwner.isNetworkLoggingEnabled;
     }
@@ -9569,9 +9654,12 @@
      * A maximum of 1200 events are returned, and the total marshalled size is in the order of
      * 100kB, so returning a List instead of ParceledListSlice is acceptable.
      * Ideally this would be done with ParceledList, however it only supports homogeneous types.
+     *
+     * @see NetworkLoggingHandler#MAX_EVENTS_PER_BATCH
      */
     @Override
-    public synchronized List<NetworkEvent> retrieveNetworkLogs(ComponentName admin) {
+    public synchronized List<NetworkEvent> retrieveNetworkLogs(ComponentName admin,
+            long batchToken) {
         if (!mHasFeature) {
             return null;
         }
@@ -9581,6 +9669,50 @@
         if (mNetworkLogger == null) {
             return null;
         }
-        return isNetworkLoggingEnabledInternal() ? mNetworkLogger.retrieveLogs() : null;
+        return isNetworkLoggingEnabledInternalLocked()
+                ? mNetworkLogger.retrieveLogs(batchToken)
+                : null;
+    }
+
+    /**
+     * Return the package name of owner in a given user.
+     */
+    private String getOwnerPackageNameForUserLocked(int userId) {
+        return getDeviceOwnerUserId() == userId
+                ? mOwners.getDeviceOwnerPackageName()
+                : mOwners.getProfileOwnerPackage(userId);
+    }
+
+    /**
+     * @param rawIntent Original service intent specified by caller.
+     * @param expectedPackageName The expected package name in the incoming intent.
+     * @return Intent that have component explicitly set. {@code null} if the incoming intent
+     *         or target service is invalid.
+     */
+    private Intent createCrossUserServiceIntent (
+            @NonNull Intent rawIntent, @NonNull String expectedPackageName) {
+        if (rawIntent.getComponent() == null && rawIntent.getPackage() == null) {
+            Log.e(LOG_TAG, "Service intent must be explicit (with a package name or component): "
+                    + rawIntent);
+            return null;
+        }
+        ResolveInfo info = mInjector.getPackageManager().resolveService(rawIntent, 0);
+        if (info == null || info.serviceInfo == null) {
+            Log.e(LOG_TAG, "Fail to look up the service: " + rawIntent);
+            return null;
+        }
+        if (!expectedPackageName.equals(info.serviceInfo.packageName)) {
+            Log.e(LOG_TAG, "Only allow to bind service in " + expectedPackageName);
+            return null;
+        }
+        if (info.serviceInfo.exported) {
+            Log.e(LOG_TAG, "The service must be unexported.");
+            return null;
+        }
+        // It is the system server to bind the service, it would be extremely dangerous if it
+        // can be exploited to bind any service. Set the component explicitly to make sure we
+        // do not bind anything accidentally.
+        rawIntent.setComponent(info.serviceInfo.getComponentName());
+        return rawIntent;
     }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java
index 185ccc2..8cb13da 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java
@@ -147,7 +147,7 @@
         }
     }
 
-    List<NetworkEvent> retrieveLogs() {
-        return mNetworkLoggingHandler.retrieveFullLogBatch();
+    List<NetworkEvent> retrieveLogs(long batchToken) {
+        return mNetworkLoggingHandler.retrieveFullLogBatch(batchToken);
     }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java
index 96884e6..29cc43f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java
@@ -55,11 +55,16 @@
     private final DevicePolicyManagerService mDpm;
 
     // threadsafe as it's Handler's thread confined
+    @GuardedBy("this")
     private ArrayList<NetworkEvent> mNetworkEvents = new ArrayList<NetworkEvent>();
 
     @GuardedBy("this")
     private ArrayList<NetworkEvent> mFullBatch;
 
+    // each full batch is represented by its token, which the DPC has to provide back to revieve it
+    @GuardedBy("this")
+    private long mCurrentFullBatchToken;
+
     NetworkLoggingHandler(Looper looper, DevicePolicyManagerService dpm) {
         super(looper);
         mDpm = dpm;
@@ -97,17 +102,21 @@
         scheduleBatchFinalization(BATCH_FINALIZATION_TIMEOUT_MS);
         // notify DO that there's a new non-empty batch waiting
         if (mFullBatch.size() > 0) {
-            mDpm.sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_NETWORK_LOGS_AVAILABLE,
-                    /* extras */ null);
+            mCurrentFullBatchToken++;
+            Bundle extras = new Bundle();
+            extras.putLong(DeviceAdminReceiver.EXTRA_NETWORK_LOGS_TOKEN, mCurrentFullBatchToken);
+            extras.putInt(DeviceAdminReceiver.EXTRA_NETWORK_LOGS_COUNT, mFullBatch.size());
+            mDpm.sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_NETWORK_LOGS_AVAILABLE, extras);
         } else {
             mFullBatch = null;
         }
     }
 
-    synchronized List<NetworkEvent> retrieveFullLogBatch() {
-        List<NetworkEvent> ret = mFullBatch;
-        mFullBatch = null;
-        return ret;
+    synchronized List<NetworkEvent> retrieveFullLogBatch(long batchToken) {
+        if (batchToken != mCurrentFullBatchToken) {
+            return null;
+        }
+        return mFullBatch;
     }
 }
 
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index 3c0a8d6..434caad 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -168,20 +168,34 @@
     }
 
     /**
-     * @hide
+     * Get reference signal received quality
      */
     public int getRsrq() {
         return mRsrq;
     }
 
     /**
-     * @hide
+     * Get reference signal signal-to-noise ratio
      */
     public int getRssnr() {
         return mRssnr;
     }
 
     /**
+     * Get reference signal received power
+     */
+    public int getRsrp() {
+        return mRsrp;
+    }
+
+    /**
+     * Get channel quality indicator
+     */
+    public int getCqi() {
+        return mCqi;
+    }
+
+    /**
      * Get signal strength as dBm
      */
     @Override
diff --git a/test-runner/src/android/test/mock/MockContentProvider.java b/test-runner/src/android/test/mock/MockContentProvider.java
index 5ef71df..e443911 100644
--- a/test-runner/src/android/test/mock/MockContentProvider.java
+++ b/test-runner/src/android/test/mock/MockContentProvider.java
@@ -147,6 +147,12 @@
         public Uri uncanonicalize(String callingPkg, Uri uri) throws RemoteException {
             return MockContentProvider.this.uncanonicalize(uri);
         }
+
+        @Override
+        public boolean refresh(String callingPkg, Uri url, Bundle args,
+                ICancellationSignal cancellationSignal) throws RemoteException {
+            return MockContentProvider.this.refresh(url, args);
+        }
     }
     private final InversionIContentProvider mIContentProvider = new InversionIContentProvider();
 
@@ -251,6 +257,13 @@
     }
 
     /**
+     * @hide
+     */
+    public boolean refresh(Uri url, Bundle args) {
+        throw new UnsupportedOperationException("unimplemented mock method call");
+    }
+
+    /**
      * Returns IContentProvider which calls back same methods in this class.
      * By overriding this class, we avoid the mechanism hidden behind ContentProvider
      * (IPC, etc.)
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index fdd971b..190fc35 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -17,6 +17,8 @@
 package android.test.mock;
 
 import android.annotation.SystemApi;
+import android.app.IApplicationThread;
+import android.app.IServiceConnection;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -759,4 +761,23 @@
     public boolean isCredentialProtectedStorage() {
         throw new UnsupportedOperationException();
     }
+
+    /** {@hide} */
+    @Override
+    public IBinder getActivityToken() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @Override
+    public IServiceConnection getServiceDispatcher(ServiceConnection conn, Handler handler,
+            int flags) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @Override
+    public IApplicationThread getIApplicationThread() {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/test-runner/src/android/test/mock/MockIContentProvider.java b/test-runner/src/android/test/mock/MockIContentProvider.java
index ee8c376..09d45d1 100644
--- a/test-runner/src/android/test/mock/MockIContentProvider.java
+++ b/test-runner/src/android/test/mock/MockIContentProvider.java
@@ -125,4 +125,10 @@
     public Uri uncanonicalize(String callingPkg, Uri uri) throws RemoteException {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
+
+    @Override
+    public boolean refresh(String callingPkg, Uri url, Bundle args,
+            ICancellationSignal cancellationSignal) throws RemoteException {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
 }
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
index e1fc5ec..2ae4654 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -326,7 +326,7 @@
 
     @LayoutlibDelegate
     /*package*/ static void nativeReconfigure(long nativeBitmap, int width, int height,
-            int config, int allocSize, boolean isPremultiplied) {
+            int config, boolean isPremultiplied) {
         Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
                 "Bitmap.reconfigure() is not supported", null /*data*/);
     }
@@ -600,6 +600,22 @@
         return Arrays.equals(argb1, argb2);
     }
 
+    @LayoutlibDelegate
+    /*package*/ static int nativeGetAllocationByteCount(long nativeBitmap) {
+        // get the delegate from the native int.
+        Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+        if (delegate == null) {
+            return 0;
+        }
+        return nativeRowBytes(nativeBitmap) * delegate.mImage.getHeight();
+
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void nativePrepareToDraw(long nativeBitmap) {
+        // do nothing as Bitmap_Delegate does not have caches
+    }
+
     // ---- Private delegate/helper methods ----
 
     private Bitmap_Delegate(BufferedImage image, Config config) {
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index 4a4c6c8..94152cd 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -110,17 +110,17 @@
     // ---- native methods ----
 
     @LayoutlibDelegate
-    /*package*/ static void freeCaches() {
+    /*package*/ static void nFreeCaches() {
         // nothing to be done here.
     }
 
     @LayoutlibDelegate
-    /*package*/ static void freeTextLayoutCaches() {
+    /*package*/ static void nFreeTextLayoutCaches() {
         // nothing to be done here yet.
     }
 
     @LayoutlibDelegate
-    /*package*/ static long initRaster(@Nullable Bitmap bitmap) {
+    /*package*/ static long nInitRaster(@Nullable Bitmap bitmap) {
         long nativeBitmapOrZero = 0;
         if (bitmap != null) {
             nativeBitmapOrZero = bitmap.getNativeInstance();
@@ -142,7 +142,7 @@
     }
 
     @LayoutlibDelegate
-    public static void native_setBitmap(long canvas, Bitmap bitmap) {
+    public static void nSetBitmap(long canvas, Bitmap bitmap) {
         Canvas_Delegate canvasDelegate = sManager.getDelegate(canvas);
         Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
         if (canvasDelegate == null || bitmapDelegate==null) {
@@ -153,7 +153,7 @@
     }
 
     @LayoutlibDelegate
-    public static boolean native_isOpaque(long nativeCanvas) {
+    public static boolean nIsOpaque(long nativeCanvas) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
@@ -164,10 +164,10 @@
     }
 
     @LayoutlibDelegate
-    public static void native_setHighContrastText(long nativeCanvas, boolean highContrastText){}
+    public static void nSetHighContrastText(long nativeCanvas, boolean highContrastText){}
 
     @LayoutlibDelegate
-    public static int native_getWidth(long nativeCanvas) {
+    public static int nGetWidth(long nativeCanvas) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
@@ -178,7 +178,7 @@
     }
 
     @LayoutlibDelegate
-    public static int native_getHeight(long nativeCanvas) {
+    public static int nGetHeight(long nativeCanvas) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
@@ -189,7 +189,7 @@
     }
 
     @LayoutlibDelegate
-    public static int native_save(long nativeCanvas, int saveFlags) {
+    public static int nSave(long nativeCanvas, int saveFlags) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
@@ -200,7 +200,7 @@
     }
 
     @LayoutlibDelegate
-    public static int native_saveLayer(long nativeCanvas, float l,
+    public static int nSaveLayer(long nativeCanvas, float l,
                                                float t, float r, float b,
                                                long paint, int layerFlags) {
         // get the delegate from the native int.
@@ -219,7 +219,7 @@
     }
 
     @LayoutlibDelegate
-    public static int native_saveLayerAlpha(long nativeCanvas, float l,
+    public static int nSaveLayerAlpha(long nativeCanvas, float l,
                                                     float t, float r, float b,
                                                     int alpha, int layerFlags) {
         // get the delegate from the native int.
@@ -232,7 +232,7 @@
     }
 
     @LayoutlibDelegate
-    public static void native_restore(long nativeCanvas, boolean throwOnUnderflow) {
+    public static void nRestore(long nativeCanvas, boolean throwOnUnderflow) {
         // FIXME: implement throwOnUnderflow.
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
@@ -244,7 +244,7 @@
     }
 
     @LayoutlibDelegate
-    public static void native_restoreToCount(long nativeCanvas, int saveCount,
+    public static void nRestoreToCount(long nativeCanvas, int saveCount,
             boolean throwOnUnderflow) {
         // FIXME: implement throwOnUnderflow.
         // get the delegate from the native int.
@@ -257,7 +257,7 @@
     }
 
     @LayoutlibDelegate
-    public static int native_getSaveCount(long nativeCanvas) {
+    public static int nGetSaveCount(long nativeCanvas) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
@@ -268,7 +268,7 @@
     }
 
     @LayoutlibDelegate
-   public static void native_translate(long nativeCanvas, float dx, float dy) {
+   public static void nTranslate(long nativeCanvas, float dx, float dy) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
@@ -279,7 +279,7 @@
     }
 
     @LayoutlibDelegate
-       public static void native_scale(long nativeCanvas, float sx, float sy) {
+       public static void nScale(long nativeCanvas, float sx, float sy) {
             // get the delegate from the native int.
             Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
             if (canvasDelegate == null) {
@@ -290,7 +290,7 @@
         }
 
     @LayoutlibDelegate
-    public static void native_rotate(long nativeCanvas, float degrees) {
+    public static void nRotate(long nativeCanvas, float degrees) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
@@ -301,7 +301,7 @@
     }
 
     @LayoutlibDelegate
-   public static void native_skew(long nativeCanvas, float kx, float ky) {
+   public static void nSkew(long nativeCanvas, float kx, float ky) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
@@ -325,7 +325,7 @@
     }
 
     @LayoutlibDelegate
-    public static void native_concat(long nCanvas, long nMatrix) {
+    public static void nConcat(long nCanvas, long nMatrix) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
         if (canvasDelegate == null) {
@@ -353,7 +353,7 @@
     }
 
     @LayoutlibDelegate
-    public static void native_setMatrix(long nCanvas, long nMatrix) {
+    public static void nSetMatrix(long nCanvas, long nMatrix) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
         if (canvasDelegate == null) {
@@ -383,7 +383,7 @@
     }
 
     @LayoutlibDelegate
-    public static boolean native_clipRect(long nCanvas,
+    public static boolean nClipRect(long nCanvas,
                                                   float left, float top,
                                                   float right, float bottom,
                                                   int regionOp) {
@@ -397,7 +397,7 @@
     }
 
     @LayoutlibDelegate
-    public static boolean native_clipPath(long nativeCanvas,
+    public static boolean nClipPath(long nativeCanvas,
                                                   long nativePath,
                                                   int regionOp) {
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
@@ -414,7 +414,7 @@
     }
 
     @LayoutlibDelegate
-    public static boolean native_clipRegion(long nativeCanvas,
+    public static boolean nClipRegion(long nativeCanvas,
                                                     long nativeRegion,
                                                     int regionOp) {
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
@@ -431,7 +431,7 @@
     }
 
     @LayoutlibDelegate
-    public static void nativeSetDrawFilter(long nativeCanvas, long nativeFilter) {
+    public static void nSetDrawFilter(long nativeCanvas, long nativeFilter) {
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
             return;
@@ -446,7 +446,7 @@
     }
 
     @LayoutlibDelegate
-    public static boolean native_getClipBounds(long nativeCanvas,
+    public static boolean nGetClipBounds(long nativeCanvas,
                                                        Rect bounds) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
@@ -467,7 +467,7 @@
     }
 
     @LayoutlibDelegate
-    public static void native_getCTM(long canvas, long matrix) {
+    public static void nGetCTM(long canvas, long matrix) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(canvas);
         if (canvasDelegate == null) {
@@ -484,13 +484,13 @@
     }
 
     @LayoutlibDelegate
-    public static boolean native_quickReject(long nativeCanvas, long path) {
+    public static boolean nQuickReject(long nativeCanvas, long path) {
         // FIXME properly implement quickReject
         return false;
     }
 
     @LayoutlibDelegate
-    public static boolean native_quickReject(long nativeCanvas,
+    public static boolean nQuickReject(long nativeCanvas,
                                                      float left, float top,
                                                      float right, float bottom) {
         // FIXME properly implement quickReject
@@ -498,7 +498,7 @@
     }
 
     @LayoutlibDelegate
-    public static void native_drawColor(long nativeCanvas, final int color, final int mode) {
+    public static void nDrawColor(long nativeCanvas, final int color, final int mode) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
@@ -529,14 +529,14 @@
     }
 
     @LayoutlibDelegate
-    public static void native_drawPaint(long nativeCanvas, long paint) {
+    public static void nDrawPaint(long nativeCanvas, long paint) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
                 "Canvas.drawPaint is not supported.", null, null /*data*/);
     }
 
     @LayoutlibDelegate
-    public static void native_drawPoint(long nativeCanvas, float x, float y,
+    public static void nDrawPoint(long nativeCanvas, float x, float y,
             long nativePaint) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -544,7 +544,7 @@
     }
 
     @LayoutlibDelegate
-    public static void native_drawPoints(long nativeCanvas, float[] pts, int offset, int count,
+    public static void nDrawPoints(long nativeCanvas, float[] pts, int offset, int count,
             long nativePaint) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -552,7 +552,7 @@
     }
 
     @LayoutlibDelegate
-    public static void native_drawLine(long nativeCanvas,
+    public static void nDrawLine(long nativeCanvas,
             final float startX, final float startY, final float stopX, final float stopY,
             long paint) {
         draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
@@ -565,7 +565,7 @@
     }
 
     @LayoutlibDelegate
-    public static void native_drawLines(long nativeCanvas,
+    public static void nDrawLines(long nativeCanvas,
             final float[] pts, final int offset, final int count,
             long nativePaint) {
         draw(nativeCanvas, nativePaint, false /*compositeOnly*/,
@@ -581,7 +581,7 @@
     }
 
     @LayoutlibDelegate
-    public static void native_drawRect(long nativeCanvas,
+    public static void nDrawRect(long nativeCanvas,
             final float left, final float top, final float right, final float bottom, long paint) {
 
         draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
@@ -607,7 +607,7 @@
     }
 
     @LayoutlibDelegate
-    public static void native_drawOval(long nativeCanvas, final float left,
+    public static void nDrawOval(long nativeCanvas, final float left,
             final float top, final float right, final float bottom, long paint) {
         if (right > left && bottom > top) {
             draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
@@ -634,15 +634,15 @@
     }
 
     @LayoutlibDelegate
-    public static void native_drawCircle(long nativeCanvas,
+    public static void nDrawCircle(long nativeCanvas,
             float cx, float cy, float radius, long paint) {
-        native_drawOval(nativeCanvas,
+        nDrawOval(nativeCanvas,
                 cx - radius, cy - radius, cx + radius, cy + radius,
                 paint);
     }
 
     @LayoutlibDelegate
-    public static void native_drawArc(long nativeCanvas,
+    public static void nDrawArc(long nativeCanvas,
             final float left, final float top, final float right, final float bottom,
             final float startAngle, final float sweep,
             final boolean useCenter, long paint) {
@@ -674,7 +674,7 @@
     }
 
     @LayoutlibDelegate
-    public static void native_drawRoundRect(long nativeCanvas,
+    public static void nDrawRoundRect(long nativeCanvas,
             final float left, final float top, final float right, final float bottom,
             final float rx, final float ry, long paint) {
         draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
@@ -704,7 +704,7 @@
     }
 
     @LayoutlibDelegate
-    public static void native_drawPath(long nativeCanvas, long path, long paint) {
+    public static void nDrawPath(long nativeCanvas, long path, long paint) {
         final Path_Delegate pathDelegate = Path_Delegate.getDelegate(path);
         if (pathDelegate == null) {
             return;
@@ -756,7 +756,7 @@
     }
 
     @LayoutlibDelegate
-    public static void native_drawRegion(long nativeCanvas, long nativeRegion,
+    public static void nDrawRegion(long nativeCanvas, long nativeRegion,
             long nativePaint) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -764,7 +764,7 @@
     }
 
     @LayoutlibDelegate
-    public static void native_drawNinePatch(Canvas thisCanvas, long nativeCanvas,
+    public static void nDrawNinePatch(Canvas thisCanvas, long nativeCanvas,
             long nativeBitmap, long ninePatch, final float dstLeft, final float dstTop,
             final float dstRight, final float dstBottom, long nativePaintOrZero,
             final int screenDensity, final int bitmapDensity) {
@@ -811,7 +811,7 @@
     }
 
     @LayoutlibDelegate
-    public static void native_drawBitmap(Canvas thisCanvas, long nativeCanvas, Bitmap bitmap,
+    public static void nDrawBitmap(Canvas thisCanvas, long nativeCanvas, Bitmap bitmap,
                                                  float left, float top,
                                                  long nativePaintOrZero,
                                                  int canvasDensity,
@@ -833,7 +833,7 @@
     }
 
     @LayoutlibDelegate
-    public static void native_drawBitmap(Canvas thisCanvas, long nativeCanvas, Bitmap bitmap,
+    public static void nDrawBitmap(Canvas thisCanvas, long nativeCanvas, Bitmap bitmap,
                                  float srcLeft, float srcTop, float srcRight, float srcBottom,
                                  float dstLeft, float dstTop, float dstRight, float dstBottom,
                                  long nativePaintOrZero, int screenDensity, int bitmapDensity) {
@@ -849,7 +849,7 @@
     }
 
     @LayoutlibDelegate
-    public static void native_drawBitmap(long nativeCanvas, int[] colors,
+    public static void nDrawBitmap(long nativeCanvas, int[] colors,
                                                 int offset, int stride, final float x,
                                                  final float y, int width, int height,
                                                  boolean hasAlpha,
@@ -936,25 +936,25 @@
     }
 
     @LayoutlibDelegate
-    public static void native_drawText(long nativeCanvas, char[] text, int index, int count,
+    public static void nDrawText(long nativeCanvas, char[] text, int index, int count,
             float startX, float startY, int flags, long paint, long typeface) {
         drawText(nativeCanvas, text, index, count, startX, startY, (flags & 1) != 0,
                 paint, typeface);
     }
 
     @LayoutlibDelegate
-    public static void native_drawText(long nativeCanvas, String text,
+    public static void nDrawText(long nativeCanvas, String text,
             int start, int end, float x, float y, final int flags, long paint,
             long typeface) {
         int count = end - start;
         char[] buffer = TemporaryBuffer.obtain(count);
         TextUtils.getChars(text, start, end, buffer, 0);
 
-        native_drawText(nativeCanvas, buffer, 0, count, x, y, flags, paint, typeface);
+        nDrawText(nativeCanvas, buffer, 0, count, x, y, flags, paint, typeface);
     }
 
     @LayoutlibDelegate
-    public static void native_drawTextRun(long nativeCanvas, String text,
+    public static void nDrawTextRun(long nativeCanvas, String text,
             int start, int end, int contextStart, int contextEnd,
             float x, float y, boolean isRtl, long paint, long typeface) {
         int count = end - start;
@@ -965,14 +965,14 @@
     }
 
     @LayoutlibDelegate
-    public static void native_drawTextRun(long nativeCanvas, char[] text,
+    public static void nDrawTextRun(long nativeCanvas, char[] text,
             int start, int count, int contextStart, int contextCount,
             float x, float y, boolean isRtl, long paint, long typeface) {
         drawText(nativeCanvas, text, start, count, x, y, isRtl, paint, typeface);
     }
 
     @LayoutlibDelegate
-    public static void native_drawTextOnPath(long nativeCanvas,
+    public static void nDrawTextOnPath(long nativeCanvas,
                                                      char[] text, int index,
                                                      int count, long path,
                                                      float hOffset,
@@ -984,7 +984,7 @@
     }
 
     @LayoutlibDelegate
-    public static void native_drawTextOnPath(long nativeCanvas,
+    public static void nDrawTextOnPath(long nativeCanvas,
                                                      String text, long path,
                                                      float hOffset,
                                                      float vOffset,
diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
index a503e50..354f919 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
@@ -27,6 +27,8 @@
 import java.awt.geom.AffineTransform;
 import java.awt.geom.NoninvertibleTransformException;
 
+import libcore.util.NativeAllocationRegistry_Delegate;
+
 /**
  * Delegate implementing the native methods of android.graphics.Matrix
  *
@@ -47,6 +49,7 @@
     // ---- delegate manager ----
     private static final DelegateManager<Matrix_Delegate> sManager =
             new DelegateManager<Matrix_Delegate>(Matrix_Delegate.class);
+    private static long sFinalizer = -1;
 
     // ---- delegate data ----
     private float mValues[] = new float[MATRIX_SIZE];
@@ -174,7 +177,7 @@
     // ---- native methods ----
 
     @LayoutlibDelegate
-    /*package*/ static long native_create(long native_src_or_zero) {
+    /*package*/ static long nCreate(long native_src_or_zero) {
         // create the delegate
         Matrix_Delegate newDelegate = new Matrix_Delegate();
 
@@ -193,7 +196,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean native_isIdentity(long native_object) {
+    /*package*/ static boolean nIsIdentity(long native_object) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             return false;
@@ -203,7 +206,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean native_isAffine(long native_object) {
+    /*package*/ static boolean nIsAffine(long native_object) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             return true;
@@ -213,7 +216,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean native_rectStaysRect(long native_object) {
+    /*package*/ static boolean nRectStaysRect(long native_object) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             return true;
@@ -223,7 +226,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_reset(long native_object) {
+    /*package*/ static void nReset(long native_object) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             return;
@@ -233,7 +236,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_set(long native_object, long other) {
+    /*package*/ static void nSet(long native_object, long other) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             return;
@@ -248,7 +251,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_setTranslate(long native_object, float dx, float dy) {
+    /*package*/ static void nSetTranslate(long native_object, float dx, float dy) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             return;
@@ -258,7 +261,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_setScale(long native_object, float sx, float sy,
+    /*package*/ static void nSetScale(long native_object, float sx, float sy,
             float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
@@ -269,7 +272,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_setScale(long native_object, float sx, float sy) {
+    /*package*/ static void nSetScale(long native_object, float sx, float sy) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             return;
@@ -287,7 +290,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_setRotate(long native_object, float degrees, float px, float py) {
+    /*package*/ static void nSetRotate(long native_object, float degrees, float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             return;
@@ -297,7 +300,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_setRotate(long native_object, float degrees) {
+    /*package*/ static void nSetRotate(long native_object, float degrees) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             return;
@@ -307,7 +310,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_setSinCos(long native_object, float sinValue, float cosValue,
+    /*package*/ static void nSetSinCos(long native_object, float sinValue, float cosValue,
             float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
@@ -326,7 +329,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_setSinCos(long native_object, float sinValue, float cosValue) {
+    /*package*/ static void nSetSinCos(long native_object, float sinValue, float cosValue) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             return;
@@ -336,7 +339,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_setSkew(long native_object, float kx, float ky,
+    /*package*/ static void nSetSkew(long native_object, float kx, float ky,
             float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
@@ -347,7 +350,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_setSkew(long native_object, float kx, float ky) {
+    /*package*/ static void nSetSkew(long native_object, float kx, float ky) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             return;
@@ -365,12 +368,12 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_setConcat(long native_object, long a, long b) {
+    /*package*/ static void nSetConcat(long native_object, long a, long b) {
         if (a == native_object) {
-            native_preConcat(native_object, b);
+            nPreConcat(native_object, b);
             return;
         } else if (b == native_object) {
-            native_postConcat(native_object, a);
+            nPostConcat(native_object, a);
             return;
         }
 
@@ -383,7 +386,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_preTranslate(long native_object, float dx, float dy) {
+    /*package*/ static void nPreTranslate(long native_object, float dx, float dy) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d != null) {
             d.preTransform(getTranslate(dx, dy));
@@ -391,7 +394,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_preScale(long native_object, float sx, float sy,
+    /*package*/ static void nPreScale(long native_object, float sx, float sy,
             float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d != null) {
@@ -400,7 +403,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_preScale(long native_object, float sx, float sy) {
+    /*package*/ static void nPreScale(long native_object, float sx, float sy) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d != null) {
             d.preTransform(getScale(sx, sy));
@@ -408,7 +411,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_preRotate(long native_object, float degrees,
+    /*package*/ static void nPreRotate(long native_object, float degrees,
             float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d != null) {
@@ -417,7 +420,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_preRotate(long native_object, float degrees) {
+    /*package*/ static void nPreRotate(long native_object, float degrees) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d != null) {
 
@@ -430,7 +433,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_preSkew(long native_object, float kx, float ky,
+    /*package*/ static void nPreSkew(long native_object, float kx, float ky,
             float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d != null) {
@@ -439,7 +442,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_preSkew(long native_object, float kx, float ky) {
+    /*package*/ static void nPreSkew(long native_object, float kx, float ky) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d != null) {
             d.preTransform(getSkew(kx, ky));
@@ -447,7 +450,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_preConcat(long native_object, long other_matrix) {
+    /*package*/ static void nPreConcat(long native_object, long other_matrix) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         Matrix_Delegate other = sManager.getDelegate(other_matrix);
         if (d != null && other != null) {
@@ -456,7 +459,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_postTranslate(long native_object, float dx, float dy) {
+    /*package*/ static void nPostTranslate(long native_object, float dx, float dy) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d != null) {
             d.postTransform(getTranslate(dx, dy));
@@ -464,7 +467,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_postScale(long native_object, float sx, float sy,
+    /*package*/ static void nPostScale(long native_object, float sx, float sy,
             float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d != null) {
@@ -473,7 +476,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_postScale(long native_object, float sx, float sy) {
+    /*package*/ static void nPostScale(long native_object, float sx, float sy) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d != null) {
             d.postTransform(getScale(sx, sy));
@@ -481,7 +484,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_postRotate(long native_object, float degrees,
+    /*package*/ static void nPostRotate(long native_object, float degrees,
             float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d != null) {
@@ -490,7 +493,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_postRotate(long native_object, float degrees) {
+    /*package*/ static void nPostRotate(long native_object, float degrees) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d != null) {
             d.postTransform(getRotate(degrees));
@@ -498,7 +501,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_postSkew(long native_object, float kx, float ky,
+    /*package*/ static void nPostSkew(long native_object, float kx, float ky,
             float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d != null) {
@@ -507,7 +510,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_postSkew(long native_object, float kx, float ky) {
+    /*package*/ static void nPostSkew(long native_object, float kx, float ky) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d != null) {
             d.postTransform(getSkew(kx, ky));
@@ -515,7 +518,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_postConcat(long native_object, long other_matrix) {
+    /*package*/ static void nPostConcat(long native_object, long other_matrix) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         Matrix_Delegate other = sManager.getDelegate(other_matrix);
         if (d != null && other != null) {
@@ -524,7 +527,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean native_setRectToRect(long native_object, RectF src,
+    /*package*/ static boolean nSetRectToRect(long native_object, RectF src,
             RectF dst, int stf) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
@@ -589,7 +592,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean native_setPolyToPoly(long native_object, float[] src, int srcIndex,
+    /*package*/ static boolean nSetPolyToPoly(long native_object, float[] src, int srcIndex,
             float[] dst, int dstIndex, int pointCount) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -599,7 +602,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean native_invert(long native_object, long inverse) {
+    /*package*/ static boolean nInvert(long native_object, long inverse) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             return false;
@@ -627,7 +630,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_mapPoints(long native_object, float[] dst, int dstIndex,
+    /*package*/ static void nMapPoints(long native_object, float[] dst, int dstIndex,
             float[] src, int srcIndex, int ptCount, boolean isPts) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
@@ -642,7 +645,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean native_mapRect(long native_object, RectF dst, RectF src) {
+    /*package*/ static boolean nMapRect(long native_object, RectF dst, RectF src) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             return false;
@@ -652,7 +655,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static float native_mapRadius(long native_object, float radius) {
+    /*package*/ static float nMapRadius(long native_object, float radius) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             return 0.f;
@@ -667,7 +670,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_getValues(long native_object, float[] values) {
+    /*package*/ static void nGetValues(long native_object, float[] values) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             return;
@@ -677,7 +680,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_setValues(long native_object, float[] values) {
+    /*package*/ static void nSetValues(long native_object, float[] values) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             return;
@@ -687,7 +690,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean native_equals(long native_a, long native_b) {
+    /*package*/ static boolean nEquals(long native_a, long native_b) {
         Matrix_Delegate a = sManager.getDelegate(native_a);
         if (a == null) {
             return false;
@@ -708,8 +711,13 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void finalizer(long native_instance) {
-        sManager.removeJavaReferenceFor(native_instance);
+    /*package*/ static long nGetNativeFinalizer() {
+        synchronized (Matrix_Delegate.class) {
+            if (sFinalizer == -1) {
+                sFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(sManager::removeJavaReferenceFor);
+            }
+        }
+        return sFinalizer;
     }
 
     // ---- Private helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index 33296e1..0bbe33d 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -261,7 +261,7 @@
     // ---- native methods ----
 
     @LayoutlibDelegate
-    /*package*/ static int nGetFlags(Paint thisPaint, long nativePaint) {
+    /*package*/ static int nGetFlags(long nativePaint) {
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
         if (delegate == null) {
@@ -274,7 +274,7 @@
 
 
     @LayoutlibDelegate
-    /*package*/ static void nSetFlags(Paint thisPaint, long nativePaint, int flags) {
+    /*package*/ static void nSetFlags(long nativePaint, int flags) {
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
         if (delegate == null) {
@@ -285,12 +285,12 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nSetFilterBitmap(Paint thisPaint, long nativePaint, boolean filter) {
+    /*package*/ static void nSetFilterBitmap(long nativePaint, boolean filter) {
         setFlag(nativePaint, Paint.FILTER_BITMAP_FLAG, filter);
     }
 
     @LayoutlibDelegate
-    /*package*/ static int nGetHinting(Paint thisPaint, long nativePaint) {
+    /*package*/ static int nGetHinting(long nativePaint) {
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
         if (delegate == null) {
@@ -301,7 +301,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nSetHinting(Paint thisPaint, long nativePaint, int mode) {
+    /*package*/ static void nSetHinting(long nativePaint, int mode) {
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
         if (delegate == null) {
@@ -312,46 +312,46 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nSetAntiAlias(Paint thisPaint, long nativePaint, boolean aa) {
+    /*package*/ static void nSetAntiAlias(long nativePaint, boolean aa) {
         setFlag(nativePaint, Paint.ANTI_ALIAS_FLAG, aa);
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nSetSubpixelText(Paint thisPaint, long nativePaint,
+    /*package*/ static void nSetSubpixelText(long nativePaint,
             boolean subpixelText) {
         setFlag(nativePaint, Paint.SUBPIXEL_TEXT_FLAG, subpixelText);
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nSetUnderlineText(Paint thisPaint, long nativePaint,
+    /*package*/ static void nSetUnderlineText(long nativePaint,
             boolean underlineText) {
         setFlag(nativePaint, Paint.UNDERLINE_TEXT_FLAG, underlineText);
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nSetStrikeThruText(Paint thisPaint, long nativePaint,
+    /*package*/ static void nSetStrikeThruText(long nativePaint,
             boolean strikeThruText) {
         setFlag(nativePaint, Paint.STRIKE_THRU_TEXT_FLAG, strikeThruText);
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nSetFakeBoldText(Paint thisPaint, long nativePaint,
+    /*package*/ static void nSetFakeBoldText(long nativePaint,
             boolean fakeBoldText) {
         setFlag(nativePaint, Paint.FAKE_BOLD_TEXT_FLAG, fakeBoldText);
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nSetDither(Paint thisPaint, long nativePaint, boolean dither) {
+    /*package*/ static void nSetDither(long nativePaint, boolean dither) {
         setFlag(nativePaint, Paint.DITHER_FLAG, dither);
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nSetLinearText(Paint thisPaint, long nativePaint, boolean linearText) {
+    /*package*/ static void nSetLinearText(long nativePaint, boolean linearText) {
         setFlag(nativePaint, Paint.LINEAR_TEXT_FLAG, linearText);
     }
 
     @LayoutlibDelegate
-    /*package*/ static int nGetColor(Paint thisPaint, long nativePaint) {
+    /*package*/ static int nGetColor(long nativePaint) {
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
         if (delegate == null) {
@@ -362,7 +362,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nSetColor(Paint thisPaint, long nativePaint, int color) {
+    /*package*/ static void nSetColor(long nativePaint, int color) {
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
         if (delegate == null) {
@@ -373,7 +373,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static int nGetAlpha(Paint thisPaint, long nativePaint) {
+    /*package*/ static int nGetAlpha(long nativePaint) {
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
         if (delegate == null) {
@@ -384,7 +384,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nSetAlpha(Paint thisPaint, long nativePaint, int a) {
+    /*package*/ static void nSetAlpha(long nativePaint, int a) {
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
         if (delegate == null) {
@@ -395,7 +395,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static float nGetStrokeWidth(Paint thisPaint, long nativePaint) {
+    /*package*/ static float nGetStrokeWidth(long nativePaint) {
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
         if (delegate == null) {
@@ -406,7 +406,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nSetStrokeWidth(Paint thisPaint, long nativePaint, float width) {
+    /*package*/ static void nSetStrokeWidth(long nativePaint, float width) {
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
         if (delegate == null) {
@@ -417,7 +417,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static float nGetStrokeMiter(Paint thisPaint, long nativePaint) {
+    /*package*/ static float nGetStrokeMiter(long nativePaint) {
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
         if (delegate == null) {
@@ -428,7 +428,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nSetStrokeMiter(Paint thisPaint, long nativePaint, float miter) {
+    /*package*/ static void nSetStrokeMiter(long nativePaint, float miter) {
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
         if (delegate == null) {
@@ -455,14 +455,14 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean nIsElegantTextHeight(Paint thisPaint, long nativePaint) {
+    /*package*/ static boolean nIsElegantTextHeight(long nativePaint) {
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
         return delegate != null && delegate.mFontVariant == FontVariant.ELEGANT;
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nSetElegantTextHeight(Paint thisPaint, long nativePaint,
+    /*package*/ static void nSetElegantTextHeight(long nativePaint,
             boolean elegant) {
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
@@ -474,7 +474,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static float nGetTextSize(Paint thisPaint, long nativePaint) {
+    /*package*/ static float nGetTextSize(long nativePaint) {
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
         if (delegate == null) {
@@ -485,7 +485,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nSetTextSize(Paint thisPaint, long nativePaint, float textSize) {
+    /*package*/ static void nSetTextSize(long nativePaint, float textSize) {
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
         if (delegate == null) {
@@ -499,7 +499,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static float nGetTextScaleX(Paint thisPaint, long nativePaint) {
+    /*package*/ static float nGetTextScaleX(long nativePaint) {
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
         if (delegate == null) {
@@ -510,7 +510,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nSetTextScaleX(Paint thisPaint, long nativePaint, float scaleX) {
+    /*package*/ static void nSetTextScaleX(long nativePaint, float scaleX) {
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
         if (delegate == null) {
@@ -524,7 +524,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static float nGetTextSkewX(Paint thisPaint, long nativePaint) {
+    /*package*/ static float nGetTextSkewX(long nativePaint) {
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
         if (delegate == null) {
@@ -535,7 +535,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nSetTextSkewX(Paint thisPaint, long nativePaint, float skewX) {
+    /*package*/ static void nSetTextSkewX(long nativePaint, float skewX) {
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
         if (delegate == null) {
@@ -549,7 +549,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static float nAscent(Paint thisPaint, long nativePaint, long nativeTypeface) {
+    /*package*/ static float nAscent(long nativePaint, long nativeTypeface) {
         // get the delegate
         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
         if (delegate == null) {
@@ -566,7 +566,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static float nDescent(Paint thisPaint, long nativePaint, long nativeTypeface) {
+    /*package*/ static float nDescent(long nativePaint, long nativeTypeface) {
         // get the delegate
         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
         if (delegate == null) {
@@ -583,7 +583,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static float nGetFontMetrics(Paint thisPaint, long nativePaint, long nativeTypeface,
+    /*package*/ static float nGetFontMetrics(long nativePaint, long nativeTypeface,
             FontMetrics metrics) {
         // get the delegate
         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
@@ -595,7 +595,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static int nGetFontMetricsInt(Paint thisPaint, long nativePaint,
+    /*package*/ static int nGetFontMetricsInt(long nativePaint,
             long nativeTypeface, FontMetricsInt fmi) {
         // get the delegate
         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
@@ -998,7 +998,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static int nGetTextRunCursor(Paint thisPaint, long native_object, char[] text,
+    /*package*/ static int nGetTextRunCursor(long native_object, char[] text,
             int contextStart, int contextLength, int flags, int offset, int cursorOpt) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -1007,7 +1007,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static int nGetTextRunCursor(Paint thisPaint, long native_object, String text,
+    /*package*/ static int nGetTextRunCursor(long native_object, String text,
             int contextStart, int contextEnd, int flags, int offset, int cursorOpt) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
diff --git a/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
index 3e81e83..9904263 100644
--- a/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
@@ -141,12 +141,12 @@
             long colorFilterPtr, Rect bounds, boolean needsMirroring, boolean canReuseCache) {
         VPathRenderer_Delegate nativePathRenderer = VNativeObject.getDelegate(rendererPtr);
 
-        Canvas_Delegate.native_save(canvasWrapperPtr, MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG);
-        Canvas_Delegate.native_translate(canvasWrapperPtr, bounds.left, bounds.top);
+        Canvas_Delegate.nSave(canvasWrapperPtr, MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG);
+        Canvas_Delegate.nTranslate(canvasWrapperPtr, bounds.left, bounds.top);
 
         if (needsMirroring) {
-            Canvas_Delegate.native_translate(canvasWrapperPtr, bounds.width(), 0);
-            Canvas_Delegate.native_scale(canvasWrapperPtr, -1.0f, 1.0f);
+            Canvas_Delegate.nTranslate(canvasWrapperPtr, bounds.width(), 0);
+            Canvas_Delegate.nScale(canvasWrapperPtr, -1.0f, 1.0f);
         }
 
         // At this point, canvas has been translated to the right position.
@@ -155,7 +155,7 @@
         bounds.offsetTo(0, 0);
         nativePathRenderer.draw(canvasWrapperPtr, colorFilterPtr, bounds.width(), bounds.height());
 
-        Canvas_Delegate.native_restore(canvasWrapperPtr, true);
+        Canvas_Delegate.nRestore(canvasWrapperPtr, true);
 
         return bounds.width() * bounds.height();
     }
@@ -1108,7 +1108,7 @@
             currentGroup.mStackedMatrix.preConcat(currentGroup.mLocalMatrix);
 
             // Save the current clip information, which is local to this group.
-            Canvas_Delegate.native_save(canvasPtr, MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG);
+            Canvas_Delegate.nSave(canvasPtr, MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG);
             // Draw the group tree in the same order as the XML file.
             for (int i = 0; i < currentGroup.mChildren.size(); i++) {
                 Object child = currentGroup.mChildren.get(i);
@@ -1121,7 +1121,7 @@
                     drawPath(currentGroup, childPath, canvasPtr, w, h, filterPtr);
                 }
             }
-            Canvas_Delegate.native_restore(canvasPtr, true);
+            Canvas_Delegate.nRestore(canvasPtr, true);
         }
 
         public void draw(long canvasPtr, long filterPtr, int w, int h) {
@@ -1153,7 +1153,7 @@
 
             if (VPath.isClipPath()) {
                 mRenderPath.addPath(path, mFinalPathMatrix);
-                Canvas_Delegate.native_clipPath(canvasPtr, mRenderPath.mNativePath, Op
+                Canvas_Delegate.nClipPath(canvasPtr, mRenderPath.mNativePath, Op
                         .INTERSECT.nativeInt);
             } else {
                 VFullPath_Delegate fullPath = (VFullPath_Delegate) VPath;
@@ -1197,7 +1197,7 @@
                     fillPaintDelegate.setColorFilter(filterPtr);
                     fillPaintDelegate.setShader(fullPath.mFillGradient);
                     Path_Delegate.native_setFillType(mRenderPath.mNativePath, fullPath.mFillType);
-                    Canvas_Delegate.native_drawPath(canvasPtr, mRenderPath.mNativePath, fillPaint
+                    Canvas_Delegate.nDrawPath(canvasPtr, mRenderPath.mNativePath, fillPaint
                             .getNativeInstance());
                 }
 
@@ -1228,7 +1228,7 @@
                     final float finalStrokeScale = minScale * matrixScale;
                     strokePaint.setStrokeWidth(fullPath.mStrokeWidth * finalStrokeScale);
                     strokePaintDelegate.setShader(fullPath.mStrokeGradient);
-                    Canvas_Delegate.native_drawPath(canvasPtr, mRenderPath.mNativePath, strokePaint
+                    Canvas_Delegate.nDrawPath(canvasPtr, mRenderPath.mNativePath, strokePaint
                             .getNativeInstance());
                 }
             }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
index e4cbb2f..3471165 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
@@ -145,4 +145,10 @@
     public Uri uncanonicalize(String callingPkg, Uri uri) throws RemoteException {
         return null;
     }
+
+    @Override
+    public boolean refresh(String callingPkg, Uri url, Bundle args,
+                    ICancellationSignal cancellationSignal) throws RemoteException {
+        return false;
+    }
 }
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/CustomCalendar.java b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/CustomCalendar.java
index 80bbaf1..5c53af9 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/CustomCalendar.java
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/CustomCalendar.java
@@ -26,6 +26,6 @@
     }
 
     private void init() {
-        setDate(871703200000L, false, true);
+        setDate(871732800000L, false, true);
     }
 }
diff --git a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl
index ee2e895..8b1cfae 100644
--- a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl
+++ b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl
@@ -28,5 +28,6 @@
     Messenger getMessenger();
     Messenger getP2pStateMachineMessenger();
     void setMiracastMode(int mode);
+    void checkConfigureWifiDisplayPermission();
 }
 
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 398308d..c93ac7b 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -1324,6 +1324,11 @@
             Channel c, WifiP2pWfdInfo wfdInfo,
             ActionListener listener) {
         checkChannel(c);
+        try {
+            mService.checkConfigureWifiDisplayPermission();
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
         c.mAsyncChannel.sendMessage(SET_WFD_INFO, 0, c.putListener(listener), wfdInfo);
     }