Merge "Keep track of all bound services."
diff --git a/api/current.txt b/api/current.txt
index 8892b24..f90ab4b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -39666,6 +39666,7 @@
     field public static final int SHOW_SOURCE_ACTIVITY = 16; // 0x10
     field public static final int SHOW_SOURCE_APPLICATION = 8; // 0x8
     field public static final int SHOW_SOURCE_ASSIST_GESTURE = 4; // 0x4
+    field public static final int SHOW_SOURCE_PUSH_TO_TALK = 32; // 0x20
     field public static final int SHOW_WITH_ASSIST = 1; // 0x1
     field public static final int SHOW_WITH_SCREENSHOT = 2; // 0x2
   }
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 89408cc..8914535 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -302,7 +302,6 @@
     private int mResultCode;
     private int mExitCoordinatorIndex;
     private PendingIntent mUsageTimeReport;
-    private boolean mLockTaskMode = false;
     private int mLaunchDisplayId = INVALID_DISPLAY;
     @WindowConfiguration.WindowingMode
     private int mLaunchWindowingMode = WINDOWING_MODE_UNDEFINED;
@@ -310,6 +309,7 @@
     private int mLaunchActivityType = ACTIVITY_TYPE_UNDEFINED;
     private int mLaunchTaskId = -1;
     private int mSplitScreenCreateMode = SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
+    private boolean mLockTaskMode = false;
     private boolean mDisallowEnterPictureInPictureWhileLaunching;
     private boolean mTaskOverlay;
     private boolean mTaskOverlayCanResume;
@@ -946,7 +946,7 @@
             mAnimationFinishedListener = IRemoteCallback.Stub.asInterface(
                     opts.getBinder(KEY_ANIMATION_FINISHED_LISTENER));
         }
-        mRotationAnimationHint = opts.getInt(KEY_ROTATION_ANIMATION_HINT);
+        mRotationAnimationHint = opts.getInt(KEY_ROTATION_ANIMATION_HINT, -1);
         mAppVerificationBundle = opts.getBundle(KEY_INSTANT_APP_VERIFICATION_BUNDLE);
         if (opts.containsKey(KEY_SPECS_FUTURE)) {
             mSpecsFuture = IAppTransitionAnimationSpecsFuture.Stub.asInterface(opts.getBinder(
@@ -1442,17 +1442,37 @@
                 b.putInt(KEY_EXIT_COORDINATOR_INDEX, mExitCoordinatorIndex);
                 break;
         }
-        b.putBoolean(KEY_LOCK_TASK_MODE, mLockTaskMode);
-        b.putInt(KEY_LAUNCH_DISPLAY_ID, mLaunchDisplayId);
-        b.putInt(KEY_LAUNCH_WINDOWING_MODE, mLaunchWindowingMode);
-        b.putInt(KEY_LAUNCH_ACTIVITY_TYPE, mLaunchActivityType);
-        b.putInt(KEY_LAUNCH_TASK_ID, mLaunchTaskId);
-        b.putBoolean(KEY_TASK_OVERLAY, mTaskOverlay);
-        b.putBoolean(KEY_TASK_OVERLAY_CAN_RESUME, mTaskOverlayCanResume);
-        b.putBoolean(KEY_AVOID_MOVE_TO_FRONT, mAvoidMoveToFront);
-        b.putInt(KEY_SPLIT_SCREEN_CREATE_MODE, mSplitScreenCreateMode);
-        b.putBoolean(KEY_DISALLOW_ENTER_PICTURE_IN_PICTURE_WHILE_LAUNCHING,
-                mDisallowEnterPictureInPictureWhileLaunching);
+        if (mLockTaskMode) {
+            b.putBoolean(KEY_LOCK_TASK_MODE, mLockTaskMode);
+        }
+        if (mLaunchDisplayId != INVALID_DISPLAY) {
+            b.putInt(KEY_LAUNCH_DISPLAY_ID, mLaunchDisplayId);
+        }
+        if (mLaunchWindowingMode != WINDOWING_MODE_UNDEFINED) {
+            b.putInt(KEY_LAUNCH_WINDOWING_MODE, mLaunchWindowingMode);
+        }
+        if (mLaunchActivityType != ACTIVITY_TYPE_UNDEFINED) {
+            b.putInt(KEY_LAUNCH_ACTIVITY_TYPE, mLaunchActivityType);
+        }
+        if (mLaunchTaskId != -1) {
+            b.putInt(KEY_LAUNCH_TASK_ID, mLaunchTaskId);
+        }
+        if (mTaskOverlay) {
+            b.putBoolean(KEY_TASK_OVERLAY, mTaskOverlay);
+        }
+        if (mTaskOverlayCanResume) {
+            b.putBoolean(KEY_TASK_OVERLAY_CAN_RESUME, mTaskOverlayCanResume);
+        }
+        if (mAvoidMoveToFront) {
+            b.putBoolean(KEY_AVOID_MOVE_TO_FRONT, mAvoidMoveToFront);
+        }
+        if (mSplitScreenCreateMode != SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT) {
+            b.putInt(KEY_SPLIT_SCREEN_CREATE_MODE, mSplitScreenCreateMode);
+        }
+        if (mDisallowEnterPictureInPictureWhileLaunching) {
+            b.putBoolean(KEY_DISALLOW_ENTER_PICTURE_IN_PICTURE_WHILE_LAUNCHING,
+                    mDisallowEnterPictureInPictureWhileLaunching);
+        }
         if (mAnimSpecs != null) {
             b.putParcelableArray(KEY_ANIM_SPECS, mAnimSpecs);
         }
@@ -1462,7 +1482,9 @@
         if (mSpecsFuture != null) {
             b.putBinder(KEY_SPECS_FUTURE, mSpecsFuture.asBinder());
         }
-        b.putInt(KEY_ROTATION_ANIMATION_HINT, mRotationAnimationHint);
+        if (mRotationAnimationHint != -1) {
+            b.putInt(KEY_ROTATION_ANIMATION_HINT, mRotationAnimationHint);
+        }
         if (mAppVerificationBundle != null) {
             b.putBundle(KEY_INSTANT_APP_VERIFICATION_BUNDLE, mAppVerificationBundle);
         }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 5e7f1e4..bbdc532 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -4153,8 +4153,11 @@
      * Called by a device or profile owner, or delegated certificate installer, to generate a
      * new private/public key pair. If the device supports key generation via secure hardware,
      * this method is useful for creating a key in KeyChain that never left the secure hardware.
-     *
      * Access to the key is controlled the same way as in {@link #installKeyPair}.
+     *
+     * <p>Because this method might take several seconds to complete, it should only be called from
+     * a worker thread. This method returns {@code null} when called from the main thread.
+     *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
      *            {@code null} if calling from a delegated certificate installer.
      * @param algorithm The key generation algorithm, see {@link java.security.KeyPairGenerator}.
diff --git a/core/java/android/app/timezone/RulesState.aidl b/core/java/android/app/timezone/RulesState.aidl
index f789120..665220d 100644
--- a/core/java/android/app/timezone/RulesState.aidl
+++ b/core/java/android/app/timezone/RulesState.aidl
@@ -14,4 +14,6 @@
  * limitations under the License.
  */
 
+package android.app.timezone;
+
 parcelable RulesState;
\ No newline at end of file
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 7adea6a8..ef0dce3 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -642,8 +642,7 @@
      *           tool. This integer encodes the package, type, and resource
      *           entry. The value 0 is an invalid identifier.
      * 
-     * @return Resource dimension value multiplied by the appropriate 
-     * metric.
+     * @return Resource dimension value multiplied by the appropriate metric to convert to pixels.
      * 
      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
      *
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index cd177c4..26223f7 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -109,6 +109,12 @@
      */
     public static final int SHOW_SOURCE_ACTIVITY = 1<<4;
 
+    /**
+     * Flag for use with {@link #onShow}: indicates that the voice interaction service was invoked
+     * from a physical button.
+     */
+    public static final int SHOW_SOURCE_PUSH_TO_TALK = 1 << 5;
+
     final Context mContext;
     final HandlerCaller mHandlerCaller;
 
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 6b7b89c..c037cd0 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -33,6 +33,8 @@
 
     public static final String FFLAG_PREFIX = "sys.fflag.";
     public static final String FFLAG_OVERRIDE_PREFIX = FFLAG_PREFIX + "override.";
+    public static final String PERSIST_PREFIX = "persist." + FFLAG_OVERRIDE_PREFIX;
+    public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid";
 
     private static final Map<String, String> DEFAULT_FLAGS;
     static {
@@ -42,6 +44,7 @@
         DEFAULT_FLAGS.put("settings_audio_switcher", "true");
         DEFAULT_FLAGS.put("settings_systemui_theme", "true");
         DEFAULT_FLAGS.put("settings_dynamic_homepage", "false");
+        DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "true");
     }
 
     /**
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index 47bda53..496bc9f 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -29,6 +29,7 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Region;
+import android.graphics.Region.Op;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -325,14 +326,9 @@
      * @hide
      */
     public static DisplayCutout fromBoundingRect(int left, int top, int right, int bottom) {
-        Path path = new Path();
-        path.reset();
-        path.moveTo(left, top);
-        path.lineTo(left, bottom);
-        path.lineTo(right, bottom);
-        path.lineTo(right, top);
-        path.close();
-        return fromBounds(path);
+        Region r = Region.obtain();
+        r.set(left, top, right, bottom);
+        return fromBounds(r);
     }
 
     /**
@@ -340,26 +336,19 @@
      *
      * @hide
      */
-    public static DisplayCutout fromBounds(Path path) {
-        RectF clipRect = new RectF();
-        path.computeBounds(clipRect, false /* unused */);
-        Region clipRegion = Region.obtain();
-        clipRegion.set((int) clipRect.left, (int) clipRect.top,
-                (int) clipRect.right, (int) clipRect.bottom);
-
-        Region bounds = new Region();
-        bounds.setPath(path, clipRegion);
-        clipRegion.recycle();
-        return new DisplayCutout(ZERO_RECT, bounds, false /* copyArguments */);
+    public static DisplayCutout fromBounds(Region region) {
+        return new DisplayCutout(ZERO_RECT, region, false /* copyArguments */);
     }
 
     /**
-     * Creates the bounding path according to @android:string/config_mainBuiltInDisplayCutout.
+     * Creates the display cutout according to
+     * @android:string/config_mainBuiltInDisplayCutoutRectApproximation, which is the closest
+     * rectangle-base approximation of the cutout.
      *
      * @hide
      */
-    public static DisplayCutout fromResources(Resources res, int displayWidth, int displayHeight) {
-        return fromSpec(res.getString(R.string.config_mainBuiltInDisplayCutout),
+    public static DisplayCutout fromResourcesRectApproximation(Resources res, int displayWidth, int displayHeight) {
+        return fromSpec(res.getString(R.string.config_mainBuiltInDisplayCutoutRectApproximation),
                 displayWidth, displayHeight, DENSITY_DEVICE_STABLE / (float) DENSITY_DEFAULT);
     }
 
@@ -369,7 +358,8 @@
      * @hide
      */
     public static Path pathFromResources(Resources res, int displayWidth, int displayHeight) {
-        return pathAndDisplayCutoutFromSpec(res.getString(R.string.config_mainBuiltInDisplayCutout),
+        return pathAndDisplayCutoutFromSpec(
+                res.getString(R.string.config_mainBuiltInDisplayCutout),
                 displayWidth, displayHeight, DENSITY_DEVICE_STABLE / (float) DENSITY_DEFAULT).first;
     }
 
@@ -417,6 +407,7 @@
         }
 
         final Path p;
+        final Region r = Region.obtain();
         try {
             p = PathParser.createPathFromPathData(spec);
         } catch (Throwable e) {
@@ -431,6 +422,8 @@
         m.postTranslate(offsetX, 0);
         p.transform(m);
 
+        addToRegion(p, r);
+
         if (bottomSpec != null) {
             final Path bottomPath;
             try {
@@ -443,9 +436,10 @@
             m.postTranslate(0, displayHeight);
             bottomPath.transform(m);
             p.addPath(bottomPath);
+            addToRegion(bottomPath, r);
         }
 
-        final Pair<Path, DisplayCutout> result = new Pair<>(p, fromBounds(p));
+        final Pair<Path, DisplayCutout> result = new Pair<>(p, fromBounds(r));
         synchronized (CACHE_LOCK) {
             sCachedSpec = spec;
             sCachedDisplayWidth = displayWidth;
@@ -456,6 +450,14 @@
         return result;
     }
 
+    private static void addToRegion(Path p, Region r) {
+        final RectF rectF = new RectF();
+        final Rect rect = new Rect();
+        p.computeBounds(rectF, false /* unused */);
+        rectF.round(rect);
+        r.op(rect, Op.UNION);
+    }
+
     private static Region boundingRectsToRegion(List<Rect> rects) {
         Region result = Region.obtain();
         if (rects != null) {
diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java
index fbb99e4..75d714f 100644
--- a/core/java/com/android/internal/os/BinderCallsStats.java
+++ b/core/java/com/android/internal/os/BinderCallsStats.java
@@ -122,25 +122,25 @@
                 mUidEntries.put(callingUid, uidEntry);
             }
 
+            CallStat callStat;
             if (mDetailedTracking) {
                 // Find CallStat entry and update its total time
-                CallStat callStat = uidEntry.getOrCreate(s.callStat);
-                callStat.callCount++;
-                callStat.cpuTimeMicros += duration;
-                callStat.latencyMicros += latencyDuration;
+                callStat = uidEntry.getOrCreate(s.callStat);
                 callStat.exceptionCount += s.exceptionThrown ? 1 : 0;
-                callStat.maxLatencyMicros = Math.max(callStat.maxLatencyMicros, latencyDuration);
                 callStat.maxRequestSizeBytes =
                         Math.max(callStat.maxRequestSizeBytes, parcelRequestSize);
                 callStat.maxReplySizeBytes =
                         Math.max(callStat.maxReplySizeBytes, parcelReplySize);
             } else {
                 // update sampled timings in the beginning of each interval
-                if (s.cpuTimeStarted >= 0) {
-                    s.sampledCallStat.cpuTimeMicros += duration;
-                    s.sampledCallStat.latencyMicros += latencyDuration;
-                }
-                s.sampledCallStat.callCount++;
+                callStat = s.sampledCallStat;
+            }
+            callStat.callCount++;
+            if (s.cpuTimeStarted >= 0) {
+                callStat.cpuTimeMicros += duration;
+                callStat.maxCpuTimeMicros = Math.max(callStat.maxCpuTimeMicros, duration);
+                callStat.latencyMicros += latencyDuration;
+                callStat.maxLatencyMicros = Math.max(callStat.maxLatencyMicros, latencyDuration);
             }
 
             uidEntry.cpuTimeMicros += duration;
@@ -189,7 +189,7 @@
         StringBuilder sb = new StringBuilder();
         if (mDetailedTracking) {
             pw.println("Per-UID raw data " + datasetSizeDesc
-                    + "(uid, call_desc, cpu_time_micros, latency_time_micros, "
+                    + "(uid, call_desc, cpu_time_micros, max_cpu_time_micros, latency_time_micros, "
                     + "max_latency_time_micros, exception_count, max_request_size_bytes, "
                     + "max_reply_size_bytes, call_count):");
             List<UidEntry> topEntries = verbose ? entries
@@ -200,6 +200,7 @@
                     sb.append("    ")
                             .append(uidEntry.uid).append(",").append(e)
                             .append(',').append(e.cpuTimeMicros)
+                            .append(',').append(e.maxCpuTimeMicros)
                             .append(',').append(e.latencyMicros)
                             .append(',').append(e.maxLatencyMicros)
                             .append(',').append(e.exceptionCount)
@@ -260,7 +261,7 @@
         return Binder.getCallingUid();
     }
 
-    private long getElapsedRealtimeMicro() {
+    protected long getElapsedRealtimeMicro() {
         return SystemClock.elapsedRealtimeNanos() / 1000;
     }
 
@@ -288,11 +289,13 @@
         public String className;
         public int msg;
         public long cpuTimeMicros;
+        public long maxCpuTimeMicros;
         public long latencyMicros;
         public long maxLatencyMicros;
+        public long callCount;
+        // The following fields are only computed if mDetailedTracking is set.
         public long maxRequestSizeBytes;
         public long maxReplySizeBytes;
-        public long callCount;
         public long exceptionCount;
 
         CallStat() {
diff --git a/core/java/com/android/internal/util/DumpUtils.java b/core/java/com/android/internal/util/DumpUtils.java
index 7fd83bc..f6d80a5 100644
--- a/core/java/com/android/internal/util/DumpUtils.java
+++ b/core/java/com/android/internal/util/DumpUtils.java
@@ -34,9 +34,18 @@
 /**
  * Helper functions for dumping the state of system services.
  * Test:
- atest /android/pi-dev/frameworks/base/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java
+ atest FrameworksCoreTests:DumpUtilsTest
  */
 public final class DumpUtils {
+
+    /**
+     * List of component names that should be dumped in the bug report critical section.
+     *
+     * @hide
+     */
+    public static final ComponentName[] CRITICAL_SECTION_COMPONENTS = {
+            new ComponentName("com.android.systemui", "com.android.systemui.SystemUIService")
+    };
     private static final String TAG = "DumpUtils";
     private static final boolean DEBUG = false;
 
@@ -213,6 +222,45 @@
     }
 
     /**
+     * Return whether a package should be dumped in the critical section.
+     */
+    private static boolean isCriticalPackage(@Nullable ComponentName cname) {
+        if (cname == null) {
+            return false;
+        }
+
+        for (int i = 0; i < CRITICAL_SECTION_COMPONENTS.length; i++) {
+            if (cname.equals(CRITICAL_SECTION_COMPONENTS[i])) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Return whether a package name is considered to be part of the platform and in the critical
+     * section.
+     *
+     * @hide
+     */
+    public static boolean isPlatformCriticalPackage(@Nullable ComponentName.WithComponentName wcn) {
+        return (wcn != null) && isPlatformPackage(wcn.getComponentName()) &&
+                isCriticalPackage(wcn.getComponentName());
+    }
+
+    /**
+     * Return whether a package name is considered to be part of the platform but not in the the
+     * critical section.
+     *
+     * @hide
+     */
+    public static boolean isPlatformNonCriticalPackage(
+            @Nullable ComponentName.WithComponentName wcn) {
+        return (wcn != null) && isPlatformPackage(wcn.getComponentName()) &&
+                !isCriticalPackage(wcn.getComponentName());
+    }
+
+    /**
      * Used for dumping providers and services. Return a predicate for a given filter string.
      * @hide
      */
@@ -238,6 +286,16 @@
             return DumpUtils::isNonPlatformPackage;
         }
 
+        // Dump all platform-critical?
+        if ("all-platform-critical".equals(filterString)) {
+            return DumpUtils::isPlatformCriticalPackage;
+        }
+
+        // Dump all platform-non-critical?
+        if ("all-platform-non-critical".equals(filterString)) {
+            return DumpUtils::isPlatformNonCriticalPackage;
+        }
+
         // Is the filter a component name? If so, do an exact match.
         final ComponentName filterCname = ComponentName.unflattenFromString(filterString);
         if (filterCname != null) {
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index aef48fa..fae4b10b 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2966,6 +2966,14 @@
          -->
     <string translatable="false" name="config_mainBuiltInDisplayCutout"></string>
 
+    <!-- Like config_mainBuiltInDisplayCutout, but this path is used to report the
+         one single bounding rect per device edge to the app via
+         {@link DisplayCutout#getBoundingRect}. Note that this path should try to match the visual
+         appearance of the cutout as much as possible, and may be smaller than
+         config_mainBuiltInDisplayCutout
+         -->
+    <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">@string/config_mainBuiltInDisplayCutout</string>
+
     <!-- Whether the display cutout region of the main built-in display should be forced to
          black in software (to avoid aliasing or emulate a cutout that is not physically existent).
          -->
@@ -3487,4 +3495,7 @@
 
     <!-- Whether or not we should show the option to show battery percentage -->
     <bool name="config_battery_percentage_setting_available">true</bool>
+
+    <!-- Whether or not battery saver should be "sticky" when manually enabled. -->
+    <bool name="config_batterySaverStickyBehaviourDisabled">false</bool>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 6054180..99001e3 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3364,6 +3364,7 @@
 
   <java-symbol type="string" name="global_action_logout" />
   <java-symbol type="string" name="config_mainBuiltInDisplayCutout" />
+  <java-symbol type="string" name="config_mainBuiltInDisplayCutoutRectApproximation" />
   <java-symbol type="drawable" name="messaging_user" />
   <java-symbol type="bool" name="config_fillMainBuiltInDisplayCutout" />
   <java-symbol type="drawable" name="ic_logout" />
@@ -3405,6 +3406,7 @@
   <java-symbol type="string" name="notification_app_name_settings" />
 
   <java-symbol type="integer" name="config_lowBatteryAutoTriggerDefaultLevel" />
+  <java-symbol type="bool" name="config_batterySaverStickyBehaviourDisabled" />
 
   <!-- For car devices -->
   <java-symbol type="string" name="car_loading_profile" />
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
index b7fef13..18263ab 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
@@ -155,6 +155,42 @@
     }
 
     @Test
+    public void testMaxCpu() {
+        TestBinderCallsStats bcs = new TestBinderCallsStats(true);
+        Binder binder = new Binder();
+        BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1);
+        bcs.time += 50;
+        bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
+
+        callSession = bcs.callStarted(binder, 1);
+        bcs.time += 10;
+        bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
+
+        List<BinderCallsStats.CallStat> callStatsList =
+                bcs.getUidEntries().get(TEST_UID).getCallStatsList();
+
+        assertEquals(50, callStatsList.get(0).maxCpuTimeMicros);
+    }
+
+    @Test
+    public void testMaxLatency() {
+        TestBinderCallsStats bcs = new TestBinderCallsStats(true);
+        Binder binder = new Binder();
+        BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1);
+        bcs.elapsedTime += 5;
+        bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
+
+        callSession = bcs.callStarted(binder, 1);
+        bcs.elapsedTime += 1;
+        bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
+
+        List<BinderCallsStats.CallStat> callStatsList =
+                bcs.getUidEntries().get(TEST_UID).getCallStatsList();
+
+        assertEquals(5, callStatsList.get(0).maxLatencyMicros);
+    }
+
+    @Test
     public void testGetHighestValues() {
         List<Integer> list = Arrays.asList(1, 2, 3, 4);
         List<Integer> highestValues = BinderCallsStats
@@ -165,6 +201,7 @@
     static class TestBinderCallsStats extends BinderCallsStats {
         int callingUid = TEST_UID;
         long time = 1234;
+        long elapsedTime = 0;
 
         TestBinderCallsStats(boolean detailedTracking) {
             super(detailedTracking);
@@ -176,6 +213,11 @@
         }
 
         @Override
+        protected long getElapsedRealtimeMicro() {
+            return elapsedTime;
+        }
+
+        @Override
         protected int getCallingUid() {
             return callingUid;
         }
diff --git a/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java b/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java
index 45b19bc..a44b860 100644
--- a/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java
@@ -15,8 +15,11 @@
  */
 package com.android.internal.util;
 
+import static com.android.internal.util.DumpUtils.CRITICAL_SECTION_COMPONENTS;
 import static com.android.internal.util.DumpUtils.filterRecord;
 import static com.android.internal.util.DumpUtils.isNonPlatformPackage;
+import static com.android.internal.util.DumpUtils.isPlatformCriticalPackage;
+import static com.android.internal.util.DumpUtils.isPlatformNonCriticalPackage;
 import static com.android.internal.util.DumpUtils.isPlatformPackage;
 
 import android.content.ComponentName;
@@ -25,7 +28,7 @@
 
 /**
  * Run with:
- atest /android/pi-dev/frameworks/base/core/tests/coretests/src/com/android/internal/util/DumpTest.java
+ atest FrameworksCoreTests:DumpUtilsTest
  */
 public class DumpUtilsTest extends TestCase {
 
@@ -89,6 +92,32 @@
         assertTrue(isNonPlatformPackage(wcn("com.google.def/abc")));
     }
 
+    public void testIsPlatformCriticalPackage() {
+        for (final ComponentName componentName : CRITICAL_SECTION_COMPONENTS) {
+            assertTrue(isPlatformCriticalPackage(() -> componentName));
+            assertTrue(isPlatformPackage(componentName));
+        }
+        assertFalse(isPlatformCriticalPackage(wcn("com.google.p/abc")));
+        assertFalse(isPlatformCriticalPackage(wcn("com.android.def/abc")));
+        assertFalse(isPlatformCriticalPackage(wcn("com.android.abc")));
+        assertFalse(isPlatformCriticalPackage(wcn("com.android")));
+        assertFalse(isPlatformCriticalPackage(wcn(null)));
+        assertFalse(isPlatformCriticalPackage(null));
+    }
+
+    public void testIsPlatformNonCriticalPackage() {
+        for (final ComponentName componentName : CRITICAL_SECTION_COMPONENTS) {
+            assertFalse(isPlatformNonCriticalPackage(() -> componentName));
+        }
+        assertTrue(isPlatformNonCriticalPackage(wcn("android/abc")));
+        assertTrue(isPlatformNonCriticalPackage(wcn("android.abc/abc")));
+        assertTrue(isPlatformNonCriticalPackage(wcn("com.android.def/abc")));
+
+        assertFalse(isPlatformNonCriticalPackage(wcn("com.google.def/abc")));
+        assertFalse(isPlatformNonCriticalPackage(wcn(null)));
+        assertFalse(isPlatformNonCriticalPackage(null));
+    }
+
     public void testFilterRecord() {
         assertFalse(filterRecord(null).test(wcn("com.google.p/abc")));
         assertFalse(filterRecord(null).test(wcn("com.android.p/abc")));
@@ -105,6 +134,19 @@
         assertFalse(filterRecord("all-non-platform").test(wcn("com.android.p/abc")));
         assertFalse(filterRecord("all-non-platform").test(wcn(null)));
 
+        for (final ComponentName componentName : CRITICAL_SECTION_COMPONENTS) {
+            assertTrue(filterRecord("all-platform-critical").test((() -> componentName)));
+            assertFalse(filterRecord("all-platform-non-critical").test((() -> componentName)));
+            assertTrue(filterRecord("all-platform").test((() -> componentName)));
+        }
+        assertFalse(filterRecord("all-platform-critical").test(wcn("com.google.p/abc")));
+        assertFalse(filterRecord("all-platform-critical").test(wcn("com.android.p/abc")));
+        assertFalse(filterRecord("all-platform-critical").test(wcn(null)));
+
+        assertTrue(filterRecord("all-platform-non-critical").test(wcn("com.android.p/abc")));
+        assertFalse(filterRecord("all-platform-non-critical").test(wcn("com.google.p/abc")));
+        assertFalse(filterRecord("all-platform-non-critical").test(wcn(null)));
+
         // Partial string match.
         assertTrue(filterRecord("abc").test(wcn("com.google.p/.abc")));
         assertFalse(filterRecord("abc").test(wcn("com.google.p/.def")));
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
index 8a1c4ef..94efc71 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
@@ -16,6 +16,7 @@
 
 package com.android.settingslib.fuelgauge;
 
+import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -90,6 +91,13 @@
         if (TextUtils.equals(pkg, defaultDialer)) {
             return true;
         }
+
+        final DevicePolicyManager devicePolicyManager = mAppContext.getSystemService(
+                DevicePolicyManager.class);
+        if (devicePolicyManager.packageHasActiveAdmins(pkg)) {
+            return true;
+        }
+
         return false;
     }
 
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
index a23eebc..23087a9 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
@@ -21,8 +21,10 @@
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 
+import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -51,7 +53,8 @@
 
     @Mock
     private IDeviceIdleController mDeviceIdleService;
-
+    @Mock
+    private DevicePolicyManager mDevicePolicyManager;
     private PowerWhitelistBackend mPowerWhitelistBackend;
     private ShadowPackageManager mPackageManager;
     private Context mContext;
@@ -59,7 +62,8 @@
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
+        mContext = spy(RuntimeEnvironment.application);
+        doReturn(mContext).when(mContext).getApplicationContext();
         doReturn(new String[] {}).when(mDeviceIdleService).getFullPowerWhitelist();
         doReturn(new String[] {}).when(mDeviceIdleService).getSystemPowerWhitelist();
         doReturn(new String[] {}).when(mDeviceIdleService).getSystemPowerWhitelistExceptIdle();
@@ -67,6 +71,7 @@
         doNothing().when(mDeviceIdleService).removePowerSaveWhitelistApp(anyString());
         mPackageManager = Shadow.extract(mContext.getPackageManager());
         mPackageManager.setSystemFeature(PackageManager.FEATURE_TELEPHONY, true);
+        doReturn(mDevicePolicyManager).when(mContext).getSystemService(DevicePolicyManager.class);
 
         mPowerWhitelistBackend = new PowerWhitelistBackend(mContext, mDeviceIdleService);
     }
@@ -123,6 +128,13 @@
     }
 
     @Test
+    public void isWhitelisted_shouldWhitelistActiveDeviceAdminApp() {
+        doReturn(true).when(mDevicePolicyManager).packageHasActiveAdmins(PACKAGE_ONE);
+
+        assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue();
+    }
+
+    @Test
     public void testIsSystemWhitelisted() throws Exception {
         doReturn(new String[] {PACKAGE_ONE}).when(mDeviceIdleService).getSystemPowerWhitelist();
         mPowerWhitelistBackend.refreshList();
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index eab4b97..a5616d5 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -339,19 +339,17 @@
             android:exported="false">
         </activity>
 
-        <!-- Springboard for launching the share activity -->
-        <receiver android:name=".screenshot.GlobalScreenshot$ScreenshotActionReceiver"
-            android:process=":screenshot"
+        <!-- Springboard for launching the share and edit activity. This needs to be in the main
+             system ui process since we need to notify the status bar to dismiss the keyguard -->
+        <receiver android:name=".screenshot.GlobalScreenshot$ActionProxyReceiver"
             android:exported="false" />
 
         <!-- Callback for dismissing screenshot notification after a share target is picked -->
         <receiver android:name=".screenshot.GlobalScreenshot$TargetChosenReceiver"
-            android:process=":screenshot"
             android:exported="false" />
 
         <!-- Callback for deleting screenshot notification -->
         <receiver android:name=".screenshot.GlobalScreenshot$DeleteScreenshotReceiver"
-            android:process=":screenshot"
             android:exported="false" />
 
         <!-- started from UsbDeviceSettingsManager -->
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 6bc0965..721e9c5 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -48,10 +48,10 @@
     <string name="keyguard_enter_your_pin">Enter your PIN</string>
 
     <!-- Instructions telling the user to enter their pattern to unlock the keyguard [CHAR LIMIT=30] -->
-    <string name="keyguard_enter_your_pattern">Enter your Pattern</string>
+    <string name="keyguard_enter_your_pattern">Enter your pattern</string>
 
     <!-- Instructions telling the user to enter their text password to unlock the keyguard [CHAR LIMIT=30] -->
-    <string name="keyguard_enter_your_password">Enter your Password</string>
+    <string name="keyguard_enter_your_password">Enter your password</string>
 
     <!-- Instructions telling the user that they entered the wrong pin while trying
          to unlock the keyguard.  Displayed in one line in a large font.  -->
@@ -146,9 +146,9 @@
     <!-- Message shown in pattern unlock after some number of unsuccessful attempts -->
     <string name="kg_forgot_pattern_button_text">Forgot Pattern</string>
     <!-- Message shown when user enters wrong pattern -->
-    <string name="kg_wrong_pattern">Wrong Pattern</string>
+    <string name="kg_wrong_pattern">Wrong pattern</string>
     <!-- Message shown when user enters wrong password -->
-    <string name="kg_wrong_password">Wrong Password</string>
+    <string name="kg_wrong_password">Wrong password</string>
     <!-- Message shown when user enters wrong PIN -->
     <string name="kg_wrong_pin">Wrong PIN</string>
     <!-- Countdown message shown after too many failed unlock attempts -->
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
index 1e5b77e..70ca055 100644
--- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -99,7 +99,7 @@
             long token = Binder.clearCallingIdentity();
             try {
                 mHandler.post(() -> {
-                    StatusBar statusBar = ((SystemUIApplication) mContext).getComponent(
+                    StatusBar statusBar = SysUiServiceProvider.getComponent(mContext,
                             StatusBar.class);
                     if (statusBar != null) {
                         statusBar.showScreenPinningRequest(taskId, false /* allowCancel */);
@@ -152,7 +152,7 @@
         public Rect getNonMinimizedSplitScreenSecondaryBounds() {
             long token = Binder.clearCallingIdentity();
             try {
-                Divider divider = ((SystemUIApplication) mContext).getComponent(Divider.class);
+                Divider divider = SysUiServiceProvider.getComponent(mContext, Divider.class);
                 if (divider != null) {
                     return divider.getView().getNonMinimizedSplitScreenSecondaryBounds();
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
index b7ff984..f30b073 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -113,9 +113,7 @@
                     // The display buffers will be empty and need to be filled.
                     mHost.dozeTimeTick();
                     // The first frame may arrive when the display isn't ready yet.
-                    mHandler.postDelayed(mWakeLock.wrap(mHost::dozeTimeTick), 100);
-                    // The the delayed frame may arrive when the display isn't ready yet either.
-                    mHandler.postDelayed(mWakeLock.wrap(mHost::dozeTimeTick), 1000);
+                    mHandler.postDelayed(mWakeLock.wrap(mHost::dozeTimeTick), 500);
                 }
                 scheduleTimeTick();
                 break;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index b9d1021..120fa42 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -2103,6 +2103,9 @@
         pw.print("  mDrawnCallback: "); pw.println(mDrawnCallback);
     }
 
+    /**
+     * @param aodShowing true when AOD - or ambient mode - is showing.
+     */
     public void setAodShowing(boolean aodShowing) {
         setShowingLocked(mShowing, aodShowing);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 7e4acc2..63a65d0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -48,6 +48,7 @@
 
 import com.android.systemui.Dependency;
 import com.android.systemui.OverviewProxyService;
+import com.android.systemui.SysUiServiceProvider;
 import com.google.android.collect.Lists;
 
 import com.android.internal.logging.MetricsLogger;
@@ -1095,7 +1096,7 @@
     }
 
     private StatusBar getStatusBar() {
-        return ((SystemUIApplication) mContext).getComponent(StatusBar.class);
+        return SysUiServiceProvider.getComponent(mContext, StatusBar.class);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUserService.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUserService.java
index 2c1158d..b4212d3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUserService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUserService.java
@@ -21,6 +21,7 @@
 import android.os.IBinder;
 import android.util.Log;
 
+import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.SystemUIApplication;
 
 /**
@@ -40,8 +41,7 @@
 
     @Override
     public IBinder onBind(Intent intent) {
-        SystemUIApplication app = (SystemUIApplication) getApplication();
-        Recents recents = app.getComponent(Recents.class);
+        Recents recents = SysUiServiceProvider.getComponent(this, Recents.class);
         if (DEBUG) {
             Log.d(TAG, "onBind: " + recents);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 64ccba8..0ea941f 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -16,9 +16,11 @@
 
 package com.android.systemui.screenshot;
 
+import static android.content.Context.NOTIFICATION_SERVICE;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-
-import static com.android.systemui.screenshot.GlobalScreenshot.SHARING_INTENT;
+import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_ACTION_INTENT;
+import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_CANCEL_NOTIFICATION;
+import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_DISALLOW_ENTER_PIP;
 import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_SCREENSHOT;
 
 import android.animation.Animator;
@@ -26,7 +28,6 @@
 import android.animation.AnimatorSet;
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.Notification;
 import android.app.Notification.BigPictureStyle;
@@ -56,9 +57,9 @@
 import android.os.Environment;
 import android.os.PowerManager;
 import android.os.Process;
-import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.MediaStore;
+import android.text.TextUtils;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.Slog;
@@ -73,12 +74,13 @@
 import android.view.animation.Interpolator;
 import android.widget.ImageView;
 import android.widget.Toast;
-
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.systemui.R;
+import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.SystemUI;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.util.NotificationChannels;
-
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.OutputStream;
@@ -277,7 +279,12 @@
             values.put(MediaStore.Images.ImageColumns.SIZE, new File(mImageFilePath).length());
             Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
 
-            // Create a share intent
+            // Note: Both the share and edit actions are proxied through ActionProxyReceiver in
+            // order to do some common work like dismissing the keyguard and sending
+            // closeSystemWindows
+
+            // Create a share intent, this will always go through the chooser activity first which
+            // should not trigger auto-enter PiP
             String subjectDate = DateFormat.getDateTimeInstance().format(new Date(mImageTime));
             String subject = String.format(SCREENSHOT_SHARE_SUBJECT_TEMPLATE, subjectDate);
             Intent sharingIntent = new Intent(Intent.ACTION_SEND);
@@ -286,37 +293,47 @@
             sharingIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
             sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
 
-            // Create a share action for the notification. Note, we proxy the call to
-            // ScreenshotActionReceiver because RemoteViews currently forces an activity options
-            // on the PendingIntent being launched, and since we don't want to trigger the share
-            // sheet in this case, we start the chooser activity directly in
-            // ScreenshotActionReceiver.
+            PendingIntent chooserAction = PendingIntent.getBroadcast(context, 0,
+                    new Intent(context, GlobalScreenshot.TargetChosenReceiver.class),
+                    PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
+            Intent sharingChooserIntent = Intent.createChooser(sharingIntent, null,
+                    chooserAction.getIntentSender())
+                    .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
+
+            // Create a share action for the notification
             PendingIntent shareAction = PendingIntent.getBroadcast(context, 0,
-                    new Intent(context, GlobalScreenshot.ScreenshotActionReceiver.class)
-                            .putExtra(SHARING_INTENT, sharingIntent),
+                    new Intent(context, GlobalScreenshot.ActionProxyReceiver.class)
+                            .putExtra(EXTRA_ACTION_INTENT, sharingChooserIntent)
+                            .putExtra(EXTRA_DISALLOW_ENTER_PIP, true),
                     PendingIntent.FLAG_CANCEL_CURRENT);
             Notification.Action.Builder shareActionBuilder = new Notification.Action.Builder(
                     R.drawable.ic_screenshot_share,
                     r.getString(com.android.internal.R.string.share), shareAction);
             mNotificationBuilder.addAction(shareActionBuilder.build());
 
+            // Create an edit intent, if a specific package is provided as the editor, then launch
+            // that directly
+            String editorPackage = context.getString(R.string.config_screenshotEditor);
             Intent editIntent = new Intent(Intent.ACTION_EDIT);
+            if (!TextUtils.isEmpty(editorPackage)) {
+                editIntent.setComponent(ComponentName.unflattenFromString(editorPackage));
+            }
             editIntent.setType("image/png");
             editIntent.setData(uri);
             editIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
             editIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
 
-            // Create a edit action for the notification the same way.
+            // Create a edit action
             PendingIntent editAction = PendingIntent.getBroadcast(context, 1,
-                    new Intent(context, GlobalScreenshot.ScreenshotActionReceiver.class)
-                            .putExtra(SHARING_INTENT, editIntent),
+                    new Intent(context, GlobalScreenshot.ActionProxyReceiver.class)
+                            .putExtra(EXTRA_ACTION_INTENT, editIntent)
+                            .putExtra(EXTRA_CANCEL_NOTIFICATION, editIntent.getComponent() != null),
                     PendingIntent.FLAG_CANCEL_CURRENT);
             Notification.Action.Builder editActionBuilder = new Notification.Action.Builder(
                     R.drawable.ic_screenshot_edit,
                     r.getString(com.android.internal.R.string.screenshot_edit), editAction);
             mNotificationBuilder.addAction(editActionBuilder.build());
 
-
             // Create a delete action for the notification
             PendingIntent deleteAction = PendingIntent.getBroadcast(context, 0,
                     new Intent(context, GlobalScreenshot.DeleteScreenshotReceiver.class)
@@ -429,7 +446,9 @@
 
 class GlobalScreenshot {
     static final String SCREENSHOT_URI_ID = "android:screenshot_uri_id";
-    static final String SHARING_INTENT = "android:screenshot_sharing_intent";
+    static final String EXTRA_ACTION_INTENT = "android:screenshot_action_intent";
+    static final String EXTRA_CANCEL_NOTIFICATION = "android:screenshot_cancel_notification";
+    static final String EXTRA_DISALLOW_ENTER_PIP = "android:screenshot_disallow_enter_pip";
 
     private static final int SCREENSHOT_FLASH_TO_PEAK_DURATION = 130;
     private static final int SCREENSHOT_DROP_IN_DURATION = 430;
@@ -452,7 +471,6 @@
     private NotificationManager mNotificationManager;
     private Display mDisplay;
     private DisplayMetrics mDisplayMetrics;
-    private Matrix mDisplayMatrix;
 
     private Bitmap mScreenBitmap;
     private View mScreenshotLayout;
@@ -482,7 +500,6 @@
                 context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 
         // Inflate the screenshot layout
-        mDisplayMatrix = new Matrix();
         mScreenshotLayout = layoutInflater.inflate(R.layout.global_screenshot, null);
         mBackgroundView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_background);
         mScreenshotView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot);
@@ -512,7 +529,7 @@
         mWindowLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
         mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
         mNotificationManager =
-            (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+            (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);
         mDisplay = mWindowManager.getDefaultDisplay();
         mDisplayMetrics = new DisplayMetrics();
         mDisplay.getRealMetrics(mDisplayMetrics);
@@ -562,21 +579,6 @@
     }
 
     /**
-     * @return the current display rotation in degrees
-     */
-    private float getDegreesForRotation(int value) {
-        switch (value) {
-        case Surface.ROTATION_90:
-            return 360f - 90f;
-        case Surface.ROTATION_180:
-            return 360f - 180f;
-        case Surface.ROTATION_270:
-            return 360f - 270f;
-        }
-        return 0f;
-    }
-
-    /**
      * Takes a screenshot of the current display and shows an animation.
      */
     private void takeScreenshot(Runnable finisher, boolean statusBarVisible, boolean navBarVisible,
@@ -891,52 +893,39 @@
     }
 
     /**
-     * Receiver to proxy the share or edit intent.
+     * Receiver to proxy the share or edit intent, used to clean up the notification and send
+     * appropriate signals to the system (ie. to dismiss the keyguard if necessary).
      */
-    public static class ScreenshotActionReceiver extends BroadcastReceiver {
+    public static class ActionProxyReceiver extends BroadcastReceiver {
         @Override
-        public void onReceive(Context context, Intent intent) {
-            try {
-                ActivityManager.getService().closeSystemDialogs(SYSTEM_DIALOG_REASON_SCREENSHOT);
-            } catch (RemoteException e) {
-            }
+        public void onReceive(Context context, final Intent intent) {
+            Runnable startActivityRunnable = () -> {
+                ActivityManagerWrapper.getInstance().closeSystemWindows(
+                        SYSTEM_DIALOG_REASON_SCREENSHOT);
 
-            Intent actionIntent = intent.getParcelableExtra(SHARING_INTENT);
-
-            // If this is an edit & default editor exists, route straight there.
-            String editorPackage = context.getResources().getString(R.string.config_screenshotEditor);
-            if (actionIntent.getAction() == Intent.ACTION_EDIT &&
-                    editorPackage != null && editorPackage.length() > 0) {
-                actionIntent.setComponent(ComponentName.unflattenFromString(editorPackage));
-                final NotificationManager nm =
-                        (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
-                nm.cancel(SystemMessage.NOTE_GLOBAL_SCREENSHOT);
-            } else {
-                PendingIntent chooseAction = PendingIntent.getBroadcast(context, 0,
-                        new Intent(context, GlobalScreenshot.TargetChosenReceiver.class),
-                        PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
-                actionIntent = Intent.createChooser(actionIntent, null,
-                        chooseAction.getIntentSender())
-                        .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
-            }
-
-            ActivityOptions opts = ActivityOptions.makeBasic();
-            opts.setDisallowEnterPictureInPictureWhileLaunching(true);
-
-            context.startActivityAsUser(actionIntent, opts.toBundle(), UserHandle.CURRENT);
+                Intent actionIntent = intent.getParcelableExtra(EXTRA_ACTION_INTENT);
+                if (intent.getBooleanExtra(EXTRA_CANCEL_NOTIFICATION, false)) {
+                    cancelScreenshotNotification(context);
+                }
+                ActivityOptions opts = ActivityOptions.makeBasic();
+                opts.setDisallowEnterPictureInPictureWhileLaunching(
+                        intent.getBooleanExtra(EXTRA_DISALLOW_ENTER_PIP, false));
+                context.startActivityAsUser(actionIntent, opts.toBundle(),UserHandle.CURRENT);
+            };
+            StatusBar statusBar = SysUiServiceProvider.getComponent(context, StatusBar.class);
+            statusBar.executeRunnableDismissingKeyguard(startActivityRunnable, null,
+                    true /* dismissShade */, true /* afterKeyguardGone */, true /* deferred */);
         }
     }
 
     /**
-     * Removes the notification for a screenshot after a share or edit target is chosen.
+     * Removes the notification for a screenshot after a share target is chosen.
      */
     public static class TargetChosenReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
-            // Clear the notification
-            final NotificationManager nm =
-                    (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
-            nm.cancel(SystemMessage.NOTE_GLOBAL_SCREENSHOT);
+            // Clear the notification only after the user has chosen a share action
+            cancelScreenshotNotification(context);
         }
     }
 
@@ -950,14 +939,18 @@
                 return;
             }
 
-            // Clear the notification
-            final NotificationManager nm =
-                    (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
-            final Uri uri = Uri.parse(intent.getStringExtra(SCREENSHOT_URI_ID));
-            nm.cancel(SystemMessage.NOTE_GLOBAL_SCREENSHOT);
+            // Clear the notification when the image is deleted
+            cancelScreenshotNotification(context);
 
             // And delete the image from the media store
+            final Uri uri = Uri.parse(intent.getStringExtra(SCREENSHOT_URI_ID));
             new DeleteImageInBackgroundTask(context).execute(uri);
         }
     }
+
+    private static void cancelScreenshotNotification(Context context) {
+        final NotificationManager nm =
+                (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);
+        nm.cancel(SystemMessage.NOTE_GLOBAL_SCREENSHOT);
+    }
 }
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 ae1da56..e3e791d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -4733,7 +4733,6 @@
         boolean dozing = mDozingRequested && mState == StatusBarState.KEYGUARD
                 || mBiometricUnlockController.getMode()
                         == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
-        final boolean alwaysOn = DozeParameters.getInstance(mContext).getAlwaysOn();
         // When in wake-and-unlock we may not have received a change to mState
         // but we still should not be dozing, manually set to false.
         if (mBiometricUnlockController.getMode() ==
@@ -4742,7 +4741,7 @@
         }
         if (mDozing != dozing) {
             mDozing = dozing;
-            mKeyguardViewMediator.setAodShowing(mDozing && alwaysOn);
+            mKeyguardViewMediator.setAodShowing(mDozing);
             mStatusBarWindowManager.setDozing(mDozing);
             mStatusBarKeyguardViewManager.setDozing(mDozing);
             if (mAmbientIndicationContainer instanceof DozeReceiver) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index a4e184b..052e8e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -665,11 +665,15 @@
         int width = MeasureSpec.getSize(widthMeasureSpec);
         int childWidthSpec = MeasureSpec.makeMeasureSpec(width - mSidePaddings * 2,
                 MeasureSpec.getMode(widthMeasureSpec));
+        // Don't constrain the height of the children so we know how big they'd like to be
+        int childHeightSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec),
+                MeasureSpec.UNSPECIFIED);
+
         // We need to measure all children even the GONE ones, such that the heights are calculated
         // correctly as they are used to calculate how many we can fit on the screen.
         final int size = getChildCount();
         for (int i = 0; i < size; i++) {
-            measureChild(getChildAt(i), childWidthSpec, heightMeasureSpec);
+            measureChild(getChildAt(i), childWidthSpec, childHeightSpec);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java
index a901e88..b835909 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java
+++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java
@@ -23,7 +23,7 @@
  */
 public class DelayedWakeLock implements WakeLock {
 
-    private static final long RELEASE_DELAY_MS = 140;
+    private static final long RELEASE_DELAY_MS = 100;
 
     private final Handler mHandler;
     private final WakeLock mInner;
diff --git a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/config.xml
index 80d8066..9254b4d 100644
--- a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/config.xml
+++ b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/config.xml
@@ -37,6 +37,8 @@
         @right
     </string>
 
+    <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">@*android:string/config_mainBuiltInDisplayCutout</string>
+
     <!-- Whether the display cutout region of the main built-in display should be forced to
          black in software (to avoid aliasing or emulate a cutout that is not physically existent).
      -->
diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml
index ca261f9..80c997a 100644
--- a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml
+++ b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml
@@ -49,6 +49,8 @@
         @dp
     </string>
 
+    <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">@*android:string/config_mainBuiltInDisplayCutout</string>
+
     <!-- Whether the display cutout region of the main built-in display should be forced to
          black in software (to avoid aliasing or emulate a cutout that is not physically existent).
      -->
diff --git a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml
index c22b2e7..6fb3c7f 100644
--- a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml
+++ b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml
@@ -40,6 +40,8 @@
         @dp
     </string>
 
+    <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">@*android:string/config_mainBuiltInDisplayCutout</string>
+
     <!-- Whether the display cutout region of the main built-in display should be forced to
          black in software (to avoid aliasing or emulate a cutout that is not physically existent).
      -->
diff --git a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml
index 401e092..7c29ffb 100644
--- a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml
+++ b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml
@@ -40,6 +40,8 @@
         @dp
     </string>
 
+    <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">@*android:string/config_mainBuiltInDisplayCutout</string>
+
     <!-- Whether the display cutout region of the main built-in display should be forced to
          black in software (to avoid aliasing or emulate a cutout that is not physically existent).
      -->
diff --git a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml
index f328b83..5fb8b9e 100644
--- a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml
+++ b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml
@@ -40,6 +40,8 @@
         @dp
     </string>
 
+    <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">@*android:string/config_mainBuiltInDisplayCutout</string>
+
     <!-- Whether the display cutout region of the main built-in display should be forced to
          black in software (to avoid aliasing or emulate a cutout that is not physically existent).
      -->
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index 33fc5e5..15c0468 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -470,6 +470,9 @@
   // Counts the occurrences of each link speed (Mbps) level
   // with rssi (dBm) and rssi^2 sums (dBm^2)
   repeated LinkSpeedCount link_speed_counts = 121;
+
+  // Number of times the SarManager failed to register SAR sensor listener
+  optional int32 num_sar_sensor_registration_failures = 122;
 }
 
 // Information that gets logged for every WiFi connection.
@@ -1611,4 +1614,4 @@
 
   // Firmware alert code. Only valid when the event was triggered by a firmware alert, otherwise -1.
   optional int32 firmware_alert_code = 10 [default = -1];
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index aa426d3..78b7385 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -53,12 +53,16 @@
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.UserManagerInternal;
 import android.os.UserManagerInternal.UserRestrictionsListener;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
+import android.text.TextUtils;
+import android.util.FeatureFlagUtils;
+import android.util.Log;
 import android.util.Slog;
 import android.util.StatsLog;
 
@@ -386,6 +390,15 @@
         mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
         mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
 
+        // TODO: We need a more generic way to initialize the persist keys of FeatureFlagUtils
+        boolean isHearingAidEnabled;
+        String value = SystemProperties.get(FeatureFlagUtils.PERSIST_PREFIX + FeatureFlagUtils.HEARING_AID_SETTINGS);
+        if (!TextUtils.isEmpty(value)) {
+            isHearingAidEnabled = Boolean.parseBoolean(value);
+            Log.v(TAG, "set feature flag HEARING_AID_SETTINGS to " + isHearingAidEnabled);
+            FeatureFlagUtils.setEnabled(context, FeatureFlagUtils.HEARING_AID_SETTINGS, isHearingAidEnabled);
+        }
+
         IntentFilter filter = new IntentFilter();
         filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
         filter.addAction(BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 3c94a34..2054e0a 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2229,6 +2229,7 @@
                         updateCapabilities(oldScore, nai, nai.networkCapabilities);
                         // If score has changed, rebroadcast to NetworkFactories. b/17726566
                         if (oldScore != nai.getCurrentScore()) sendUpdatedScoreToFactories(nai);
+                        if (valid) handleFreshlyValidatedNetwork(nai);
                     }
                     updateInetCondition(nai);
                     // Let the NetworkAgent know the state of its network
@@ -2323,6 +2324,16 @@
                 mDefaultRequest.networkCapabilities, nai.networkCapabilities);
     }
 
+    private void handleFreshlyValidatedNetwork(NetworkAgentInfo nai) {
+        if (nai == null) return;
+        // If the Private DNS mode is opportunistic, reprogram the DNS servers
+        // in order to restart a validation pass from within netd.
+        final PrivateDnsConfig cfg = mDnsManager.getPrivateDnsConfig();
+        if (cfg.useTls && TextUtils.isEmpty(cfg.hostname)) {
+            updateDnses(nai.linkProperties, null, nai.network.netId);
+        }
+    }
+
     private void handlePrivateDnsSettingsChanged() {
         final PrivateDnsConfig cfg = mDnsManager.getPrivateDnsConfig();
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index cc3d73f..456b676 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -581,8 +581,6 @@
     // Whether we should use SCHED_FIFO for UI and RenderThreads.
     private boolean mUseFifoUiScheduling = false;
 
-    private static final String SYSUI_COMPONENT_NAME = "com.android.systemui/.SystemUIService";
-
     BroadcastQueue mFgBroadcastQueue;
     BroadcastQueue mBgBroadcastQueue;
     // Convenient for easy iteration over the queues. Foreground is first
@@ -639,7 +637,7 @@
                 boolean asProto) {
             if (asProto) return;
             doDump(fd, pw, new String[]{"activities"}, asProto);
-            doDump(fd, pw, new String[]{"service", SYSUI_COMPONENT_NAME}, asProto);
+            doDump(fd, pw, new String[]{"service", "all-platform-critical"}, asProto);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index b9a279a..21ae048 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -31,8 +31,6 @@
 import android.os.PowerManager;
 import android.os.SystemProperties;
 import android.os.Trace;
-import android.text.TextUtils;
-import android.util.PathParser;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
@@ -404,8 +402,8 @@
                             && SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false))) {
                         mInfo.flags |= DisplayDeviceInfo.FLAG_ROUND;
                     }
-                    mInfo.displayCutout = DisplayCutout.fromResources(res, mInfo.width,
-                            mInfo.height);
+                    mInfo.displayCutout = DisplayCutout.fromResourcesRectApproximation(res,
+                            mInfo.width, mInfo.height);
                     mInfo.type = Display.TYPE_BUILT_IN;
                     mInfo.densityDpi = (int)(phys.density * 160 + 0.5f);
                     mInfo.xDpi = phys.xDpi;
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 75b9f13..1ab05ec 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -443,6 +443,8 @@
         pw.println(prefix + "fullscreenIntent=" + notification.fullScreenIntent);
         pw.println(prefix + "contentIntent=" + notification.contentIntent);
         pw.println(prefix + "deleteIntent=" + notification.deleteIntent);
+        pw.println(prefix + "number=" + notification.number);
+        pw.println(prefix + "groupAlertBehavior=" + notification.getGroupAlertBehavior());
 
         pw.print(prefix + "tickerText=");
         if (!TextUtils.isEmpty(notification.tickerText)) {
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 24fd331..669d556 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -1182,11 +1182,8 @@
     }
 
     private void showZenUpgradeNotification(int zen) {
-        final boolean isWatch = mContext.getPackageManager().hasSystemFeature(
-            PackageManager.FEATURE_WATCH);
         final boolean showNotification = mIsBootComplete
                 && zen != Global.ZEN_MODE_OFF
-                && !isWatch
                 && Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.SHOW_ZEN_UPGRADE_NOTIFICATION, 0) != 0;
 
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 dd6d71e..4c88bf4 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
@@ -72,7 +72,7 @@
     @GuardedBy("mLock")
     private int mBatteryLevel;
 
-    /** Whether the battery level is considered to be "low" or not.*/
+    /** Whether the battery level is considered to be "low" or not. */
     @GuardedBy("mLock")
     private boolean mIsBatteryLevelLow;
 
@@ -84,6 +84,9 @@
     @GuardedBy("mLock")
     private boolean mSettingBatterySaverEnabledSticky;
 
+    /** Config flag to track if battery saver's sticky behaviour is disabled. */
+    private final boolean mBatterySaverStickyBehaviourDisabled;
+
     /**
      * Previously known value of Global.LOW_POWER_MODE_TRIGGER_LEVEL.
      * (Currently only used in dumpsys.)
@@ -124,6 +127,9 @@
         mLock = lock;
         mContext = context;
         mBatterySaverController = batterySaverController;
+
+        mBatterySaverStickyBehaviourDisabled = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled);
     }
 
     private boolean isBatterySaverEnabled() {
@@ -304,7 +310,7 @@
                     BatterySaverController.REASON_PLUGGED_IN,
                     "Plugged in");
 
-        } else if (mSettingBatterySaverEnabledSticky) {
+        } else if (mSettingBatterySaverEnabledSticky && !mBatterySaverStickyBehaviourDisabled) {
             // Re-enable BS.
             enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ true,
                     BatterySaverController.REASON_STICKY_RESTORE,
@@ -383,8 +389,9 @@
         putGlobalSetting(Global.LOW_POWER_MODE, enable ? 1 : 0);
 
         if (manual) {
-            mSettingBatterySaverEnabledSticky = enable;
-            putGlobalSetting(Global.LOW_POWER_MODE_STICKY, enable ? 1 : 0);
+            mSettingBatterySaverEnabledSticky = !mBatterySaverStickyBehaviourDisabled && enable;
+            putGlobalSetting(Global.LOW_POWER_MODE_STICKY,
+                    mSettingBatterySaverEnabledSticky ? 1 : 0);
         }
         mBatterySaverController.enableBatterySaver(enable, intReason);
 
@@ -449,6 +456,8 @@
             pw.println(mSettingBatterySaverEnabledSticky);
             pw.print("  mSettingBatterySaverTriggerThreshold=");
             pw.println(mSettingBatterySaverTriggerThreshold);
+            pw.print("  mBatterySaverStickyBehaviourDisabled=");
+            pw.println(mBatterySaverStickyBehaviourDisabled);
         }
     }
 
diff --git a/services/core/java/com/android/server/slice/PinnedSliceState.java b/services/core/java/com/android/server/slice/PinnedSliceState.java
index 4e7fb96..e139ab8 100644
--- a/services/core/java/com/android/server/slice/PinnedSliceState.java
+++ b/services/core/java/com/android/server/slice/PinnedSliceState.java
@@ -154,8 +154,8 @@
     }
 
     ContentProviderClient getClient() {
-        ContentProviderClient client =
-                mService.getContext().getContentResolver().acquireContentProviderClient(mUri);
+        ContentProviderClient client = mService.getContext().getContentResolver()
+                .acquireUnstableContentProviderClient(mUri);
         if (client == null) return null;
         client.setDetectNotResponding(SLICE_TIMEOUT);
         return client;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index f74216a..0ca8e1a 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1249,11 +1249,21 @@
                     cutout, mInitialDisplayWidth, mInitialDisplayHeight);
         }
         final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
-        final Path bounds = cutout.getBounds().getBoundaryPath();
+        final List<Rect> bounds = WmDisplayCutout.computeSafeInsets(
+                        cutout, mInitialDisplayWidth, mInitialDisplayHeight)
+                .getDisplayCutout().getBoundingRects();
         transformPhysicalToLogicalCoordinates(rotation, mInitialDisplayWidth, mInitialDisplayHeight,
                 mTmpMatrix);
-        bounds.transform(mTmpMatrix);
-        return WmDisplayCutout.computeSafeInsets(DisplayCutout.fromBounds(bounds),
+        final Region region = Region.obtain();
+        for (int i = 0; i < bounds.size(); i++) {
+            final Rect rect = bounds.get(i);
+            final RectF rectF = new RectF(bounds.get(i));
+            mTmpMatrix.mapRect(rectF);
+            rectF.round(rect);
+            region.op(rect, Op.UNION);
+        }
+
+        return WmDisplayCutout.computeSafeInsets(DisplayCutout.fromBounds(region),
                 rotated ? mInitialDisplayHeight : mInitialDisplayWidth,
                 rotated ? mInitialDisplayWidth : mInitialDisplayHeight);
     }
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 281e0a8..a626663 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -40,6 +40,7 @@
 import android.os.Looper;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.Trace;
 import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -620,6 +621,8 @@
 
         private void updateInputWindows(boolean inDrag) {
 
+            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "updateInputWindows");
+
             // TODO: multi-display
             navInputConsumer = getInputConsumer(INPUT_CONSUMER_NAVIGATION, DEFAULT_DISPLAY);
             pipInputConsumer = getInputConsumer(INPUT_CONSUMER_PIP, DEFAULT_DISPLAY);
@@ -645,6 +648,8 @@
             mService.mInputManager.setInputWindows(mInputWindowHandles, mFocusedInputWindowHandle);
 
             clearInputWindowHandlesLw();
+
+            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 399078a..54703b3 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2180,8 +2180,6 @@
 
             result |= mInTouchMode ? WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE : 0;
 
-            mInputMonitor.updateInputWindowsLw(true /*force*/);
-
             if (DEBUG_LAYOUT) {
                 Slog.v(TAG_WM, "Relayout complete " + win + ": outFrame=" + outFrame.toShortString());
             }
@@ -5666,9 +5664,9 @@
             boolean imWindowChanged = false;
             if (mInputMethodWindow != null) {
                 final WindowState prevTarget = mInputMethodTarget;
+
                 final WindowState newTarget =
                         displayContent.computeImeTarget(true /* updateImeTarget*/);
-
                 imWindowChanged = prevTarget != newTarget;
 
                 if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityOptionsTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityOptionsTest.java
new file mode 100644
index 0000000..28b37c5
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityOptionsTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.am;
+
+import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
+import static org.junit.Assert.assertEquals;
+
+import android.app.ActivityOptions;
+import android.os.Bundle;
+import android.os.Debug;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.FlakyTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * atest FrameworksServicesTests:ActivityOptionsTest
+ */
+@MediumTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class ActivityOptionsTest {
+
+    @Test
+    public void testMerge_NoClobber() {
+        // Construct some options with set values
+        ActivityOptions opts = ActivityOptions.makeBasic();
+        opts.setLaunchDisplayId(Integer.MAX_VALUE);
+        opts.setLaunchActivityType(ACTIVITY_TYPE_STANDARD);
+        opts.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
+        opts.setAvoidMoveToFront();
+        opts.setLaunchTaskId(Integer.MAX_VALUE);
+        opts.setLockTaskEnabled(true);
+        opts.setRotationAnimationHint(ROTATION_ANIMATION_ROTATE);
+        opts.setTaskOverlay(true, true);
+        opts.setSplitScreenCreateMode(SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT);
+        Bundle optsBundle = opts.toBundle();
+
+        // Try and merge the constructed options with a new set of options
+        optsBundle.putAll(ActivityOptions.makeBasic().toBundle());
+
+        // Ensure the set values are not clobbered
+        ActivityOptions restoredOpts = ActivityOptions.fromBundle(optsBundle);
+        assertEquals(Integer.MAX_VALUE, restoredOpts.getLaunchDisplayId());
+        assertEquals(ACTIVITY_TYPE_STANDARD, restoredOpts.getLaunchActivityType());
+        assertEquals(WINDOWING_MODE_FULLSCREEN, restoredOpts.getLaunchWindowingMode());
+        assertEquals(true, restoredOpts.getAvoidMoveToFront());
+        assertEquals(Integer.MAX_VALUE, restoredOpts.getLaunchTaskId());
+        assertEquals(true, restoredOpts.getLockTaskMode());
+        assertEquals(ROTATION_ANIMATION_ROTATE, restoredOpts.getRotationAnimationHint());
+        assertEquals(true, restoredOpts.getTaskOverlay());
+        assertEquals(true, restoredOpts.canTaskOverlayResume());
+        assertEquals(SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT,
+                restoredOpts.getSplitScreenCreateMode());
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java
index 2c47a94..1d37802 100644
--- a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java
@@ -37,6 +37,7 @@
 import android.graphics.Path;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
+import android.graphics.RectF;
 import android.os.IBinder;
 import android.os.UserHandle;
 import android.support.test.InstrumentationRegistry;
@@ -172,15 +173,14 @@
     }
 
     private static DisplayCutout displayCutoutForRotation(int rotation) {
-        Path p = new Path();
-        p.addRect(DISPLAY_WIDTH / 4, 0, DISPLAY_WIDTH * 3 / 4, DISPLAY_CUTOUT_HEIGHT,
-                Path.Direction.CCW);
+        RectF rectF = new RectF(DISPLAY_WIDTH / 4, 0, DISPLAY_WIDTH * 3 / 4, DISPLAY_CUTOUT_HEIGHT);
 
         Matrix m = new Matrix();
         transformPhysicalToLogicalCoordinates(rotation, DISPLAY_WIDTH, DISPLAY_HEIGHT, m);
-        p.transform(m);
+        m.mapRect(rectF);
 
-        return DisplayCutout.fromBounds(p);
+        return DisplayCutout.fromBoundingRect((int) rectF.left, (int) rectF.top,
+                (int) rectF.right, (int) rectF.bottom);
     }
 
     static class TestContextWrapper extends ContextWrapper {
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 5b24725..0764a56 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
@@ -23,6 +23,7 @@
 import static org.mockito.Mockito.when;
 
 import android.content.ContentResolver;
+import android.content.res.Resources;
 import android.provider.Settings.Global;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
@@ -48,12 +49,18 @@
     private BatterySaverController mMockBatterySaverController;
     private Device mDevice;
     private TestableBatterySaverStateMachine mTarget;
+    private Resources mMockResources;
 
     private class MyMockContext extends MockContext {
         @Override
         public ContentResolver getContentResolver() {
             return mMockContextResolver;
         }
+
+        @Override
+        public Resources getResources() {
+            return mMockResources;
+        }
     }
 
     private DevicePersistedState mPersistedState;
@@ -157,11 +164,15 @@
         mMockContext = new MyMockContext();
         mMockContextResolver = mock(ContentResolver.class);
         mMockBatterySaverController = mock(BatterySaverController.class);
+        mMockResources = mock(Resources.class);
 
         doAnswer((inv) -> mDevice.batterySaverEnabled = inv.getArgument(0))
                 .when(mMockBatterySaverController).enableBatterySaver(anyBoolean(), anyInt());
         when(mMockBatterySaverController.isEnabled())
                 .thenAnswer((inv) -> mDevice.batterySaverEnabled);
+        when(mMockResources.getBoolean(
+                com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled))
+                .thenReturn(false);
 
         mPersistedState = new DevicePersistedState();
         initDevice();
@@ -173,7 +184,6 @@
         mTarget = new TestableBatterySaverStateMachine();
 
         mDevice.pushBatteryStatus();
-        mDevice.pushGlobalSettings();
         mTarget.onBootCompleted();
     }
 
@@ -498,8 +508,83 @@
     }
 
     @Test
-    public void testNoAutoBatterySaver_fromAdb() {
+    public void testAutoBatterySaver_withStickyDisabled() {
+        when(mMockResources.getBoolean(
+                com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled))
+                .thenReturn(true);
+        initDevice();
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
 
+        mTarget.setBatterySaverEnabledManually(true);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(100, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(30);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(80);
+
+        assertEquals(false, mDevice.batterySaverEnabled); // Not sticky.
+        assertEquals(80, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setPowered(true);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(80, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(30);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mDevice.setPowered(false);
+
+        assertEquals(true, mDevice.batterySaverEnabled); // Restores BS.
+        assertEquals(30, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mDevice.setPowered(true);
+        mDevice.setBatteryLevel(90);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        initDevice();
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setPowered(false);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mTarget.setBatterySaverEnabledManually(false);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        initDevice();
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+    }
+
+    @Test
+    public void testNoAutoBatterySaver_fromAdb() {
         assertEquals(0, mDevice.getLowPowerModeTriggerLevel());
 
         assertEquals(false, mDevice.batterySaverEnabled);
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
index 3c4e333..82e0fbe 100644
--- a/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
@@ -1,16 +1,16 @@
 package com.android.server.slice;
 
+import static android.testing.TestableContentResolver.UNSTABLE;
+
 import static org.junit.Assert.assertArrayEquals;
 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 static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -71,11 +71,12 @@
         mSliceService = mock(SliceManagerService.class);
         when(mSliceService.getContext()).thenReturn(mContext);
         when(mSliceService.getLock()).thenReturn(new Object());
-        when(mSliceService.getHandler()).thenReturn(new Handler(TestableLooper.get(this).getLooper()));
+        when(mSliceService.getHandler()).thenReturn(
+                new Handler(TestableLooper.get(this).getLooper()));
         mContentProvider = mock(ContentProvider.class);
         mIContentProvider = mock(IContentProvider.class);
         when(mContentProvider.getIContentProvider()).thenReturn(mIContentProvider);
-        mContext.getContentResolver().addProvider(AUTH, mContentProvider);
+        mContext.getContentResolver().addProvider(AUTH, mContentProvider, UNSTABLE);
         mPinnedSliceManager = new PinnedSliceState(mSliceService, TEST_URI, "pkg");
     }
 
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index 7e86966..2b6928e 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -121,6 +121,8 @@
 
     /**
      * Get reference signal received quality
+     *
+     * @return the RSRQ if available or Integer.MAX_VALUE if unavailable.
      */
     public int getRsrq() {
         return mRsrq;
@@ -128,13 +130,17 @@
 
     /**
      * Get reference signal signal-to-noise ratio
+     *
+     * @return the RSSNR if available or Integer.MAX_VALUE if unavailable.
      */
     public int getRssnr() {
         return mRssnr;
     }
 
     /**
-     * Get reference signal received power
+     * Get reference signal received power in dBm
+     *
+     * @return the RSRP of the measured cell.
      */
     public int getRsrp() {
         return mRsrp;
@@ -142,13 +148,17 @@
 
     /**
      * Get channel quality indicator
+     *
+     * @return the CQI if available or Integer.MAX_VALUE if unavailable.
      */
     public int getCqi() {
         return mCqi;
     }
 
     /**
-     * Get signal strength as dBm
+     * Get signal strength in dBm
+     *
+     * @return the RSRP of the measured cell.
      */
     @Override
     public int getDbm() {
@@ -175,7 +185,8 @@
      * Get the timing advance value for LTE, as a value in range of 0..1282.
      * Integer.MAX_VALUE is reported when there is no active RRC
      * connection. Refer to 3GPP 36.213 Sec 4.2.3
-     * @return the LTE timing advance, if available.
+     *
+     * @return the LTE timing advance if available or Integer.MAX_VALUE if unavailable.
      */
     public int getTimingAdvance() {
         return mTimingAdvance;
diff --git a/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivity.java b/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivity.java
index b763c78..b4b5ca7 100644
--- a/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivity.java
+++ b/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivity.java
@@ -30,6 +30,7 @@
 import android.view.MenuItem;
 import android.view.MotionEvent;
 import android.view.View;
+import android.os.Trace;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -42,6 +43,7 @@
 
     public TouchLatencyView(Context context, AttributeSet attrs) {
         super(context, attrs);
+        Trace.beginSection("TouchLatencyView constructor");
         setOnTouchListener(this);
         setWillNotDraw(false);
         mBluePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
@@ -63,48 +65,56 @@
         mBallY = 100.0f;
         mVelocityX = 7.0f;
         mVelocityY = 7.0f;
+        Trace.endSection();
     }
 
     @Override
     public boolean onTouch(View view, MotionEvent event) {
+        Trace.beginSection("TouchLatencyView onTouch");
         int action = event.getActionMasked();
         if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_MOVE) {
             mTouching = true;
             invalidate();
+
+            mTouchX = event.getX();
+            mTouchY = event.getY();
         } else if (action == MotionEvent.ACTION_UP) {
             mTouching = false;
             invalidate();
-            return true;
-        } else {
-            return true;
         }
-        mTouchX = event.getX();
-        mTouchY = event.getY();
+        Trace.endSection();
         return true;
     }
 
     private void drawTouch(Canvas canvas) {
-        if (!mTouching) {
-            Log.d(LOG_TAG, "Filling background");
+        Trace.beginSection("TouchLatencyView drawTouch");
+
+        try {
+            if (!mTouching) {
+                Log.d(LOG_TAG, "Filling background");
+                canvas.drawColor(BACKGROUND_COLOR);
+                return;
+            }
+
+            float deltaX = (mTouchX - mLastDrawnX);
+            float deltaY = (mTouchY - mLastDrawnY);
+            float scaleFactor = (float) Math.sqrt(deltaX * deltaX + deltaY * deltaY) * 1.5f;
+
+            mLastDrawnX = mTouchX;
+            mLastDrawnY = mTouchY;
+
             canvas.drawColor(BACKGROUND_COLOR);
-            return;
+            canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + 3 * scaleFactor, mRedPaint);
+            canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + 2 * scaleFactor, mYellowPaint);
+            canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + scaleFactor, mGreenPaint);
+            canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS, mBluePaint);
+        } finally {
+            Trace.endSection();
         }
-
-        float deltaX = (mTouchX - mLastDrawnX);
-        float deltaY = (mTouchY - mLastDrawnY);
-        float scaleFactor = (float) Math.sqrt(deltaX * deltaX + deltaY * deltaY) * 1.5f;
-
-        mLastDrawnX = mTouchX;
-        mLastDrawnY = mTouchY;
-
-        canvas.drawColor(BACKGROUND_COLOR);
-        canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + 3 * scaleFactor, mRedPaint);
-        canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + 2 * scaleFactor, mYellowPaint);
-        canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + scaleFactor, mGreenPaint);
-        canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS, mBluePaint);
     }
 
     private void drawBall(Canvas canvas) {
+        Trace.beginSection("TouchLatencyView drawBall");
         int width = canvas.getWidth();
         int height = canvas.getHeight();
 
@@ -141,25 +151,29 @@
         canvas.drawColor(BACKGROUND_COLOR);
         canvas.drawOval(left, top, right, bottom, mYellowPaint);
         invalidate();
+        Trace.endSection();
     }
 
     @Override
     protected void onDraw(Canvas canvas) {
         super.onDraw(canvas);
-
+        Trace.beginSection("TouchLatencyView onDraw");
         if (mMode == 0) {
             drawTouch(canvas);
         } else {
             drawBall(canvas);
         }
+        Trace.endSection();
     }
 
     public void changeMode(MenuItem item) {
+        Trace.beginSection("TouchLatencyView changeMode");
         final int NUM_MODES = 2;
         final String modes[] = {"Touch", "Ball"};
         mMode = (mMode + 1) % NUM_MODES;
         invalidate();
         item.setTitle(modes[mMode]);
+        Trace.endSection();
     }
 
     private Paint mBluePaint, mGreenPaint, mYellowPaint, mRedPaint;
@@ -178,21 +192,26 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        Trace.beginSection("TouchLatencyActivity onCreate");
         setContentView(R.layout.activity_touch_latency);
 
         mTouchView = findViewById(R.id.canvasView);
+        Trace.endSection();
     }
 
 
     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
+        Trace.beginSection("TouchLatencyActivity onCreateOptionsMenu");
         // Inflate the menu; this adds items to the action bar if it is present.
         getMenuInflater().inflate(R.menu.menu_touch_latency, menu);
+        Trace.endSection();
         return true;
     }
 
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
+        Trace.beginSection("TouchLatencyActivity onOptionsItemSelected");
         // Handle action bar item clicks here. The action bar will
         // automatically handle clicks on the Home/Up button, so long
         // as you specify a parent activity in AndroidManifest.xml.
@@ -203,6 +222,7 @@
             mTouchView.changeMode(item);
         }
 
+        Trace.endSection();
         return super.onOptionsItemSelected(item);
     }
 
diff --git a/tests/testables/src/android/testing/TestableContentResolver.java b/tests/testables/src/android/testing/TestableContentResolver.java
index 0850916..a0afef8 100644
--- a/tests/testables/src/android/testing/TestableContentResolver.java
+++ b/tests/testables/src/android/testing/TestableContentResolver.java
@@ -20,6 +20,7 @@
 import android.content.IContentProvider;
 import android.database.ContentObserver;
 import android.net.Uri;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 
 import com.google.android.collect.Maps;
@@ -35,7 +36,11 @@
  */
 public class TestableContentResolver extends ContentResolver {
 
-    private final Map<String, ContentProvider> mProviders = Maps.newHashMap();
+    public static final int STABLE = 1;
+    public static final int UNSTABLE = 2;
+
+    private final Map<String, ContentProvider> mProviders = new ArrayMap<>();
+    private final Map<String, ContentProvider> mUnstableProviders = new ArrayMap<>();
     private final ContentResolver mParent;
     private final ArraySet<ContentProvider> mInUse = new ArraySet<>();
     private boolean mFallbackToExisting;
@@ -62,7 +67,23 @@
      * subclasses, or null.
      */
     public void addProvider(String name, ContentProvider provider) {
-        mProviders.put(name, provider);
+        addProvider(name, provider, STABLE | UNSTABLE);
+    }
+
+    /**
+     * Adds access to a provider based on its authority
+     *
+     * @param name The authority name associated with the provider.
+     * @param provider An instance of {@link android.content.ContentProvider} or one of its
+     * subclasses, or null.
+     */
+    public void addProvider(String name, ContentProvider provider, int flags) {
+        if ((flags & STABLE) != 0) {
+            mProviders.put(name, provider);
+        }
+        if ((flags & UNSTABLE) != 0) {
+            mUnstableProviders.put(name, provider);
+        }
     }
 
     @Override
@@ -98,7 +119,7 @@
 
     @Override
     protected IContentProvider acquireUnstableProvider(Context c, String name) {
-        final ContentProvider provider = mProviders.get(name);
+        final ContentProvider provider = mUnstableProviders.get(name);
         if (provider != null) {
             return provider.getIContentProvider();
         } else {
@@ -128,7 +149,8 @@
     @Override
     public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
         if (!mFallbackToExisting) return;
-        if (!mProviders.containsKey(uri.getAuthority())) {
+        if (!mProviders.containsKey(uri.getAuthority())
+                && !mUnstableProviders.containsKey(uri.getAuthority())) {
             super.notifyChange(uri, observer, syncToNetwork);
         }
     }
diff --git a/tests/testables/tests/src/android/testing/TestableContentResolverTest.java b/tests/testables/tests/src/android/testing/TestableContentResolverTest.java
new file mode 100644
index 0000000..71afda0
--- /dev/null
+++ b/tests/testables/tests/src/android/testing/TestableContentResolverTest.java
@@ -0,0 +1,61 @@
+package android.testing;
+
+import android.content.ContentProvider;
+import android.content.IContentProvider;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class TestableContentResolverTest {
+
+    @Rule
+    public TestableContext mContext = new TestableContext(InstrumentationRegistry.getContext());
+    private TestableContentResolver mContentResolver;
+
+    @Before
+    public void setup() {
+        mContentResolver = new TestableContentResolver(mContext);
+        mContentResolver.setFallbackToExisting(false);
+    }
+
+    @Test
+    public void testDefaultContentProvider() {
+        ContentProvider provider = Mockito.mock(ContentProvider.class);
+        IContentProvider iprovider = Mockito.mock(IContentProvider.class);
+        Mockito.when(provider.getIContentProvider()).thenReturn(iprovider);
+        mContentResolver.addProvider("test", provider);
+
+        Assert.assertEquals(iprovider, mContentResolver.acquireProvider(mContext, "test"));
+        Assert.assertEquals(iprovider, mContentResolver.acquireUnstableProvider(mContext, "test"));
+    }
+
+    @Test
+    public void testStableContentProvider() {
+        ContentProvider provider = Mockito.mock(ContentProvider.class);
+        IContentProvider iprovider = Mockito.mock(IContentProvider.class);
+        Mockito.when(provider.getIContentProvider()).thenReturn(iprovider);
+        mContentResolver.addProvider("test", provider, TestableContentResolver.STABLE);
+
+        Assert.assertEquals(iprovider, mContentResolver.acquireProvider(mContext, "test"));
+        Assert.assertNull(mContentResolver.acquireUnstableProvider(mContext, "test"));
+    }
+
+    @Test
+    public void testUnstableContentProvider() {
+        ContentProvider provider = Mockito.mock(ContentProvider.class);
+        IContentProvider iprovider = Mockito.mock(IContentProvider.class);
+        Mockito.when(provider.getIContentProvider()).thenReturn(iprovider);
+        mContentResolver.addProvider("test", provider, TestableContentResolver.UNSTABLE);
+
+        Assert.assertEquals(iprovider, mContentResolver.acquireUnstableProvider(mContext, "test"));
+        Assert.assertNull(mContentResolver.acquireProvider(mContext, "test"));
+    }
+}
diff --git a/tools/aapt2/StringPool.cpp b/tools/aapt2/StringPool.cpp
index b37e1fb..8eabd32 100644
--- a/tools/aapt2/StringPool.cpp
+++ b/tools/aapt2/StringPool.cpp
@@ -367,7 +367,7 @@
 static bool EncodeString(const std::string& str, const bool utf8, BigBuffer* out,
                          IDiagnostics* diag) {
   if (utf8) {
-    const std::string& encoded = str;
+    const std::string& encoded = util::Utf8ToModifiedUtf8(str);
     const ssize_t utf16_length = utf8_to_utf16_length(
         reinterpret_cast<const uint8_t*>(encoded.data()), encoded.size());
     CHECK(utf16_length >= 0);
diff --git a/tools/aapt2/StringPool_test.cpp b/tools/aapt2/StringPool_test.cpp
index 4b3afe2..0778564 100644
--- a/tools/aapt2/StringPool_test.cpp
+++ b/tools/aapt2/StringPool_test.cpp
@@ -303,6 +303,25 @@
   }
 }
 
+TEST(StringPoolTest, FlattenModifiedUTF8) {
+  using namespace android;  // For NO_ERROR on Windows.
+  StdErrDiagnostics diag;
+  StringPool pool;
+  StringPool::Ref ref_a = pool.MakeRef("\xF0\x90\x90\x80"); // 𐐀 (U+10400)
+  StringPool::Ref ref_b = pool.MakeRef("foo \xF0\x90\x90\xB7 bar"); // 𐐷 (U+10437)
+  StringPool::Ref ref_c = pool.MakeRef("\xF0\x90\x90\x80\xF0\x90\x90\xB7");
+
+  BigBuffer buffer(1024);
+  StringPool::FlattenUtf8(&buffer, pool, &diag);
+  std::unique_ptr<uint8_t[]> data = util::Copy(buffer);
+
+  // Check that the 4 byte utf-8 codepoint is encoded using 2 3 byte surrogate pairs
+  ResStringPool test;
+  ASSERT_EQ(test.setTo(data.get(), buffer.size()), NO_ERROR);
+  EXPECT_THAT(util::GetString(test, 0), Eq("\xED\xA0\x81\xED\xB0\x80"));
+  EXPECT_THAT(util::GetString(test, 1), Eq("foo \xED\xA0\x81\xED\xB0\xB7 bar"));
+  EXPECT_THAT(util::GetString(test, 2), Eq("\xED\xA0\x81\xED\xB0\x80\xED\xA0\x81\xED\xB0\xB7"));
+}
 
 TEST(StringPoolTest, MaxEncodingLength) {
   StdErrDiagnostics diag;
diff --git a/tools/aapt2/util/Util.cpp b/tools/aapt2/util/Util.cpp
index d1c9ca1..9bef54e5 100644
--- a/tools/aapt2/util/Util.cpp
+++ b/tools/aapt2/util/Util.cpp
@@ -297,6 +297,53 @@
   return true;
 }
 
+std::string Utf8ToModifiedUtf8(const std::string& utf8) {
+  // Java uses Modified UTF-8 which only supports the 1, 2, and 3 byte formats of UTF-8. To encode
+  // 4 byte UTF-8 codepoints, Modified UTF-8 allows the use of surrogate pairs in the same format
+  // of CESU-8 surrogate pairs. Calculate the size of the utf8 string with all 4 byte UTF-8
+  // codepoints replaced with 2 3 byte surrogate pairs
+  size_t modified_size = 0;
+  const size_t size = utf8.size();
+  for (size_t i = 0; i < size; i++) {
+    if (((uint8_t) utf8[i] >> 4) == 0xF) {
+      modified_size += 6;
+      i += 3;
+    } else {
+      modified_size++;
+    }
+  }
+
+  // Early out if no 4 byte codepoints are found
+  if (size == modified_size) {
+    return utf8;
+  }
+
+  std::string output;
+  output.reserve(modified_size);
+  for (size_t i = 0; i < size; i++) {
+    if (((uint8_t) utf8[i] >> 4) == 0xF) {
+      auto codepoint = (char32_t) utf32_from_utf8_at(utf8.data(), size, i, nullptr);
+
+      // Calculate the high and low surrogates as UTF-16 would
+      char32_t high = ((codepoint - 0x10000) / 0x400) + 0xD800;
+      char32_t low = ((codepoint - 0x10000) % 0x400) + 0xDC00;
+
+      // Encode each surrogate in UTF-8
+      output.push_back((char) (0xE4 | ((high >> 12) & 0xF)));
+      output.push_back((char) (0x80 | ((high >> 6) & 0x3F)));
+      output.push_back((char) (0x80 | (high & 0x3F)));
+      output.push_back((char) (0xE4 | ((low >> 12) & 0xF)));
+      output.push_back((char) (0x80 | ((low >> 6) & 0x3F)));
+      output.push_back((char) (0x80 | (low & 0x3F)));
+      i += 3;
+    } else {
+      output.push_back(utf8[i]);
+    }
+  }
+
+  return output;
+}
+
 std::u16string Utf8ToUtf16(const StringPiece& utf8) {
   ssize_t utf16_length = utf8_to_utf16_length(
       reinterpret_cast<const uint8_t*>(utf8.data()), utf8.length());
diff --git a/tools/aapt2/util/Util.h b/tools/aapt2/util/Util.h
index 0eb35d1..36b7333 100644
--- a/tools/aapt2/util/Util.h
+++ b/tools/aapt2/util/Util.h
@@ -197,6 +197,9 @@
   return error_.empty();
 }
 
+// Converts a UTF8 string into Modified UTF8
+std::string Utf8ToModifiedUtf8(const std::string& utf8);
+
 // Converts a UTF8 string to a UTF16 string.
 std::u16string Utf8ToUtf16(const android::StringPiece& utf8);
 std::string Utf16ToUtf8(const android::StringPiece16& utf16);