Merge "Remove unneeded pipeline check"
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index e21392c..511aec3 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -122,6 +122,12 @@
     VLOG("Metric %lld onSlicedConditionMayChange", (long long)mMetricId);
 }
 
+
+void CountMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) {
+    flushIfNeededLocked(dumpTimeNs);
+    mPastBuckets.clear();
+}
+
 void CountMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
                                              const bool include_current_partial_bucket,
                                              ProtoOutputStream* protoOutput) {
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index cafc882..8e94a75 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -59,6 +59,8 @@
                             const bool include_current_partial_bucket,
                             android::util::ProtoOutputStream* protoOutput) override;
 
+    void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
+
     // Internal interface to handle condition change.
     void onConditionChangedLocked(const bool conditionMet, const int64_t eventTime) override;
 
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 3661b31..5610492 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -438,6 +438,11 @@
     mPastBuckets.clear();
 }
 
+void DurationMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) {
+    flushIfNeededLocked(dumpTimeNs);
+    mPastBuckets.clear();
+}
+
 void DurationMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
                                                 const bool include_current_partial_bucket,
                                                 ProtoOutputStream* protoOutput) {
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 80fbdde..f755294 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -65,6 +65,8 @@
                             const bool include_current_partial_bucket,
                             android::util::ProtoOutputStream* protoOutput) override;
 
+    void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
+
     // Internal interface to handle condition change.
     void onConditionChangedLocked(const bool conditionMet, const int64_t eventTime) override;
 
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index 2f2679e..23f780a 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -100,6 +100,10 @@
     return buffer;
 }
 
+void EventMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) {
+    mProto->clear();
+}
+
 void EventMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
                                              const bool include_current_partial_bucket,
                                              ProtoOutputStream* protoOutput) {
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
index 5c29174..23302c4 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -49,6 +49,7 @@
     void onDumpReportLocked(const int64_t dumpTimeNs,
                             const bool include_current_partial_bucket,
                             android::util::ProtoOutputStream* protoOutput) override;
+    void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
 
     // Internal interface to handle condition change.
     void onConditionChangedLocked(const bool conditionMet, const int64_t eventTime) override;
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 1270856..005cb71 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -160,6 +160,12 @@
     }
 }
 
+void GaugeMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) {
+    flushIfNeededLocked(dumpTimeNs);
+    mPastBuckets.clear();
+    mSkippedBuckets.clear();
+}
+
 void GaugeMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
                                              const bool include_current_partial_bucket,
                                              ProtoOutputStream* protoOutput) {
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index 71d5912..8af2f36 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -91,6 +91,7 @@
     void onDumpReportLocked(const int64_t dumpTimeNs,
                             const bool include_current_partial_bucket,
                             android::util::ProtoOutputStream* protoOutput) override;
+    void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
 
     // for testing
     GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& gaugeMetric,
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 532ecbf..4239649 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -119,6 +119,11 @@
         return onDumpReportLocked(dumpTimeNs, include_current_partial_bucket, protoOutput);
     }
 
+    void clearPastBuckets(const int64_t dumpTimeNs) {
+        std::lock_guard<std::mutex> lock(mMutex);
+        return clearPastBucketsLocked(dumpTimeNs);
+    }
+
     void dumpStates(FILE* out, bool verbose) const {
         std::lock_guard<std::mutex> lock(mMutex);
         dumpStatesLocked(out, verbose);
@@ -177,6 +182,7 @@
     virtual void onDumpReportLocked(const int64_t dumpTimeNs,
                                     const bool include_current_partial_bucket,
                                     android::util::ProtoOutputStream* protoOutput) = 0;
+    virtual void clearPastBucketsLocked(const int64_t dumpTimeNs) = 0;
     virtual size_t byteSizeLocked() const = 0;
     virtual void dumpStatesLocked(FILE* out, bool verbose) const = 0;
 
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 47a1a86..0d3aebf 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -201,6 +201,8 @@
                     protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_METRICS);
             producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, protoOutput);
             protoOutput->end(token);
+        } else {
+            producer->clearPastBuckets(dumpTimeStampNs);
         }
     }
     for (const auto& annotation : mAnnotations) {
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 27fd78f..506cf38 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -151,6 +151,12 @@
     mPastBuckets.clear();
 }
 
+void ValueMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) {
+    flushIfNeededLocked(dumpTimeNs);
+    mPastBuckets.clear();
+    mSkippedBuckets.clear();
+}
+
 void ValueMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
                                              const bool include_current_partial_bucket,
                                              ProtoOutputStream* protoOutput) {
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 8df30d3..64604c2 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -89,6 +89,7 @@
     void onDumpReportLocked(const int64_t dumpTimeNs,
                             const bool include_current_partial_bucket,
                             android::util::ProtoOutputStream* protoOutput) override;
+    void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
 
     // Internal interface to handle condition change.
     void onConditionChangedLocked(const bool conditionMet, const int64_t eventTime) override;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index f18b92a..9c1c700 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5104,6 +5104,10 @@
                     savedBundle.getBoolean(EXTRA_SHOW_CHRONOMETER));
             publicExtras.putBoolean(EXTRA_CHRONOMETER_COUNT_DOWN,
                     savedBundle.getBoolean(EXTRA_CHRONOMETER_COUNT_DOWN));
+            String appName = savedBundle.getString(EXTRA_SUBSTITUTE_APP_NAME);
+            if (appName != null) {
+                publicExtras.putString(EXTRA_SUBSTITUTE_APP_NAME, appName);
+            }
             mN.extras = publicExtras;
             RemoteViews view;
             if (ambient) {
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 1b6b5a0..1b9e27c 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -394,6 +394,58 @@
     public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 23;
 
     /**
+     * Device only has a display.
+     *
+     * @hide
+     */
+    public static final int IO_CAPABILITY_OUT = 0;
+
+    /**
+     * Device has a display and the ability to input Yes/No.
+     *
+     * @hide
+     */
+    public static final int IO_CAPABILITY_IO = 1;
+
+    /**
+     * Device only has a keyboard for entry but no display.
+     *
+     * @hide
+     */
+    public static final int IO_CAPABILITY_IN = 2;
+
+    /**
+     * Device has no Input or Output capability.
+     *
+     * @hide
+     */
+    public static final int IO_CAPABILITY_NONE = 3;
+
+    /**
+     * Device has a display and a full keyboard.
+     *
+     * @hide
+     */
+    public static final int IO_CAPABILITY_KBDISP = 4;
+
+    /**
+     * Maximum range value for Input/Output capabilities.
+     *
+     * <p>This should be updated when adding a new Input/Output capability. Other code
+     * like validation depends on this being accurate.
+     *
+     * @hide
+     */
+    public static final int IO_CAPABILITY_MAX = 5;
+
+    /**
+     * The Input/Output capability of the device is unknown.
+     *
+     * @hide
+     */
+    public static final int IO_CAPABILITY_UNKNOWN = 255;
+
+    /**
      * Broadcast Action: The local Bluetooth adapter has started the remote
      * device discovery process.
      * <p>This usually involves an inquiry scan of about 12 seconds, followed
@@ -1225,6 +1277,106 @@
     }
 
     /**
+     * Returns the Input/Output capability of the device for classic Bluetooth.
+     *
+     * @return Input/Output capability of the device. One of {@link #IO_CAPABILITY_OUT},
+     *         {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_IN}, {@link #IO_CAPABILITY_NONE},
+     *         {@link #IO_CAPABILITY_KBDISP} or {@link #IO_CAPABILITY_UNKNOWN}.
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+    public int getIoCapability() {
+        if (getState() != STATE_ON) return BluetoothAdapter.IO_CAPABILITY_UNKNOWN;
+        try {
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.getIoCapability();
+        } catch (RemoteException e) {
+            Log.e(TAG, e.getMessage(), e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
+        return BluetoothAdapter.IO_CAPABILITY_UNKNOWN;
+    }
+
+    /**
+     * Sets the Input/Output capability of the device for classic Bluetooth.
+     *
+     * <p>Changing the Input/Output capability of a device only takes effect on restarting the
+     * Bluetooth stack. You would need to restart the stack using {@link BluetoothAdapter#disable()}
+     * and {@link BluetoothAdapter#enable()} to see the changes.
+     *
+     * @param capability Input/Output capability of the device. One of {@link #IO_CAPABILITY_OUT},
+     *                   {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_IN},
+     *                   {@link #IO_CAPABILITY_NONE} or {@link #IO_CAPABILITY_KBDISP}.
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+    public boolean setIoCapability(int capability) {
+        if (getState() != STATE_ON) return false;
+        try {
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.setIoCapability(capability);
+        } catch (RemoteException e) {
+            Log.e(TAG, e.getMessage(), e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
+        return false;
+    }
+
+    /**
+     * Returns the Input/Output capability of the device for BLE operations.
+     *
+     * @return Input/Output capability of the device. One of {@link #IO_CAPABILITY_OUT},
+     *         {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_IN}, {@link #IO_CAPABILITY_NONE},
+     *         {@link #IO_CAPABILITY_KBDISP} or {@link #IO_CAPABILITY_UNKNOWN}.
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+    public int getLeIoCapability() {
+        if (getState() != STATE_ON) return BluetoothAdapter.IO_CAPABILITY_UNKNOWN;
+        try {
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.getLeIoCapability();
+        } catch (RemoteException e) {
+            Log.e(TAG, e.getMessage(), e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
+        return BluetoothAdapter.IO_CAPABILITY_UNKNOWN;
+    }
+
+    /**
+     * Sets the Input/Output capability of the device for BLE operations.
+     *
+     * <p>Changing the Input/Output capability of a device only takes effect on restarting the
+     * Bluetooth stack. You would need to restart the stack using {@link BluetoothAdapter#disable()}
+     * and {@link BluetoothAdapter#enable()} to see the changes.
+     *
+     * @param capability Input/Output capability of the device. One of {@link #IO_CAPABILITY_OUT},
+     *                   {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_IN},
+     *                   {@link #IO_CAPABILITY_NONE} or {@link #IO_CAPABILITY_KBDISP}.
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+    public boolean setLeIoCapability(int capability) {
+        if (getState() != STATE_ON) return false;
+        try {
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.setLeIoCapability(capability);
+        } catch (RemoteException e) {
+            Log.e(TAG, e.getMessage(), e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
+        return false;
+    }
+
+    /**
      * Get the current Bluetooth scan mode of the local Bluetooth adapter.
      * <p>The Bluetooth scan mode determines if the local adapter is
      * connectable and/or discoverable from remote Bluetooth devices.
diff --git a/core/java/android/hardware/radio/RadioMetadata.java b/core/java/android/hardware/radio/RadioMetadata.java
index 6e51060..baa7a50 100644
--- a/core/java/android/hardware/radio/RadioMetadata.java
+++ b/core/java/android/hardware/radio/RadioMetadata.java
@@ -269,6 +269,29 @@
         mBundle = in.readBundle();
     }
 
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("RadioMetadata[");
+
+        final String removePrefix = "android.hardware.radio.metadata";
+
+        boolean first = true;
+        for (String key : mBundle.keySet()) {
+            if (first) first = false;
+            else sb.append(", ");
+
+            String keyDisp = key;
+            if (key.startsWith(removePrefix)) keyDisp = key.substring(removePrefix.length());
+
+            sb.append(keyDisp);
+            sb.append('=');
+            sb.append(mBundle.get(key));
+        }
+
+        sb.append("]");
+        return sb.toString();
+    }
+
     /**
      * Returns {@code true} if the given key is contained in the meta data
      *
diff --git a/core/java/com/android/internal/policy/DecorContext.java b/core/java/com/android/internal/policy/DecorContext.java
index eac9f64..cd80d53 100644
--- a/core/java/com/android/internal/policy/DecorContext.java
+++ b/core/java/com/android/internal/policy/DecorContext.java
@@ -23,6 +23,8 @@
 import android.view.WindowManager;
 import android.view.WindowManagerImpl;
 
+import java.lang.ref.WeakReference;
+
 /**
  * Context for decor views which can be seeded with pure application context and not depend on the
  * activity, but still provide some of the facilities that Activity has,
@@ -35,9 +37,12 @@
     private WindowManager mWindowManager;
     private Resources mActivityResources;
 
-    public DecorContext(Context context, Resources activityResources) {
+    private WeakReference<Context> mActivityContext;
+
+    public DecorContext(Context context, Context activityContext) {
         super(context, null);
-        mActivityResources = activityResources;
+        mActivityContext = new WeakReference<>(activityContext);
+        mActivityResources = activityContext.getResources();
     }
 
     void setPhoneWindow(PhoneWindow phoneWindow) {
@@ -60,6 +65,13 @@
 
     @Override
     public Resources getResources() {
+        Context activityContext = mActivityContext.get();
+        // Attempt to update the local cached Resources from the activity context. If the activity
+        // is no longer around, return the old cached values.
+        if (activityContext != null) {
+            mActivityResources = activityContext.getResources();
+        }
+
         return mActivityResources;
     }
 
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 6bf2e0e..a186f1a 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -1849,6 +1849,13 @@
     }
 
     @Override
+    public Resources getResources() {
+        // Make sure the Resources object is propogated from the Context since it can be updated in
+        // the Context object.
+        return getContext().getResources();
+    }
+
+    @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
 
diff --git a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
index 3af3e2a..a3c7a9e 100644
--- a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
@@ -344,7 +344,7 @@
             if (dockedSide == DOCKED_LEFT) {
                 position += mInsets.left;
             } else if (dockedSide == DOCKED_RIGHT) {
-                position = mDisplayWidth - position - mInsets.right;
+                position = mDisplayWidth - position - mInsets.right - mDividerSize;
             }
         }
         mTargets.add(new SnapTarget(position, position, SnapTarget.FLAG_NONE));
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index f090aca..64a8f9f 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -2298,7 +2298,7 @@
             if (applicationContext == null) {
                 context = getContext();
             } else {
-                context = new DecorContext(applicationContext, getContext().getResources());
+                context = new DecorContext(applicationContext, getContext());
                 if (mTheme != -1) {
                     context.setTheme(mTheme);
                 }
diff --git a/core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java b/core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java
index ff3452c..0fd0136 100644
--- a/core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java
@@ -28,7 +28,6 @@
 import android.graphics.Matrix;
 import android.graphics.RectF;
 import android.os.Parcel;
-import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.text.TextUtils;
@@ -40,7 +39,6 @@
 import java.util.Objects;
 
 @SmallTest
-@Presubmit
 @RunWith(AndroidJUnit4.class)
 public class CursorAnchorInfoTest {
     private static final float EPSILON = 0.0000001f;
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
index 52df338..9edbf3e 100644
--- a/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
@@ -26,7 +26,6 @@
 import android.content.pm.ServiceInfo;
 import android.os.Bundle;
 import android.os.Parcel;
-import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.LargeTest;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
@@ -37,7 +36,6 @@
 import org.junit.runner.RunWith;
 
 @LargeTest
-@Presubmit
 @RunWith(AndroidJUnit4.class)
 public class InputMethodInfoTest {
 
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java
index ff71c00..8df1848 100644
--- a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java
@@ -19,7 +19,6 @@
 import static org.junit.Assert.assertEquals;
 
 import android.os.Parcel;
-import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
@@ -30,7 +29,6 @@
 import java.util.ArrayList;
 
 @SmallTest
-@Presubmit
 @RunWith(AndroidJUnit4.class)
 public class InputMethodSubtypeArrayTest {
 
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java
index 2c85ce7..c76359e 100644
--- a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java
@@ -23,7 +23,6 @@
 import static org.junit.Assert.assertTrue;
 
 import android.os.Parcel;
-import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
@@ -35,7 +34,6 @@
 import java.util.Objects;
 
 @SmallTest
-@Presubmit
 @RunWith(AndroidJUnit4.class)
 public class InputMethodSubtypeTest {
 
diff --git a/core/tests/coretests/src/android/view/inputmethod/SparseRectFArrayTest.java b/core/tests/coretests/src/android/view/inputmethod/SparseRectFArrayTest.java
index c7b5933..8c96b58 100644
--- a/core/tests/coretests/src/android/view/inputmethod/SparseRectFArrayTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/SparseRectFArrayTest.java
@@ -23,7 +23,6 @@
 
 import android.graphics.RectF;
 import android.os.Parcel;
-import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.view.inputmethod.SparseRectFArray.SparseRectFArrayBuilder;
@@ -34,7 +33,6 @@
 import java.util.Objects;
 
 @SmallTest
-@Presubmit
 @RunWith(AndroidJUnit4.class)
 public class SparseRectFArrayTest {
     // A test data for {@link SparseRectFArray}. null represents the gap of indices.
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
index 0429d99..13d6749 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
@@ -23,7 +23,6 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
-import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.view.inputmethod.InputMethodInfo;
@@ -41,7 +40,6 @@
 import java.util.List;
 
 @SmallTest
-@Presubmit
 @RunWith(AndroidJUnit4.class)
 public class InputMethodSubtypeSwitchingControllerTest {
     private static final String DUMMY_PACKAGE_NAME = "dummy package name";
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
index a49e203..3064afa 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
@@ -37,7 +37,6 @@
 import android.os.Build;
 import android.os.LocaleList;
 import android.os.Parcel;
-import android.platform.test.annotations.Presubmit;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
@@ -54,7 +53,6 @@
 import java.util.Objects;
 
 @SmallTest
-@Presubmit
 @RunWith(AndroidJUnit4.class)
 public class InputMethodUtilsTest {
     private static final boolean IS_AUX = true;
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java
index 1269ffd..549511a 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java
@@ -19,7 +19,6 @@
 import static org.junit.Assert.assertEquals;
 
 import android.os.LocaleList;
-import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
@@ -30,7 +29,6 @@
 import java.util.Locale;
 
 @SmallTest
-@Presubmit
 @RunWith(AndroidJUnit4.class)
 public class LocaleUtilsTest {
 
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index be7d663..569de76 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -40,7 +40,6 @@
 }
 
 DeferredLayerUpdater::~DeferredLayerUpdater() {
-    SkSafeUnref(mColorFilter);
     setTransform(nullptr);
     mRenderState.unregisterDeferredLayerUpdater(this);
     destroyLayer();
@@ -67,8 +66,11 @@
 void DeferredLayerUpdater::setPaint(const SkPaint* paint) {
     mAlpha = PaintUtils::getAlphaDirect(paint);
     mMode = PaintUtils::getBlendModeDirect(paint);
-    SkColorFilter* colorFilter = (paint) ? paint->getColorFilter() : nullptr;
-    SkRefCnt_SafeAssign(mColorFilter, colorFilter);
+    if (paint) {
+        mColorFilter = paint->refColorFilter();
+    } else {
+        mColorFilter.reset();
+    }
 }
 
 void DeferredLayerUpdater::apply() {
@@ -143,7 +145,7 @@
 #endif
         mSurfaceTexture->getTransformMatrix(transform);
 
-        updateLayer(forceFilter, transform);
+        updateLayer(forceFilter, transform, mSurfaceTexture->getCurrentDataSpace());
     }
 }
 
@@ -153,17 +155,19 @@
                         Layer::Api::OpenGL, Layer::Api::Vulkan);
 
     static const mat4 identityMatrix;
-    updateLayer(false, identityMatrix.data);
+    updateLayer(false, identityMatrix.data, HAL_DATASPACE_UNKNOWN);
 
     VkLayer* vkLayer = static_cast<VkLayer*>(mLayer);
     vkLayer->updateTexture();
 }
 
-void DeferredLayerUpdater::updateLayer(bool forceFilter, const float* textureTransform) {
+void DeferredLayerUpdater::updateLayer(bool forceFilter, const float* textureTransform,
+                                       android_dataspace dataspace) {
     mLayer->setBlend(mBlend);
     mLayer->setForceFilter(forceFilter);
     mLayer->setSize(mWidth, mHeight);
     mLayer->getTexTransform().load(textureTransform);
+    mLayer->setDataSpace(dataspace);
 }
 
 void DeferredLayerUpdater::detachSurfaceTexture() {
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 9dc029f..fe3ee7a 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -20,6 +20,7 @@
 #include <SkMatrix.h>
 #include <cutils/compiler.h>
 #include <gui/GLConsumer.h>
+#include <system/graphics.h>
 #include <utils/StrongPointer.h>
 
 #include <GLES2/gl2.h>
@@ -41,7 +42,7 @@
     // Note that DeferredLayerUpdater assumes it is taking ownership of the layer
     // and will not call incrementRef on it as a result.
     typedef std::function<Layer*(RenderState& renderState, uint32_t layerWidth,
-                                 uint32_t layerHeight, SkColorFilter* colorFilter, int alpha,
+                                 uint32_t layerHeight, sk_sp<SkColorFilter> colorFilter, int alpha,
                                  SkBlendMode mode, bool blend)>
             CreateLayerFn;
     ANDROID_API explicit DeferredLayerUpdater(RenderState& renderState, CreateLayerFn createLayerFn,
@@ -96,7 +97,7 @@
 
     void detachSurfaceTexture();
 
-    void updateLayer(bool forceFilter, const float* textureTransform);
+    void updateLayer(bool forceFilter, const float* textureTransform, android_dataspace dataspace);
 
     void destroyLayer();
 
@@ -109,7 +110,7 @@
     int mWidth = 0;
     int mHeight = 0;
     bool mBlend = false;
-    SkColorFilter* mColorFilter = nullptr;
+    sk_sp<SkColorFilter> mColorFilter;
     int mAlpha = 255;
     SkBlendMode mMode = SkBlendMode::kSrcOver;
     sp<GLConsumer> mSurfaceTexture;
diff --git a/libs/hwui/GlLayer.cpp b/libs/hwui/GlLayer.cpp
index 32a3014..42ae29d 100644
--- a/libs/hwui/GlLayer.cpp
+++ b/libs/hwui/GlLayer.cpp
@@ -32,7 +32,7 @@
 namespace uirenderer {
 
 GlLayer::GlLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
-                 SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend)
+                 sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode, bool blend)
         : Layer(renderState, Api::OpenGL, colorFilter, alpha, mode)
         , caches(Caches::getInstance())
         , texture(caches) {
diff --git a/libs/hwui/GlLayer.h b/libs/hwui/GlLayer.h
index 1b09191..28749a0 100644
--- a/libs/hwui/GlLayer.h
+++ b/libs/hwui/GlLayer.h
@@ -32,7 +32,7 @@
 class GlLayer : public Layer {
 public:
     GlLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
-            SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend);
+            sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode, bool blend);
     virtual ~GlLayer();
 
     uint32_t getWidth() const override { return texture.mWidth; }
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 86950d5..fb8f033 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -18,34 +18,58 @@
 
 #include "renderstate/RenderState.h"
 
-#include <SkColorFilter.h>
+#include <SkToSRGBColorFilter.h>
 
 namespace android {
 namespace uirenderer {
 
-Layer::Layer(RenderState& renderState, Api api, SkColorFilter* colorFilter, int alpha,
+Layer::Layer(RenderState& renderState, Api api, sk_sp<SkColorFilter> colorFilter, int alpha,
              SkBlendMode mode)
         : GpuMemoryTracker(GpuObjectType::Layer)
         , mRenderState(renderState)
         , mApi(api)
-        , colorFilter(nullptr)
+        , mColorFilter(colorFilter)
         , alpha(alpha)
         , mode(mode) {
     // TODO: This is a violation of Android's typical ref counting, but it
     // preserves the old inc/dec ref locations. This should be changed...
     incStrong(nullptr);
-
+    buildColorSpaceWithFilter();
     renderState.registerLayer(this);
 }
 
 Layer::~Layer() {
-    SkSafeUnref(colorFilter);
-
     mRenderState.unregisterLayer(this);
 }
 
-void Layer::setColorFilter(SkColorFilter* filter) {
-    SkRefCnt_SafeAssign(colorFilter, filter);
+void Layer::setColorFilter(sk_sp<SkColorFilter> filter) {
+    if (filter != mColorFilter) {
+        mColorFilter = filter;
+        buildColorSpaceWithFilter();
+    }
+}
+
+void Layer::setDataSpace(android_dataspace dataspace) {
+    if (dataspace != mCurrentDataspace) {
+        mCurrentDataspace = dataspace;
+        buildColorSpaceWithFilter();
+    }
+}
+
+void Layer::buildColorSpaceWithFilter() {
+    sk_sp<SkColorFilter> colorSpaceFilter;
+    sk_sp<SkColorSpace> colorSpace = DataSpaceToColorSpace(mCurrentDataspace);
+    if (colorSpace && !colorSpace->isSRGB()) {
+        colorSpaceFilter = SkToSRGBColorFilter::Make(colorSpace);
+    }
+
+    if (mColorFilter && colorSpaceFilter) {
+        mColorSpaceWithFilter = mColorFilter->makeComposed(colorSpaceFilter);
+    } else if (colorSpaceFilter) {
+        mColorSpaceWithFilter = colorSpaceFilter;
+    } else {
+        mColorSpaceWithFilter = mColorFilter;
+    }
 }
 
 void Layer::postDecStrong() {
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 6921381..89bcddc 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -19,6 +19,8 @@
 #include <GpuMemoryTracker.h>
 #include <utils/RefBase.h>
 
+#include <SkColorFilter.h>
+#include <SkColorSpace.h>
 #include <SkBlendMode.h>
 #include <SkPaint.h>
 
@@ -72,9 +74,15 @@
 
     inline SkBlendMode getMode() const { return mode; }
 
-    inline SkColorFilter* getColorFilter() const { return colorFilter; }
+    inline SkColorFilter* getColorFilter() const { return mColorFilter.get(); }
 
-    void setColorFilter(SkColorFilter* filter);
+    void setColorFilter(sk_sp<SkColorFilter> filter);
+
+    void setDataSpace(android_dataspace dataspace);
+
+    void setColorSpace(sk_sp<SkColorSpace> colorSpace);
+
+    inline sk_sp<SkColorFilter> getColorSpaceWithFilter() const { return mColorSpaceWithFilter; }
 
     inline mat4& getTexTransform() { return texTransform; }
 
@@ -87,18 +95,30 @@
     void postDecStrong();
 
 protected:
-    Layer(RenderState& renderState, Api api, SkColorFilter* colorFilter, int alpha,
+    Layer(RenderState& renderState, Api api, sk_sp<SkColorFilter>, int alpha,
           SkBlendMode mode);
 
     RenderState& mRenderState;
 
 private:
+    void buildColorSpaceWithFilter();
+
     Api mApi;
 
     /**
      * Color filter used to draw this layer. Optional.
      */
-    SkColorFilter* colorFilter;
+    sk_sp<SkColorFilter> mColorFilter;
+
+    /**
+     * Colorspace of the contents of the layer. Optional.
+     */
+    android_dataspace mCurrentDataspace = HAL_DATASPACE_UNKNOWN;
+
+    /**
+     * A color filter that is the combination of the mColorFilter and mColorSpace. Optional.
+     */
+    sk_sp<SkColorFilter> mColorSpaceWithFilter;
 
     /**
      * Indicates raster data backing the layer is scaled, requiring filtration.
diff --git a/libs/hwui/VkLayer.h b/libs/hwui/VkLayer.h
index f23f472..e9664d0 100644
--- a/libs/hwui/VkLayer.h
+++ b/libs/hwui/VkLayer.h
@@ -28,7 +28,7 @@
 class VkLayer : public Layer {
 public:
     VkLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
-            SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend)
+            sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode, bool blend)
             : Layer(renderState, Api::Vulkan, colorFilter, alpha, mode)
             , mWidth(layerWidth)
             , mHeight(layerHeight)
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index 896c01c..00ba7130 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -50,9 +50,13 @@
         GlLayer* glLayer = static_cast<GlLayer*>(layer);
         GrGLTextureInfo externalTexture;
         externalTexture.fTarget = glLayer->getRenderTarget();
-        SkASSERT(GL_RGBA == glLayer->getTexture().internalFormat());
-        externalTexture.fFormat = GL_RGBA8;
         externalTexture.fID = glLayer->getTextureId();
+        // The format may not be GL_RGBA8, but given the DeferredLayerUpdater and GLConsumer don't
+        // expose that info we use it as our default.  Further, given that we only use this texture
+        // as a source this will not impact how Skia uses the texture.  The only potential affect
+        // this is anticipated to have is that for some format types if we are not bound as an OES
+        // texture we may get invalid results for SKP capture if we read back the texture.
+        externalTexture.fFormat = GL_RGBA8;
         GrBackendTexture backendTexture(layerWidth, layerHeight, GrMipMapped::kNo, externalTexture);
         layerImage = SkImage::MakeFromTexture(context, backendTexture, kTopLeft_GrSurfaceOrigin,
                                               kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr);
@@ -83,7 +87,7 @@
         SkPaint paint;
         paint.setAlpha(layer->getAlpha());
         paint.setBlendMode(layer->getMode());
-        paint.setColorFilter(sk_ref_sp(layer->getColorFilter()));
+        paint.setColorFilter(layer->getColorSpaceWithFilter());
 
         const bool nonIdentityMatrix = !matrix.isIdentity();
         if (nonIdentityMatrix) {
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 5b2adbf..cfcfd2b 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -158,7 +158,7 @@
 }
 
 static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
-                          SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
+                          sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode, bool blend) {
     GlLayer* layer =
             new GlLayer(renderState, layerWidth, layerHeight, colorFilter, alpha, mode, blend);
     layer->generateTexture();
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 9e73046..d66cba1 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -147,6 +147,7 @@
             GrContext* currentContext = layerNode->getLayerSurface()->getCanvas()->getGrContext();
             if (cachedContext.get() != currentContext) {
                 if (cachedContext.get()) {
+                    ATRACE_NAME("flush layers (context changed)");
                     cachedContext->flush();
                 }
                 cachedContext.reset(SkSafeRef(currentContext));
@@ -155,6 +156,7 @@
     }
 
     if (cachedContext.get()) {
+        ATRACE_NAME("flush layers");
         cachedContext->flush();
     }
 }
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 6530074..5825060 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -115,7 +115,8 @@
 }
 
 static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
-                          SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
+                          sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode,
+                          bool blend) {
     return new VkLayer(renderState, layerWidth, layerHeight, colorFilter, alpha, mode, blend);
 }
 
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index b2fccd4..a7ac930 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -72,7 +72,7 @@
     layerUpdater->setTransform(&transform);
 
     // updateLayer so it's ready to draw
-    layerUpdater->updateLayer(true, Matrix4::identity().data);
+    layerUpdater->updateLayer(true, Matrix4::identity().data, HAL_DATASPACE_UNKNOWN);
     if (layerUpdater->backingLayer()->getApi() == Layer::Api::OpenGL) {
         static_cast<GlLayer*>(layerUpdater->backingLayer())
                 ->setRenderTarget(GL_TEXTURE_EXTERNAL_OES);
diff --git a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
index b8b5050..f29830f 100644
--- a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
+++ b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
@@ -44,7 +44,7 @@
     // push the deferred updates to the layer
     Matrix4 scaledMatrix;
     scaledMatrix.loadScale(0.5, 0.5, 0.0);
-    layerUpdater->updateLayer(true, scaledMatrix.data);
+    layerUpdater->updateLayer(true, scaledMatrix.data, HAL_DATASPACE_UNKNOWN);
     if (layerUpdater->backingLayer()->getApi() == Layer::Api::OpenGL) {
         GlLayer* glLayer = static_cast<GlLayer*>(layerUpdater->backingLayer());
         glLayer->setRenderTarget(GL_TEXTURE_EXTERNAL_OES);
diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp
index c2af867..75740e8 100644
--- a/libs/hwui/utils/Color.cpp
+++ b/libs/hwui/utils/Color.cpp
@@ -16,6 +16,8 @@
 
 #include "Color.h"
 
+
+#include <utils/Log.h>
 #include <cmath>
 
 namespace android {
@@ -53,5 +55,57 @@
     return false;
 }
 
+sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) {
+
+    SkColorSpace::Gamut gamut;
+    switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
+        case HAL_DATASPACE_STANDARD_BT709:
+            gamut = SkColorSpace::kSRGB_Gamut;
+            break;
+        case HAL_DATASPACE_STANDARD_BT2020:
+            gamut = SkColorSpace::kRec2020_Gamut;
+            break;
+        case HAL_DATASPACE_STANDARD_DCI_P3:
+            gamut = SkColorSpace::kDCIP3_D65_Gamut;
+            break;
+        case HAL_DATASPACE_STANDARD_ADOBE_RGB:
+            gamut = SkColorSpace::kAdobeRGB_Gamut;
+            break;
+        case HAL_DATASPACE_STANDARD_UNSPECIFIED:
+            return nullptr;
+        case HAL_DATASPACE_STANDARD_BT601_625:
+        case HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED:
+        case HAL_DATASPACE_STANDARD_BT601_525:
+        case HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED:
+        case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE:
+        case HAL_DATASPACE_STANDARD_BT470M:
+        case HAL_DATASPACE_STANDARD_FILM:
+        default:
+            ALOGW("Unsupported Gamut: %d", dataspace);
+            return nullptr;
+    }
+
+    switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) {
+        case HAL_DATASPACE_TRANSFER_LINEAR:
+            return SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma, gamut);
+        case HAL_DATASPACE_TRANSFER_SRGB:
+            return SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, gamut);
+        case HAL_DATASPACE_TRANSFER_GAMMA2_2:
+            return SkColorSpace::MakeRGB({2.2f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
+        case HAL_DATASPACE_TRANSFER_GAMMA2_6:
+            return SkColorSpace::MakeRGB({2.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
+        case HAL_DATASPACE_TRANSFER_GAMMA2_8:
+            return SkColorSpace::MakeRGB({2.8f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
+        case HAL_DATASPACE_TRANSFER_UNSPECIFIED:
+            return nullptr;
+        case HAL_DATASPACE_TRANSFER_SMPTE_170M:
+        case HAL_DATASPACE_TRANSFER_ST2084:
+        case HAL_DATASPACE_TRANSFER_HLG:
+        default:
+            ALOGW("Unsupported Gamma: %d", dataspace);
+            return nullptr;
+    }
+}
+
 };  // namespace uirenderer
 };  // namespace android
diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h
index 7ac0d96..2bec1f5 100644
--- a/libs/hwui/utils/Color.h
+++ b/libs/hwui/utils/Color.h
@@ -17,6 +17,7 @@
 #define COLOR_H
 
 #include <math.h>
+#include <system/graphics.h>
 
 #include <SkColor.h>
 #include <SkColorSpace.h>
@@ -111,6 +112,8 @@
 // approximated with the native sRGB transfer function. This method
 // returns true for sRGB, gamma 2.2 and Display P3 for instance
 bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace);
+
+sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace);
 } /* namespace uirenderer */
 } /* namespace android */
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
index 07b980e..ed2f831 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
@@ -26,6 +26,10 @@
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
+
 import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
 import com.android.systemui.shared.recents.view.RecentsTransition;
 
@@ -58,6 +62,11 @@
     public static final int TRANSIT_KEYGUARD_OCCLUDE = WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
     public static final int TRANSIT_KEYGUARD_UNOCCLUDE = WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
 
+    public static final int NAV_BAR_POS_INVALID = -1;
+    public static final int NAV_BAR_POS_LEFT = NAV_BAR_LEFT;
+    public static final int NAV_BAR_POS_RIGHT = NAV_BAR_RIGHT;
+    public static final int NAV_BAR_POS_BOTTOM = NAV_BAR_BOTTOM;
+
     public static final int ACTIVITY_TYPE_STANDARD = WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 
     public static final int WINDOWING_MODE_UNDEFINED = WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -141,4 +150,20 @@
             Log.w(TAG, "Failed to set recents visibility");
         }
     }
+
+    /**
+     * @return The side of the screen where navigation bar is positioned.
+     * @see #NAV_BAR_POS_RIGHT
+     * @see #NAV_BAR_POS_LEFT
+     * @see #NAV_BAR_POS_BOTTOM
+     * @see #NAV_BAR_POS_INVALID
+     */
+    public int getNavBarPosition() {
+        try {
+            return WindowManagerGlobal.getWindowManagerService().getNavBarPosition();
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to get nav bar position");
+        }
+        return NAV_BAR_POS_INVALID;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 1149ad1..79fea9f 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -21,6 +21,8 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.view.PointerIcon.TYPE_HORIZONTAL_DOUBLE_ARROW;
 import static android.view.PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW;
+import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_RIGHT;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -364,14 +366,7 @@
         if (mStableInsets.isEmpty()) {
             SystemServicesProxy.getInstance(mContext).getStableInsets(mStableInsets);
         }
-        int position = (int) (mState.mRatioPositionBeforeMinimized *
-                (isHorizontalDivision() ? mDisplayHeight : mDisplayWidth));
-        mSnapAlgorithm = null;
-        initializeSnapAlgorithm();
-
-        // Set the snap target before minimized but do not save until divider is attached and not
-        // minimized because it does not know its minimized state yet.
-        mSnapTargetBeforeMinimized = mSnapAlgorithm.calculateNonDismissingSnapTarget(position);
+        repositionSnapTargetBeforeMinimized();
     }
 
     public WindowManagerProxy getWindowManagerProxy() {
@@ -878,9 +873,36 @@
     }
 
     public void notifyDockSideChanged(int newDockSide) {
+        int oldDockSide = mDockSide;
         mDockSide = newDockSide;
         mMinimizedShadow.setDockSide(mDockSide);
         requestLayout();
+
+        // Update the snap position to the new docked side with correct insets
+        SystemServicesProxy.getInstance(mContext).getStableInsets(mStableInsets);
+        mMinimizedSnapAlgorithm = null;
+        initializeSnapAlgorithm();
+
+        if (oldDockSide == DOCKED_LEFT && mDockSide == DOCKED_RIGHT
+                || oldDockSide == DOCKED_RIGHT && mDockSide == DOCKED_LEFT) {
+            repositionSnapTargetBeforeMinimized();
+        }
+
+        // Landscape to seascape rotation requires minimized to resize docked app correctly
+        if (mHomeStackResizable && mDockedStackMinimized) {
+            resizeStack(mMinimizedSnapAlgorithm.getMiddleTarget());
+        }
+    }
+
+    private void repositionSnapTargetBeforeMinimized() {
+        int position = (int) (mState.mRatioPositionBeforeMinimized *
+                (isHorizontalDivision() ? mDisplayHeight : mDisplayWidth));
+        mSnapAlgorithm = null;
+        initializeSnapAlgorithm();
+
+        // Set the snap target before minimized but do not save until divider is attached and not
+        // minimized because it does not know its minimized state yet.
+        mSnapTargetBeforeMinimized = mSnapAlgorithm.calculateNonDismissingSnapTarget(position);
     }
 
     private void updateDisplayInfo() {
@@ -962,6 +984,12 @@
         if (mHomeStackResizable && mIsInMinimizeInteraction) {
             calculateBoundsForPosition(mSnapTargetBeforeMinimized.position, mDockSide,
                     mDockedTaskRect);
+
+            // Move a right-docked-app to line up with the divider while dragging it
+            if (mDockSide == DOCKED_RIGHT) {
+                mDockedTaskRect.offset(Math.max(position, mStableInsets.left - mDividerSize)
+                        - mDockedTaskRect.left + mDividerSize, 0);
+            }
             calculateBoundsForPosition(mSnapTargetBeforeMinimized.position,
                     DockedDividerUtils.invertDockSide(mDockSide), mOtherTaskRect);
             mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, mDockedTaskRect,
@@ -976,6 +1004,12 @@
                 calculateBoundsForPosition(isHorizontalDivision() ? mDisplayHeight : mDisplayWidth,
                         mDockSide, mDockedTaskRect);
             }
+
+            // Move a docked app if from the right in position with the divider up to insets
+            if (mDockSide == DOCKED_RIGHT) {
+                mDockedTaskRect.offset(Math.max(position,
+                        mStableInsets.left) - mDockedTaskRect.left, 0);
+            }
             calculateBoundsForPosition(taskPosition, DockedDividerUtils.invertDockSide(mDockSide),
                     mOtherTaskRect);
             mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, null,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 1d64088..ff0adb6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -24,6 +24,8 @@
 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
+import static com.android.systemui.shared.system.WindowManagerWrapper.NAV_BAR_POS_LEFT;
+import static com.android.systemui.shared.system.WindowManagerWrapper.NAV_BAR_POS_INVALID;
 import static com.android.systemui.statusbar.NotificationLockscreenUserManager
         .NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION;
 import static com.android.systemui.statusbar.NotificationLockscreenUserManager.PERMISSION_SELF;
@@ -178,6 +180,7 @@
 import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent;
 import com.android.systemui.recents.events.activity.UndockingTaskEvent;
 import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.shared.system.WindowManagerWrapper;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.stackdivider.WindowManagerProxy;
 import com.android.systemui.statusbar.ActivatableNotificationView;
@@ -207,14 +210,12 @@
 import com.android.systemui.statusbar.NotificationViewHierarchyManager;
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.ScrimView;
-import com.android.systemui.statusbar.SignalClusterView;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.notification.AboveShelfObserver;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
-import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
 import com.android.systemui.statusbar.policy.BrightnessMirrorController;
@@ -1339,8 +1340,15 @@
         }
         int dockSide = WindowManagerProxy.getInstance().getDockSide();
         if (dockSide == WindowManager.DOCKED_INVALID) {
-            return mRecents.splitPrimaryTask(NavigationBarGestureHelper.DRAG_MODE_NONE,
-                    ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, null, metricsDockAction);
+            final int navbarPos = WindowManagerWrapper.getInstance().getNavBarPosition();
+            if (navbarPos == NAV_BAR_POS_INVALID) {
+                return false;
+            }
+            int createMode = navbarPos == NAV_BAR_POS_LEFT
+                    ? ActivityManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT
+                    : ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
+            return mRecents.splitPrimaryTask(NavigationBarGestureHelper.DRAG_MODE_NONE, createMode,
+                    null, metricsDockAction);
         } else {
             Divider divider = getComponent(Divider.class);
             if (divider != null && divider.isMinimized() && !divider.isHomeStackResizable()) {
@@ -1896,6 +1904,13 @@
             }
         }
 
+        if (!panelsEnabled()) {
+            if (DEBUG) {
+                Log.d(TAG, "No peeking: disabled panel : " + sbn.getKey());
+            }
+            return false;
+        }
+
         if (sbn.getNotification().fullScreenIntent != null) {
             if (mAccessibilityManager.isTouchExplorationEnabled()) {
                 if (DEBUG) Log.d(TAG, "No peeking: accessible fullscreen: " + sbn.getKey());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index d3cb5a6..37e0005 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -443,6 +443,30 @@
     }
 
     @Test
+    public void testPeek_disabledStatusBar() {
+        Notification n = new Notification.Builder(getContext(), "a").build();
+        StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
+                UserHandle.of(0), null, 0);
+        NotificationData.Entry entry = new NotificationData.Entry(sbn);
+        mStatusBar.disable(StatusBarManager.DISABLE_EXPAND, 0, false /* animate */);
+
+        assertFalse("The panel shouldn't allow peek while disabled",
+                mStatusBar.shouldPeek(entry, sbn));
+    }
+
+    @Test
+    public void testPeek_disabledNotificationShade() {
+        Notification n = new Notification.Builder(getContext(), "a").build();
+        StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
+                UserHandle.of(0), null, 0);
+        NotificationData.Entry entry = new NotificationData.Entry(sbn);
+        mStatusBar.disable(0, StatusBarManager.DISABLE2_NOTIFICATION_SHADE, false /* animate */);
+
+        assertFalse("The panel shouldn't allow peek while notitifcation shade disabled",
+                mStatusBar.shouldPeek(entry, sbn));
+    }
+
+    @Test
     public void testLogHidden() {
         try {
             mStatusBar.handleVisibleToUserChanged(false);
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index 2465ba2..d869734 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -33,10 +33,11 @@
 # It logs the time remaining before the device would've normally gone to sleep without the request.
 2731 power_soft_sleep_requested (savedwaketimems|2)
 # Power save state has changed. See BatterySaverController.java for the details.
-2739 battery_saver_mode (prevOffOrOn|1|5),(nowOffOrOn|1|5),(interactive|1|5),(features|3|5)
+2739 battery_saver_mode (prevOffOrOn|1|5),(nowOffOrOn|1|5),(interactive|1|5),(features|3|5),(reason|1|5)
 27390 battery_saving_stats (batterySaver|1|5),(interactive|1|5),(doze|1|5),(delta_duration|2|3),(delta_battery_drain|1|1),(delta_battery_drain_percent|1|6),(total_duration|2|3),(total_battery_drain|1|1),(total_battery_drain_percent|1|6)
 # Note when the user activity timeout has been overriden by ActivityManagerService
 27391 user_activity_timeout_override (override|2|3)
+27392 battery_saver_setting (threshold|1)
 
 #
 # Leave IDs through 2740 for more power logs (2730 used by battery_discharge above)
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index e840a29..03d8f39 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -1279,7 +1279,9 @@
                 case Process.SYSTEM_UID:
                     break; // Okay
                 default:
-                    throw new SecurityException("Invalid extras specified.");
+                    final String msg = "Invalid extras specified.";
+                    Log.w(TAG, msg + " requestsync -f/-F needs to run on 'adb shell'");
+                    throw new SecurityException(msg);
             }
         }
     }
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index f403953..0425844 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -316,7 +316,7 @@
         return true;
     }
 
-    private void resetShortTermModel() {
+    public void resetShortTermModel() {
         mBrightnessMapper.clearUserDataPoints();
         mShortTermModelValid = true;
         mShortTermModelAnchor = -1;
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 46e883c..3b35d02 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -774,14 +774,8 @@
             brightness = mScreenBrightnessForVr;
         }
 
-        boolean setBrightnessToOverride = false;
         if (brightness < 0 && mPowerRequest.screenBrightnessOverride > 0) {
             brightness = mPowerRequest.screenBrightnessOverride;
-            // If there's a screen brightness override, we want to reset the brightness to it
-            // whenever the user changes it, to communicate that these changes aren't taking
-            // effect. However, for a nicer user experience, we don't do it here, but rather after
-            // the temporary brightness has been taken into account.
-            setBrightnessToOverride = true;
         }
 
         final boolean autoBrightnessEnabledInDoze =
@@ -804,12 +798,6 @@
             brightnessIsTemporary = true;
         }
 
-        // Reset the brightness to the screen brightness override to communicate to the user that
-        // her changes aren't taking effect.
-        if (setBrightnessToOverride && !brightnessIsTemporary) {
-            putScreenBrightnessSetting(brightness);
-        }
-
         final boolean autoBrightnessAdjustmentChanged = updateAutoBrightnessAdjustment();
         if (autoBrightnessAdjustmentChanged) {
             mTemporaryAutoBrightnessAdjustment = Float.NaN;
@@ -1452,6 +1440,9 @@
         if (userSwitch) {
             // Don't treat user switches as user initiated change.
             mCurrentScreenBrightnessSetting = mPendingScreenBrightnessSetting;
+            if (mAutomaticBrightnessController != null) {
+                mAutomaticBrightnessController.resetShortTermModel();
+            }
         }
         mPendingAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting();
         // We don't bother with a pending variable for VR screen brightness since we just
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index b3003ac..9af02a1 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -234,6 +234,7 @@
 import android.util.proto.ProtoOutputStream;
 import android.view.Display;
 import android.view.DisplayCutout;
+import android.view.DisplayInfo;
 import android.view.Gravity;
 import android.view.HapticFeedbackConstants;
 import android.view.IApplicationToken;
@@ -7191,14 +7192,35 @@
     }
 
     @Override
-    public boolean isDockSideAllowed(int dockSide) {
+    public boolean isDockSideAllowed(int dockSide, int originalDockSide, int displayWidth,
+            int displayHeight, int displayRotation) {
+        final int barPosition = navigationBarPosition(displayWidth, displayHeight, displayRotation);
+        return isDockSideAllowed(dockSide, originalDockSide, barPosition, mNavigationBarCanMove);
+    }
 
-        // We do not allow all dock sides at which the navigation bar touches the docked stack.
-        if (!mNavigationBarCanMove) {
-            return dockSide == DOCKED_TOP || dockSide == DOCKED_LEFT || dockSide == DOCKED_RIGHT;
-        } else {
-            return dockSide == DOCKED_TOP || dockSide == DOCKED_LEFT;
+    @VisibleForTesting
+    static boolean isDockSideAllowed(int dockSide, int originalDockSide,
+            int navBarPosition, boolean navigationBarCanMove) {
+        if (dockSide == DOCKED_TOP) {
+            return true;
         }
+
+        if (navigationBarCanMove) {
+            // Only allow the dockside opposite to the nav bar position in landscape
+            return dockSide == DOCKED_LEFT && navBarPosition == NAV_BAR_RIGHT
+                    || dockSide == DOCKED_RIGHT && navBarPosition == NAV_BAR_LEFT;
+        }
+
+        // Side is the same as original side
+        if (dockSide == originalDockSide) {
+            return true;
+        }
+
+        // Only if original docked side was top in portrait will allow left for landscape
+        if (dockSide == DOCKED_LEFT && originalDockSide == DOCKED_TOP) {
+            return true;
+        }
+        return false;
     }
 
     void sendCloseSystemWindows() {
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index ccbf502..8690a83 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -1706,11 +1706,19 @@
             DisplayCutout displayCutout, Rect outInsets);
 
     /**
+     * @param displayRotation the current display rotation
+     * @param displayWidth the current display width
+     * @param displayHeight the current display height
+     * @param dockSide the dockside asking if allowed
+     * @param originalDockSide the side that was original docked to in split screen
      * @return True if a specified {@param dockSide} is allowed on the current device, or false
      *         otherwise. It is guaranteed that at least one dock side for a particular orientation
      *         is allowed, so for example, if DOCKED_RIGHT is not allowed, DOCKED_LEFT is allowed.
+     *         If navigation bar is movable then the docked side would bias towards the
+     *         {@param originalDockSide}.
      */
-    public boolean isDockSideAllowed(int dockSide);
+    public boolean isDockSideAllowed(int dockSide, int originalDockSide, int displayWidth,
+            int displayHeight, int displayRotation);
 
     /**
      * Called when the configuration has changed, and it's safe to load new values from resources.
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 20283a7..a492672 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -719,13 +719,14 @@
      * Plays the wireless charging sound for both wireless and non-wireless charging
      */
     private void playChargingStartedSound() {
-        // TODO (b/77912907): add back charging sound enabled check & default to charging sounds ON
+        final boolean enabled = Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.CHARGING_SOUNDS_ENABLED, 1) != 0;
         final boolean dndOff = Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS)
                 == Settings.Global.ZEN_MODE_OFF;
         final String soundPath = Settings.Global.getString(mContext.getContentResolver(),
                 Settings.Global.CHARGING_STARTED_SOUND);
-        if (dndOff && soundPath != null) {
+        if (enabled && dndOff && soundPath != null) {
             final Uri soundUri = Uri.parse("file://" + soundPath);
             if (soundUri != null) {
                 final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
index c527533..cb84cf3 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
@@ -90,6 +90,16 @@
      */
     private final Plugin[] mPlugins;
 
+    public static final int REASON_AUTOMATIC_ON = 0;
+    public static final int REASON_AUTOMATIC_OFF = 1;
+    public static final int REASON_MANUAL_ON = 2;
+    public static final int REASON_MANUAL_OFF = 3;
+    public static final int REASON_STICKY_RESTORE = 4;
+    public static final int REASON_INTERACTIVE_CHANGED = 5;
+    public static final int REASON_POLICY_CHANGED = 6;
+    public static final int REASON_PLUGGED_IN = 7;
+    public static final int REASON_SETTING_CHANGED = 8;
+
     /**
      * Plugin interface. All methods are guaranteed to be called on the same (handler) thread.
      */
@@ -113,7 +123,8 @@
                         return; // No need to send it if not enabled.
                     }
                     // Don't send the broadcast, because we never did so in this case.
-                    mHandler.postStateChanged(/*sendBroadcast=*/ false);
+                    mHandler.postStateChanged(/*sendBroadcast=*/ false,
+                            REASON_INTERACTIVE_CHANGED);
                     break;
                 case Intent.ACTION_BATTERY_CHANGED:
                     synchronized (mLock) {
@@ -184,7 +195,7 @@
         if (!isEnabled()) {
             return; // No need to send it if not enabled.
         }
-        mHandler.postStateChanged(/*sendBroadcast=*/ true);
+        mHandler.postStateChanged(/*sendBroadcast=*/ true, REASON_POLICY_CHANGED);
     }
 
     private class MyHandler extends Handler {
@@ -199,9 +210,9 @@
             super(looper);
         }
 
-        public void postStateChanged(boolean sendBroadcast) {
+        public void postStateChanged(boolean sendBroadcast, int reason) {
             obtainMessage(MSG_STATE_CHANGED, sendBroadcast ?
-                    ARG_SEND_BROADCAST : ARG_DONT_SEND_BROADCAST, 0).sendToTarget();
+                    ARG_SEND_BROADCAST : ARG_DONT_SEND_BROADCAST, reason).sendToTarget();
         }
 
         public void postSystemReady() {
@@ -212,7 +223,9 @@
         public void dispatchMessage(Message msg) {
             switch (msg.what) {
                 case MSG_STATE_CHANGED:
-                    handleBatterySaverStateChanged(msg.arg1 == ARG_SEND_BROADCAST);
+                    handleBatterySaverStateChanged(
+                            msg.arg1 == ARG_SEND_BROADCAST,
+                            msg.arg2);
                     break;
 
                 case MSG_SYSTEM_READY:
@@ -227,14 +240,14 @@
     /**
      * Called by {@link PowerManagerService} to update the battery saver stete.
      */
-    public void enableBatterySaver(boolean enable) {
+    public void enableBatterySaver(boolean enable, int reason) {
         synchronized (mLock) {
             if (mEnabled == enable) {
                 return;
             }
             mEnabled = enable;
 
-            mHandler.postStateChanged(/*sendBroadcast=*/ true);
+            mHandler.postStateChanged(/*sendBroadcast=*/ true, reason);
         }
     }
 
@@ -275,7 +288,7 @@
      * - When battery saver is on the interactive state changes.
      * - When battery saver is on the battery saver policy changes.
      */
-    void handleBatterySaverStateChanged(boolean sendBroadcast) {
+    void handleBatterySaverStateChanged(boolean sendBroadcast, int reason) {
         final LowPowerModeListener[] listeners;
 
         final boolean enabled;
@@ -287,7 +300,8 @@
                     mPreviouslyEnabled ? 1 : 0, // Previously off or on.
                     mEnabled ? 1 : 0, // Now off or on.
                     isInteractive ?  1 : 0, // Device interactive state.
-                    mEnabled ? mBatterySaverPolicy.toEventLogString() : "");
+                    mEnabled ? mBatterySaverPolicy.toEventLogString() : "",
+                    reason);
             mPreviouslyEnabled = mEnabled;
 
             listeners = mListeners.toArray(new LowPowerModeListener[mListeners.size()]);
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
index 2860521..b9f31b1 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
@@ -18,6 +18,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.database.ContentObserver;
+import android.os.Handler;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.provider.Settings.Global;
@@ -27,6 +28,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.BackgroundThread;
+import com.android.server.EventLogTags;
 import com.android.server.power.BatterySaverPolicy;
 import com.android.server.power.BatterySaverStateMachineProto;
 
@@ -95,6 +97,18 @@
     @GuardedBy("mLock")
     private boolean mBatterySaverSnoozing;
 
+    /**
+     * Last reason passed to {@link #enableBatterySaverLocked}.
+     */
+    @GuardedBy("mLock")
+    private int mLastChangedIntReason;
+
+    /**
+     * Last reason passed to {@link #enableBatterySaverLocked}.
+     */
+    @GuardedBy("mLock")
+    private String mLastChangedStrReason;
+
     private final ContentObserver mSettingsObserver = new ContentObserver(null) {
         @Override
         public void onChange(boolean selfChange) {
@@ -149,11 +163,25 @@
         });
     }
 
+    /**
+     * Run a {@link Runnable} on a background handler.
+     */
     @VisibleForTesting
     void runOnBgThread(Runnable r) {
         BackgroundThread.getHandler().post(r);
     }
 
+    /**
+     * Run a {@link Runnable} on a background handler, but lazily. If the same {@link Runnable},
+     * it'll be first removed before a new one is posted.
+     */
+    @VisibleForTesting
+    void runOnBgThreadLazy(Runnable r, int delayMillis) {
+        final Handler h = BackgroundThread.getHandler();
+        h.removeCallbacks(r);
+        h.postDelayed(r, delayMillis);
+    }
+
     void refreshSettingsLocked() {
         final ContentResolver cr = mContext.getContentResolver();
 
@@ -199,14 +227,23 @@
         mSettingBatterySaverEnabledSticky = batterySaverEnabledSticky;
         mSettingBatterySaverTriggerThreshold = batterySaverTriggerThreshold;
 
+        if (thresholdChanged) {
+            // To avoid spamming the event log, we throttle logging here.
+            runOnBgThreadLazy(mThresholdChangeLogger, 2000);
+        }
+
         if (enabledChanged) {
             final String reason = batterySaverEnabled
                     ? "Global.low_power changed to 1" : "Global.low_power changed to 0";
             enableBatterySaverLocked(/*enable=*/ batterySaverEnabled, /*manual=*/ true,
-                    reason);
+                    BatterySaverController.REASON_SETTING_CHANGED, reason);
         }
     }
 
+    private final Runnable mThresholdChangeLogger = () -> {
+        EventLogTags.writeBatterySaverSetting(mSettingBatterySaverTriggerThreshold);
+    };
+
     /**
      * {@link com.android.server.power.PowerManagerService} calls it when battery state changes.
      *
@@ -257,18 +294,26 @@
         }
         if (mIsPowered) {
             updateSnoozingLocked(false, "Plugged in");
-            enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false, "Plugged in");
+            enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false,
+                    BatterySaverController.REASON_PLUGGED_IN,
+                    "Plugged in");
 
         } else if (mSettingBatterySaverEnabledSticky) {
             // Re-enable BS.
-            enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ true, "Sticky restore");
+            enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ true,
+                    BatterySaverController.REASON_STICKY_RESTORE,
+                    "Sticky restore");
 
         } else if (mIsBatteryLevelLow) {
             if (!mBatterySaverSnoozing && isAutoBatterySaverConfigured()) {
-                enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ false, "Auto ON");
+                enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ false,
+                        BatterySaverController.REASON_AUTOMATIC_ON,
+                        "Auto ON");
             }
         } else { // Battery not low
-            enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false, "Auto OFF");
+            enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false,
+                    BatterySaverController.REASON_AUTOMATIC_OFF,
+                    "Auto OFF");
         }
     }
 
@@ -284,6 +329,8 @@
         }
         synchronized (mLock) {
             enableBatterySaverLocked(/*enable=*/ enabled, /*manual=*/ true,
+                    (enabled ? BatterySaverController.REASON_MANUAL_ON
+                            : BatterySaverController.REASON_MANUAL_OFF),
                     (enabled ? "Manual ON" : "Manual OFF"));
         }
     }
@@ -292,10 +339,11 @@
      * Actually enable / disable battery saver. Write the new state to the global settings
      * and propagate it to {@link #mBatterySaverController}.
      */
-    private void enableBatterySaverLocked(boolean enable, boolean manual, String reason) {
+    private void enableBatterySaverLocked(boolean enable, boolean manual, int intReason,
+            String strReason) {
         if (DEBUG) {
             Slog.d(TAG, "enableBatterySaver: enable=" + enable + " manual=" + manual
-                    + " reason=" + reason);
+                    + " reason=" + strReason + "(" + intReason + ")");
         }
         final boolean wasEnabled = mBatterySaverController.isEnabled();
 
@@ -309,6 +357,8 @@
             if (DEBUG) Slog.d(TAG, "Can't enable: isPowered");
             return;
         }
+        mLastChangedIntReason = intReason;
+        mLastChangedStrReason = strReason;
 
         if (manual) {
             if (enable) {
@@ -330,12 +380,12 @@
             mSettingBatterySaverEnabledSticky = enable;
             putGlobalSetting(Global.LOW_POWER_MODE_STICKY, enable ? 1 : 0);
         }
-        mBatterySaverController.enableBatterySaver(enable);
+        mBatterySaverController.enableBatterySaver(enable, intReason);
 
         if (DEBUG) {
             Slog.d(TAG, "Battery saver: Enabled=" + enable
                     + " manual=" + manual
-                    + " reason=" + reason);
+                    + " reason=" + strReason + "(" + intReason + ")");
         }
     }
 
@@ -365,6 +415,11 @@
             pw.print("  Enabled=");
             pw.println(mBatterySaverController.isEnabled());
 
+            pw.print("  mLastChangedIntReason=");
+            pw.println(mLastChangedIntReason);
+            pw.print("  mLastChangedStrReason=");
+            pw.println(mLastChangedStrReason);
+
             pw.print("  mBootCompleted=");
             pw.println(mBootCompleted);
             pw.print("  mSettingsLoaded=");
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 2cd2ef1..c8baced 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -170,7 +170,7 @@
             final int orientation = mTmpRect2.width() <= mTmpRect2.height()
                     ? ORIENTATION_PORTRAIT
                     : ORIENTATION_LANDSCAPE;
-            final int dockSide = TaskStack.getDockSideUnchecked(mTmpRect, mTmpRect2, orientation);
+            final int dockSide = getDockSide(mTmpRect, mTmpRect2, orientation);
             final int position = DockedDividerUtils.calculatePositionForBounds(mTmpRect, dockSide,
                     getContentWidth());
 
@@ -191,6 +191,39 @@
         return (int) (minWidth / mDisplayContent.getDisplayMetrics().density);
     }
 
+    /**
+     * Get the current docked side. Determined by its location of {@param bounds} within
+     * {@param displayRect} but if both are the same, it will try to dock to each side and determine
+     * if allowed in its respected {@param orientation}.
+     *
+     * @param bounds bounds of the docked task to get which side is docked
+     * @param displayRect bounds of the display that contains the docked task
+     * @param orientation the origination of device
+     * @return current docked side
+     */
+    int getDockSide(Rect bounds, Rect displayRect, int orientation) {
+        if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+            // Portrait mode, docked either at the top or the bottom.
+            final int diff = (displayRect.bottom - bounds.bottom) - (bounds.top - displayRect.top);
+            if (diff > 0) {
+                return DOCKED_TOP;
+            } else if (diff < 0) {
+                return DOCKED_BOTTOM;
+            }
+            return canPrimaryStackDockTo(DOCKED_TOP) ? DOCKED_TOP : DOCKED_BOTTOM;
+        } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
+            // Landscape mode, docked either on the left or on the right.
+            final int diff = (displayRect.right - bounds.right) - (bounds.left - displayRect.left);
+            if (diff > 0) {
+                return DOCKED_LEFT;
+            } else if (diff < 0) {
+                return DOCKED_RIGHT;
+            }
+            return canPrimaryStackDockTo(DOCKED_LEFT) ? DOCKED_LEFT : DOCKED_RIGHT;
+        }
+        return DOCKED_INVALID;
+    }
+
     void getHomeStackBoundsInDockedMode(Rect outBounds) {
         final DisplayInfo di = mDisplayContent.getDisplayInfo();
         mService.mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
@@ -203,10 +236,20 @@
             outBounds.set(0, mTaskHeightInMinimizedMode + dividerSize + mTmpRect.top,
                     di.logicalWidth, di.logicalHeight);
         } else {
-            // In landscape append the left position with the statusbar height to match the
+            // In landscape also inset the left/right side with the statusbar height to match the
             // minimized size height in portrait mode.
-            outBounds.set(mTaskHeightInMinimizedMode + dividerSize + mTmpRect.left + mTmpRect.top,
-                    0, di.logicalWidth, di.logicalHeight);
+            final TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
+            final int primaryTaskWidth = mTaskHeightInMinimizedMode + dividerSize + mTmpRect.top;
+            int left = mTmpRect.left;
+            int right = di.logicalWidth - mTmpRect.right;
+            if (stack != null) {
+                if (stack.getDockSide() == DOCKED_LEFT) {
+                    left += primaryTaskWidth;
+                } else if (stack.getDockSide() == DOCKED_RIGHT) {
+                    right -= primaryTaskWidth;
+                }
+            }
+            outBounds.set(left, 0, right, di.logicalHeight);
         }
     }
 
@@ -420,21 +463,9 @@
      * @return true if the side provided is valid
      */
     boolean canPrimaryStackDockTo(int dockSide) {
-        if (mService.mPolicy.isDockSideAllowed(dockSide)) {
-            // Side is the same as original side
-            if (dockSide == mOriginalDockedSide) {
-                return true;
-            }
-            // Special rule that the top in portrait is always valid
-            if (dockSide == DOCKED_TOP) {
-                return true;
-            }
-            // Only if original docked side was top in portrait will allow left side for landscape
-            if (dockSide == DOCKED_LEFT && mOriginalDockedSide == DOCKED_TOP) {
-                return true;
-            }
-        }
-        return false;
+        final DisplayInfo di = mDisplayContent.getDisplayInfo();
+        return mService.mPolicy.isDockSideAllowed(dockSide, mOriginalDockedSide, di.logicalWidth,
+                di.logicalHeight, di.rotation);
     }
 
     void notifyDockedStackExistsChanged(boolean exists) {
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 018765d..891ee2e 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -1462,27 +1462,7 @@
         }
         dc.getBounds(mTmpRect);
         final int orientation = dc.getConfiguration().orientation;
-        return getDockSideUnchecked(bounds, mTmpRect, orientation);
-    }
-
-    static int getDockSideUnchecked(Rect bounds, Rect displayRect, int orientation) {
-        if (orientation == Configuration.ORIENTATION_PORTRAIT) {
-            // Portrait mode, docked either at the top or the bottom.
-            if (bounds.top - displayRect.top <= displayRect.bottom - bounds.bottom) {
-                return DOCKED_TOP;
-            } else {
-                return DOCKED_BOTTOM;
-            }
-        } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
-            // Landscape mode, docked either on the left or on the right.
-            if (bounds.left - displayRect.left <= displayRect.right - bounds.right) {
-                return DOCKED_LEFT;
-            } else {
-                return DOCKED_RIGHT;
-            }
-        } else {
-            return DOCKED_INVALID;
-        }
+        return dc.getDockedDividerController().getDockSide(bounds, mTmpRect, orientation);
     }
 
     boolean hasTaskForUser(int userId) {
diff --git a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTest.java b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTest.java
index 64637f4..30665b5 100644
--- a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTest.java
@@ -28,12 +28,19 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.DOCKED_BOTTOM;
+import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_RIGHT;
+import static android.view.WindowManager.DOCKED_TOP;
 
+import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_LEFT;
 import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM;
 import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_RIGHT;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
 import android.graphics.PixelFormat;
 import android.platform.test.annotations.Presubmit;
@@ -194,4 +201,53 @@
                 PhoneWindowManager.updateLightNavigationBarLw(0, opaqueDarkNavBar,
                         opaqueDarkNavBar, imeDrawLightNavBar, imeDrawLightNavBar));
     }
+
+    @Test
+    public void testIsDockSideAllowedDockTop() throws Exception {
+        // Docked top is always allowed
+        assertTrue(PhoneWindowManager.isDockSideAllowed(DOCKED_TOP, DOCKED_LEFT, NAV_BAR_BOTTOM,
+                true /* navigationBarCanMove */));
+        assertTrue(PhoneWindowManager.isDockSideAllowed(DOCKED_TOP, DOCKED_LEFT, NAV_BAR_BOTTOM,
+                false /* navigationBarCanMove */));
+    }
+
+    @Test
+    public void testIsDockSideAllowedDockBottom() throws Exception {
+        // Cannot dock bottom
+        assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_BOTTOM, DOCKED_LEFT, NAV_BAR_BOTTOM,
+                true /* navigationBarCanMove */));
+    }
+
+    @Test
+    public void testIsDockSideAllowedNavigationBarMovable() throws Exception {
+        assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_LEFT, DOCKED_LEFT, NAV_BAR_BOTTOM,
+                true /* navigationBarCanMove */));
+        assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_LEFT, DOCKED_LEFT, NAV_BAR_LEFT,
+                true /* navigationBarCanMove */));
+        assertTrue(PhoneWindowManager.isDockSideAllowed(DOCKED_LEFT, DOCKED_LEFT, NAV_BAR_RIGHT,
+                true /* navigationBarCanMove */));
+        assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_RIGHT, DOCKED_LEFT, NAV_BAR_BOTTOM,
+                true /* navigationBarCanMove */));
+        assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_RIGHT, DOCKED_LEFT, NAV_BAR_RIGHT,
+                true /* navigationBarCanMove */));
+        assertTrue(PhoneWindowManager.isDockSideAllowed(DOCKED_RIGHT, DOCKED_LEFT, NAV_BAR_LEFT,
+                true /* navigationBarCanMove */));
+    }
+
+    @Test
+    public void testIsDockSideAllowedNavigationBarNotMovable() throws Exception {
+        // Navigation bar is not movable such as tablets
+        assertTrue(PhoneWindowManager.isDockSideAllowed(DOCKED_LEFT, DOCKED_LEFT, NAV_BAR_BOTTOM,
+                false /* navigationBarCanMove */));
+        assertTrue(PhoneWindowManager.isDockSideAllowed(DOCKED_LEFT, DOCKED_TOP, NAV_BAR_BOTTOM,
+                false /* navigationBarCanMove */));
+        assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_LEFT, DOCKED_RIGHT, NAV_BAR_BOTTOM,
+                false /* navigationBarCanMove */));
+        assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_RIGHT, DOCKED_LEFT, NAV_BAR_BOTTOM,
+                false /* navigationBarCanMove */));
+        assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_RIGHT, DOCKED_TOP, NAV_BAR_BOTTOM,
+                false /* navigationBarCanMove */));
+        assertTrue(PhoneWindowManager.isDockSideAllowed(DOCKED_RIGHT, DOCKED_RIGHT, NAV_BAR_BOTTOM,
+                false /* navigationBarCanMove */));
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
index 1367f58..62fe6b2 100644
--- a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
@@ -17,6 +17,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
@@ -144,6 +145,11 @@
         void runOnBgThread(Runnable r) {
             r.run();
         }
+
+        @Override
+        void runOnBgThreadLazy(Runnable r, int delayMillis) {
+            r.run();
+        }
     }
 
     @Before
@@ -153,7 +159,7 @@
         mMockBatterySaverController = mock(BatterySaverController.class);
 
         doAnswer((inv) -> mDevice.batterySaverEnabled = inv.getArgument(0))
-                .when(mMockBatterySaverController).enableBatterySaver(anyBoolean());
+                .when(mMockBatterySaverController).enableBatterySaver(anyBoolean(), anyInt());
         when(mMockBatterySaverController.isEnabled())
                 .thenAnswer((inv) -> mDevice.batterySaverEnabled);
 
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 1c2d538..013c672 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -552,7 +552,8 @@
     }
 
     @Override
-    public boolean isDockSideAllowed(int dockSide) {
+    public boolean isDockSideAllowed(int dockSide, int originalDockSide, int displayWidth,
+            int displayHeight, int displayRotation) {
         return false;
     }
 
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index f164bcd..e213d79 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -2964,12 +2964,30 @@
          * @hide
          */
         public static final int OWNED_BY_DPC = 0;
+
         /**
          * Possible value for the OWNED_BY field.
          * APN is owned by other sources.
          * @hide
          */
         public static final int OWNED_BY_OTHERS = 1;
+
+        /**
+         * The APN set id. When the user manually selects an APN or the framework sets an APN as
+         * preferred, all APNs with the same set id as the selected APN should be prioritized over
+         * APNs in other sets.
+         * @hide
+         */
+        public static final String APN_SET_ID = "apn_set_id";
+
+        /**
+         * Possible value for the APN_SET_ID field. By default APNs will not belong to a set. If the
+         * user manually selects an APN with no set set, there is no need to prioritize any specific
+         * APN set ids.
+         * @hide
+         */
+        public static final int NO_SET_SET = 0;
+
     }
 
     /**