Merge "Don't use user-tagged Uris in slice callbacks"
diff --git a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
index 6975609..682885b 100644
--- a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
@@ -25,9 +25,12 @@
 import android.support.test.runner.AndroidJUnit4;
 
 import android.content.res.ColorStateList;
+import android.graphics.Canvas;
 import android.graphics.Typeface;
 import android.text.Layout;
 import android.text.style.TextAppearanceSpan;
+import android.view.DisplayListCanvas;
+import android.view.RenderNode;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -285,4 +288,157 @@
                     .build();
         }
     }
+
+    @Test
+    public void testDraw_FixedText_NoStyled() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final CharSequence text = generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
+        final RenderNode node = RenderNode.create("benchmark", null);
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            final StaticLayout layout =
+                    StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
+            final DisplayListCanvas c = node.start(1200, 200);
+            state.resumeTiming();
+
+            layout.draw(c);
+        }
+    }
+
+    @Test
+    public void testDraw_RandomText_Styled() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final RenderNode node = RenderNode.create("benchmark", null);
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            final CharSequence text = generateRandomParagraph(WORD_LENGTH, STYLE_TEXT);
+            final StaticLayout layout =
+                    StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
+            final DisplayListCanvas c = node.start(1200, 200);
+            state.resumeTiming();
+
+            layout.draw(c);
+        }
+    }
+
+    @Test
+    public void testDraw_RandomText_NoStyled() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final RenderNode node = RenderNode.create("benchmark", null);
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            final CharSequence text = generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
+            final StaticLayout layout =
+                    StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
+            final DisplayListCanvas c = node.start(1200, 200);
+            state.resumeTiming();
+
+            layout.draw(c);
+        }
+    }
+
+    @Test
+    public void testDraw_RandomText_Styled_WithoutCache() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final RenderNode node = RenderNode.create("benchmark", null);
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            final CharSequence text = generateRandomParagraph(WORD_LENGTH, STYLE_TEXT);
+            final StaticLayout layout =
+                    StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
+            final DisplayListCanvas c = node.start(1200, 200);
+            Canvas.freeTextLayoutCaches();
+            state.resumeTiming();
+
+            layout.draw(c);
+        }
+    }
+
+    @Test
+    public void testDraw_RandomText_NoStyled_WithoutCache() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final RenderNode node = RenderNode.create("benchmark", null);
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            final CharSequence text = generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
+            final StaticLayout layout =
+                    StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
+            final DisplayListCanvas c = node.start(1200, 200);
+            Canvas.freeTextLayoutCaches();
+            state.resumeTiming();
+
+            layout.draw(c);
+        }
+    }
+
+    @Test
+    public void testDraw_MeasuredText_Styled() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final RenderNode node = RenderNode.create("benchmark", null);
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            final MeasuredText text = new MeasuredText.Builder(
+                    generateRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT).build();
+            final StaticLayout layout =
+                    StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
+            final DisplayListCanvas c = node.start(1200, 200);
+            state.resumeTiming();
+
+            layout.draw(c);
+        }
+    }
+
+    @Test
+    public void testDraw_MeasuredText_NoStyled() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final RenderNode node = RenderNode.create("benchmark", null);
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            final MeasuredText text = new MeasuredText.Builder(
+                    generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT).build();
+            final StaticLayout layout =
+                    StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
+            final DisplayListCanvas c = node.start(1200, 200);
+            state.resumeTiming();
+
+            layout.draw(c);
+        }
+    }
+
+    @Test
+    public void testDraw_MeasuredText_Styled_WithoutCache() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final RenderNode node = RenderNode.create("benchmark", null);
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            final MeasuredText text = new MeasuredText.Builder(
+                    generateRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT).build();
+            final StaticLayout layout =
+                    StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
+            final DisplayListCanvas c = node.start(1200, 200);
+            Canvas.freeTextLayoutCaches();
+            state.resumeTiming();
+
+            layout.draw(c);
+        }
+    }
+
+    @Test
+    public void testDraw_MeasuredText_NoStyled_WithoutCache() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final RenderNode node = RenderNode.create("benchmark", null);
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            final MeasuredText text = new MeasuredText.Builder(
+                    generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT).build();
+            final StaticLayout layout =
+                    StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
+            final DisplayListCanvas c = node.start(1200, 200);
+            Canvas.freeTextLayoutCaches();
+            state.resumeTiming();
+
+            layout.draw(c);
+        }
+    }
+
 }
diff --git a/api/current.txt b/api/current.txt
index bb4c383..52dbe9b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6474,6 +6474,7 @@
     method public boolean isMasterVolumeMuted(android.content.ComponentName);
     method public boolean isNetworkLoggingEnabled(android.content.ComponentName);
     method public boolean isPackageSuspended(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public boolean isPrintingEnabled();
     method public boolean isProfileOwnerApp(java.lang.String);
     method public boolean isProvisioningAllowed(java.lang.String);
     method public boolean isResetPasswordTokenActive(android.content.ComponentName);
@@ -6543,6 +6544,7 @@
     method public boolean setPermittedAccessibilityServices(android.content.ComponentName, java.util.List<java.lang.String>);
     method public boolean setPermittedCrossProfileNotificationListeners(android.content.ComponentName, java.util.List<java.lang.String>);
     method public boolean setPermittedInputMethods(android.content.ComponentName, java.util.List<java.lang.String>);
+    method public void setPrintingEnabled(android.content.ComponentName, boolean);
     method public void setProfileEnabled(android.content.ComponentName);
     method public void setProfileName(android.content.ComponentName, java.lang.String);
     method public void setRecommendedGlobalProxy(android.content.ComponentName, android.net.ProxyInfo);
@@ -15843,6 +15845,7 @@
     field public static final int HOT_PIXEL_MODE_HIGH_QUALITY = 2; // 0x2
     field public static final int HOT_PIXEL_MODE_OFF = 0; // 0x0
     field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_3 = 3; // 0x3
+    field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL = 4; // 0x4
     field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_FULL = 1; // 0x1
     field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY = 2; // 0x2
     field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED = 0; // 0x0
@@ -21751,7 +21754,13 @@
     field public static final int CHANNEL_OUT_STEREO = 12; // 0xc
     field public static final int CHANNEL_OUT_SURROUND = 1052; // 0x41c
     field public static final android.os.Parcelable.Creator<android.media.AudioFormat> CREATOR;
+    field public static final int ENCODING_AAC_ELD = 15; // 0xf
+    field public static final int ENCODING_AAC_HE_V1 = 11; // 0xb
+    field public static final int ENCODING_AAC_HE_V2 = 12; // 0xc
+    field public static final int ENCODING_AAC_LC = 10; // 0xa
+    field public static final int ENCODING_AAC_XHE = 16; // 0x10
     field public static final int ENCODING_AC3 = 5; // 0x5
+    field public static final int ENCODING_AC4 = 17; // 0x11
     field public static final int ENCODING_DEFAULT = 1; // 0x1
     field public static final int ENCODING_DOLBY_TRUEHD = 14; // 0xe
     field public static final int ENCODING_DTS = 7; // 0x7
@@ -21759,6 +21768,7 @@
     field public static final int ENCODING_E_AC3 = 6; // 0x6
     field public static final int ENCODING_IEC61937 = 13; // 0xd
     field public static final int ENCODING_INVALID = 0; // 0x0
+    field public static final int ENCODING_MP3 = 9; // 0x9
     field public static final int ENCODING_PCM_16BIT = 2; // 0x2
     field public static final int ENCODING_PCM_8BIT = 3; // 0x3
     field public static final int ENCODING_PCM_FLOAT = 4; // 0x4
@@ -21801,6 +21811,7 @@
     method public boolean isBluetoothScoOn();
     method public boolean isMicrophoneMute();
     method public boolean isMusicActive();
+    method public boolean isOffloadedPlaybackSupported(android.media.AudioFormat);
     method public boolean isSpeakerphoneOn();
     method public boolean isStreamMute(int);
     method public boolean isVolumeFixed();
@@ -22101,6 +22112,7 @@
     method public int reloadStaticData();
     method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
     method public deprecated void removeOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener);
+    method public void removeStreamEventCallback();
     method public int setAuxEffectSendLevel(float);
     method public int setBufferSizeInFrames(int);
     method public int setLoopPoints(int, int, int);
@@ -22114,6 +22126,7 @@
     method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
     method protected deprecated void setState(int);
     method public deprecated int setStereoVolume(float, float);
+    method public void setStreamEventCallback(java.util.concurrent.Executor, android.media.AudioTrack.StreamEventCallback);
     method public int setVolume(float);
     method public void stop() throws java.lang.IllegalStateException;
     method public int write(byte[], int, int);
@@ -22149,6 +22162,7 @@
     method public android.media.AudioTrack.Builder setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
     method public android.media.AudioTrack.Builder setAudioFormat(android.media.AudioFormat) throws java.lang.IllegalArgumentException;
     method public android.media.AudioTrack.Builder setBufferSizeInBytes(int) throws java.lang.IllegalArgumentException;
+    method public android.media.AudioTrack.Builder setOffloadedPlayback(boolean);
     method public android.media.AudioTrack.Builder setPerformanceMode(int);
     method public android.media.AudioTrack.Builder setSessionId(int) throws java.lang.IllegalArgumentException;
     method public android.media.AudioTrack.Builder setTransferMode(int) throws java.lang.IllegalArgumentException;
@@ -22164,6 +22178,12 @@
     method public default void onRoutingChanged(android.media.AudioRouting);
   }
 
+  public static abstract class AudioTrack.StreamEventCallback {
+    method public void onStreamDataRequest(android.media.AudioTrack);
+    method public void onStreamPresentationEnd(android.media.AudioTrack);
+    method public void onTearDown(android.media.AudioTrack);
+  }
+
   public class CamcorderProfile {
     method public static android.media.CamcorderProfile get(int);
     method public static android.media.CamcorderProfile get(int, int);
diff --git a/api/system-current.txt b/api/system-current.txt
index 66b6d99..dcea004 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -380,6 +380,7 @@
     method public java.lang.CharSequence getDeviceOwnerOrganizationName();
     method public java.util.List<java.lang.String> getPermittedAccessibilityServices(int);
     method public java.util.List<java.lang.String> getPermittedInputMethodsForCurrentUser();
+    method public java.lang.CharSequence getPrintingDisabledReason();
     method public android.content.ComponentName getProfileOwner() throws java.lang.IllegalArgumentException;
     method public java.lang.String getProfileOwnerNameAsUser(int) throws java.lang.IllegalArgumentException;
     method public int getUserProvisioningState();
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index b469de5..c5a58f2 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -17,6 +17,7 @@
 package android.app;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
@@ -458,7 +459,8 @@
      *
      * @see Context#startActivity(Intent, Bundle)
      */
-    public Activity startActivitySync(Intent intent, @Nullable Bundle options) {
+    @NonNull
+    public Activity startActivitySync(@NonNull Intent intent, @Nullable Bundle options) {
         validateNotAppThread();
 
         synchronized (mSync) {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index d465e0d..7fccda8 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -9210,10 +9210,13 @@
     /**
      * Allows/disallows printing.
      *
+     * Called by a device owner or a profile owner.
+     * Device owner changes policy for all users. Profile owner can override it if present.
+     * Printing is enabled by default. If {@code FEATURE_PRINTING} is absent, the call is ignored.
+     *
      * @param admin which {@link DeviceAdminReceiver} this request is associated with.
      * @param enabled whether printing should be allowed or not.
      * @throws SecurityException if {@code admin} is neither device, nor profile owner.
-     * @hide
      */
     public void setPrintingEnabled(@NonNull ComponentName admin, boolean enabled) {
         try {
@@ -9224,10 +9227,12 @@
     }
 
     /**
-     * Returns whether printing is enabled for current user.
+     * Returns whether printing is enabled for this user.
+     *
+     * Always {@code false} if {@code FEATURE_PRINTING} is absent.
+     * Otherwise, {@code true} by default.
      *
      * @return {@code true} iff printing is enabled.
-     * @hide
      */
     public boolean isPrintingEnabled() {
         try {
@@ -9242,9 +9247,9 @@
      *
      * Used only by PrintService.
      * @return Localized error message.
-     * @throws SecurityException if caller is not system.
      * @hide
      */
+    @SystemApi
     public CharSequence getPrintingDisabledReason() {
         try {
             return mService.getPrintingDisabledReason();
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 1201ef4..a9ed9a3 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -2978,6 +2978,7 @@
      *   <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL}</li>
      *   <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY LEGACY}</li>
      *   <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_3 3}</li>
+     *   <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL EXTERNAL}</li>
      * </ul></p>
      * <p>This key is available on all devices.</p>
      *
@@ -2991,6 +2992,7 @@
      * @see #INFO_SUPPORTED_HARDWARE_LEVEL_FULL
      * @see #INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY
      * @see #INFO_SUPPORTED_HARDWARE_LEVEL_3
+     * @see #INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL
      */
     @PublicKey
     public static final Key<Integer> INFO_SUPPORTED_HARDWARE_LEVEL =
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 2294ec5..cc6e9a9 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -1134,6 +1134,38 @@
      */
     public static final int INFO_SUPPORTED_HARDWARE_LEVEL_3 = 3;
 
+    /**
+     * <p>This camera device is backed by an external camera connected to this Android device.</p>
+     * <p>The device has capability identical to a LIMITED level device, with the following
+     * exceptions:</p>
+     * <ul>
+     * <li>The device may not report lens/sensor related information such as<ul>
+     * <li>{@link CaptureRequest#LENS_FOCAL_LENGTH android.lens.focalLength}</li>
+     * <li>{@link CameraCharacteristics#LENS_INFO_HYPERFOCAL_DISTANCE android.lens.info.hyperfocalDistance}</li>
+     * <li>{@link CameraCharacteristics#SENSOR_INFO_PHYSICAL_SIZE android.sensor.info.physicalSize}</li>
+     * <li>{@link CameraCharacteristics#SENSOR_INFO_WHITE_LEVEL android.sensor.info.whiteLevel}</li>
+     * <li>{@link CameraCharacteristics#SENSOR_BLACK_LEVEL_PATTERN android.sensor.blackLevelPattern}</li>
+     * <li>{@link CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT android.sensor.info.colorFilterArrangement}</li>
+     * <li>{@link CaptureResult#SENSOR_ROLLING_SHUTTER_SKEW android.sensor.rollingShutterSkew}</li>
+     * </ul>
+     * </li>
+     * <li>The device will report 0 for {@link CameraCharacteristics#SENSOR_ORIENTATION android.sensor.orientation}</li>
+     * <li>The device has less guarantee on stable framerate, as the framerate partly depends
+     *   on the external camera being used.</li>
+     * </ul>
+     *
+     * @see CaptureRequest#LENS_FOCAL_LENGTH
+     * @see CameraCharacteristics#LENS_INFO_HYPERFOCAL_DISTANCE
+     * @see CameraCharacteristics#SENSOR_BLACK_LEVEL_PATTERN
+     * @see CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT
+     * @see CameraCharacteristics#SENSOR_INFO_PHYSICAL_SIZE
+     * @see CameraCharacteristics#SENSOR_INFO_WHITE_LEVEL
+     * @see CameraCharacteristics#SENSOR_ORIENTATION
+     * @see CaptureResult#SENSOR_ROLLING_SHUTTER_SKEW
+     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     */
+    public static final int INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL = 4;
+
     //
     // Enumeration values for CameraCharacteristics#SYNC_MAX_LATENCY
     //
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b2cc18b..60ce42b 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10375,6 +10375,15 @@
         public static final String FORCED_APP_STANDBY_ENABLED = "forced_app_standby_enabled";
 
         /**
+         * Whether or not to enable Forced App Standby on small battery devices.
+         * Type: int (0 for false, 1 for true)
+         * Default: 0
+         * @hide
+         */
+        public static final String FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED
+                = "forced_app_standby_for_small_battery_enabled";
+
+        /**
          * Whether or not Network Watchlist feature is enabled.
          * Type: int (0 for false, 1 for true)
          * Default: 0
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index f409e5b..72afbb8 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -73,6 +73,7 @@
     public static final int KM_TAG_USER_AUTH_TYPE = KM_ENUM | 504;
     public static final int KM_TAG_AUTH_TIMEOUT = KM_UINT | 505;
     public static final int KM_TAG_ALLOW_WHILE_ON_BODY = KM_BOOL | 506;
+    public static final int KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED = KM_BOOL | 507;
 
     public static final int KM_TAG_ALL_APPLICATIONS = KM_BOOL | 600;
     public static final int KM_TAG_APPLICATION_ID = KM_BYTES | 601;
diff --git a/core/jni/android_database_SQLiteCommon.cpp b/core/jni/android_database_SQLiteCommon.cpp
index eefcb74..34544d3 100644
--- a/core/jni/android_database_SQLiteCommon.cpp
+++ b/core/jni/android_database_SQLiteCommon.cpp
@@ -18,8 +18,108 @@
 
 #include <utils/String8.h>
 
+#include <map>
+
 namespace android {
 
+static const std::map<int, std::string> sErrorCodesMap = {
+    // Primary Result Code List
+    {4,     "SQLITE_ABORT"},
+    {23,    "SQLITE_AUTH"},
+    {5,     "SQLITE_BUSY"},
+    {14,    "SQLITE_CANTOPEN"},
+    {19,    "SQLITE_CONSTRAINT"},
+    {11,    "SQLITE_CORRUPT"},
+    {101,   "SQLITE_DONE"},
+    {16,    "SQLITE_EMPTY"},
+    {1,     "SQLITE_ERROR"},
+    {24,    "SQLITE_FORMAT"},
+    {13,    "SQLITE_FULL"},
+    {2,     "SQLITE_INTERNAL"},
+    {9,     "SQLITE_INTERRUPT"},
+    {10,    "SQLITE_IOERR"},
+    {6,     "SQLITE_LOCKED"},
+    {20,    "SQLITE_MISMATCH"},
+    {21,    "SQLITE_MISUSE"},
+    {22,    "SQLITE_NOLFS"},
+    {7,     "SQLITE_NOMEM"},
+    {26,    "SQLITE_NOTADB"},
+    {12,    "SQLITE_NOTFOUND"},
+    {27,    "SQLITE_NOTICE"},
+    {0,     "SQLITE_OK"},
+    {3,     "SQLITE_PERM"},
+    {15,    "SQLITE_PROTOCOL"},
+    {25,    "SQLITE_RANGE"},
+    {8,     "SQLITE_READONLY"},
+    {100,   "SQLITE_ROW"},
+    {17,    "SQLITE_SCHEMA"},
+    {18,    "SQLITE_TOOBIG"},
+    {28,    "SQLITE_WARNING"},
+    // Extended Result Code List
+    {516,   "SQLITE_ABORT_ROLLBACK"},
+    {261,   "SQLITE_BUSY_RECOVERY"},
+    {517,   "SQLITE_BUSY_SNAPSHOT"},
+    {1038,  "SQLITE_CANTOPEN_CONVPATH"},
+    {782,   "SQLITE_CANTOPEN_FULLPATH"},
+    {526,   "SQLITE_CANTOPEN_ISDIR"},
+    {270,   "SQLITE_CANTOPEN_NOTEMPDIR"},
+    {275,   "SQLITE_CONSTRAINT_CHECK"},
+    {531,   "SQLITE_CONSTRAINT_COMMITHOOK"},
+    {787,   "SQLITE_CONSTRAINT_FOREIGNKEY"},
+    {1043,  "SQLITE_CONSTRAINT_FUNCTION"},
+    {1299,  "SQLITE_CONSTRAINT_NOTNULL"},
+    {1555,  "SQLITE_CONSTRAINT_PRIMARYKEY"},
+    {2579,  "SQLITE_CONSTRAINT_ROWID"},
+    {1811,  "SQLITE_CONSTRAINT_TRIGGER"},
+    {2067,  "SQLITE_CONSTRAINT_UNIQUE"},
+    {2323,  "SQLITE_CONSTRAINT_VTAB"},
+    {267,   "SQLITE_CORRUPT_VTAB"},
+    {3338,  "SQLITE_IOERR_ACCESS"},
+    {2826,  "SQLITE_IOERR_BLOCKED"},
+    {3594,  "SQLITE_IOERR_CHECKRESERVEDLOCK"},
+    {4106,  "SQLITE_IOERR_CLOSE"},
+    {6666,  "SQLITE_IOERR_CONVPATH"},
+    {2570,  "SQLITE_IOERR_DELETE"},
+    {5898,  "SQLITE_IOERR_DELETE_NOENT"},
+    {4362,  "SQLITE_IOERR_DIR_CLOSE"},
+    {1290,  "SQLITE_IOERR_DIR_FSYNC"},
+    {1802,  "SQLITE_IOERR_FSTAT"},
+    {1034,  "SQLITE_IOERR_FSYNC"},
+    {6410,  "SQLITE_IOERR_GETTEMPPATH"},
+    {3850,  "SQLITE_IOERR_LOCK"},
+    {6154,  "SQLITE_IOERR_MMAP"},
+    {3082,  "SQLITE_IOERR_NOMEM"},
+    {2314,  "SQLITE_IOERR_RDLOCK"},
+    {266,   "SQLITE_IOERR_READ"},
+    {5642,  "SQLITE_IOERR_SEEK"},
+    {5130,  "SQLITE_IOERR_SHMLOCK"},
+    {5386,  "SQLITE_IOERR_SHMMAP"},
+    {4618,  "SQLITE_IOERR_SHMOPEN"},
+    {4874,  "SQLITE_IOERR_SHMSIZE"},
+    {522,   "SQLITE_IOERR_SHORT_READ"},
+    {1546,  "SQLITE_IOERR_TRUNCATE"},
+    {2058,  "SQLITE_IOERR_UNLOCK"},
+    {778,   "SQLITE_IOERR_WRITE"},
+    {262,   "SQLITE_LOCKED_SHAREDCACHE"},
+    {539,   "SQLITE_NOTICE_RECOVER_ROLLBACK"},
+    {283,   "SQLITE_NOTICE_RECOVER_WAL"},
+    {256,   "SQLITE_OK_LOAD_PERMANENTLY"},
+    {520,   "SQLITE_READONLY_CANTLOCK"},
+    {1032,  "SQLITE_READONLY_DBMOVED"},
+    {264,   "SQLITE_READONLY_RECOVERY"},
+    {776,   "SQLITE_READONLY_ROLLBACK"},
+    {284,   "SQLITE_WARNING_AUTOINDEX"},
+};
+
+static std::string sqlite3_error_code_to_msg(int errcode) {
+    auto it = sErrorCodesMap.find(errcode);
+    if (it != sErrorCodesMap.end()) {
+        return std::to_string(errcode) + " " + it->second;
+    } else {
+        return std::to_string(errcode);
+    }
+}
+
 /* throw a SQLiteException with a message appropriate for the error in handle */
 void throw_sqlite3_exception(JNIEnv* env, sqlite3* handle) {
     throw_sqlite3_exception(env, handle, NULL);
@@ -123,7 +223,8 @@
     if (sqlite3Message) {
         String8 fullMessage;
         fullMessage.append(sqlite3Message);
-        fullMessage.appendFormat(" (code %d)", errcode); // print extended error code
+        const char* errcode_msg = sqlite3_error_code_to_msg(errcode).c_str();
+        fullMessage.appendFormat(" (code %s)", errcode_msg); // print extended error code
         if (message) {
             fullMessage.append(": ");
             fullMessage.append(message);
diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h
index 51cefb9..c79f5bd 100644
--- a/core/jni/android_media_AudioFormat.h
+++ b/core/jni/android_media_AudioFormat.h
@@ -35,6 +35,7 @@
 #define ENCODING_DOLBY_TRUEHD   14
 #define ENCODING_AAC_ELD        15
 #define ENCODING_AAC_XHE        16
+#define ENCODING_AC4            17
 
 #define ENCODING_INVALID    0
 #define ENCODING_DEFAULT    1
@@ -77,6 +78,8 @@
         return AUDIO_FORMAT_AAC_ELD;
     case ENCODING_AAC_XHE:
         return AUDIO_FORMAT_AAC; // FIXME temporary value, needs addition of xHE-AAC
+    case ENCODING_AC4:
+        return AUDIO_FORMAT_AC4;
     case ENCODING_DEFAULT:
         return AUDIO_FORMAT_DEFAULT;
     default:
@@ -125,6 +128,8 @@
     // FIXME needs addition of AUDIO_FORMAT_AAC_XHE
     //case AUDIO_FORMAT_AAC_XHE:
     //    return ENCODING_AAC_XHE;
+    case AUDIO_FORMAT_AC4:
+        return ENCODING_AC4;
     case AUDIO_FORMAT_DEFAULT:
         return ENCODING_DEFAULT;
     default:
diff --git a/core/proto/android/server/forceappstandbytracker.proto b/core/proto/android/server/forceappstandbytracker.proto
index 8753bf7..c9f7d52 100644
--- a/core/proto/android/server/forceappstandbytracker.proto
+++ b/core/proto/android/server/forceappstandbytracker.proto
@@ -41,4 +41,13 @@
 
   // Packages that are disallowed OP_RUN_ANY_IN_BACKGROUND.
   repeated RunAnyInBackgroundRestrictedPackages run_any_in_background_restricted_packages = 5;
+
+  // Whether device is a small battery device
+  optional bool is_small_battery_device = 6;
+
+  // Whether force app standby for small battery device setting is enabled
+  optional bool force_all_apps_standby_for_small_battery = 7;
+
+  // Whether device is charging
+  optional bool is_charging = 8;
 }
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 0c844c9..170ba42 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4821,4 +4821,7 @@
     <!-- Text describing a permission request for one app to show another app's
          slices [CHAR LIMIT=NONE] -->
     <string name="slices_permission_request"><xliff:g id="app" example="Example App">%1$s</xliff:g> wants to show <xliff:g id="app_2" example="Other Example App">%2$s</xliff:g> slices</string>
+
+    <!-- Notification action for editing a screenshot (drawing on it, cropping it, etc) -->
+    <string name="screenshot_edit">Edit</string>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 03a800d..9550657 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3227,5 +3227,8 @@
   <java-symbol type="string" name="config_defaultAssistantAccessPackage" />
 
   <java-symbol type="bool" name="config_supportBluetoothPersistedState" />
+
   <java-symbol type="string" name="slices_permission_request" />
+
+  <java-symbol type="string" name="screenshot_edit" />
 </resources>
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index ec3a6ce..fa0ea5c 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -213,6 +213,7 @@
                     Settings.Global.FANCY_IME_ANIMATIONS,
                     Settings.Global.FORCE_ALLOW_ON_EXTERNAL,
                     Settings.Global.FORCED_APP_STANDBY_ENABLED,
+                    Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED,
                     Settings.Global.FSTRIM_MANDATORY_INTERVAL,
                     Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
                     Settings.Global.GLOBAL_HTTP_PROXY_HOST,
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index 46fe89a..b07d042 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -238,25 +238,13 @@
     public static final int ENCODING_DTS = 7;
     /** Audio data format: DTS HD compressed */
     public static final int ENCODING_DTS_HD = 8;
-    /** Audio data format: MP3 compressed
-     * @hide
-     * TODO unhide and add to @Encoding (intentional white space   
-     * */
+    /** Audio data format: MP3 compressed */
     public static final int ENCODING_MP3 = 9;
-    /** Audio data format: AAC LC compressed
-     * @hide
-     * TODO unhide and add to @Encoding (intentional white space   
-     * */
+    /** Audio data format: AAC LC compressed */
     public static final int ENCODING_AAC_LC = 10;
-    /** Audio data format: AAC HE V1 compressed
-     * @hide
-     * TODO unhide and add to @Encoding (intentional white space   
-     * */
+    /** Audio data format: AAC HE V1 compressed */
     public static final int ENCODING_AAC_HE_V1 = 11;
-    /** Audio data format: AAC HE V2 compressed
-     * @hide
-     * TODO unhide and add to @Encoding (intentional white space   
-     * */
+    /** Audio data format: AAC HE V2 compressed */
     public static final int ENCODING_AAC_HE_V2 = 12;
 
     /** Audio data format: compressed audio wrapped in PCM for HDMI
@@ -271,16 +259,12 @@
     /** Audio data format: DOLBY TRUEHD compressed
      **/
     public static final int ENCODING_DOLBY_TRUEHD = 14;
-    /** Audio data format: AAC ELD compressed
-     * @hide
-     * TODO unhide and add to @Encoding (intentional white space   
-     * */
+    /** Audio data format: AAC ELD compressed */
     public static final int ENCODING_AAC_ELD = 15;
-    /** Audio data format: AAC xHE compressed
-     * @hide
-     * TODO unhide and add to @Encoding (intentional white space   
-     * */
+    /** Audio data format: AAC xHE compressed */
     public static final int ENCODING_AAC_XHE = 16;
+    /** Audio data format: AC-4 sync frame transport format */
+    public static final int ENCODING_AC4 = 17;
 
     /** @hide */
     public static String toLogFriendlyEncoding(int enc) {
@@ -317,6 +301,8 @@
                 return "ENCODING_AAC_ELD";
             case ENCODING_AAC_XHE:
                 return "ENCODING_AAC_XHE";
+            case ENCODING_AC4:
+                return "ENCODING_AC4";
             default :
                 return "invalid encoding " + enc;
         }
@@ -535,6 +521,7 @@
         case ENCODING_IEC61937:
         case ENCODING_AAC_ELD:
         case ENCODING_AAC_XHE:
+        case ENCODING_AC4:
             return true;
         default:
             return false;
@@ -553,13 +540,13 @@
         case ENCODING_DTS:
         case ENCODING_DTS_HD:
         case ENCODING_IEC61937:
-            //TODO not true yet (intended white space     
         case ENCODING_MP3:
         case ENCODING_AAC_LC:
         case ENCODING_AAC_HE_V1:
         case ENCODING_AAC_HE_V2:
         case ENCODING_AAC_ELD:
         case ENCODING_AAC_XHE:
+        case ENCODING_AC4:
             return true;
         default:
             return false;
@@ -586,6 +573,7 @@
         case ENCODING_IEC61937: // wrapped in PCM but compressed
         case ENCODING_AAC_ELD:
         case ENCODING_AAC_XHE:
+        case ENCODING_AC4:
             return false;
         case ENCODING_INVALID:
         default:
@@ -613,6 +601,7 @@
         case ENCODING_AAC_HE_V2:
         case ENCODING_AAC_ELD:
         case ENCODING_AAC_XHE:
+        case ENCODING_AC4:
             return false;
         case ENCODING_INVALID:
         default:
@@ -849,6 +838,7 @@
                 case ENCODING_AAC_HE_V2:
                 case ENCODING_AAC_ELD:
                 case ENCODING_AAC_XHE:
+                case ENCODING_AC4:
                     mEncoding = encoding;
                     break;
                 case ENCODING_INVALID:
@@ -1056,7 +1046,13 @@
         ENCODING_E_AC3,
         ENCODING_DTS,
         ENCODING_DTS_HD,
-        ENCODING_IEC61937 }
+        ENCODING_IEC61937,
+        ENCODING_AAC_HE_V1,
+        ENCODING_AAC_HE_V2,
+        ENCODING_AAC_LC,
+        ENCODING_AAC_ELD,
+        ENCODING_AAC_XHE,
+        ENCODING_AC4 }
     )
     @Retention(RetentionPolicy.SOURCE)
     public @interface Encoding {}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 4d5343c..2ac4063 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1331,15 +1331,13 @@
     //====================================================================
     // Offload query
     /**
-     * @hide
-     * TODO unhide (intentional white space to attract attention:    
      * Returns whether offloaded playback of an audio format is supported on the device.
      * Offloaded playback is where the decoding of an audio stream is not competing with other
      * software resources. In general, it is supported by dedicated hardware, such as audio DSPs.
      * @param format the audio format (codec, sample rate, channels) being checked.
      * @return true if the given audio format can be offloaded.
      */
-    public static boolean isOffloadedPlaybackSupported(@NonNull AudioFormat format) {
+    public boolean isOffloadedPlaybackSupported(@NonNull AudioFormat format) {
         return AudioSystem.isOffloadSupported(format);
     }
 
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 6add381..5928d03 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -755,8 +755,8 @@
      * <code>MODE_STREAM</code> will be used.
      * <br>If the session ID is not specified with {@link #setSessionId(int)}, a new one will
      * be generated.
+     * <br>Offload is false by default.
      */
-    // TODO add that offload is false by default (intended white space   
     public static class Builder {
         private AudioAttributes mAttributes;
         private AudioFormat mFormat;
@@ -895,14 +895,11 @@
         }
 
         /**
-         * @hide
-         * TODO unhide (intentional whitespace    
-         * TODO should offload require POWER_SAVING?    
          * Sets whether this track will play through the offloaded audio path.
          * When set to true, at build time, the audio format will be checked against
          * {@link AudioManager#isOffloadedPlaybackSupported(AudioFormat)} to verify the audio format
          * used by this track is supported on the device's offload path (if any).
-         * <br>Offload is only supported for media audio data, and therefore require that
+         * <br>Offload is only supported for media audio streams, and therefore requires that
          * the usage be {@link AudioAttributes#USAGE_MEDIA}.
          * @param offload true to require the offload path for playback.
          * @return the same Builder instance.
@@ -962,7 +959,7 @@
                     throw new UnsupportedOperationException(
                             "Cannot create AudioTrack, offload requires USAGE_MEDIA");
                 }
-                if (!AudioManager.isOffloadedPlaybackSupported(mFormat)) {
+                if (!AudioSystem.isOffloadSupported(mFormat)) {
                     throw new UnsupportedOperationException(
                             "Cannot create AudioTrack, offload format not supported");
                 }
@@ -2942,14 +2939,31 @@
     }
 
     /**
-     * @hide
-     * TODO unhide (intentional white space to attract attention:    
      * Abstract class to receive event notification about the stream playback.
+     * See {@link AudioTrack#setStreamEventCallback(Executor, StreamEventCallback)} to register
+     * the callback on the given {@link AudioTrack} instance.
      */
     public abstract static class StreamEventCallback {
-        // TODO rename if supported for non offload tracks
+        /** @hide */ // add hidden empty constructor so it doesn't show in SDK
+        public StreamEventCallback() { }
+        /**
+         * Called when an offloaded track is no longer valid and has been discarded by the system.
+         * An example of this happening is when an offloaded track has been paused too long, and
+         * gets invalidated by the system to prevent any other offload.
+         * @param track the {@link AudioTrack} on which the event happened
+         */
         public void onTearDown(AudioTrack track) { }
+        /**
+         * Called when all the buffers of an offloaded track that were queued in the audio system
+         * (e.g. the combination of the Android audio framework and the device's audio hardware)
+         * have been played after {@link AudioTrack#stop()} has been called.
+         * @param track the {@link AudioTrack} on which the event happened
+         */
         public void onStreamPresentationEnd(AudioTrack track) { }
+        /**
+         * Called when more audio data can be written without blocking on an offloaded track.
+         * @param track the {@link AudioTrack} on which the event happened
+         */
         public void onStreamDataRequest(AudioTrack track) { }
     }
 
@@ -2958,11 +2972,9 @@
     private final Object mStreamEventCbLock = new Object();
 
     /**
-     * @hide
-     * TODO unhide (intentional white space to attract attention:    
-     * Registers a callback for notification of stream events.
+     * Sets the callback for the notification of stream events.
      * @param executor {@link Executor} to handle the callbacks
-     * @param eventCallback the callback to receive the stream events
+     * @param eventCallback the callback to receive the stream event notifications
      */
     public void setStreamEventCallback(@NonNull @CallbackExecutor Executor executor,
             @NonNull StreamEventCallback eventCallback) {
@@ -2979,9 +2991,8 @@
     }
 
     /**
-     * @hide
      * Unregisters the callback for notification of stream events, previously set
-     * by {@link #setStreamEventCallback(StreamEventCallback, Executor)}.
+     * by {@link #setStreamEventCallback(Executor, StreamEventCallback)}.
      */
     public void removeStreamEventCallback() {
         synchronized (mStreamEventCbLock) {
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 3c49b80..78477f7 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -1380,7 +1380,8 @@
             if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
                 enableNativeRoutingCallbacksLocked(true);
                 mRoutingChangeListeners.put(
-                        listener, new NativeRoutingEventHandlerDelegate(this, listener, handler));
+                        listener, new NativeRoutingEventHandlerDelegate(this, listener,
+                                handler != null ? handler : mEventHandler));
             }
         }
     }
@@ -1401,36 +1402,6 @@
         }
     }
 
-    /**
-     * Helper class to handle the forwarding of native events to the appropriate listener
-     * (potentially) handled in a different thread
-     */
-    private class NativeRoutingEventHandlerDelegate {
-        private MediaRecorder mMediaRecorder;
-        private AudioRouting.OnRoutingChangedListener mOnRoutingChangedListener;
-        private Handler mHandler;
-
-        NativeRoutingEventHandlerDelegate(final MediaRecorder mediaRecorder,
-                final AudioRouting.OnRoutingChangedListener listener, Handler handler) {
-            mMediaRecorder = mediaRecorder;
-            mOnRoutingChangedListener = listener;
-            mHandler = handler != null ? handler : mEventHandler;
-        }
-
-        void notifyClient() {
-            if (mHandler != null) {
-                mHandler.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        if (mOnRoutingChangedListener != null) {
-                            mOnRoutingChangedListener.onRoutingChanged(mMediaRecorder);
-                        }
-                    }
-                });
-            }
-        }
-    }
-
     private native final boolean native_setInputDevice(int deviceId);
     private native final int native_getRoutedDeviceId();
     private native final void native_enableDeviceCallback(boolean enabled);
diff --git a/packages/SystemUI/res/color/qs_background_dark.xml b/packages/SystemUI/res/color/qs_background_dark.xml
index c19fa08..24afebd 100644
--- a/packages/SystemUI/res/color/qs_background_dark.xml
+++ b/packages/SystemUI/res/color/qs_background_dark.xml
@@ -15,6 +15,6 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:alpha="0.87"
+    <item android:alpha="1"
           android:color="?android:attr/colorBackgroundFloating"/>
 </selector>
diff --git a/packages/SystemUI/res/drawable/ic_screenshot_edit.xml b/packages/SystemUI/res/drawable/ic_screenshot_edit.xml
new file mode 100644
index 0000000..d901292
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_screenshot_edit.xml
@@ -0,0 +1,27 @@
+<!--
+Copyright (C) 2014 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M3.0,17.25L3.0,21.0l3.75,0.0L17.81,9.94l-3.75,-3.75L3.0,17.25zM20.71,7.04c0.39,-0.3 0.39,-1.02 0.0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0.0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
+    <path
+        android:pathData="M0 0h24v24H0z"
+        android:fillColor="#00000000"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/qs_bg_gradient.xml b/packages/SystemUI/res/drawable/qs_bg_gradient.xml
new file mode 100644
index 0000000..a1ad528
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_bg_gradient.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <gradient
+        android:angle="270"
+        android:startColor="#ff000000"
+        android:endColor="#00000000"
+        android:type="linear" />
+</shape>
diff --git a/packages/SystemUI/res/layout/battery_percentage_view.xml b/packages/SystemUI/res/layout/battery_percentage_view.xml
index 59c0957..e52aa14 100644
--- a/packages/SystemUI/res/layout/battery_percentage_view.xml
+++ b/packages/SystemUI/res/layout/battery_percentage_view.xml
@@ -25,6 +25,6 @@
         android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
         android:textColor="?android:attr/textColorPrimary"
         android:gravity="center_vertical|start"
-        android:paddingEnd="@dimen/battery_level_padding_start"
+        android:paddingStart="@dimen/battery_level_padding_start"
         android:importantForAccessibility="no"
         />
diff --git a/packages/SystemUI/res/layout/qs_customize_panel.xml b/packages/SystemUI/res/layout/qs_customize_panel.xml
index 9ab8ac6..b3b6a0c 100644
--- a/packages/SystemUI/res/layout/qs_customize_panel.xml
+++ b/packages/SystemUI/res/layout/qs_customize_panel.xml
@@ -20,6 +20,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="0dp"
+    android:elevation="4dp"
     android:orientation="vertical"
     android:background="@drawable/qs_customizer_background"
     android:gravity="center_horizontal">
diff --git a/packages/SystemUI/res/layout/qs_detail.xml b/packages/SystemUI/res/layout/qs_detail.xml
index 1fd239b..0b9a7b2 100644
--- a/packages/SystemUI/res/layout/qs_detail.xml
+++ b/packages/SystemUI/res/layout/qs_detail.xml
@@ -23,7 +23,8 @@
     android:clickable="true"
     android:orientation="vertical"
     android:paddingBottom="8dp"
-    android:visibility="invisible">
+    android:visibility="invisible"
+    android:elevation="4dp" >
 
     <include
         android:id="@+id/qs_detail_header"
diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index 3d09b74..9f6a946 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -21,6 +21,7 @@
     android:id="@+id/qs_footer"
     android:layout_width="match_parent"
     android:layout_height="48dp"
+    android:elevation="4dp"
     android:baselineAligned="false"
     android:clickable="false"
     android:clipChildren="false"
@@ -105,17 +106,6 @@
                 android:visibility="invisible"/>
 
         </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
-
-        <com.android.systemui.statusbar.phone.ExpandableIndicator
-            android:id="@+id/expand_indicator"
-            android:layout_width="48dp"
-            android:layout_height="48dp"
-            android:clipToPadding="false"
-            android:clickable="true"
-            android:focusable="true"
-            android:background="?android:attr/selectableItemBackgroundBorderless"
-            android:contentDescription="@string/accessibility_quick_settings_expand"
-            android:padding="14dp" />
     </LinearLayout>
 
 </com.android.systemui.qs.QSFooterImpl>
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index 5541f3d..5bcb7fd 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -18,17 +18,46 @@
     android:id="@+id/quick_settings_container"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:background="@drawable/qs_background_primary"
-    android:elevation="4dp"
     android:clipToPadding="false"
-    android:clipChildren="false">
+    android:clipChildren="false" >
+
+    <!-- Main QS background -->
+    <View
+        android:id="@+id/quick_settings_background"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:elevation="4dp"
+        android:background="@drawable/qs_background_primary" />
+
+    <!-- Black part behind the status bar -->
+    <View
+        android:id="@+id/quick_settings_status_bar_background"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/qs_header_system_icons_area_height"
+        android:clipToPadding="false"
+        android:clipChildren="false"
+        android:background="#ff000000" />
+
+    <!-- Gradient view behind QS -->
+    <View
+        android:id="@+id/quick_settings_gradient_view"
+        android:layout_width="match_parent"
+        android:layout_height="126dp"
+        android:layout_marginTop="@dimen/qs_header_system_icons_area_height"
+        android:clipToPadding="false"
+        android:clipChildren="false"
+        android:background="@drawable/qs_bg_gradient" />
+
 
     <com.android.systemui.qs.QSPanel
         android:id="@+id/quick_settings_panel"
-        android:layout_marginTop="28dp"
+        android:layout_marginTop="@dimen/qs_header_system_icons_area_height"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginBottom="48dp" />
+        android:layout_marginBottom="48dp"
+        android:elevation="4dp"
+    />
+
 
     <include layout="@layout/quick_status_bar_expanded_header" />
 
diff --git a/packages/SystemUI/res/layout/quick_qs_status_icons.xml b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
new file mode 100644
index 0000000..e0f0ed9
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<View
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/quick_qs_status_icons"
+    android:layout_width="match_parent"
+    android:layout_height="20dp"
+    android:layout_marginBottom="22dp"
+    android:layout_below="@id/quick_status_bar_system_icons"
+    >
+
+</View>
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index e8b418c..dacc3f9 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -28,23 +28,21 @@
     android:clipToPadding="false"
     android:paddingTop="0dp"
     android:paddingEnd="0dp"
-    android:paddingStart="0dp">
+    android:paddingStart="0dp"
+    android:elevation="4dp" >
 
     <include layout="@layout/quick_status_bar_header_system_icons" />
+    <include layout="@layout/quick_qs_status_icons" />
 
     <com.android.systemui.qs.QuickQSPanel
         android:id="@+id/quick_qs_panel"
         android:layout_width="match_parent"
         android:layout_height="48dp"
-        android:layout_alignParentEnd="true"
-        android:layout_marginTop="31dp"
-        android:layout_alignParentTop="true"
+        android:layout_below="@id/quick_qs_status_icons"
         android:accessibilityTraversalAfter="@+id/date_time_group"
         android:accessibilityTraversalBefore="@id/expand_indicator"
         android:clipChildren="false"
         android:clipToPadding="false"
-        android:layout_marginStart="8dp"
-        android:layout_marginEnd="8dp"
         android:focusable="true"
         android:importantForAccessibility="yes" />
 
diff --git a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
index 739a255..bfe1b62 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
@@ -17,6 +17,7 @@
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/quick_status_bar_system_icons"
     android:layout_width="match_parent"
     android:layout_height="@dimen/qs_header_system_icons_area_height"
     android:layout_alignParentEnd="true"
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 17b38cb..8c0b9ba 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -54,30 +54,47 @@
             android:layout_height="match_parent"
             android:layout="@layout/operator_name" />
 
-        <com.android.systemui.statusbar.policy.Clock
-            android:id="@+id/clock"
-            android:textAppearance="@style/TextAppearance.StatusBar.Clock"
-            android:layout_width="wrap_content"
+        <LinearLayout
             android:layout_height="match_parent"
-            android:singleLine="true"
-            android:paddingStart="@dimen/status_bar_left_clock_starting_padding"
-            android:paddingEnd="@dimen/status_bar_left_clock_end_padding"
-            android:gravity="center_vertical|start"
+            android:layout_width="0dp"
+            android:layout_weight="1"
+        >
+            <com.android.systemui.statusbar.policy.Clock
+                android:id="@+id/clock"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:textAppearance="@style/TextAppearance.StatusBar.Clock"
+                android:singleLine="true"
+                android:paddingStart="@dimen/status_bar_left_clock_starting_padding"
+                android:paddingEnd="@dimen/status_bar_left_clock_end_padding"
+                android:gravity="center_vertical|start"
+            />
+
+            <!-- The alpha of this area is controlled from both PhoneStatusBarTransitions and
+                 PhoneStatusBar (DISABLE_NOTIFICATION_ICONS). -->
+            <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
+                android:id="@+id/notification_icon_area"
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="1"
+                android:orientation="horizontal" />
+
+        </LinearLayout>
+
+        <!-- Space should cover the notch (if it exists) and let other views lay out around it -->
+        <android.widget.Space
+            android:id="@+id/cutout_space_view"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:gravity="center_horizontal|center_vertical"
         />
 
-        <!-- The alpha of this area is controlled from both PhoneStatusBarTransitions and
-             PhoneStatusBar (DISABLE_NOTIFICATION_ICONS). -->
-        <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
-            android:id="@+id/notification_icon_area"
-            android:layout_width="0dip"
+        <com.android.keyguard.AlphaOptimizedLinearLayout android:id="@+id/system_icon_area"
+            android:layout_width="0dp"
             android:layout_height="match_parent"
             android:layout_weight="1"
-            android:orientation="horizontal" />
-
-        <com.android.keyguard.AlphaOptimizedLinearLayout android:id="@+id/system_icon_area"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
             android:orientation="horizontal"
+            android:gravity="center_vertical|end"
             >
 
             <include layout="@layout/system_icons" />
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index c5e5ee1..bef0830 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -43,8 +43,6 @@
             android:layout_width="@dimen/qs_panel_width"
             android:layout_height="match_parent"
             android:layout_gravity="@integer/notification_panel_layout_gravity"
-            android:layout_marginStart="@dimen/notification_side_paddings"
-            android:layout_marginEnd="@dimen/notification_side_paddings"
             android:clipToPadding="false"
             android:clipChildren="false"
             systemui:viewType="com.android.systemui.plugins.qs.QS" />
diff --git a/packages/SystemUI/res/layout/system_icons.xml b/packages/SystemUI/res/layout/system_icons.xml
index bfa92ad..1fafb2f 100644
--- a/packages/SystemUI/res/layout/system_icons.xml
+++ b/packages/SystemUI/res/layout/system_icons.xml
@@ -16,12 +16,13 @@
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/system_icons"
-    android:layout_width="wrap_content"
+    android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:gravity="center_vertical">
 
-    <com.android.keyguard.AlphaOptimizedLinearLayout android:id="@+id/statusIcons"
-        android:layout_width="wrap_content"
+    <com.android.systemui.statusbar.phone.StatusIconContainer android:id="@+id/statusIcons"
+        android:layout_width="0dp"
+        android:layout_weight="1"
         android:layout_height="match_parent"
         android:gravity="center_vertical"
         android:orientation="horizontal"/>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 0134086..4e17c71 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -215,7 +215,7 @@
     <dimen name="close_handle_underlap">32dp</dimen>
 
     <!-- Height of the status bar header bar -->
-    <dimen name="status_bar_header_height">124dp</dimen>
+    <dimen name="status_bar_header_height">178dp</dimen>
 
     <!-- Height of the status bar header bar in the car setting. -->
     <dimen name="car_status_bar_header_height">128dp</dimen>
@@ -223,8 +223,9 @@
     <!-- The bottom padding of the status bar header. -->
     <dimen name="status_bar_header_padding_bottom">48dp</dimen>
 
-    <!-- The height of the container that holds the system icons in the quick settings header. -->
-    <dimen name="qs_header_system_icons_area_height">40dp</dimen>
+    <!-- The height of the container that holds the battery and time in the quick settings header.
+         -->
+    <dimen name="qs_header_system_icons_area_height">48dp</dimen>
 
     <!-- The height of the container that holds the system icons in the quick settings header in the
          car setting. -->
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index fed97c5..edda613 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -93,5 +93,8 @@
     <item type="id" name="action_snooze_long"/>
     <item type="id" name="action_snooze_longer"/>
     <item type="id" name="action_snooze_assistant_suggestion_1"/>
+
+    <!-- For StatusBarIconContainer to tag its icon views -->
+    <item type="id" name="status_bar_view_state_tag" />
 </resources>
 
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 2fe66a1..8666b0c 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -224,7 +224,6 @@
                 if (mTextColor != 0) mBatteryPercentView.setTextColor(mTextColor);
                 updatePercentText();
                 addView(mBatteryPercentView,
-                        0,
                         new ViewGroup.LayoutParams(
                                 LayoutParams.WRAP_CONTENT,
                                 LayoutParams.MATCH_PARENT));
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index 7f0acc2..7320b86 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -45,8 +45,9 @@
     protected float mQsExpansion;
     private QSCustomizer mQSCustomizer;
     private View mQSFooter;
-    private float mFullElevation;
+    private View mBackground;
     private float mRadius;
+    private int mSideMargins;
 
     public QSContainerImpl(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -60,12 +61,14 @@
         mHeader = findViewById(R.id.header);
         mQSCustomizer = findViewById(R.id.qs_customize);
         mQSFooter = findViewById(R.id.qs_footer);
-        mFullElevation = mQSPanel.getElevation();
+        mBackground = findViewById(R.id.quick_settings_background);
         mRadius = getResources().getDimensionPixelSize(
                 Utils.getThemeAttr(mContext, android.R.attr.dialogCornerRadius));
+        mSideMargins = getResources().getDimensionPixelSize(R.dimen.notification_side_paddings);
 
         setClickable(true);
         setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
+        setMargins();
     }
 
     @Override
@@ -131,6 +134,8 @@
         mQSDetail.setBottom(getTop() + height);
         // Pin QS Footer to the bottom of the panel.
         mQSFooter.setTranslationY(height - mQSFooter.getHeight());
+        mBackground.setTop(mQSPanel.getTop());
+        mBackground.setBottom(height);
 
         ExpandableOutlineView.getRoundedRectPath(0, 0, getWidth(), height, mRadius,
                 mRadius,
@@ -148,4 +153,19 @@
         mQsExpansion = expansion;
         updateExpansion();
     }
+
+    private void setMargins() {
+        setMargins(mQSDetail);
+        setMargins(mBackground);
+        setMargins(mQSFooter);
+        setMargins(mQSPanel);
+        setMargins(mHeader);
+        setMargins(mQSCustomizer);
+    }
+
+    private void setMargins(View view) {
+        FrameLayout.LayoutParams lp = (LayoutParams) view.getLayoutParams();
+        lp.rightMargin = mSideMargins;
+        lp.leftMargin = mSideMargins;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index 927a49c..92475da 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -61,18 +61,16 @@
 public class QSFooterImpl extends FrameLayout implements QSFooter,
         OnClickListener, OnUserInfoChangedListener, EmergencyListener,
         SignalCallback, CommandQueue.Callbacks {
-    private static final float EXPAND_INDICATOR_THRESHOLD = .93f;
-
     private ActivityStarter mActivityStarter;
     private UserInfoController mUserInfoController;
     private SettingsButton mSettingsButton;
     protected View mSettingsContainer;
+    private View mCarrierText;
 
     private boolean mQsDisabled;
     private QSPanel mQsPanel;
 
     private boolean mExpanded;
-    protected ExpandableIndicator mExpandIndicator;
 
     private boolean mListening;
 
@@ -100,18 +98,18 @@
                 Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() ->
                         mQsPanel.showEdit(view)));
 
-        mExpandIndicator = findViewById(R.id.expand_indicator);
         mSettingsButton = findViewById(R.id.settings_button);
         mSettingsContainer = findViewById(R.id.settings_button_container);
         mSettingsButton.setOnClickListener(this);
 
+        mCarrierText = findViewById(R.id.qs_carrier_text);
+
         mMultiUserSwitch = findViewById(R.id.multi_user_switch);
         mMultiUserAvatar = mMultiUserSwitch.findViewById(R.id.multi_user_avatar);
 
         // RenderThread is doing more harm than good when touching the header (to expand quick
         // settings), so disable it for this view
         ((RippleDrawable) mSettingsButton.getBackground()).setForceSoftware(true);
-        ((RippleDrawable) mExpandIndicator.getBackground()).setForceSoftware(true);
 
         updateResources();
 
@@ -162,6 +160,8 @@
         return new TouchAnimator.Builder()
                 .addFloat(mEdit, "alpha", 0, 1)
                 .addFloat(mMultiUserSwitch, "alpha", 0, 1)
+                .addFloat(mCarrierText, "alpha", 0, 1)
+                .addFloat(mSettingsButton, "alpha", 0, 1)
                 .build();
     }
 
@@ -185,8 +185,6 @@
         if (mSettingsAlpha != null) {
             mSettingsAlpha.setPosition(headerExpansionFraction);
         }
-
-        mExpandIndicator.setExpanded(headerExpansionFraction > EXPAND_INDICATOR_THRESHOLD);
     }
 
     @Override
@@ -237,8 +235,6 @@
         mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility(
                 TunerService.isTunerEnabled(mContext) ? View.VISIBLE : View.INVISIBLE);
 
-        mExpandIndicator.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
-
         final boolean isDemo = UserManager.isDeviceInDemoMode(mContext);
 
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 398592a..e6fd2f4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -38,6 +38,7 @@
 import com.android.systemui.qs.QSDetail.Callback;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.SignalClusterView;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher;
 import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
 
 public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue.Callbacks {
@@ -69,15 +70,13 @@
 
         updateResources();
 
-        // Set the light/dark theming on the header status UI to match the current theme.
+        // Set light text on the header icons because they will always be on a black background
         int colorForeground = Utils.getColorAttr(getContext(), android.R.attr.colorForeground);
-        float intensity = colorForeground == Color.WHITE ? 0 : 1;
         Rect tintArea = new Rect(0, 0, 0, 0);
-
-        applyDarkness(R.id.battery, tintArea, intensity, colorForeground);
-        applyDarkness(R.id.clock, tintArea, intensity, colorForeground);
+        applyDarkness(R.id.clock, tintArea, 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
 
         BatteryMeterView battery = findViewById(R.id.battery);
+        battery.setFillColor(Color.WHITE);
         battery.setForceShowPercent(true);
 
         mActivityStarter = Dependency.get(ActivityStarter.class);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 6db46b5..675aa8f 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -293,12 +293,13 @@
             sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
             sharingIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
 
-            // Create a share action for the notification. Note, we proxy the call to ShareReceiver
-            // 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 will
-            // start the chooser activitiy directly in ShareReceiver.
+            // 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 shareAction = PendingIntent.getBroadcast(context, 0,
-                    new Intent(context, GlobalScreenshot.ShareReceiver.class)
+                    new Intent(context, GlobalScreenshot.ScreenshotActionReceiver.class)
                             .putExtra(SHARING_INTENT, sharingIntent),
                     PendingIntent.FLAG_CANCEL_CURRENT);
             Notification.Action.Builder shareActionBuilder = new Notification.Action.Builder(
@@ -306,15 +307,19 @@
                     r.getString(com.android.internal.R.string.share), shareAction);
             mNotificationBuilder.addAction(shareActionBuilder.build());
 
-            // Create a delete action for the notification
-            PendingIntent deleteAction = PendingIntent.getBroadcast(context, 0,
-                    new Intent(context, GlobalScreenshot.DeleteScreenshotReceiver.class)
-                            .putExtra(GlobalScreenshot.SCREENSHOT_URI_ID, uri.toString()),
-                    PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
-            Notification.Action.Builder deleteActionBuilder = new Notification.Action.Builder(
-                    R.drawable.ic_screenshot_delete,
-                    r.getString(com.android.internal.R.string.delete), deleteAction);
-            mNotificationBuilder.addAction(deleteActionBuilder.build());
+            Intent editIntent = new Intent(Intent.ACTION_EDIT);
+            editIntent.setType("image/png");
+            editIntent.putExtra(Intent.EXTRA_STREAM, uri);
+
+            // Create a edit action for the notification the same way.
+            PendingIntent editAction = PendingIntent.getBroadcast(context, 1,
+                    new Intent(context, GlobalScreenshot.ScreenshotActionReceiver.class)
+                            .putExtra(SHARING_INTENT, editIntent),
+                    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());
 
             mParams.imageUri = uri;
             mParams.image = null;
@@ -879,9 +884,9 @@
     }
 
     /**
-     * Receiver to proxy the share intent.
+     * Receiver to proxy the share or edit intent.
      */
-    public static class ShareReceiver extends BroadcastReceiver {
+    public static class ScreenshotActionReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
             try {
@@ -903,7 +908,7 @@
     }
 
     /**
-     * Removes the notification for a screenshot after a share target is chosen.
+     * Removes the notification for a screenshot after a share or edit target is chosen.
      */
     public static class TargetChosenReceiver extends BroadcastReceiver {
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 970d1de..e8b28f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -16,26 +16,34 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+
+import android.annotation.Nullable;
 import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.util.EventLog;
+import android.view.DisplayCutout;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 
-import com.android.systemui.BatteryMeterView;
-import com.android.systemui.DejankUtils;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
 import com.android.systemui.Dependency;
 import com.android.systemui.EventLogTags;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.policy.DarkIconDispatcher;
 import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
+import com.android.systemui.util.leak.RotationUtils;
 
 public class PhoneStatusBarView extends PanelBar {
     private static final String TAG = "PhoneStatusBarView";
     private static final boolean DEBUG = StatusBar.DEBUG;
     private static final boolean DEBUG_GESTURES = false;
+    private static final int NO_VALUE = Integer.MIN_VALUE;
 
     StatusBar mBar;
 
@@ -53,6 +61,10 @@
         }
     };
     private DarkReceiver mBattery;
+    private int mLastOrientation;
+    private View mCutoutSpace;
+    @Nullable
+    private DisplayCutout mDisplayCutout;
 
     public PhoneStatusBarView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -76,6 +88,7 @@
     public void onFinishInflate() {
         mBarTransitions.init();
         mBattery = findViewById(R.id.battery);
+        mCutoutSpace = findViewById(R.id.cutout_space_view);
     }
 
     @Override
@@ -83,12 +96,51 @@
         super.onAttachedToWindow();
         // Always have Battery meters in the status bar observe the dark/light modes.
         Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mBattery);
+        if (updateOrientationAndCutout(getResources().getConfiguration().orientation)) {
+            postUpdateLayoutForCutout();
+        }
     }
 
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
         Dependency.get(DarkIconDispatcher.class).removeDarkReceiver(mBattery);
+        mDisplayCutout = null;
+    }
+
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+
+        // May trigger cutout space layout-ing
+        if (updateOrientationAndCutout(newConfig.orientation)) {
+            postUpdateLayoutForCutout();
+        }
+    }
+
+    /**
+     *
+     * @param newOrientation may pass NO_VALUE for no change
+     * @return boolean indicating if we need to update the cutout location / margins
+     */
+    private boolean updateOrientationAndCutout(int newOrientation) {
+        boolean changed = false;
+        if (newOrientation != NO_VALUE) {
+            if (mLastOrientation != newOrientation) {
+                changed = true;
+                mLastOrientation = newOrientation;
+            }
+        }
+
+        if (mDisplayCutout == null) {
+            DisplayCutout cutout = getRootWindowInsets().getDisplayCutout();
+            if (cutout != null) {
+                changed = true;
+                mDisplayCutout = cutout;
+            }
+        }
+
+        return changed;
     }
 
     @Override
@@ -214,4 +266,75 @@
                 R.dimen.status_bar_height);
         setLayoutParams(layoutParams);
     }
+
+    private void updateLayoutForCutout() {
+        updateCutoutLocation();
+        updateSafeInsets();
+    }
+
+    private void postUpdateLayoutForCutout() {
+        Runnable r = new Runnable() {
+            @Override
+            public void run() {
+                updateLayoutForCutout();
+            }
+        };
+        // Let the cutout emulation draw first
+        postDelayed(r, 0);
+    }
+
+    private void updateCutoutLocation() {
+        if (mDisplayCutout == null || mDisplayCutout.isEmpty()
+                    || mLastOrientation != ORIENTATION_PORTRAIT) {
+            mCutoutSpace.setVisibility(View.GONE);
+            return;
+        }
+
+        mCutoutSpace.setVisibility(View.VISIBLE);
+        LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mCutoutSpace.getLayoutParams();
+        lp.width = mDisplayCutout.getBoundingRect().width();
+        lp.height = mDisplayCutout.getBoundingRect().height();
+    }
+
+    private void updateSafeInsets() {
+        // Depending on our rotation, we may have to work around a cutout in the middle of the view,
+        // or letterboxing from the right or left sides.
+
+        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
+        if (mDisplayCutout == null || mDisplayCutout.isEmpty()) {
+            lp.leftMargin = 0;
+            lp.rightMargin = 0;
+            return;
+        }
+
+        int leftMargin = 0;
+        int rightMargin = 0;
+        switch (RotationUtils.getRotation(getContext())) {
+            /*
+             * Landscape: <-|
+             * Seascape:  |->
+             */
+            case RotationUtils.ROTATION_LANDSCAPE:
+                leftMargin = getDisplayCutoutHeight();
+                break;
+            case RotationUtils.ROTATION_SEASCAPE:
+                rightMargin = getDisplayCutoutHeight();
+                break;
+            default:
+                break;
+        }
+
+        lp.leftMargin = leftMargin;
+        lp.rightMargin = rightMargin;
+    }
+
+    //TODO: Find a better way
+    private int getDisplayCutoutHeight() {
+        if (mDisplayCutout == null || mDisplayCutout.isEmpty()) {
+            return 0;
+        }
+
+        Rect r = mDisplayCutout.getBoundingRect();
+        return r.bottom - r.top;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index bcda60e..07610ce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -62,7 +62,7 @@
     }
 
     /**
-     * Version of ViewGroup that observers state from the DarkIconDispatcher.
+     * Version of ViewGroup that observes state from the DarkIconDispatcher.
      */
     public static class DarkIconManager extends IconManager {
         private final DarkIconDispatcher mDarkIconDispatcher;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
new file mode 100644
index 0000000..1897171
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+/**
+ * A container for Status bar system icons. Limits the number of system icons and handles overflow
+ * similar to NotificationIconController. Can be used to layout nested StatusIconContainers
+ *
+ * Children are expected to be of type StatusBarIconView.
+ */
+package com.android.systemui.statusbar.phone;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.util.ArrayMap;
+import android.util.AttributeSet;
+
+import android.view.View;
+import com.android.keyguard.AlphaOptimizedLinearLayout;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.stack.ViewState;
+
+public class StatusIconContainer extends AlphaOptimizedLinearLayout {
+
+    private static final String TAG = "StatusIconContainer";
+    private static final int MAX_ICONS = 5;
+    private static final int MAX_DOTS = 3;
+
+    public StatusIconContainer(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        float midY = getHeight() / 2.0f;
+
+        // Layout all child views so that we can move them around later
+        for (int i = 0; i < getChildCount(); i++) {
+            View child = getChildAt(i);
+            int width = child.getMeasuredWidth();
+            int height = child.getMeasuredHeight();
+            int top = (int) (midY - height / 2.0f);
+            child.layout(0, top, width, top + height);
+        }
+
+        resetViewStates();
+        calculateIconTranslations();
+        applyIconStates();
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        final int count = getChildCount();
+        // Measure all children so that they report the correct width
+        for (int i = 0; i < count; i++) {
+            measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec);
+        }
+    }
+
+    @Override
+    public void onViewAdded(View child) {
+        super.onViewAdded(child);
+        ViewState vs = new ViewState();
+        child.setTag(R.id.status_bar_view_state_tag, vs);
+    }
+
+    @Override
+    public void onViewRemoved(View child) {
+        super.onViewRemoved(child);
+        child.setTag(R.id.status_bar_view_state_tag, null);
+    }
+
+    /**
+     * Layout is happening from end -> start
+     */
+    private void calculateIconTranslations() {
+        float translationX = getWidth();
+        float contentStart = getPaddingStart();
+        int childCount = getChildCount();
+        // Underflow === don't show content until that index
+        int firstUnderflowIndex = -1;
+        android.util.Log.d(TAG, "calculateIconTransitions: start=" + translationX);
+
+        //TODO: Dots
+        for (int i = childCount - 1; i >= 0; i--) {
+            View child = getChildAt(i);
+            if (!(child instanceof StatusBarIconView)) {
+                continue;
+            }
+
+            ViewState childState = getViewStateFromChild(child);
+            if (childState == null ) {
+                continue;
+            }
+
+            // Rely on StatusBarIcon for truth about visibility
+            if (!((StatusBarIconView) child).getStatusBarIcon().visible) {
+                childState.hidden = true;
+                continue;
+            }
+
+            childState.xTranslation = translationX - child.getWidth();
+
+            if (childState.xTranslation < contentStart) {
+                if (firstUnderflowIndex == -1) {
+                    firstUnderflowIndex = i;
+                }
+            }
+
+            translationX -= child.getWidth();
+        }
+
+        if (firstUnderflowIndex != -1) {
+            for (int i = 0; i <= firstUnderflowIndex; i++) {
+                View child = getChildAt(i);
+                ViewState vs = getViewStateFromChild(child);
+                if (vs != null) {
+                    vs.hidden = true;
+                }
+            }
+        }
+    }
+
+    private void applyIconStates() {
+        for (int i = 0; i < getChildCount(); i++) {
+            View child = getChildAt(i);
+            ViewState vs = getViewStateFromChild(child);
+            if (vs != null) {
+                vs.applyToView(child);
+            }
+        }
+    }
+
+    private void resetViewStates() {
+        for (int i = 0; i < getChildCount(); i++) {
+            View child = getChildAt(i);
+            ViewState vs = getViewStateFromChild(child);
+            if (vs == null) {
+                continue;
+            }
+
+            vs.initFrom(child);
+            vs.alpha = 1.0f;
+            if (child instanceof StatusBarIconView) {
+                vs.hidden = !((StatusBarIconView)child).getStatusBarIcon().visible;
+            } else {
+                vs.hidden = false;
+            }
+        }
+    }
+
+    private static @Nullable ViewState getViewStateFromChild(View child) {
+        return (ViewState) child.getTag(R.id.status_bar_view_state_tag);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
index 66524cc..2edcd01 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
@@ -74,6 +74,8 @@
 
         assertEquals(View.VISIBLE, mFragment.getView().findViewById(R.id.system_icon_area)
                 .getVisibility());
+        assertEquals(View.VISIBLE, mFragment.getView().findViewById(R.id.clock)
+                .getVisibility());
     }
 
     @Test
@@ -87,11 +89,15 @@
 
         assertEquals(View.INVISIBLE, mFragment.getView().findViewById(R.id.system_icon_area)
                 .getVisibility());
+        assertEquals(View.INVISIBLE, mFragment.getView().findViewById(R.id.clock)
+                .getVisibility());
 
         fragment.disable(0, 0, false);
 
         assertEquals(View.VISIBLE, mFragment.getView().findViewById(R.id.system_icon_area)
                 .getVisibility());
+        assertEquals(View.VISIBLE, mFragment.getView().findViewById(R.id.clock)
+                .getVisibility());
     }
 
     @Test
diff --git a/services/core/java/com/android/server/ForceAppStandbyTracker.java b/services/core/java/com/android/server/ForceAppStandbyTracker.java
index a538bde..de113a6 100644
--- a/services/core/java/com/android/server/ForceAppStandbyTracker.java
+++ b/services/core/java/com/android/server/ForceAppStandbyTracker.java
@@ -26,6 +26,8 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.BatteryManager;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -89,6 +91,9 @@
 
     private final MyHandler mHandler;
 
+    @VisibleForTesting
+    FeatureFlagsObserver mFlagsObserver;
+
     /**
      * Pair of (uid (not user-id), packageName) with OP_RUN_ANY_IN_BACKGROUND *not* allowed.
      */
@@ -113,14 +118,36 @@
     @GuardedBy("mLock")
     boolean mStarted;
 
+    /**
+     * Only used for small battery use-case.
+     */
     @GuardedBy("mLock")
-    boolean mForceAllAppsStandby;   // True if device is in extreme battery saver mode
+    boolean mIsPluggedIn;
 
     @GuardedBy("mLock")
-    boolean mForcedAppStandbyEnabled;   // True if the forced app standby feature is enabled
+    boolean mBatterySaverEnabled;
 
-    private class FeatureFlagObserver extends ContentObserver {
-        FeatureFlagObserver() {
+    /**
+     * True if the forced app standby is currently enabled
+     */
+    @GuardedBy("mLock")
+    boolean mForceAllAppsStandby;
+
+    /**
+     * True if the forced app standby for small battery devices feature is enabled in settings
+     */
+    @GuardedBy("mLock")
+    boolean mForceAllAppStandbyForSmallBattery;
+
+    /**
+     * True if the forced app standby feature is enabled in settings
+     */
+    @GuardedBy("mLock")
+    boolean mForcedAppStandbyEnabled;
+
+    @VisibleForTesting
+    class FeatureFlagsObserver extends ContentObserver {
+        FeatureFlagsObserver() {
             super(null);
         }
 
@@ -128,6 +155,9 @@
             mContext.getContentResolver().registerContentObserver(
                     Settings.Global.getUriFor(Settings.Global.FORCED_APP_STANDBY_ENABLED),
                     false, this);
+
+            mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
+                    Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED), false, this);
         }
 
         boolean isForcedAppStandbyEnabled() {
@@ -135,20 +165,43 @@
                     Settings.Global.FORCED_APP_STANDBY_ENABLED, 1) == 1;
         }
 
+        boolean isForcedAppStandbyForSmallBatteryEnabled() {
+            return Settings.Global.getInt(mContext.getContentResolver(),
+                    Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED, 0) == 1;
+        }
+
         @Override
-        public void onChange(boolean selfChange) {
-            final boolean enabled = isForcedAppStandbyEnabled();
-            synchronized (mLock) {
-                if (mForcedAppStandbyEnabled == enabled) {
-                    return;
+        public void onChange(boolean selfChange, Uri uri) {
+            if (Settings.Global.getUriFor(Settings.Global.FORCED_APP_STANDBY_ENABLED).equals(uri)) {
+                final boolean enabled = isForcedAppStandbyEnabled();
+                synchronized (mLock) {
+                    if (mForcedAppStandbyEnabled == enabled) {
+                        return;
+                    }
+                    mForcedAppStandbyEnabled = enabled;
+                    if (DEBUG) {
+                        Slog.d(TAG,"Forced app standby feature flag changed: "
+                                + mForcedAppStandbyEnabled);
+                    }
                 }
-                mForcedAppStandbyEnabled = enabled;
-                if (DEBUG) {
-                    Slog.d(TAG,
-                            "Forced app standby feature flag changed: " + mForcedAppStandbyEnabled);
+                mHandler.notifyForcedAppStandbyFeatureFlagChanged();
+            } else if (Settings.Global.getUriFor(
+                    Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED).equals(uri)) {
+                final boolean enabled = isForcedAppStandbyForSmallBatteryEnabled();
+                synchronized (mLock) {
+                    if (mForceAllAppStandbyForSmallBattery == enabled) {
+                        return;
+                    }
+                    mForceAllAppStandbyForSmallBattery = enabled;
+                    if (DEBUG) {
+                        Slog.d(TAG, "Forced app standby for small battery feature flag changed: "
+                                + mForceAllAppStandbyForSmallBattery);
+                    }
+                    updateForceAllAppStandbyState();
                 }
+            } else {
+                Slog.w(TAG, "Unexpected feature flag uri encountered: " + uri);
             }
-            mHandler.notifyFeatureFlagChanged();
         }
     }
 
@@ -289,9 +342,11 @@
             mAppOpsManager = Preconditions.checkNotNull(injectAppOpsManager());
             mAppOpsService = Preconditions.checkNotNull(injectIAppOpsService());
             mPowerManagerInternal = Preconditions.checkNotNull(injectPowerManagerInternal());
-            final FeatureFlagObserver flagObserver = new FeatureFlagObserver();
-            flagObserver.register();
-            mForcedAppStandbyEnabled = flagObserver.isForcedAppStandbyEnabled();
+            mFlagsObserver = new FeatureFlagsObserver();
+            mFlagsObserver.register();
+            mForcedAppStandbyEnabled = mFlagsObserver.isForcedAppStandbyEnabled();
+            mForceAllAppStandbyForSmallBattery =
+                    mFlagsObserver.isForcedAppStandbyForSmallBatteryEnabled();
 
             try {
                 mIActivityManager.registerUidObserver(new UidObserver(),
@@ -306,16 +361,24 @@
 
             IntentFilter filter = new IntentFilter();
             filter.addAction(Intent.ACTION_USER_REMOVED);
+            filter.addAction(Intent.ACTION_BATTERY_CHANGED);
             mContext.registerReceiver(new MyReceiver(), filter);
 
             refreshForcedAppStandbyUidPackagesLocked();
 
             mPowerManagerInternal.registerLowPowerModeObserver(
                     ServiceType.FORCE_ALL_APPS_STANDBY,
-                    (state) -> updateForceAllAppsStandby(state.batterySaverEnabled));
+                    (state) -> {
+                        synchronized (mLock) {
+                            mBatterySaverEnabled = state.batterySaverEnabled;
+                            updateForceAllAppStandbyState();
+                        }
+                    });
 
-            updateForceAllAppsStandby(mPowerManagerInternal.getLowPowerState(
-                    ServiceType.FORCE_ALL_APPS_STANDBY).batterySaverEnabled);
+            mBatterySaverEnabled = mPowerManagerInternal.getLowPowerState(
+                    ServiceType.FORCE_ALL_APPS_STANDBY).batterySaverEnabled;
+
+            updateForceAllAppStandbyState();
         }
     }
 
@@ -340,6 +403,11 @@
         return LocalServices.getService(PowerManagerInternal.class);
     }
 
+    @VisibleForTesting
+    boolean isSmallBatteryDevice() {
+        return ActivityManager.isSmallBatteryDevice();
+    }
+
     /**
      * Update {@link #mRunAnyRestrictedPackages} with the current app ops state.
      */
@@ -369,18 +437,26 @@
         }
     }
 
+    private void updateForceAllAppStandbyState() {
+        synchronized (mLock) {
+            if (mForceAllAppStandbyForSmallBattery && isSmallBatteryDevice()) {
+                toggleForceAllAppsStandbyLocked(!mIsPluggedIn);
+            } else {
+                toggleForceAllAppsStandbyLocked(mBatterySaverEnabled);
+            }
+        }
+    }
+
     /**
      * Update {@link #mForceAllAppsStandby} and notifies the listeners.
      */
-    void updateForceAllAppsStandby(boolean enable) {
-        synchronized (mLock) {
-            if (enable == mForceAllAppsStandby) {
-                return;
-            }
-            mForceAllAppsStandby = enable;
-
-            mHandler.notifyForceAllAppsStandbyChanged();
+    private void toggleForceAllAppsStandbyLocked(boolean enable) {
+        if (enable == mForceAllAppsStandby) {
+            return;
         }
+        mForceAllAppsStandby = enable;
+
+        mHandler.notifyForceAllAppsStandbyChanged();
     }
 
     private int findForcedAppStandbyUidPackageIndexLocked(int uid, @NonNull String packageName) {
@@ -515,6 +591,11 @@
                 if (userId > 0) {
                     mHandler.doUserRemoved(userId);
                 }
+            } else if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
+                synchronized (mLock) {
+                    mIsPluggedIn = (intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0);
+                }
+                updateForceAllAppStandbyState();
             }
         }
     }
@@ -533,7 +614,7 @@
         private static final int MSG_TEMP_WHITELIST_CHANGED = 5;
         private static final int MSG_FORCE_ALL_CHANGED = 6;
         private static final int MSG_USER_REMOVED = 7;
-        private static final int MSG_FEATURE_FLAG_CHANGED = 8;
+        private static final int MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 8;
 
         public MyHandler(Looper looper) {
             super(looper);
@@ -563,8 +644,8 @@
             obtainMessage(MSG_FORCE_ALL_CHANGED).sendToTarget();
         }
 
-        public void notifyFeatureFlagChanged() {
-            obtainMessage(MSG_FEATURE_FLAG_CHANGED).sendToTarget();
+        public void notifyForcedAppStandbyFeatureFlagChanged() {
+            obtainMessage(MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED).sendToTarget();
         }
 
         public void doUserRemoved(int userId) {
@@ -618,7 +699,7 @@
                         l.onForceAllAppsStandbyChanged(sender);
                     }
                     return;
-                case MSG_FEATURE_FLAG_CHANGED:
+                case MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED:
                     // Feature flag for forced app standby changed.
                     final boolean unblockAlarms;
                     synchronized (mLock) {
@@ -845,6 +926,18 @@
             pw.println(isForceAllAppsStandbyEnabled());
 
             pw.print(indent);
+            pw.print("Small Battery Device: ");
+            pw.println(isSmallBatteryDevice());
+
+            pw.print(indent);
+            pw.print("Force all apps standby for small battery device: ");
+            pw.println(mForceAllAppStandbyForSmallBattery);
+
+            pw.print(indent);
+            pw.print("Plugged In: ");
+            pw.println(mIsPluggedIn);
+
+            pw.print(indent);
             pw.print("Foreground uids: [");
 
             String sep = "";
@@ -883,6 +976,11 @@
             final long token = proto.start(fieldId);
 
             proto.write(ForceAppStandbyTrackerProto.FORCE_ALL_APPS_STANDBY, mForceAllAppsStandby);
+            proto.write(ForceAppStandbyTrackerProto.IS_SMALL_BATTERY_DEVICE,
+                    isSmallBatteryDevice());
+            proto.write(ForceAppStandbyTrackerProto.FORCE_ALL_APPS_STANDBY_FOR_SMALL_BATTERY,
+                    mForceAllAppStandbyForSmallBattery);
+            proto.write(ForceAppStandbyTrackerProto.IS_CHARGING, mIsPluggedIn);
 
             for (int i = 0; i < mForegroundUids.size(); i++) {
                 if (mForegroundUids.valueAt(i)) {
diff --git a/services/core/java/com/android/server/PersistentDataBlockManagerInternal.java b/services/core/java/com/android/server/PersistentDataBlockManagerInternal.java
index 80f8e51..833def3 100644
--- a/services/core/java/com/android/server/PersistentDataBlockManagerInternal.java
+++ b/services/core/java/com/android/server/PersistentDataBlockManagerInternal.java
@@ -26,4 +26,7 @@
 
     /** Retrieves handle to a lockscreen credential to be used for Factory Reset Protection. */
     byte[] getFrpCredentialHandle();
+
+    /** Update the OEM unlock enabled bit, bypassing user restriction checks. */
+    void forceOemUnlockEnabled(boolean enabled);
 }
diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java
index c32a2d1..4298140 100644
--- a/services/core/java/com/android/server/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/PersistentDataBlockService.java
@@ -668,5 +668,13 @@
                 IoUtils.closeQuietly(inputStream);
             }
         }
+
+        @Override
+        public void forceOemUnlockEnabled(boolean enabled) {
+            synchronized (mLock) {
+                doSetOemUnlockEnabledLocked(enabled);
+                computeAndWriteDigestLocked();
+            }
+        }
     };
 }
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 8910274..26d65bc 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -745,7 +745,7 @@
                     mContext.getContentResolver(),
                     Settings.Secure.SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
                     0,
-                    UserHandle.USER_CURRENT) != 0;
+                    mService.mUserController.getCurrentUserId()) != 0;
             final boolean crashSilenced = mAppsNotReportingCrashes != null &&
                     mAppsNotReportingCrashes.contains(proc.info.packageName);
             if ((mService.canShowErrorDialogs() || showBackground) && !crashSilenced
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistConfig.java b/services/core/java/com/android/server/net/watchlist/WatchlistConfig.java
index fbf11fc..7387ad4 100644
--- a/services/core/java/com/android/server/net/watchlist/WatchlistConfig.java
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistConfig.java
@@ -161,7 +161,7 @@
     public boolean containsDomain(String domain) {
         final CrcShaDigests domainDigests = mDomainDigests;
         if (domainDigests == null) {
-            Slog.wtf(TAG, "domainDigests should not be null");
+            // mDomainDigests is not initialized
             return false;
         }
         // First it does a quick CRC32 check.
@@ -177,7 +177,7 @@
     public boolean containsIp(String ip) {
         final CrcShaDigests ipDigests = mIpDigests;
         if (ipDigests == null) {
-            Slog.wtf(TAG, "ipDigests should not be null");
+            // mIpDigests is not initialized
             return false;
         }
         // First it does a quick CRC32 check.
@@ -234,12 +234,20 @@
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("Domain CRC32 digest list:");
-        mDomainDigests.crc32Digests.dump(fd, pw, args);
+        if (mDomainDigests != null) {
+            mDomainDigests.crc32Digests.dump(fd, pw, args);
+        }
         pw.println("Domain SHA256 digest list:");
-        mDomainDigests.sha256Digests.dump(fd, pw, args);
+        if (mDomainDigests != null) {
+            mDomainDigests.sha256Digests.dump(fd, pw, args);
+        }
         pw.println("Ip CRC32 digest list:");
-        mIpDigests.crc32Digests.dump(fd, pw, args);
+        if (mIpDigests != null) {
+            mIpDigests.crc32Digests.dump(fd, pw, args);
+        }
         pw.println("Ip SHA256 digest list:");
-        mIpDigests.sha256Digests.dump(fd, pw, args);
+        if (mIpDigests != null) {
+            mIpDigests.sha256Digests.dump(fd, pw, args);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/oemlock/OemLockService.java b/services/core/java/com/android/server/oemlock/OemLockService.java
index 2a2ff06..a6200bf 100644
--- a/services/core/java/com/android/server/oemlock/OemLockService.java
+++ b/services/core/java/com/android/server/oemlock/OemLockService.java
@@ -31,10 +31,10 @@
 import android.os.UserManagerInternal;
 import android.os.UserManagerInternal.UserRestrictionsListener;
 import android.service.oemlock.IOemLockService;
-import android.service.persistentdata.PersistentDataBlockManager;
 import android.util.Slog;
 
 import com.android.server.LocalServices;
+import com.android.server.PersistentDataBlockManagerInternal;
 import com.android.server.SystemService;
 import com.android.server.pm.UserRestrictionsUtils;
 
@@ -217,13 +217,12 @@
      * is used to erase FRP information on a unlockable device.
      */
     private void setPersistentDataBlockOemUnlockAllowedBit(boolean allowed) {
-        final PersistentDataBlockManager pdbm = (PersistentDataBlockManager)
-                mContext.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE);
+        final PersistentDataBlockManagerInternal pdbmi
+                = LocalServices.getService(PersistentDataBlockManagerInternal.class);
         // if mOemLock is PersistentDataBlockLock, then the bit should have already been set
-        if (pdbm != null && !(mOemLock instanceof PersistentDataBlockLock)
-                && pdbm.getOemUnlockEnabled() != allowed) {
+        if (pdbmi != null && !(mOemLock instanceof PersistentDataBlockLock)) {
             Slog.i(TAG, "Update OEM Unlock bit in pst partition to " + allowed);
-            pdbm.setOemUnlockEnabled(allowed);
+            pdbmi.forceOemUnlockEnabled(allowed);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index b474c62..ce3f512 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -463,10 +463,14 @@
                 mService.mActivityManagerAppTransitionNotifier.onAppTransitionFinishedLocked(token);
             }
 
-            // Update the client visibility if we are not running an animation. Otherwise, we'll
-            // update client visibility state in onAnimationFinished.
-            if (!visible && !delayed) {
-                setClientHidden(true);
+            // If we're becoming visible, immediately change client visibility as well although it
+            // usually gets changed in AppWindowContainerController.setVisibility already. However,
+            // there seem to be some edge cases where we change our visibility but client visibility
+            // never gets updated.
+            // If we're becoming invisible, update the client visibility if we are not running an
+            // animation. Otherwise, we'll update client visibility in onAnimationFinished.
+            if (visible || !delayed) {
+                setClientHidden(!visible);
             }
 
             // If we are hidden but there is no delay needed we immediately
diff --git a/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java b/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
index 429dd8f..de54e52 100644
--- a/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
@@ -42,6 +42,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.os.BatteryManager;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.PowerManager.ServiceType;
@@ -51,6 +52,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.provider.Settings.Global;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.mock.MockContentResolver;
@@ -105,6 +107,9 @@
         PowerManagerInternal injectPowerManagerInternal() {
             return mMockPowerManagerInternal;
         }
+
+        @Override
+        boolean isSmallBatteryDevice() { return mIsSmallBatteryDevice; };
     }
 
     private static final int UID_1 = Process.FIRST_APPLICATION_UID + 1;
@@ -144,6 +149,7 @@
     private FakeSettingsProvider mFakeSettingsProvider;
 
     private boolean mPowerSaveMode;
+    private boolean mIsSmallBatteryDevice;
 
     private final ArraySet<Pair<Integer, String>> mRestrictedPackages = new ArraySet();
 
@@ -232,6 +238,7 @@
         assertNotNull(mAppOpsCallback);
         assertNotNull(mPowerSaveObserver);
         assertNotNull(mReceiver);
+        assertNotNull(instance.mFlagsObserver);
     }
 
     private void setAppOps(int uid, String packageName, boolean restrict) throws RemoteException {
@@ -852,6 +859,56 @@
         assertTrue(instance.isRunAnyInBackgroundAppOpsAllowed(UID_10_2, PACKAGE_2));
     }
 
+    @Test
+    public void testSmallBatteryAndPluggedIn() throws Exception {
+        // This is a small battery device
+        mIsSmallBatteryDevice = true;
+
+        final ForceAppStandbyTrackerTestable instance = newInstance();
+        callStart(instance);
+        assertFalse(instance.isForceAllAppsStandbyEnabled());
+
+        // Setting/experiment for all app standby for small battery is enabled
+        Global.putInt(mMockContentResolver, Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED, 1);
+        instance.mFlagsObserver.onChange(true,
+                Global.getUriFor(Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED));
+        assertTrue(instance.isForceAllAppsStandbyEnabled());
+
+        // When battery is plugged in, force app standby is disabled
+        Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
+        intent.putExtra(BatteryManager.EXTRA_PLUGGED, BatteryManager.BATTERY_PLUGGED_USB);
+        mReceiver.onReceive(mMockContext, intent);
+        assertFalse(instance.isForceAllAppsStandbyEnabled());
+
+        // When battery stops plugged in, force app standby is enabled
+        mReceiver.onReceive(mMockContext, new Intent(Intent.ACTION_BATTERY_CHANGED));
+        assertTrue(instance.isForceAllAppsStandbyEnabled());
+    }
+
+    @Test
+    public void testNotSmallBatteryAndPluggedIn() throws Exception {
+        // Not a small battery device, so plugged in status should not affect forced app standby
+        mIsSmallBatteryDevice = false;
+
+        final ForceAppStandbyTrackerTestable instance = newInstance();
+        callStart(instance);
+        assertFalse(instance.isForceAllAppsStandbyEnabled());
+
+        mPowerSaveMode = true;
+        mPowerSaveObserver.accept(getPowerSaveState());
+        assertTrue(instance.isForceAllAppsStandbyEnabled());
+
+        // When battery is plugged in, force app standby is unaffected
+        Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
+        intent.putExtra(BatteryManager.EXTRA_PLUGGED, BatteryManager.BATTERY_PLUGGED_USB);
+        mReceiver.onReceive(mMockContext, intent);
+        assertTrue(instance.isForceAllAppsStandbyEnabled());
+
+        // When battery stops plugged in, force app standby is unaffected
+        mReceiver.onReceive(mMockContext, new Intent(Intent.ACTION_BATTERY_CHANGED));
+        assertTrue(instance.isForceAllAppsStandbyEnabled());
+    }
+
     static int[] array(int... appIds) {
         Arrays.sort(appIds);
         return appIds;
diff --git a/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistConfigTests.java b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistConfigTests.java
index 851d2c6..654acc2 100644
--- a/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistConfigTests.java
+++ b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistConfigTests.java
@@ -33,12 +33,15 @@
 import org.junit.runner.RunWith;
 
 import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.io.InputStreamReader;
+import java.io.PrintWriter;
 import java.util.Arrays;
 
+
 /**
  * runtest frameworks-services -c com.android.server.net.watchlist.WatchlistConfigTests
  */
@@ -117,6 +120,15 @@
         assertEquals(TEST_XML_1_HASH, HexDump.toHexString(config.getWatchlistConfigHash()));
     }
 
+    @Test
+    public void testWatchlistConfig_testDumpDoesNotCrash() throws Exception {
+        WatchlistConfig config = new WatchlistConfig(new File("/not_exist_path.xml"));
+        ByteArrayOutputStream bs = new ByteArrayOutputStream(2048);
+        PrintWriter pw = new PrintWriter(bs);
+        // Make sure dump still works even watchlist does not exist
+        config.dump(null, pw, null);
+    }
+
     private static void copyWatchlistConfigXml(Context context, String xmlAsset, File outFile)
             throws IOException {
         writeToFile(outFile, readAsset(context, xmlAsset));
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 2534327..d146707 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -71,8 +71,18 @@
      * TODO(b/35851809): Make this a SystemApi.
      */
     @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String ACTION_OTA_STATUS_CHANGED
-            = "android.telephony.euicc.action.OTA_STATUS_CHANGED";
+    public static final String ACTION_OTA_STATUS_CHANGED =
+            "android.telephony.euicc.action.OTA_STATUS_CHANGED";
+
+    /**
+     * Broadcast Action: The action sent to carrier app so it knows the carrier setup is not
+     * completed.
+     *
+     * TODO(b/35851809): Make this a public API.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_NOTIFY_CARRIER_SETUP =
+            "android.telephony.euicc.action.NOTIFY_CARRIER_SETUP";
 
     /**
      * Intent action to provision an embedded subscription.
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
index 10d6deb..9f2cb92 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
@@ -66,6 +66,7 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -174,6 +175,7 @@
     }
 
     @Test
+    @Ignore
     public void testDefaultNetworkEvents() throws Exception {
         final long cell = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_CELLULAR});
         final long wifi = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_WIFI});
@@ -292,6 +294,7 @@
     }
 
     @Test
+    @Ignore
     public void testEndToEndLogging() throws Exception {
         // TODO: instead of comparing textpb to textpb, parse textpb and compare proto to proto.
         IpConnectivityLog logger = new IpConnectivityLog(mService.impl);