Merge "Overhaul RenderNode's DisplayList management"
diff --git a/api/current.txt b/api/current.txt
index 76a2289..85747c1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -20900,6 +20900,40 @@
     method public default void onRoutingChanged(android.media.AudioRouting);
   }
 
+  public final class BufferingParams implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getInitialBufferingMode();
+    method public int getInitialBufferingWatermarkKB();
+    method public int getInitialBufferingWatermarkMs();
+    method public int getRebufferingMode();
+    method public int getRebufferingWatermarkHighKB();
+    method public int getRebufferingWatermarkHighMs();
+    method public int getRebufferingWatermarkLowKB();
+    method public int getRebufferingWatermarkLowMs();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int BUFFERING_MODE_NONE = 0; // 0x0
+    field public static final int BUFFERING_MODE_SIZE_ONLY = 2; // 0x2
+    field public static final int BUFFERING_MODE_TIME_ONLY = 1; // 0x1
+    field public static final int BUFFERING_MODE_TIME_THEN_SIZE = 3; // 0x3
+    field public static final android.os.Parcelable.Creator<android.media.BufferingParams> CREATOR;
+  }
+
+  public static class BufferingParams.Builder {
+    ctor public BufferingParams.Builder();
+    ctor public BufferingParams.Builder(android.media.BufferingParams);
+    method public android.media.BufferingParams build();
+    method public android.media.BufferingParams.Builder setInitialBufferingMode(int);
+    method public android.media.BufferingParams.Builder setInitialBufferingWatermarkKB(int);
+    method public android.media.BufferingParams.Builder setInitialBufferingWatermarkMs(int);
+    method public android.media.BufferingParams.Builder setRebufferingMode(int);
+    method public android.media.BufferingParams.Builder setRebufferingWatermarkHighKB(int);
+    method public android.media.BufferingParams.Builder setRebufferingWatermarkHighMs(int);
+    method public android.media.BufferingParams.Builder setRebufferingWatermarkLowKB(int);
+    method public android.media.BufferingParams.Builder setRebufferingWatermarkLowMs(int);
+    method public android.media.BufferingParams.Builder setRebufferingWatermarksKB(int, int);
+    method public android.media.BufferingParams.Builder setRebufferingWatermarksMs(int, int);
+  }
+
   public class CamcorderProfile {
     method public static android.media.CamcorderProfile get(int);
     method public static android.media.CamcorderProfile get(int, int);
@@ -22072,7 +22106,9 @@
     method public static android.media.MediaPlayer create(android.content.Context, int, android.media.AudioAttributes, int);
     method public void deselectTrack(int) throws java.lang.IllegalStateException;
     method public int getAudioSessionId();
+    method public android.media.BufferingParams getBufferingParams();
     method public int getCurrentPosition();
+    method public android.media.BufferingParams getDefaultBufferingParams();
     method public int getDuration();
     method public android.media.PlaybackParams getPlaybackParams();
     method public int getSelectedTrack(int) throws java.lang.IllegalStateException;
@@ -22095,6 +22131,7 @@
     method public void setAudioSessionId(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public deprecated void setAudioStreamType(int);
     method public void setAuxEffectSendLevel(float);
+    method public void setBufferingParams(android.media.BufferingParams);
     method public void setDataSource(android.content.Context, android.net.Uri) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
     method public void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
     method public void setDataSource(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
@@ -33513,6 +33550,7 @@
     field public static final java.lang.String ACTION_BLUETOOTH_SETTINGS = "android.settings.BLUETOOTH_SETTINGS";
     field public static final java.lang.String ACTION_CAPTIONING_SETTINGS = "android.settings.CAPTIONING_SETTINGS";
     field public static final java.lang.String ACTION_CAST_SETTINGS = "android.settings.CAST_SETTINGS";
+    field public static final java.lang.String ACTION_CHANNEL_NOTIFICATION_SETTINGS = "android.settings.CHANNEL_NOTIFICATION_SETTINGS";
     field public static final java.lang.String ACTION_DATA_ROAMING_SETTINGS = "android.settings.DATA_ROAMING_SETTINGS";
     field public static final java.lang.String ACTION_DATE_SETTINGS = "android.settings.DATE_SETTINGS";
     field public static final java.lang.String ACTION_DEVICE_INFO_SETTINGS = "android.settings.DEVICE_INFO_SETTINGS";
@@ -33565,8 +33603,10 @@
     field public static final java.lang.String AUTHORITY = "settings";
     field public static final java.lang.String EXTRA_ACCOUNT_TYPES = "account_types";
     field public static final java.lang.String EXTRA_AIRPLANE_MODE_ENABLED = "airplane_mode_enabled";
+    field public static final java.lang.String EXTRA_APP_PACKAGE = "android.provider.extra.APP_PACKAGE";
     field public static final java.lang.String EXTRA_AUTHORITIES = "authorities";
     field public static final java.lang.String EXTRA_BATTERY_SAVER_MODE_ENABLED = "android.settings.extra.battery_saver_mode_enabled";
+    field public static final java.lang.String EXTRA_CHANNEL_ID = "android.provider.extra.CHANNEL_ID";
     field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_ENABLED = "android.settings.extra.do_not_disturb_mode_enabled";
     field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_MINUTES = "android.settings.extra.do_not_disturb_mode_minutes";
     field public static final java.lang.String EXTRA_INPUT_METHOD_ID = "input_method_id";
@@ -46207,6 +46247,13 @@
     field public static final android.os.Parcelable.Creator<android.view.autofill.AutoFillId> CREATOR;
   }
 
+  public final class AutoFillManager {
+    method public void updateAutoFillInput(android.view.View, int);
+    method public void updateAutoFillInput(android.view.View, int, android.graphics.Rect, int);
+    field public static final int FLAG_UPDATE_UI_HIDE = 2; // 0x2
+    field public static final int FLAG_UPDATE_UI_SHOW = 1; // 0x1
+  }
+
   public final class AutoFillType implements android.os.Parcelable {
     method public int describeContents();
     method public static android.view.autofill.AutoFillType forList();
@@ -46266,7 +46313,7 @@
 
   public static abstract class VirtualViewDelegate.Callback {
     ctor public VirtualViewDelegate.Callback();
-    method public void onFocusChanged(int, boolean);
+    method public void onAutoFillInputUpdated(int, android.graphics.Rect, int);
     method public void onNodeRemoved(int...);
     method public void onValueChanged(int);
   }
diff --git a/api/system-current.txt b/api/system-current.txt
index bda634f..6a37e82 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -22500,6 +22500,40 @@
     method public default void onRoutingChanged(android.media.AudioRouting);
   }
 
+  public final class BufferingParams implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getInitialBufferingMode();
+    method public int getInitialBufferingWatermarkKB();
+    method public int getInitialBufferingWatermarkMs();
+    method public int getRebufferingMode();
+    method public int getRebufferingWatermarkHighKB();
+    method public int getRebufferingWatermarkHighMs();
+    method public int getRebufferingWatermarkLowKB();
+    method public int getRebufferingWatermarkLowMs();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int BUFFERING_MODE_NONE = 0; // 0x0
+    field public static final int BUFFERING_MODE_SIZE_ONLY = 2; // 0x2
+    field public static final int BUFFERING_MODE_TIME_ONLY = 1; // 0x1
+    field public static final int BUFFERING_MODE_TIME_THEN_SIZE = 3; // 0x3
+    field public static final android.os.Parcelable.Creator<android.media.BufferingParams> CREATOR;
+  }
+
+  public static class BufferingParams.Builder {
+    ctor public BufferingParams.Builder();
+    ctor public BufferingParams.Builder(android.media.BufferingParams);
+    method public android.media.BufferingParams build();
+    method public android.media.BufferingParams.Builder setInitialBufferingMode(int);
+    method public android.media.BufferingParams.Builder setInitialBufferingWatermarkKB(int);
+    method public android.media.BufferingParams.Builder setInitialBufferingWatermarkMs(int);
+    method public android.media.BufferingParams.Builder setRebufferingMode(int);
+    method public android.media.BufferingParams.Builder setRebufferingWatermarkHighKB(int);
+    method public android.media.BufferingParams.Builder setRebufferingWatermarkHighMs(int);
+    method public android.media.BufferingParams.Builder setRebufferingWatermarkLowKB(int);
+    method public android.media.BufferingParams.Builder setRebufferingWatermarkLowMs(int);
+    method public android.media.BufferingParams.Builder setRebufferingWatermarksKB(int, int);
+    method public android.media.BufferingParams.Builder setRebufferingWatermarksMs(int, int);
+  }
+
   public class CamcorderProfile {
     method public static android.media.CamcorderProfile get(int);
     method public static android.media.CamcorderProfile get(int, int);
@@ -23672,7 +23706,9 @@
     method public static android.media.MediaPlayer create(android.content.Context, int, android.media.AudioAttributes, int);
     method public void deselectTrack(int) throws java.lang.IllegalStateException;
     method public int getAudioSessionId();
+    method public android.media.BufferingParams getBufferingParams();
     method public int getCurrentPosition();
+    method public android.media.BufferingParams getDefaultBufferingParams();
     method public int getDuration();
     method public android.media.PlaybackParams getPlaybackParams();
     method public int getSelectedTrack(int) throws java.lang.IllegalStateException;
@@ -23695,6 +23731,7 @@
     method public void setAudioSessionId(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public deprecated void setAudioStreamType(int);
     method public void setAuxEffectSendLevel(float);
+    method public void setBufferingParams(android.media.BufferingParams);
     method public void setDataSource(android.content.Context, android.net.Uri) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
     method public void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
     method public void setDataSource(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
@@ -36504,6 +36541,7 @@
     field public static final java.lang.String ACTION_BLUETOOTH_SETTINGS = "android.settings.BLUETOOTH_SETTINGS";
     field public static final java.lang.String ACTION_CAPTIONING_SETTINGS = "android.settings.CAPTIONING_SETTINGS";
     field public static final java.lang.String ACTION_CAST_SETTINGS = "android.settings.CAST_SETTINGS";
+    field public static final java.lang.String ACTION_CHANNEL_NOTIFICATION_SETTINGS = "android.settings.CHANNEL_NOTIFICATION_SETTINGS";
     field public static final java.lang.String ACTION_CONFIGURE_WIFI_SETTINGS = "android.settings.CONFIGURE_WIFI_SETTINGS";
     field public static final java.lang.String ACTION_DATA_ROAMING_SETTINGS = "android.settings.DATA_ROAMING_SETTINGS";
     field public static final java.lang.String ACTION_DATE_SETTINGS = "android.settings.DATE_SETTINGS";
@@ -36559,8 +36597,10 @@
     field public static final java.lang.String AUTHORITY = "settings";
     field public static final java.lang.String EXTRA_ACCOUNT_TYPES = "account_types";
     field public static final java.lang.String EXTRA_AIRPLANE_MODE_ENABLED = "airplane_mode_enabled";
+    field public static final java.lang.String EXTRA_APP_PACKAGE = "android.provider.extra.APP_PACKAGE";
     field public static final java.lang.String EXTRA_AUTHORITIES = "authorities";
     field public static final java.lang.String EXTRA_BATTERY_SAVER_MODE_ENABLED = "android.settings.extra.battery_saver_mode_enabled";
+    field public static final java.lang.String EXTRA_CHANNEL_ID = "android.provider.extra.CHANNEL_ID";
     field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_ENABLED = "android.settings.extra.do_not_disturb_mode_enabled";
     field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_MINUTES = "android.settings.extra.do_not_disturb_mode_minutes";
     field public static final java.lang.String EXTRA_INPUT_METHOD_ID = "input_method_id";
@@ -49592,6 +49632,13 @@
     field public static final android.os.Parcelable.Creator<android.view.autofill.AutoFillId> CREATOR;
   }
 
+  public final class AutoFillManager {
+    method public void updateAutoFillInput(android.view.View, int);
+    method public void updateAutoFillInput(android.view.View, int, android.graphics.Rect, int);
+    field public static final int FLAG_UPDATE_UI_HIDE = 2; // 0x2
+    field public static final int FLAG_UPDATE_UI_SHOW = 1; // 0x1
+  }
+
   public final class AutoFillType implements android.os.Parcelable {
     method public int describeContents();
     method public static android.view.autofill.AutoFillType forList();
@@ -49651,7 +49698,7 @@
 
   public static abstract class VirtualViewDelegate.Callback {
     ctor public VirtualViewDelegate.Callback();
-    method public void onFocusChanged(int, boolean);
+    method public void onAutoFillInputUpdated(int, android.graphics.Rect, int);
     method public void onNodeRemoved(int...);
     method public void onValueChanged(int);
   }
diff --git a/api/test-current.txt b/api/test-current.txt
index c6de2e4..d67c022 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -20990,6 +20990,40 @@
     method public default void onRoutingChanged(android.media.AudioRouting);
   }
 
+  public final class BufferingParams implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getInitialBufferingMode();
+    method public int getInitialBufferingWatermarkKB();
+    method public int getInitialBufferingWatermarkMs();
+    method public int getRebufferingMode();
+    method public int getRebufferingWatermarkHighKB();
+    method public int getRebufferingWatermarkHighMs();
+    method public int getRebufferingWatermarkLowKB();
+    method public int getRebufferingWatermarkLowMs();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int BUFFERING_MODE_NONE = 0; // 0x0
+    field public static final int BUFFERING_MODE_SIZE_ONLY = 2; // 0x2
+    field public static final int BUFFERING_MODE_TIME_ONLY = 1; // 0x1
+    field public static final int BUFFERING_MODE_TIME_THEN_SIZE = 3; // 0x3
+    field public static final android.os.Parcelable.Creator<android.media.BufferingParams> CREATOR;
+  }
+
+  public static class BufferingParams.Builder {
+    ctor public BufferingParams.Builder();
+    ctor public BufferingParams.Builder(android.media.BufferingParams);
+    method public android.media.BufferingParams build();
+    method public android.media.BufferingParams.Builder setInitialBufferingMode(int);
+    method public android.media.BufferingParams.Builder setInitialBufferingWatermarkKB(int);
+    method public android.media.BufferingParams.Builder setInitialBufferingWatermarkMs(int);
+    method public android.media.BufferingParams.Builder setRebufferingMode(int);
+    method public android.media.BufferingParams.Builder setRebufferingWatermarkHighKB(int);
+    method public android.media.BufferingParams.Builder setRebufferingWatermarkHighMs(int);
+    method public android.media.BufferingParams.Builder setRebufferingWatermarkLowKB(int);
+    method public android.media.BufferingParams.Builder setRebufferingWatermarkLowMs(int);
+    method public android.media.BufferingParams.Builder setRebufferingWatermarksKB(int, int);
+    method public android.media.BufferingParams.Builder setRebufferingWatermarksMs(int, int);
+  }
+
   public class CamcorderProfile {
     method public static android.media.CamcorderProfile get(int);
     method public static android.media.CamcorderProfile get(int, int);
@@ -22162,7 +22196,9 @@
     method public static android.media.MediaPlayer create(android.content.Context, int, android.media.AudioAttributes, int);
     method public void deselectTrack(int) throws java.lang.IllegalStateException;
     method public int getAudioSessionId();
+    method public android.media.BufferingParams getBufferingParams();
     method public int getCurrentPosition();
+    method public android.media.BufferingParams getDefaultBufferingParams();
     method public int getDuration();
     method public android.media.PlaybackParams getPlaybackParams();
     method public int getSelectedTrack(int) throws java.lang.IllegalStateException;
@@ -22185,6 +22221,7 @@
     method public void setAudioSessionId(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public deprecated void setAudioStreamType(int);
     method public void setAuxEffectSendLevel(float);
+    method public void setBufferingParams(android.media.BufferingParams);
     method public void setDataSource(android.content.Context, android.net.Uri) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
     method public void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
     method public void setDataSource(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
@@ -33629,6 +33666,7 @@
     field public static final java.lang.String ACTION_BLUETOOTH_SETTINGS = "android.settings.BLUETOOTH_SETTINGS";
     field public static final java.lang.String ACTION_CAPTIONING_SETTINGS = "android.settings.CAPTIONING_SETTINGS";
     field public static final java.lang.String ACTION_CAST_SETTINGS = "android.settings.CAST_SETTINGS";
+    field public static final java.lang.String ACTION_CHANNEL_NOTIFICATION_SETTINGS = "android.settings.CHANNEL_NOTIFICATION_SETTINGS";
     field public static final java.lang.String ACTION_DATA_ROAMING_SETTINGS = "android.settings.DATA_ROAMING_SETTINGS";
     field public static final java.lang.String ACTION_DATE_SETTINGS = "android.settings.DATE_SETTINGS";
     field public static final java.lang.String ACTION_DEVICE_INFO_SETTINGS = "android.settings.DEVICE_INFO_SETTINGS";
@@ -33682,8 +33720,10 @@
     field public static final java.lang.String AUTHORITY = "settings";
     field public static final java.lang.String EXTRA_ACCOUNT_TYPES = "account_types";
     field public static final java.lang.String EXTRA_AIRPLANE_MODE_ENABLED = "airplane_mode_enabled";
+    field public static final java.lang.String EXTRA_APP_PACKAGE = "android.provider.extra.APP_PACKAGE";
     field public static final java.lang.String EXTRA_AUTHORITIES = "authorities";
     field public static final java.lang.String EXTRA_BATTERY_SAVER_MODE_ENABLED = "android.settings.extra.battery_saver_mode_enabled";
+    field public static final java.lang.String EXTRA_CHANNEL_ID = "android.provider.extra.CHANNEL_ID";
     field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_ENABLED = "android.settings.extra.do_not_disturb_mode_enabled";
     field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_MINUTES = "android.settings.extra.do_not_disturb_mode_minutes";
     field public static final java.lang.String EXTRA_INPUT_METHOD_ID = "input_method_id";
@@ -46517,6 +46557,13 @@
     field public static final android.os.Parcelable.Creator<android.view.autofill.AutoFillId> CREATOR;
   }
 
+  public final class AutoFillManager {
+    method public void updateAutoFillInput(android.view.View, int);
+    method public void updateAutoFillInput(android.view.View, int, android.graphics.Rect, int);
+    field public static final int FLAG_UPDATE_UI_HIDE = 2; // 0x2
+    field public static final int FLAG_UPDATE_UI_SHOW = 1; // 0x1
+  }
+
   public final class AutoFillType implements android.os.Parcelable {
     method public int describeContents();
     method public static android.view.autofill.AutoFillType forList();
@@ -46576,7 +46623,7 @@
 
   public static abstract class VirtualViewDelegate.Callback {
     ctor public VirtualViewDelegate.Callback();
-    method public void onFocusChanged(int, boolean);
+    method public void onAutoFillInputUpdated(int, android.graphics.Rect, int);
     method public void onNodeRemoved(int...);
     method public void onValueChanged(int);
   }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 3cb920a..3902bd6 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -698,6 +698,13 @@
         }
 
         /**
+         * Returns true if the input stack is affected by drag resizing.
+         */
+        public static boolean isStackAffectedByDragResizing(int stackId) {
+            return isStaticStack(stackId) && stackId != PINNED_STACK_ID;
+        }
+
+        /**
          * Returns true if the windows of tasks being moved to the target stack from the source
          * stack should be replaced, meaning that window manager will keep the old window around
          * until the new is ready.
diff --git a/core/java/android/app/IUiModeManager.aidl b/core/java/android/app/IUiModeManager.aidl
index 848464c..7f0b6fb 100644
--- a/core/java/android/app/IUiModeManager.aidl
+++ b/core/java/android/app/IUiModeManager.aidl
@@ -58,11 +58,16 @@
     void setTheme(String theme);
 
     /**
-     * Gets whith theme overlays to use within /vendor/overlay.
+     * Gets which theme overlays to use within /vendor/overlay.
      */
     String getTheme();
 
     /**
+     * Gets the themes available in /vendor/overlay.
+     */
+    String[] getAvailableThemes();
+
+    /**
      * Tells if UI mode is locked or not.
      */
     boolean isUiModeLocked();
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 3270349..b4fe6b8 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -46,6 +46,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.SystemClock;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.text.BidiFormatter;
 import android.text.SpannableStringBuilder;
@@ -2427,6 +2428,9 @@
 
         private static final int MAX_ACTION_BUTTONS = 3;
 
+        private static final boolean USE_ONLY_TITLE_IN_LOW_PRIORITY_SUMMARY =
+                SystemProperties.getBoolean("notifications.only_title", true);
+
         private Context mContext;
         private Notification mN;
         private Bundle mUserExtras = new Bundle();
@@ -3760,7 +3764,7 @@
             } else if (mActions.size() != 0) {
                 result = applyStandardTemplateWithActions(getBigBaseLayoutResource());
             }
-            adaptNotificationHeaderForBigContentView(result);
+            makeHeaderExpanded(result);
             return result;
         }
 
@@ -3795,7 +3799,12 @@
             }
         }
 
-        private void adaptNotificationHeaderForBigContentView(RemoteViews result) {
+        /**
+         * Adapt the Notification header if this view is used as an expanded view.
+         *
+         * @hide
+         */
+        public static void makeHeaderExpanded(RemoteViews result) {
             if (result != null) {
                 result.setBoolean(R.id.notification_header, "setExpanded", true);
             }
@@ -3855,7 +3864,57 @@
             return publicView;
         }
 
+        /**
+         * Construct a content view for the display when low - priority
+         *
+         * @param useRegularSubtext uses the normal subtext set if there is one available. Otherwise
+         *                          a new subtext is created consisting of the content of the
+         *                          notification.
+         * @hide
+         */
+        public RemoteViews makeLowPriorityContentView(boolean useRegularSubtext) {
+            int color = mN.color;
+            mN.color = COLOR_DEFAULT;
+            CharSequence summary = mN.extras.getCharSequence(EXTRA_SUB_TEXT);
+            if (!useRegularSubtext || TextUtils.isEmpty(summary)) {
+                CharSequence newSummary = createSummaryText();
+                if (!TextUtils.isEmpty(newSummary)) {
+                    mN.extras.putCharSequence(EXTRA_SUB_TEXT, newSummary);
+                }
+            }
+            RemoteViews header = makeNotificationHeader();
+            if (summary != null) {
+                mN.extras.putCharSequence(EXTRA_SUB_TEXT, summary);
+            } else {
+                mN.extras.remove(EXTRA_SUB_TEXT);
+            }
+            mN.color = color;
+            return header;
+        }
 
+        private CharSequence createSummaryText() {
+            CharSequence titleText = mN.extras.getCharSequence(Notification.EXTRA_TITLE);
+            if (USE_ONLY_TITLE_IN_LOW_PRIORITY_SUMMARY) {
+                return titleText;
+            }
+            SpannableStringBuilder summary = new SpannableStringBuilder();
+            if (titleText == null) {
+                titleText = mN.extras.getCharSequence(Notification.EXTRA_TITLE_BIG);
+            }
+            BidiFormatter bidi = BidiFormatter.getInstance();
+            if (titleText != null) {
+                summary.append(bidi.unicodeWrap(titleText));
+            }
+            CharSequence contentText = mN.extras.getCharSequence(Notification.EXTRA_TEXT);
+            if (titleText != null && contentText != null) {
+                summary.append(bidi.unicodeWrap(mContext.getText(
+                        R.string.notification_header_divider_symbol_with_spaces)));
+            }
+            if (contentText != null) {
+                summary.append(bidi.unicodeWrap(contentText));
+            }
+            return summary;
+        }
 
         private RemoteViews generateActionButton(Action action, boolean emphazisedMode,
                 boolean oddAction, boolean ambient) {
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 5d8909c..5a75a67 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -112,6 +112,7 @@
 import android.os.storage.StorageManager;
 import android.print.IPrintManager;
 import android.print.PrintManager;
+import android.service.autofill.IAutoFillManagerService;
 import android.service.persistentdata.IPersistentDataBlockService;
 import android.service.persistentdata.PersistentDataBlockManager;
 import android.telecom.TelecomManager;
@@ -126,6 +127,7 @@
 import android.view.WindowManagerImpl;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.CaptioningManager;
+import android.view.autofill.AutoFillManager;
 import android.view.inputmethod.InputMethodManager;
 import android.view.textclassifier.TextClassificationManager;
 import android.view.textservice.TextServicesManager;
@@ -804,6 +806,14 @@
                         IBinder b = ServiceManager.getServiceOrThrow(Context.FONT_SERVICE);
                         return new FontManager(IFontManager.Stub.asInterface(b));
                     }});
+        registerService(Context.AUTO_FILL_MANAGER_SERVICE, AutoFillManager.class,
+                new CachedServiceFetcher<AutoFillManager>() {
+            @Override
+            public AutoFillManager createService(ContextImpl ctx) throws ServiceNotFoundException {
+                IBinder b = ServiceManager.getServiceOrThrow(Context.AUTO_FILL_MANAGER_SERVICE);
+                IAutoFillManagerService service = IAutoFillManagerService.Stub.asInterface(b);
+                return new AutoFillManager(ctx, service);
+            }});
     }
 
     /**
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index 2572a20..af41a7d 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -271,6 +271,21 @@
     }
 
     /**
+     * Gets the valid inputs to {@link #setTheme(String)}.
+     * @hide
+     */
+    public String[] getAvailableThemes() {
+        if (mService != null) {
+            try {
+                return mService.getAvailableThemes();
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return null;
+    }
+
+    /**
      * Returns the currently configured night mode.
      * <p>
      * May be one of:
diff --git a/core/java/android/content/ContentValues.java b/core/java/android/content/ContentValues.java
index 7ed827c..3a87cb3 100644
--- a/core/java/android/content/ContentValues.java
+++ b/core/java/android/content/ContentValues.java
@@ -414,7 +414,11 @@
             return (Boolean) value;
         } catch (ClassCastException e) {
             if (value instanceof CharSequence) {
-                return Boolean.valueOf(value.toString());
+                // Note that we also check against 1 here because SQLite's internal representation
+                // for booleans is an integer with a value of 0 or 1. Without this check, boolean
+                // values obtained via DatabaseUtils#cursorRowToContentValues will always return
+                // false.
+                return Boolean.valueOf(value.toString()) || "1".equals(value);
             } else if (value instanceof Number) {
                 return ((Number) value).intValue() != 0;
             } else {
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index 227066d..8cd3d7b 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -728,13 +728,10 @@
      * @param values the {@link ContentValues} to put the row into.
      */
     public static void cursorRowToContentValues(Cursor cursor, ContentValues values) {
-        AbstractWindowedCursor awc =
-                (cursor instanceof AbstractWindowedCursor) ? (AbstractWindowedCursor) cursor : null;
-
         String[] columns = cursor.getColumnNames();
         int length = columns.length;
         for (int i = 0; i < length; i++) {
-            if (awc != null && awc.isBlob(i)) {
+            if (cursor.getType(i) == Cursor.FIELD_TYPE_BLOB) {
                 values.put(columns[i], cursor.getBlob(i));
             } else {
                 values.put(columns[i], cursor.getString(i));
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index 2d5c4ce..6b7546f 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -358,7 +358,12 @@
             throw new IllegalArgumentException("Exceeds maximum number of surfaces");
         }
 
-        if (!mConfiguredSize.equals(SurfaceUtils.getSurfaceSize(surface))) {
+        // TODO: b/34697112. This needs to be reverted once app fix is merged.
+        // Do not throw exception for below case:
+        // - OutputConfiguration(Size(0, 0), klass)
+        // - addSurface(surface)
+        if ((mConfiguredSize.getWidth() != 0 || mConfiguredSize.getHeight() != 0) &&
+                !mConfiguredSize.equals(SurfaceUtils.getSurfaceSize(surface))) {
             throw new IllegalArgumentException("The size of added surface doesn't match");
         }
         if (mConfiguredDataspace != SurfaceUtils.getSurfaceDataspace(surface)) {
diff --git a/core/java/android/nfc/NdefRecord.java b/core/java/android/nfc/NdefRecord.java
index 83d17ba..bd32314 100644
--- a/core/java/android/nfc/NdefRecord.java
+++ b/core/java/android/nfc/NdefRecord.java
@@ -805,7 +805,7 @@
 
                 if (!mb && records.size() == 0 && !inChunk && !ignoreMbMe) {
                     throw new FormatException("expected MB flag");
-                } else if (mb && records.size() != 0 && !ignoreMbMe) {
+                } else if (mb && (records.size() != 0 || inChunk) && !ignoreMbMe) {
                     throw new FormatException("unexpected MB flag");
                 } else if (inChunk && il) {
                     throw new FormatException("unexpected IL flag in non-leading chunk");
@@ -839,6 +839,9 @@
 
                 if (cf && !inChunk) {
                     // first chunk
+                    if (typeLength == 0) {
+                        throw new FormatException("expected non-zero type length in first chunk");
+                    }
                     chunks.clear();
                     chunkTnf = tnf;
                 }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 9e2d4a7..fd8b2ca 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -30,6 +30,7 @@
 import android.app.ActivityThread;
 import android.app.AppOpsManager;
 import android.app.Application;
+import android.app.NotificationChannel;
 import android.app.SearchManager;
 import android.app.WallpaperManager;
 import android.content.ComponentName;
@@ -58,6 +59,7 @@
 import android.os.LocaleList;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.ResultReceiver;
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.speech.tts.TextToSpeech;
@@ -162,13 +164,13 @@
      * In some cases, a matching Activity may not exist, so ensure you
      * safeguard against this.
      * <p>
-     * Input: {@link ConnectivityManager.EXTRA_TETHER_TYPE} should be included to specify which type
-     * of tethering should be checked. {@link ConnectivityManager.EXTRA_PROVISION_CALLBACK} should
+     * Input: {@link ConnectivityManager#EXTRA_TETHER_TYPE} should be included to specify which type
+     * of tethering should be checked. {@link ConnectivityManager#EXTRA_PROVISION_CALLBACK} should
      * contain a {@link ResultReceiver} which will be called back with a tether result code.
      * <p>
      * Output: The result of the provisioning check.
-     * {@link ConnectivityManager.TETHER_ERROR_NO_ERROR} if successful,
-     * {@link ConnectivityManager.TETHER_ERROR_PROVISION_FAILED} for failure.
+     * {@link ConnectivityManager#TETHER_ERROR_NO_ERROR} if successful,
+     * {@link ConnectivityManager#TETHER_ERROR_PROVISION_FAILED} for failure.
      *
      * @hide
      */
@@ -1274,6 +1276,7 @@
     /**
      * Activity Action: Show notification settings for a single app.
      *
+     * Input: Optionally, {@link #EXTRA_CHANNEL_ID}, to highlight that channel.
      * @hide
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
@@ -1281,6 +1284,35 @@
             = "android.settings.APP_NOTIFICATION_SETTINGS";
 
     /**
+     * Activity Action: Show notification settings for a single {@link NotificationChannel}.
+     * <p>
+     * Must be called from an activity.
+     * <p>
+     *     Input: {@link #EXTRA_APP_PACKAGE}, the package containing the channel to display.
+     *     Input: {@link #EXTRA_CHANNEL_ID}, the id of the channel to display.
+     * <p>
+     * Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_CHANNEL_NOTIFICATION_SETTINGS
+            = "android.settings.CHANNEL_NOTIFICATION_SETTINGS";
+
+    /**
+     * Activity Extra: The package owner of the notification channel settings to display.
+     * <p>
+     * This must be passed as an extra field to the {@link #ACTION_CHANNEL_NOTIFICATION_SETTINGS}.
+     */
+    public static final String EXTRA_APP_PACKAGE = "android.provider.extra.APP_PACKAGE";
+
+    /**
+     * Activity Extra: The {@link NotificationChannel#getId()} of the notification channel settings
+     * to display.
+     * <p>
+     * This must be passed as an extra field to the {@link #ACTION_CHANNEL_NOTIFICATION_SETTINGS}.
+     */
+    public static final String EXTRA_CHANNEL_ID = "android.provider.extra.CHANNEL_ID";
+
+    /**
      * Activity Action: Show notification redaction settings.
      *
      * @hide
@@ -1290,7 +1322,6 @@
             = "android.settings.ACTION_APP_NOTIFICATION_REDACTION";
 
     /** @hide */ public static final String EXTRA_APP_UID = "app_uid";
-    /** @hide */ public static final String EXTRA_APP_PACKAGE = "app_package";
 
     /**
      * Activity Action: Show a dialog with disabled by policy message.
@@ -8755,6 +8786,26 @@
                 BLUETOOTH_PAN_PRIORITY_PREFIX = "bluetooth_pan_priority_";
 
         /**
+         * Activity manager specific settings.
+         * This is encoded as a key=value list, separated by commas. Ex:
+         *
+         * "enforce_bg_check=true,max_cached_processes=24"
+         *
+         * The following keys are supported:
+         *
+         * <pre>
+         * enforce_bg_check                     (boolean)
+         * max_cached_processes                 (int)
+         * </pre>
+         *
+         * <p>
+         * Type: string
+         * @hide
+         * @see com.android.server.am.ActivityManagerConstants
+         */
+        public static final String ACTIVITY_MANAGER_CONSTANTS = "activity_manager_constants";
+
+        /**
          * Device Idle (Doze) specific settings.
          * This is encoded as a key=value list, separated by commas. Ex:
          *
@@ -8820,6 +8871,25 @@
         public static final String APP_IDLE_CONSTANTS = "app_idle_constants";
 
         /**
+         * Power manager specific settings.
+         * This is encoded as a key=value list, separated by commas. Ex:
+         *
+         * "no_cached_wake_locks=1"
+         *
+         * The following keys are supported:
+         *
+         * <pre>
+         * no_cached_wake_locks                 (boolean)
+         * </pre>
+         *
+         * <p>
+         * Type: string
+         * @hide
+         * @see com.android.server.power.PowerManagerConstants
+         */
+        public static final String POWER_MANAGER_CONSTANTS = "power_manager_constants";
+
+        /**
          * Alarm manager specific settings.
          * This is encoded as a key=value list, separated by commas. Ex:
          *
@@ -9368,7 +9438,7 @@
         /**
          * WFC mode on roaming network.
          * <p>
-         * Type: int - see {@link WFC_IMS_MODE} for values
+         * Type: int - see {@link #WFC_IMS_MODE} for values
          *
          * @hide
          */
diff --git a/core/java/android/service/autofill/AutoFillService.java b/core/java/android/service/autofill/AutoFillService.java
index 805d8e5..c7c8321 100644
--- a/core/java/android/service/autofill/AutoFillService.java
+++ b/core/java/android/service/autofill/AutoFillService.java
@@ -15,8 +15,6 @@
  */
 package android.service.autofill;
 
-import static android.service.voice.VoiceInteractionSession.KEY_FLAGS;
-import static android.service.voice.VoiceInteractionSession.KEY_STRUCTURE;
 import static android.view.View.AUTO_FILL_FLAG_TYPE_FILL;
 import static android.view.View.AUTO_FILL_FLAG_TYPE_SAVE;
 
@@ -30,13 +28,11 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
-import android.os.RemoteException;
 import android.util.Log;
 import android.view.autofill.AutoFillId;
 import android.view.autofill.FillResponse;
 
 import com.android.internal.os.HandlerCaller;
-import com.android.internal.os.IResultReceiver;
 import com.android.internal.os.SomeArgs;
 
 // TODO(b/33197203): improve javadoc (of both class and methods); in particular, make sure the
@@ -49,8 +45,8 @@
  */
 public abstract class AutoFillService extends Service {
 
-    static final String TAG = "AutoFillService";
-    static final boolean DEBUG = true; // TODO: set to false once stable
+    private static final String TAG = "AutoFillService";
+    static final boolean DEBUG = true; // TODO(b/33197203): set to false once stable
 
     /**
      * The {@link Intent} that must be declared as handled by the service.
diff --git a/core/java/android/service/autofill/FillCallback.java b/core/java/android/service/autofill/FillCallback.java
index 5a9a9f6..925da8b 100644
--- a/core/java/android/service/autofill/FillCallback.java
+++ b/core/java/android/service/autofill/FillCallback.java
@@ -21,7 +21,6 @@
 import android.annotation.Nullable;
 import android.app.Activity;
 import android.os.Bundle;
-import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
 import android.view.autofill.FillResponse;
diff --git a/core/java/android/service/autofill/IAutoFillManagerService.aidl b/core/java/android/service/autofill/IAutoFillManagerService.aidl
index f8ae57b..ce42107 100644
--- a/core/java/android/service/autofill/IAutoFillManagerService.aidl
+++ b/core/java/android/service/autofill/IAutoFillManagerService.aidl
@@ -16,7 +16,9 @@
 
 package android.service.autofill;
 
+import android.graphics.Rect;
 import android.os.Bundle;
+import android.view.autofill.AutoFillId;
 
 /**
  * Mediator between apps being auto-filled and auto-fill service implementations.
@@ -24,5 +26,9 @@
  * {@hide}
  */
 oneway interface IAutoFillManagerService {
+
+    void showAutoFillInput(in AutoFillId id, in Rect boundaries);
+
+    // TODO(b/33197203): remove it and refactor onShellCommand
     void requestAutoFill(IBinder activityToken, int userId, in Bundle extras, int flags);
 }
diff --git a/core/java/android/service/autofill/SaveCallback.java b/core/java/android/service/autofill/SaveCallback.java
index 627d74c..04f8c9f 100644
--- a/core/java/android/service/autofill/SaveCallback.java
+++ b/core/java/android/service/autofill/SaveCallback.java
@@ -21,7 +21,6 @@
 import android.app.Activity;
 import android.app.assist.AssistStructure.ViewNode;
 import android.os.Bundle;
-import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
 import android.view.autofill.AutoFillId;
diff --git a/core/java/android/util/ByteStringUtils.java b/core/java/android/util/ByteStringUtils.java
index 7103e6d..333208d 100644
--- a/core/java/android/util/ByteStringUtils.java
+++ b/core/java/android/util/ByteStringUtils.java
@@ -33,7 +33,7 @@
    * @param bytes Byte array to encode.
    * @return Hex encoded string representation of bytes.
    */
-  public static String toString(byte[] bytes) {
+  public static String toHexString(byte[] bytes) {
     if (bytes == null || bytes.length == 0 || bytes.length % 2 != 0) {
       return null;
     }
@@ -55,7 +55,7 @@
    * @param str Hex encoded string to decode.
    * @return Decoded byte array representation of str.
    */
-  public static byte[] toByteArray(String str) {
+  public static byte[] fromHexToByteArray(String str) {
     if (str == null || str.length() == 0 || str.length() % 2 != 0) {
       return null;
     }
diff --git a/core/java/android/util/KeyValueListParser.java b/core/java/android/util/KeyValueListParser.java
index e4c025d..be531ff 100644
--- a/core/java/android/util/KeyValueListParser.java
+++ b/core/java/android/util/KeyValueListParser.java
@@ -129,4 +129,22 @@
         }
         return def;
     }
+
+    /**
+     * Get the value for key as a boolean.
+     * @param key The key to lookup.
+     * @param def The value to return if the key was not found.
+     * @return the string value associated with the key.
+     */
+    public boolean getBoolean(String key, boolean def) {
+        String value = mValues.get(key);
+        if (value != null) {
+            try {
+                return Boolean.parseBoolean(value);
+            } catch (NumberFormatException e) {
+                // fallthrough
+            }
+        }
+        return def;
+    }
 }
diff --git a/core/java/android/util/PackageUtils.java b/core/java/android/util/PackageUtils.java
index 3181979..0fe56f6 100644
--- a/core/java/android/util/PackageUtils.java
+++ b/core/java/android/util/PackageUtils.java
@@ -80,6 +80,6 @@
 
         messageDigest.update(data);
 
-        return ByteStringUtils.toString(messageDigest.digest());
+        return ByteStringUtils.toHexString(messageDigest.digest());
     }
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 57ebd34..123e368 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1765,6 +1765,12 @@
      */
     int mAccessibilityViewId = NO_ID;
 
+    /**
+     * The stable ID of this view for auto-fill purposes.
+     */
+    private int mAutoFillId = NO_ID;
+
+
     private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED;
 
     SendViewStateChangedAccessibilityEvent mSendViewStateChangedAccessibilityEvent;
@@ -6932,8 +6938,8 @@
         if (forAutoFill) {
             // The auto-fill id needs to be unique, but its value doesn't matter, so it's better to
             // reuse the accessibility id to save space.
-            structure.setAutoFillId(getAccessibilityViewId());
-
+            mAutoFillId = getAccessibilityViewId();
+            structure.setAutoFillId(mAutoFillId);
             structure.setAutoFillType(getAutoFillType());
         }
 
@@ -7063,7 +7069,7 @@
     }
 
     /**
-     * Describes the auto-fill type that should be used on callas to
+     * Describes the auto-fill type that should be used on calls to
      * {@link #autoFill(AutoFillValue)} and
      * {@link VirtualViewDelegate#autoFill(int, AutoFillValue)}.
      *
@@ -7560,6 +7566,20 @@
     }
 
     /**
+     * Gets the unique identifier of this view for auto-fill purposes.
+     *
+     * <p>It's only set after {@link #onProvideAutoFillStructure(ViewStructure, int)} is called.
+     *
+     * @return The view autofill id or {@link #NO_ID} if
+     * {@link #onProvideAutoFillStructure(ViewStructure, int)}  was not called yet.
+     *
+     * @hide
+     */
+    public int getAutoFillViewId() {
+        return mAutoFillId;
+    }
+
+    /**
      * Gets the unique identifier of the window in which this View reseides.
      *
      * @return The window accessibility id.
diff --git a/core/java/android/view/autofill/AutoFillId.java b/core/java/android/view/autofill/AutoFillId.java
index b7b694d..e9c1c3b 100644
--- a/core/java/android/view/autofill/AutoFillId.java
+++ b/core/java/android/view/autofill/AutoFillId.java
@@ -43,6 +43,13 @@
     }
 
     /** @hide */
+    public AutoFillId(int parentId, int virtualChildId) {
+        mVirtual = true;
+        mViewId = parentId;
+        mVirtualId = virtualChildId;
+    }
+
+    /** @hide */
     public int getViewId() {
         return mViewId;
     }
diff --git a/core/java/android/view/autofill/AutoFillManager.java b/core/java/android/view/autofill/AutoFillManager.java
new file mode 100644
index 0000000..cd9842f
--- /dev/null
+++ b/core/java/android/view/autofill/AutoFillManager.java
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+
+package android.view.autofill;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.RemoteException;
+import android.service.autofill.IAutoFillManagerService;
+import android.util.Log;
+import android.view.View;
+
+/**
+ * App entry point to the AutoFill Framework.
+ */
+// TODO(b/33197203): improve this javadoc
+public final class AutoFillManager {
+
+    private static final String TAG = "AutoFillManager";
+    private static final boolean DEBUG = true; // TODO(b/33197203): change to false once stable
+
+    /**
+     * Flag used to show the auto-fill UI affordance for a view.
+     */
+    public static final int FLAG_UPDATE_UI_SHOW = 1 << 0;
+
+    /**
+     * Flag used to hide the auto-fill UI affordance for a view.
+     */
+    public static final int FLAG_UPDATE_UI_HIDE = 1 << 1;
+
+    private final IAutoFillManagerService mService;
+
+    /**
+     * @hide
+     */
+    public AutoFillManager(@SuppressWarnings("unused") Context context,
+            IAutoFillManagerService service) {
+        mService = service;
+    }
+
+    /**
+     * Updates the auto-fill bar for a given {@link View}.
+     *
+     * <b>Typically called twice, with different flags ({@link #FLAG_UPDATE_UI_SHOW} and
+     * {@link #FLAG_UPDATE_UI_HIDE} respectively), as the user "entered" and "exited" a view.
+     *
+     * @param view view to be updated.
+     * @param flags either {@link #FLAG_UPDATE_UI_SHOW} or
+     * {@link #FLAG_UPDATE_UI_HIDE}.
+     */
+    public void updateAutoFillInput(View view, int flags) {
+        if (DEBUG) {
+            Log.v(TAG, "updateAutoFillInput(" + view.getAutoFillViewId() + "): flags=" + flags);
+        }
+
+        updateAutoFillInput(view, false, View.NO_ID, null, flags);
+    }
+
+    /**
+     * Updates the auto-fill bar for a virtual child of a given {@link View}.
+     *
+     * <b>Typically called twice, with different flags ({@link #FLAG_UPDATE_UI_SHOW} and
+     * {@link #FLAG_UPDATE_UI_HIDE} respectively), as the user "entered" and "exited" a view.
+     *
+     * @param parent parent view.
+     * @param childId id identifying the virtual child inside the parent view.
+     * @param boundaries boundaries of the child (inside the parent; could be {@code null} when
+     * flag is {@link #FLAG_UPDATE_UI_HIDE}.
+     * @param flags either {@link #FLAG_UPDATE_UI_SHOW} or
+     * {@link #FLAG_UPDATE_UI_HIDE}.
+     */
+    public void updateAutoFillInput(View parent, int childId, @Nullable Rect boundaries,
+            int flags) {
+        if (DEBUG) {
+            Log.v(TAG, "updateAutoFillInput(" + parent.getAutoFillViewId() + ", " + childId
+                    + "): boundaries=" + boundaries + ", flags=" + flags);
+        }
+        updateAutoFillInput(parent, true, childId, boundaries, flags);
+    }
+
+    private void updateAutoFillInput(View view, boolean virtual, int childId, Rect boundaries,
+            int flags) {
+        if ((flags & FLAG_UPDATE_UI_SHOW) != 0) {
+            final int viewId = view.getAutoFillViewId();
+            final AutoFillId id = virtual
+                    ? new AutoFillId(viewId, childId)
+                    : new AutoFillId(viewId);
+            showAutoFillInput(id, boundaries);
+            return;
+        }
+        // TODO(b/33197203): handle FLAG_UPDATE_UI_HIDE
+    }
+
+    private void showAutoFillInput(AutoFillId id, Rect boundaries) {
+        final int autoFillViewId = id.getViewId();
+        /*
+         * TODO(b/33197203): currently SHOW_AUTO_FILL_BAR is only set once per activity (i.e, when
+         * the view does not have an auto-fill id), but it should be called again for views that
+         * were not part of the initial auto-fill dataset returned by the service. For example:
+         *
+         * 1.Activity has 4 fields, `first_name`, `last_name`, and `address`.
+         * 2.User taps `first_name`.
+         * 3.Service returns a dataset with ids for `first_name` and `last_name`.
+         * 4.When user taps `first_name` (again) or `last_name`, flag should not have
+         *   SHOW_AUTO_FILL_BAR set, but when user taps `address`, it should (since that field was
+         *   not part of the initial dataset).
+         *
+         * Similarly, once the activity is auto-filled, the flag logic should be reset (so if the
+         * user taps the view again, a new auto-fill request is made)
+         */
+        if (autoFillViewId != View.NO_ID) {
+            return;
+        }
+
+        try {
+            mService.showAutoFillInput(id, boundaries);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+}
diff --git a/core/java/android/view/autofill/VirtualViewDelegate.java b/core/java/android/view/autofill/VirtualViewDelegate.java
index a19b4e5..278bf4f 100644
--- a/core/java/android/view/autofill/VirtualViewDelegate.java
+++ b/core/java/android/view/autofill/VirtualViewDelegate.java
@@ -15,6 +15,8 @@
  */
 package android.view.autofill;
 
+import android.annotation.Nullable;
+import android.graphics.Rect;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewStructure;
@@ -71,20 +73,18 @@
     public abstract static class Callback {
 
         /**
-         * Sent when the focus inside the hierarchy changed.
+         * Sent when the auto-fill bar for a child must be updated.
          *
-         * <p>Typically callled twice - for the nodes that lost and gained focus.
-         *
-         * <p>This method should only be called when the change was not caused by the AutoFill
-         * Framework itselft (i.e, through {@link VirtualViewDelegate#autoFill(int, AutoFillValue)},
-         * but by external causes (for example, when the user changed the value through the view's
-         * UI).
-         *
-         * @param virtualId id of the node whose focus changed.
-         * @param hasFocus {@code true} when focus was gained, {@code false} when it was lost.
+         * See {@link AutoFillManager#updateAutoFillInput(View, int, android.graphics.Rect, int)}
+         * for more details.
          */
-        public void onFocusChanged(int virtualId, boolean hasFocus) {
-            if (DEBUG) Log.d(TAG, "onFocusChanged() for " + virtualId + ": " + hasFocus);
+        // TODO(b/33197203): do we really need it, or should the parent view just call
+        // AutoFillManager.updateAutoFillInput() directly?
+        public void onAutoFillInputUpdated(int virtualId, @Nullable Rect boundaries, int flags) {
+            if (DEBUG) {
+                Log.v(TAG, "onAutoFillInputUpdated(): virtualId=" + virtualId + ", boundaries="
+                        + boundaries + ", flags=" + flags);
+            }
         }
 
         /**
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 72796cf..0657067 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -17,20 +17,34 @@
 package android.view.textclassifier;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.graphics.drawable.Drawable;
+import android.icu.text.BreakIterator;
 import android.net.Uri;
 import android.os.ParcelFileDescriptor;
 import android.text.SmartSelection;
+import android.text.Spannable;
 import android.text.TextUtils;
+import android.text.method.WordIterator;
+import android.text.style.ClickableSpan;
+import android.text.util.Linkify;
 import android.util.Log;
+import android.view.View;
 
 import com.android.internal.util.Preconditions;
 
 import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
 
 /**
  * Default implementation of the {@link TextClassifier} interface.
@@ -99,29 +113,7 @@
                     type = type.toLowerCase().trim();
                     // TODO: Added this log for debug only. Remove before release.
                     Log.d(LOG_TAG, String.format("Classification type: %s", type));
-                    final Intent intent;
-                    final String title;
-                    switch (type) {
-                        case TextClassifier.TYPE_EMAIL:
-                            intent = new Intent(Intent.ACTION_SENDTO);
-                            intent.setData(Uri.parse(String.format("mailto:%s", text)));
-                            title = mContext.getString(com.android.internal.R.string.email);
-                            return createClassificationResult(classified, type, intent, title);
-                        case TextClassifier.TYPE_PHONE:
-                            intent = new Intent(Intent.ACTION_DIAL);
-                            intent.setData(Uri.parse(String.format("tel:%s", text)));
-                            title = mContext.getString(com.android.internal.R.string.dial);
-                            return createClassificationResult(classified, type, intent, title);
-                        case TextClassifier.TYPE_ADDRESS:
-                            intent = new Intent(Intent.ACTION_VIEW);
-                            intent.setData(Uri.parse(String.format("geo:0,0?q=%s", text)));
-                            title = mContext.getString(com.android.internal.R.string.map);
-                            return createClassificationResult(classified, type, intent, title);
-                        default:
-                            // No classification type found. Return a no-op result.
-                            break;
-                        // TODO: Add other classification types.
-                    }
+                    return createClassificationResult(type, classified);
                 }
             }
         } catch (Throwable t) {
@@ -132,9 +124,18 @@
         return TextClassifier.NO_OP.getTextClassificationResult(text, startIndex, endIndex);
     }
 
+
     @Override
-    public LinksInfo getLinks(@NonNull CharSequence text, int linkMask) {
-        // TODO: Implement
+    public LinksInfo getLinks(CharSequence text, int linkMask) {
+        Preconditions.checkArgument(text != null);
+        try {
+            return LinksInfoFactory.create(
+                    mContext, getSmartSelection(), text.toString(), linkMask);
+        } catch (Throwable t) {
+            // Avoid throwing from this method. Log the error.
+            Log.e(LOG_TAG, "Error getting links info.", t);
+        }
+        // Getting here means something went wrong, return a NO_OP result.
         return TextClassifier.NO_OP.getLinks(text, linkMask);
     }
 
@@ -145,19 +146,23 @@
         return mSmartSelection;
     }
 
-    private TextClassificationResult createClassificationResult(
-            CharSequence text, String type, Intent intent, String label) {
-        TextClassificationResult.Builder builder = new TextClassificationResult.Builder()
+    private TextClassificationResult createClassificationResult(String type, CharSequence text) {
+        final Intent intent = IntentFactory.create(type, text.toString());
+        if (intent == null) {
+            return TextClassificationResult.EMPTY;
+        }
+
+        final TextClassificationResult.Builder builder = new TextClassificationResult.Builder()
                 .setText(text.toString())
                 .setEntityType(type, 1.0f /* confidence */)
                 .setIntent(intent)
                 .setOnClickListener(TextClassificationResult.createStartActivityOnClick(
                         mContext, intent))
-                .setLabel(label);
-        PackageManager pm = mContext.getPackageManager();
-        ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
-        // TODO: If the resolveInfo is the "chooser", do not set the package name and use a
-        // default icon for this classification type.
+                .setLabel(IntentFactory.getLabel(mContext, type));
+        final PackageManager pm = mContext.getPackageManager();
+        final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
+        // TODO: If the resolveInfo is the "chooser", do not set the package name and use a default
+        // icon for this classification type.
         intent.setPackage(resolveInfo.activityInfo.packageName);
         Drawable icon = resolveInfo.activityInfo.loadIcon(pm);
         if (icon == null) {
@@ -177,4 +182,198 @@
         Preconditions.checkArgument(endIndex <= text.length());
         Preconditions.checkArgument(endIndex >= startIndex);
     }
+
+    /**
+     * Detects and creates links for specified text.
+     */
+    private static final class LinksInfoFactory {
+
+        private LinksInfoFactory() {}
+
+        public static LinksInfo create(
+                Context context, SmartSelection smartSelection, String text, int linkMask) {
+            final WordIterator wordIterator = new WordIterator();
+            wordIterator.setCharSequence(text, 0, text.length());
+            final List<SpanSpec> spans = new ArrayList<>();
+            int start = 0;
+            int end;
+            while ((end = wordIterator.nextBoundary(start)) != BreakIterator.DONE) {
+                final String token = text.substring(start, end);
+                if (TextUtils.isEmpty(token)) {
+                    continue;
+                }
+
+                final int[] selection = smartSelection.suggest(text, start, end);
+                final int selectionStart = selection[0];
+                final int selectionEnd = selection[1];
+                if (selectionStart >= 0 && selectionEnd <= text.length()
+                        && selectionStart <= selectionEnd) {
+                    final String type =
+                            smartSelection.classifyText(text, selectionStart, selectionEnd);
+                    if (matches(type, linkMask)) {
+                        final ClickableSpan span = createSpan(
+                                context, type, text.substring(selectionStart, selectionEnd));
+                        spans.add(new SpanSpec(selectionStart, selectionEnd, span));
+                    }
+                }
+                start = end;
+            }
+            return new LinksInfoImpl(text, avoidOverlaps(spans, text));
+        }
+
+        /**
+         * Returns true if the classification type matches the specified linkMask.
+         */
+        private static boolean matches(String type, int linkMask) {
+            if ((linkMask & Linkify.PHONE_NUMBERS) != 0
+                    && TextClassifier.TYPE_PHONE.equals(type)) {
+                return true;
+            }
+            if ((linkMask & Linkify.EMAIL_ADDRESSES) != 0
+                    && TextClassifier.TYPE_EMAIL.equals(type)) {
+                return true;
+            }
+            if ((linkMask & Linkify.MAP_ADDRESSES) != 0
+                    && TextClassifier.TYPE_ADDRESS.equals(type)) {
+                return true;
+            }
+            return false;
+        }
+
+        /**
+         * Trim the number of spans so that no two spans overlap.
+         *
+         * This algorithm first ensures that there is only one span per start index, then it
+         * makes sure that no two spans overlap.
+         */
+        private static List<SpanSpec> avoidOverlaps(List<SpanSpec> spans, String text) {
+            Collections.sort(spans, Comparator.comparingInt(span -> span.mStart));
+            // Group spans by start index. Take the longest span.
+            final Map<Integer, SpanSpec> reps = new LinkedHashMap<>();  // order matters.
+            final int size = spans.size();
+            for (int i = 0; i < size; i++) {
+                final SpanSpec span = spans.get(i);
+                final LinksInfoFactory.SpanSpec rep = reps.get(span.mStart);
+                if (rep == null || rep.mEnd < span.mEnd) {
+                    reps.put(span.mStart, span);
+                }
+            }
+            // Avoid span intersections. Take the longer span.
+            final LinkedList<SpanSpec> result = new LinkedList<>();
+            for (SpanSpec rep : reps.values()) {
+                if (result.isEmpty()) {
+                    result.add(rep);
+                    continue;
+                }
+
+                final SpanSpec last = result.getLast();
+                if (rep.mStart < last.mEnd) {
+                    // Spans intersect. Use the one with characters.
+                    if ((rep.mEnd - rep.mStart) > (last.mEnd - last.mStart)) {
+                        result.set(result.size() - 1, rep);
+                    }
+                } else {
+                    result.add(rep);
+                }
+            }
+            return result;
+        }
+
+        private static ClickableSpan createSpan(
+                final Context context, final String type, final String text) {
+            return new ClickableSpan() {
+                // TODO: Style this span.
+                @Override
+                public void onClick(View widget) {
+                    context.startActivity(IntentFactory.create(type, text));
+                }
+            };
+        }
+
+        /**
+         * Implementation of LinksInfo that adds ClickableSpans to the specified text.
+         */
+        private static final class LinksInfoImpl implements LinksInfo {
+
+            private final CharSequence mOriginalText;
+            private final List<SpanSpec> mSpans;
+
+            LinksInfoImpl(CharSequence originalText, List<SpanSpec> spans) {
+                mOriginalText = originalText;
+                mSpans = spans;
+            }
+
+            @Override
+            public boolean apply(@NonNull CharSequence text) {
+                Preconditions.checkArgument(text != null);
+                if (text instanceof Spannable && mOriginalText.toString().equals(text.toString())) {
+                    Spannable spannable = (Spannable) text;
+                    final int size = mSpans.size();
+                    for (int i = 0; i < size; i++) {
+                        final SpanSpec span = mSpans.get(i);
+                        spannable.setSpan(span.mSpan, span.mStart, span.mEnd, 0);
+                    }
+                    return true;
+                }
+                return false;
+            }
+        }
+
+        /**
+         * Span plus its start and end index.
+         */
+        private static final class SpanSpec {
+
+            private final int mStart;
+            private final int mEnd;
+            private final ClickableSpan mSpan;
+
+            SpanSpec(int start, int end, ClickableSpan span) {
+                mStart = start;
+                mEnd = end;
+                mSpan = span;
+            }
+        }
+    }
+
+    /**
+     * Creates intents based on the classification type.
+     */
+    private static final class IntentFactory {
+
+        private IntentFactory() {}
+
+        @Nullable
+        public static Intent create(String type, String text) {
+            switch (type) {
+                case TextClassifier.TYPE_EMAIL:
+                    return new Intent(Intent.ACTION_SENDTO)
+                            .setData(Uri.parse(String.format("mailto:%s", text)));
+                case TextClassifier.TYPE_PHONE:
+                    return new Intent(Intent.ACTION_DIAL)
+                            .setData(Uri.parse(String.format("tel:%s", text)));
+                case TextClassifier.TYPE_ADDRESS:
+                    return new Intent(Intent.ACTION_VIEW)
+                            .setData(Uri.parse(String.format("geo:0,0?q=%s", text)));
+                default:
+                    return null;
+                // TODO: Add other classification types.
+            }
+        }
+
+        @Nullable
+        public static String getLabel(Context context, String type) {
+            switch (type) {
+                case TextClassifier.TYPE_EMAIL:
+                    return context.getString(com.android.internal.R.string.email);
+                case TextClassifier.TYPE_PHONE:
+                    return context.getString(com.android.internal.R.string.dial);
+                case TextClassifier.TYPE_ADDRESS:
+                    return context.getString(com.android.internal.R.string.map);
+                default:
+                    return null;
+                // TODO: Add other classification types.
+            }
+        }
+    }
 }
diff --git a/core/java/android/widget/EditText.java b/core/java/android/widget/EditText.java
index faf0379..6706790 100644
--- a/core/java/android/widget/EditText.java
+++ b/core/java/android/widget/EditText.java
@@ -169,8 +169,6 @@
             Log.w(VIEW_LOG_TAG, "EditText.autoFill(): no text on AutoFillValue");
             return;
         }
-        // TODO(b/33197203): once auto-fill is triggered by the IME, we'll need a new setText()
-        // or setAutoFillText() method on TextView to avoid re-triggering it.
         setText(text);
     }
 
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index a11ece6..072fe4a 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -136,6 +136,7 @@
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.animation.AnimationUtils;
+import android.view.autofill.AutoFillManager;
 import android.view.inputmethod.BaseInputConnection;
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.CorrectionInfo;
@@ -264,6 +265,7 @@
 public class TextView extends View implements ViewTreeObserver.OnPreDrawListener {
     static final String LOG_TAG = "TextView";
     static final boolean DEBUG_EXTRACT = false;
+    static final boolean DEBUG_AUTOFILL = false;
 
     // Enum for the "typeface" XML parameter.
     // TODO: How can we get this from the XML instead of hardcoding it here?
@@ -9024,6 +9026,15 @@
                 Spannable sp = (Spannable) mText;
                 MetaKeyKeyListener.resetMetaState(sp);
             }
+        } else {
+            final AutoFillManager afm = mContext.getSystemService(AutoFillManager.class);
+            if (afm != null) {
+                if (DEBUG_AUTOFILL) {
+                    Log.v(LOG_TAG, "onFocusChanged(): id=" + getAutoFillViewId() + ", focused= "
+                            + focused);
+                }
+                afm.updateAutoFillInput(this, AutoFillManager.FLAG_UPDATE_UI_HIDE);
+            }
         }
 
         startStopMarquee(focused);
@@ -10602,6 +10613,14 @@
      * @hide
      */
     protected void viewClicked(InputMethodManager imm) {
+        final AutoFillManager afm = mContext.getSystemService(AutoFillManager.class);
+        if (afm != null) {
+            if (DEBUG_AUTOFILL) Log.v(LOG_TAG, "viewClicked(): id=" + getAutoFillViewId());
+
+            // TODO(b/33197203): integrate with onFocus and/or move to view?
+            afm.updateAutoFillInput(this, AutoFillManager.FLAG_UPDATE_UI_SHOW);
+        }
+
         if (imm != null) {
             imm.viewClicked(this);
         }
diff --git a/core/jni/android_hardware_SoundTrigger.cpp b/core/jni/android_hardware_SoundTrigger.cpp
index 793d132..0c7f5a1 100644
--- a/core/jni/android_hardware_SoundTrigger.cpp
+++ b/core/jni/android_hardware_SoundTrigger.cpp
@@ -509,7 +509,7 @@
     sp<MemoryDealer> memoryDealer;
     sp<IMemory> memory;
     size_t size;
-    sound_model_handle_t handle;
+    sound_model_handle_t handle = 0;
     jobject jUuid;
     jstring jUuidString;
     const char *nUuidString;
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 070a2d9..5c65241 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -247,6 +247,11 @@
 
 static void DropCapabilitiesBoundingSet(JNIEnv* env) {
   for (int i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {
+    // Keep CAP_SYS_PTRACE in our bounding set so crash_dump can gain it.
+    if (i == CAP_SYS_PTRACE) {
+      continue;
+    }
+
     int rc = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
     if (rc == -1) {
       if (errno == EINVAL) {
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index 1f71a18..0dfeb62 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -20,10 +20,11 @@
     android:id="@+id/notification_header"
     android:orientation="horizontal"
     android:layout_width="wrap_content"
-    android:layout_height="53dp"
+    android:layout_height="48dp"
     android:clipChildren="false"
     android:paddingTop="10dp"
-    android:paddingBottom="16dp"
+    android:paddingBottom="11dp"
+    android:layout_marginBottom="5dp"
     android:paddingStart="@dimen/notification_content_margin_start"
     android:paddingEnd="16dp">
     <com.android.internal.widget.CachingIconView
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index eece9fc..ac8c896 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -578,6 +578,9 @@
     <!-- The divider symbol between different parts of the notification header. not translatable [CHAR LIMIT=1] -->
     <string name="notification_header_divider_symbol" translatable="false">•</string>
 
+    <!-- The divider symbol between different parts of the notification header including spaces. not translatable [CHAR LIMIT=3] -->
+    <string name="notification_header_divider_symbol_with_spaces" translatable="false">" • "</string>
+
     <!-- Text shown in place of notification contents when the notification is hidden on a secure lockscreen -->
     <string name="notification_hidden_text">Contents hidden</string>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 58c925f..78f6b49 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2788,6 +2788,7 @@
   <java-symbol type="drawable" name="lockscreen_notselected" />
   <java-symbol type="drawable" name="lockscreen_selected" />
 
+  <java-symbol type="string" name="notification_header_divider_symbol_with_spaces" />
   <java-symbol type="string" name="config_defaultCellBroadcastReceiverComponent" />
 
   <java-symbol type="string" name="app_category_game" />
diff --git a/media/java/android/media/BufferingParams.aidl b/media/java/android/media/BufferingParams.aidl
new file mode 100644
index 0000000..d156d44
--- /dev/null
+++ b/media/java/android/media/BufferingParams.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 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.
+ */
+
+package android.media;
+
+parcelable BufferingParams;
diff --git a/media/java/android/media/BufferingParams.java b/media/java/android/media/BufferingParams.java
new file mode 100644
index 0000000..fdcd6ba
--- /dev/null
+++ b/media/java/android/media/BufferingParams.java
@@ -0,0 +1,459 @@
+/*
+ * Copyright 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.
+ */
+
+package android.media;
+
+import android.annotation.IntDef;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Structure for source buffering management params.
+ *
+ * Used by {@link MediaPlayer#getDefaultBufferingParams()},
+ * {@link MediaPlayer#getBufferingParams()} and
+ * {@link MediaPlayer#setBufferingParams(BufferingParams)}
+ * to control source buffering behavior.
+ *
+ * <p>There are two stages of source buffering in {@link MediaPlayer}: initial buffering
+ * (when {@link MediaPlayer} is being prepared) and rebuffering (when {@link MediaPlayer}
+ * is playing back source). {@link BufferingParams} includes mode and corresponding
+ * watermarks for each stage of source buffering. The watermarks could be either size
+ * based (in milliseconds), or time based (in kilobytes) or both, depending on the mode.
+ *
+ * <p>There are 4 buffering modes: {@link #BUFFERING_MODE_NONE},
+ * {@link #BUFFERING_MODE_TIME_ONLY}, {@link #BUFFERING_MODE_SIZE_ONLY} and
+ * {@link #BUFFERING_MODE_TIME_THEN_SIZE}.
+ * {@link MediaPlayer} source component has default buffering modes which can be queried
+ * by calling {@link MediaPlayer#getDefaultBufferingParams()}.
+ * Users should always use those default modes or their downsized version when trying to
+ * change buffering params. For example, {@link #BUFFERING_MODE_TIME_THEN_SIZE} can be
+ * downsized to {@link #BUFFERING_MODE_NONE}, {@link #BUFFERING_MODE_TIME_ONLY} or
+ * {@link #BUFFERING_MODE_SIZE_ONLY}. But {@link #BUFFERING_MODE_TIME_ONLY} can not be
+ * downsized to {@link #BUFFERING_MODE_SIZE_ONLY}.
+ * <ul>
+ * <li><strong>initial buffering stage:</strong> has one watermark which is used when
+ * {@link MediaPlayer} is being prepared. When cached data amount exceeds this watermark,
+ * {@link MediaPlayer} is prepared.</li>
+ * <li><strong>rebuffering stage:</strong> has two watermarks, low and high, which are
+ * used when {@link MediaPlayer} is playing back content.
+ * <ul>
+ * <li> When cached data amount exceeds high watermark, {@link MediaPlayer} will pause
+ * buffering. Buffering will resume when cache runs below some limit which could be low
+ * watermark or some intermediate value decided by the source component.</li>
+ * <li> When cached data amount runs below low watermark, {@link MediaPlayer} will paused
+ * playback. Playback will resume when cached data amount exceeds high watermark
+ * or reaches end of stream.</li>
+ * </ul>
+ * </ul>
+ * <p>Users should use {@link Builder} to change {@link BufferingParams}.
+ */
+public final class BufferingParams implements Parcelable {
+    /**
+     * This mode indicates that source buffering is not supported.
+     */
+    public static final int BUFFERING_MODE_NONE = 0;
+    /**
+     * This mode indicates that only time based source buffering is supported. This means
+     * the watermark(s) are time based.
+     */
+    public static final int BUFFERING_MODE_TIME_ONLY = 1;
+    /**
+     * This mode indicates that only size based source buffering is supported. This means
+     * the watermark(s) are size based.
+     */
+    public static final int BUFFERING_MODE_SIZE_ONLY = 2;
+    /**
+     * This mode indicates that both time and size based source buffering are supported,
+     * and time based calculation precedes size based. Size based calculation will be used
+     * only when time information is not available from the source.
+     */
+    public static final int BUFFERING_MODE_TIME_THEN_SIZE = 3;
+
+    /** @hide */
+    @IntDef(
+        value = {
+                BUFFERING_MODE_NONE,
+                BUFFERING_MODE_TIME_ONLY,
+                BUFFERING_MODE_SIZE_ONLY,
+                BUFFERING_MODE_TIME_THEN_SIZE,
+        }
+    )
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface BufferingMode {}
+
+    private static final int BUFFERING_NO_WATERMARK = -1;
+
+    // params
+    private int mInitialBufferingMode = BUFFERING_MODE_NONE;
+    private int mRebufferingMode = BUFFERING_MODE_NONE;
+
+    private int mInitialWatermarkMs = BUFFERING_NO_WATERMARK;
+    private int mInitialWatermarkKB = BUFFERING_NO_WATERMARK;
+
+    private int mRebufferingWatermarkLowMs = BUFFERING_NO_WATERMARK;
+    private int mRebufferingWatermarkHighMs = BUFFERING_NO_WATERMARK;
+    private int mRebufferingWatermarkLowKB = BUFFERING_NO_WATERMARK;
+    private int mRebufferingWatermarkHighKB = BUFFERING_NO_WATERMARK;
+
+    private BufferingParams() {
+    }
+
+    /**
+     * Return the initial buffering mode used when {@link MediaPlayer} is being prepared.
+     * @return one of the values that can be set in {@link Builder#setInitialBufferingMode(int)}
+     */
+    public int getInitialBufferingMode() {
+        return mInitialBufferingMode;
+    }
+
+    /**
+     * Return the rebuffering mode used when {@link MediaPlayer} is playing back source.
+     * @return one of the values that can be set in {@link Builder#setRebufferingMode(int)}
+     */
+    public int getRebufferingMode() {
+        return mRebufferingMode;
+    }
+
+    /**
+     * Return the time based initial buffering watermark in milliseconds.
+     * It is meaningful only when initial buffering mode obatined from
+     * {@link #getInitialBufferingMode()} is time based.
+     * @return time based initial buffering watermark in milliseconds
+     */
+    public int getInitialBufferingWatermarkMs() {
+        return mInitialWatermarkMs;
+    }
+
+    /**
+     * Return the size based initial buffering watermark in kilobytes.
+     * It is meaningful only when initial buffering mode obatined from
+     * {@link #getInitialBufferingMode()} is size based.
+     * @return size based initial buffering watermark in kilobytes
+     */
+    public int getInitialBufferingWatermarkKB() {
+        return mInitialWatermarkKB;
+    }
+
+    /**
+     * Return the time based low watermark in milliseconds for rebuffering.
+     * It is meaningful only when rebuffering mode obatined from
+     * {@link #getRebufferingMode()} is time based.
+     * @return time based low watermark for rebuffering in milliseconds
+     */
+    public int getRebufferingWatermarkLowMs() {
+        return mRebufferingWatermarkLowMs;
+    }
+
+    /**
+     * Return the time based high watermark in milliseconds for rebuffering.
+     * It is meaningful only when rebuffering mode obatined from
+     * {@link #getRebufferingMode()} is time based.
+     * @return time based high watermark for rebuffering in milliseconds
+     */
+    public int getRebufferingWatermarkHighMs() {
+        return mRebufferingWatermarkHighMs;
+    }
+
+    /**
+     * Return the size based low watermark in kilobytes for rebuffering.
+     * It is meaningful only when rebuffering mode obatined from
+     * {@link #getRebufferingMode()} is size based.
+     * @return size based low watermark for rebuffering in kilobytes
+     */
+    public int getRebufferingWatermarkLowKB() {
+        return mRebufferingWatermarkLowKB;
+    }
+
+    /**
+     * Return the size based high watermark in kilobytes for rebuffering.
+     * It is meaningful only when rebuffering mode obatined from
+     * {@link #getRebufferingMode()} is size based.
+     * @return size based high watermark for rebuffering in kilobytes
+     */
+    public int getRebufferingWatermarkHighKB() {
+        return mRebufferingWatermarkHighKB;
+    }
+
+    /**
+     * Builder class for {@link BufferingParams} objects.
+     * <p> Here is an example where <code>Builder</code> is used to define the
+     * {@link BufferingParams} to be used by a {@link MediaPlayer} instance:
+     *
+     * <pre class="prettyprint">
+     * BufferingParams myParams = mediaplayer.getDefaultBufferingParams();
+     * myParams = new BufferingParams.Builder(myParams)
+     *             .setInitialBufferingWatermarkMs(10000)
+     *             .build();
+     * mediaplayer.setBufferingParams(myParams);
+     * </pre>
+     */
+    public static class Builder {
+        private int mInitialBufferingMode = BUFFERING_MODE_NONE;
+        private int mRebufferingMode = BUFFERING_MODE_NONE;
+
+        private int mInitialWatermarkMs = BUFFERING_NO_WATERMARK;
+        private int mInitialWatermarkKB = BUFFERING_NO_WATERMARK;
+
+        private int mRebufferingWatermarkLowMs = BUFFERING_NO_WATERMARK;
+        private int mRebufferingWatermarkHighMs = BUFFERING_NO_WATERMARK;
+        private int mRebufferingWatermarkLowKB = BUFFERING_NO_WATERMARK;
+        private int mRebufferingWatermarkHighKB = BUFFERING_NO_WATERMARK;
+
+        /**
+         * Constructs a new Builder with the defaults.
+         * By default, both initial buffering mode and rebuffering mode are
+         * {@link BufferingParams#BUFFERING_MODE_NONE}, and all watermarks are -1.
+         */
+        public Builder() {
+        }
+
+        /**
+         * Constructs a new Builder from a given {@link BufferingParams} instance
+         * @param bp the {@link BufferingParams} object whose data will be reused
+         * in the new Builder.
+         */
+        public Builder(BufferingParams bp) {
+            mInitialBufferingMode = bp.mInitialBufferingMode;
+            mRebufferingMode = bp.mRebufferingMode;
+
+            mInitialWatermarkMs = bp.mInitialWatermarkMs;
+            mInitialWatermarkKB = bp.mInitialWatermarkKB;
+
+            mRebufferingWatermarkLowMs = bp.mRebufferingWatermarkLowMs;
+            mRebufferingWatermarkHighMs = bp.mRebufferingWatermarkHighMs;
+            mRebufferingWatermarkLowKB = bp.mRebufferingWatermarkLowKB;
+            mRebufferingWatermarkHighKB = bp.mRebufferingWatermarkHighKB;
+        }
+
+        /**
+         * Combines all of the fields that have been set and return a new
+         * {@link BufferingParams} object. <code>IllegalStateException</code> will be
+         * thrown if there is conflict between fields.
+         * @return a new {@link BufferingParams} object
+         */
+        public BufferingParams build() {
+            if (isTimeBasedMode(mRebufferingMode)
+                    && mRebufferingWatermarkLowMs > mRebufferingWatermarkHighMs) {
+                throw new IllegalStateException("Illegal watermark:"
+                        + mRebufferingWatermarkLowMs + " : " + mRebufferingWatermarkHighMs);
+            }
+            if (isSizeBasedMode(mRebufferingMode)
+                    && mRebufferingWatermarkLowKB > mRebufferingWatermarkHighKB) {
+                throw new IllegalStateException("Illegal watermark:"
+                        + mRebufferingWatermarkLowKB + " : " + mRebufferingWatermarkHighKB);
+            }
+
+            BufferingParams bp = new BufferingParams();
+            bp.mInitialBufferingMode = mInitialBufferingMode;
+            bp.mRebufferingMode = mRebufferingMode;
+
+            bp.mInitialWatermarkMs = mInitialWatermarkMs;
+            bp.mInitialWatermarkKB = mInitialWatermarkKB;
+
+            bp.mRebufferingWatermarkLowMs = mRebufferingWatermarkLowMs;
+            bp.mRebufferingWatermarkHighMs = mRebufferingWatermarkHighMs;
+            bp.mRebufferingWatermarkLowKB = mRebufferingWatermarkLowKB;
+            bp.mRebufferingWatermarkHighKB = mRebufferingWatermarkHighKB;
+            return bp;
+        }
+
+        private boolean isTimeBasedMode(int mode) {
+            return (mode == BUFFERING_MODE_TIME_ONLY || mode == BUFFERING_MODE_TIME_THEN_SIZE);
+        }
+
+        private boolean isSizeBasedMode(int mode) {
+            return (mode == BUFFERING_MODE_SIZE_ONLY || mode == BUFFERING_MODE_TIME_THEN_SIZE);
+        }
+
+        /**
+         * Sets the initial buffering mode.
+         * @param mode one of {@link BufferingParams#BUFFERING_MODE_NONE},
+         *     {@link BufferingParams#BUFFERING_MODE_TIME_ONLY},
+         *     {@link BufferingParams#BUFFERING_MODE_SIZE_ONLY},
+         *     {@link BufferingParams#BUFFERING_MODE_TIME_THEN_SIZE},
+         * @return the same Builder instance.
+         */
+        public Builder setInitialBufferingMode(@BufferingMode int mode) {
+            switch (mode) {
+                case BUFFERING_MODE_NONE:
+                case BUFFERING_MODE_TIME_ONLY:
+                case BUFFERING_MODE_SIZE_ONLY:
+                case BUFFERING_MODE_TIME_THEN_SIZE:
+                     mInitialBufferingMode = mode;
+                     break;
+                default:
+                     throw new IllegalArgumentException("Illegal buffering mode " + mode);
+            }
+            return this;
+        }
+
+        /**
+         * Sets the rebuffering mode.
+         * @param mode one of {@link BufferingParams#BUFFERING_MODE_NONE},
+         *     {@link BufferingParams#BUFFERING_MODE_TIME_ONLY},
+         *     {@link BufferingParams#BUFFERING_MODE_SIZE_ONLY},
+         *     {@link BufferingParams#BUFFERING_MODE_TIME_THEN_SIZE},
+         * @return the same Builder instance.
+         */
+        public Builder setRebufferingMode(@BufferingMode int mode) {
+            switch (mode) {
+                case BUFFERING_MODE_NONE:
+                case BUFFERING_MODE_TIME_ONLY:
+                case BUFFERING_MODE_SIZE_ONLY:
+                case BUFFERING_MODE_TIME_THEN_SIZE:
+                     mRebufferingMode = mode;
+                     break;
+                default:
+                     throw new IllegalArgumentException("Illegal buffering mode " + mode);
+            }
+            return this;
+        }
+
+        /**
+         * Sets the time based watermark in milliseconds for initial buffering.
+         * @param watermarkMs time based watermark in milliseconds
+         * @return the same Builder instance.
+         */
+        public Builder setInitialBufferingWatermarkMs(int watermarkMs) {
+            mInitialWatermarkMs = watermarkMs;
+            return this;
+        }
+
+        /**
+         * Sets the size based watermark in kilobytes for initial buffering.
+         * @param watermarkKB size based watermark in kilobytes
+         * @return the same Builder instance.
+         */
+        public Builder setInitialBufferingWatermarkKB(int watermarkKB) {
+            mInitialWatermarkKB = watermarkKB;
+            return this;
+        }
+
+        /**
+         * Sets the time based low watermark in milliseconds for rebuffering.
+         * @param watermarkMs time based low watermark in milliseconds
+         * @return the same Builder instance.
+         */
+        public Builder setRebufferingWatermarkLowMs(int watermarkMs) {
+            mRebufferingWatermarkLowMs = watermarkMs;
+            return this;
+        }
+
+        /**
+         * Sets the time based high watermark in milliseconds for rebuffering.
+         * @param watermarkMs time based high watermark in milliseconds
+         * @return the same Builder instance.
+         */
+        public Builder setRebufferingWatermarkHighMs(int watermarkMs) {
+            mRebufferingWatermarkHighMs = watermarkMs;
+            return this;
+        }
+
+        /**
+         * Sets the size based low watermark in milliseconds for rebuffering.
+         * @param watermarkKB size based low watermark in milliseconds
+         * @return the same Builder instance.
+         */
+        public Builder setRebufferingWatermarkLowKB(int watermarkKB) {
+            mRebufferingWatermarkLowKB = watermarkKB;
+            return this;
+        }
+
+        /**
+         * Sets the size based high watermark in milliseconds for rebuffering.
+         * @param watermarkKB size based high watermark in milliseconds
+         * @return the same Builder instance.
+         */
+        public Builder setRebufferingWatermarkHighKB(int watermarkKB) {
+            mRebufferingWatermarkHighKB = watermarkKB;
+            return this;
+        }
+
+        /**
+         * Sets the time based low and high watermarks in milliseconds for rebuffering.
+         * @param lowWatermarkMs time based low watermark in milliseconds
+         * @param highWatermarkMs time based high watermark in milliseconds
+         * @return the same Builder instance.
+         */
+        public Builder setRebufferingWatermarksMs(int lowWatermarkMs, int highWatermarkMs) {
+            mRebufferingWatermarkLowMs = lowWatermarkMs;
+            mRebufferingWatermarkHighMs = highWatermarkMs;
+            return this;
+        }
+
+        /**
+         * Sets the size based low and high watermarks in kilobytes for rebuffering.
+         * @param lowWatermarkKB size based low watermark in kilobytes
+         * @param highWatermarkKB size based high watermark in kilobytes
+         * @return the same Builder instance.
+         */
+        public Builder setRebufferingWatermarksKB(int lowWatermarkKB, int highWatermarkKB) {
+            mRebufferingWatermarkLowKB = lowWatermarkKB;
+            mRebufferingWatermarkHighKB = highWatermarkKB;
+            return this;
+        }
+    }
+
+    private BufferingParams(Parcel in) {
+        mInitialBufferingMode = in.readInt();
+        mRebufferingMode = in.readInt();
+
+        mInitialWatermarkMs = in.readInt();
+        mInitialWatermarkKB = in.readInt();
+
+        mRebufferingWatermarkLowMs = in.readInt();
+        mRebufferingWatermarkHighMs = in.readInt();
+        mRebufferingWatermarkLowKB = in.readInt();
+        mRebufferingWatermarkHighKB = in.readInt();
+    }
+
+    public static final Parcelable.Creator<BufferingParams> CREATOR =
+            new Parcelable.Creator<BufferingParams>() {
+                @Override
+                public BufferingParams createFromParcel(Parcel in) {
+                    return new BufferingParams(in);
+                }
+
+                @Override
+                public BufferingParams[] newArray(int size) {
+                    return new BufferingParams[size];
+                }
+            };
+
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mInitialBufferingMode);
+        dest.writeInt(mRebufferingMode);
+
+        dest.writeInt(mInitialWatermarkMs);
+        dest.writeInt(mInitialWatermarkKB);
+
+        dest.writeInt(mRebufferingWatermarkLowMs);
+        dest.writeInt(mRebufferingWatermarkHighMs);
+        dest.writeInt(mRebufferingWatermarkLowKB);
+        dest.writeInt(mRebufferingWatermarkHighKB);
+    }
+}
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index e3a0f25..4023400 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -45,6 +45,7 @@
 import android.widget.VideoView;
 import android.graphics.SurfaceTexture;
 import android.media.AudioManager;
+import android.media.BufferingParams;
 import android.media.MediaFormat;
 import android.media.MediaTimeProvider;
 import android.media.PlaybackParams;
@@ -479,6 +480,11 @@
  *     <td>{} </p></td>
  *     <td>This method can be called in any state and calling it does not change
  *         the object state. </p></td></tr>
+ * <tr><td>setBufferingParams</p></td>
+ *     <td>{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted, Error}</p></td>
+ *     <td>{Idle} </p></td>
+ *     <td>This method does not change the object state.
+ *         </p></td></tr>
  * <tr><td>setPlaybackParams</p></td>
  *     <td>{Initialized, Prepared, Started, Paused, PlaybackCompleted, Error}</p></td>
  *     <td>{Idle, Stopped} </p></td>
@@ -1390,6 +1396,45 @@
     public native boolean isPlaying();
 
     /**
+     * Gets the default buffering management params.
+     * Calling it only after {@code setDataSource} has been called.
+     * Each type of data source might have different set of default params.
+     *
+     * @return the default buffering management params supported by the source component.
+     * @throws IllegalStateException if the internal player engine has not been
+     * initialized, or {@code setDataSource} has not been called.
+     */
+    @NonNull
+    public native BufferingParams getDefaultBufferingParams();
+
+    /**
+     * Gets the current buffering management params used by the source component.
+     * Calling it only after {@code setDataSource} has been called.
+     *
+     * @return the current buffering management params used by the source component.
+     * @throws IllegalStateException if the internal player engine has not been
+     * initialized, or {@code setDataSource} has not been called.
+     */
+    @NonNull
+    public native BufferingParams getBufferingParams();
+
+    /**
+     * Sets buffering management params.
+     * The object sets its internal BufferingParams to the input, except that the input is
+     * invalid or not supported.
+     * Call it only after {@code setDataSource} has been called.
+     * Users should only use supported mode returned by {@link #getDefaultBufferingParams()}
+     * or its downsized version as described in {@link BufferingParams}.
+     *
+     * @param params the buffering management params.
+     *
+     * @throws IllegalStateException if the internal player engine has not been
+     * initialized or has been released, or {@code setDataSource} has not been called.
+     * @throws IllegalArgumentException if params is invalid or not supported.
+     */
+    public native void setBufferingParams(@NonNull BufferingParams params);
+
+    /**
      * Change playback speed of audio by resampling the audio.
      * <p>
      * Specifies resampling as audio mode for variable rate playback, i.e.,
diff --git a/media/jni/android_media_BufferingParams.h b/media/jni/android_media_BufferingParams.h
new file mode 100644
index 0000000..24c51f5
--- /dev/null
+++ b/media/jni/android_media_BufferingParams.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef _ANDROID_MEDIA_BUFFERING_PARAMS_H_
+#define _ANDROID_MEDIA_BUFFERING_PARAMS_H_
+
+#include <media/BufferingSettings.h>
+
+namespace android {
+
+// This entire class is inline
+struct BufferingParams {
+    BufferingSettings settings;
+
+    struct fields_t {
+        jclass      clazz;
+        jmethodID   constructID;
+
+        jfieldID    initial_buffering_mode;
+        jfieldID    rebuffering_mode;
+        jfieldID    initial_watermark_ms;
+        jfieldID    initial_watermark_kb;
+        jfieldID    rebuffering_watermark_low_ms;
+        jfieldID    rebuffering_watermark_high_ms;
+        jfieldID    rebuffering_watermark_low_kb;
+        jfieldID    rebuffering_watermark_high_kb;
+
+        void init(JNIEnv *env) {
+            jclass lclazz = env->FindClass("android/media/BufferingParams");
+            if (lclazz == NULL) {
+                return;
+            }
+
+            clazz = (jclass)env->NewGlobalRef(lclazz);
+            if (clazz == NULL) {
+                return;
+            }
+
+            constructID = env->GetMethodID(clazz, "<init>", "()V");
+
+            initial_buffering_mode = env->GetFieldID(clazz, "mInitialBufferingMode", "I");
+            rebuffering_mode = env->GetFieldID(clazz, "mRebufferingMode", "I");
+            initial_watermark_ms = env->GetFieldID(clazz, "mInitialWatermarkMs", "I");
+            initial_watermark_kb = env->GetFieldID(clazz, "mInitialWatermarkKB", "I");
+            rebuffering_watermark_low_ms = env->GetFieldID(clazz, "mRebufferingWatermarkLowMs", "I");
+            rebuffering_watermark_high_ms = env->GetFieldID(clazz, "mRebufferingWatermarkHighMs", "I");
+            rebuffering_watermark_low_kb = env->GetFieldID(clazz, "mRebufferingWatermarkLowKB", "I");
+            rebuffering_watermark_high_kb = env->GetFieldID(clazz, "mRebufferingWatermarkHighKB", "I");
+
+            env->DeleteLocalRef(lclazz);
+        }
+
+        void exit(JNIEnv *env) {
+            env->DeleteGlobalRef(clazz);
+            clazz = NULL;
+        }
+    };
+
+    void fillFromJobject(JNIEnv *env, const fields_t& fields, jobject params) {
+        settings.mInitialBufferingMode =
+            (BufferingMode)env->GetIntField(params, fields.initial_buffering_mode);
+        settings.mRebufferingMode =
+            (BufferingMode)env->GetIntField(params, fields.rebuffering_mode);
+        settings.mInitialWatermarkMs =
+            env->GetIntField(params, fields.initial_watermark_ms);
+        settings.mInitialWatermarkKB =
+            env->GetIntField(params, fields.initial_watermark_kb);
+        settings.mRebufferingWatermarkLowMs =
+            env->GetIntField(params, fields.rebuffering_watermark_low_ms);
+        settings.mRebufferingWatermarkHighMs =
+            env->GetIntField(params, fields.rebuffering_watermark_high_ms);
+        settings.mRebufferingWatermarkLowKB =
+            env->GetIntField(params, fields.rebuffering_watermark_low_kb);
+        settings.mRebufferingWatermarkHighKB =
+            env->GetIntField(params, fields.rebuffering_watermark_high_kb);
+    }
+
+    jobject asJobject(JNIEnv *env, const fields_t& fields) {
+        jobject params = env->NewObject(fields.clazz, fields.constructID);
+        if (params == NULL) {
+            return NULL;
+        }
+        env->SetIntField(params, fields.initial_buffering_mode, (jint)settings.mInitialBufferingMode);
+        env->SetIntField(params, fields.rebuffering_mode, (jint)settings.mRebufferingMode);
+        env->SetIntField(params, fields.initial_watermark_ms, (jint)settings.mInitialWatermarkMs);
+        env->SetIntField(params, fields.initial_watermark_kb, (jint)settings.mInitialWatermarkKB);
+        env->SetIntField(params, fields.rebuffering_watermark_low_ms, (jint)settings.mRebufferingWatermarkLowMs);
+        env->SetIntField(params, fields.rebuffering_watermark_high_ms, (jint)settings.mRebufferingWatermarkHighMs);
+        env->SetIntField(params, fields.rebuffering_watermark_low_kb, (jint)settings.mRebufferingWatermarkLowKB);
+        env->SetIntField(params, fields.rebuffering_watermark_high_kb, (jint)settings.mRebufferingWatermarkHighKB);
+
+        return params;
+    }
+};
+
+}  // namespace android
+
+#endif  // _ANDROID_MEDIA_BUFFERING_PARAMS_H_
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index c52ed94..8225052 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -37,6 +37,7 @@
 #include "utils/Errors.h"  // for status_t
 #include "utils/KeyedVector.h"
 #include "utils/String8.h"
+#include "android_media_BufferingParams.h"
 #include "android_media_MediaDataSource.h"
 #include "android_media_PlaybackParams.h"
 #include "android_media_SyncParams.h"
@@ -69,6 +70,7 @@
 };
 static fields_t fields;
 
+static BufferingParams::fields_t gBufferingParamsFields;
 static PlaybackParams::fields_t gPlaybackParamsFields;
 static SyncParams::fields_t gSyncParamsFields;
 
@@ -343,6 +345,66 @@
     setVideoSurface(env, thiz, jsurface, true /* mediaPlayerMustBeAlive */);
 }
 
+static jobject
+android_media_MediaPlayer_getDefaultBufferingParams(JNIEnv *env, jobject thiz)
+{
+    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+    if (mp == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return NULL;
+    }
+
+    BufferingParams bp;
+    BufferingSettings &settings = bp.settings;
+    process_media_player_call(
+            env, thiz, mp->getDefaultBufferingSettings(&settings),
+            "java/lang/IllegalStateException", "unexpected error");
+    ALOGV("getDefaultBufferingSettings:{%s}", settings.toString().string());
+
+    return bp.asJobject(env, gBufferingParamsFields);
+}
+
+static jobject
+android_media_MediaPlayer_getBufferingParams(JNIEnv *env, jobject thiz)
+{
+    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+    if (mp == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return NULL;
+    }
+
+    BufferingParams bp;
+    BufferingSettings &settings = bp.settings;
+    process_media_player_call(
+            env, thiz, mp->getBufferingSettings(&settings),
+            "java/lang/IllegalStateException", "unexpected error");
+    ALOGV("getBufferingSettings:{%s}", settings.toString().string());
+
+    return bp.asJobject(env, gBufferingParamsFields);
+}
+
+static void
+android_media_MediaPlayer_setBufferingParams(JNIEnv *env, jobject thiz, jobject params)
+{
+    if (params == NULL) {
+        return;
+    }
+
+    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+    if (mp == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return;
+    }
+
+    BufferingParams bp;
+    bp.fillFromJobject(env, gBufferingParamsFields, params);
+    ALOGV("setBufferingParams:{%s}", bp.settings.toString().string());
+
+    process_media_player_call(
+            env, thiz, mp->setBufferingSettings(bp.settings),
+            "java/lang/IllegalStateException", "unexpected error");
+}
+
 static void
 android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz)
 {
@@ -860,6 +922,7 @@
 
     env->DeleteLocalRef(clazz);
 
+    gBufferingParamsFields.init(env);
     gPlaybackParamsFields.init(env);
     gSyncParamsFields.init(env);
 }
@@ -1046,6 +1109,9 @@
     {"_setDataSource",      "(Ljava/io/FileDescriptor;JJ)V",    (void *)android_media_MediaPlayer_setDataSourceFD},
     {"_setDataSource",      "(Landroid/media/MediaDataSource;)V",(void *)android_media_MediaPlayer_setDataSourceCallback },
     {"_setVideoSurface",    "(Landroid/view/Surface;)V",        (void *)android_media_MediaPlayer_setVideoSurface},
+    {"getDefaultBufferingParams", "()Landroid/media/BufferingParams;", (void *)android_media_MediaPlayer_getDefaultBufferingParams},
+    {"getBufferingParams", "()Landroid/media/BufferingParams;", (void *)android_media_MediaPlayer_getBufferingParams},
+    {"setBufferingParams", "(Landroid/media/BufferingParams;)V", (void *)android_media_MediaPlayer_setBufferingParams},
     {"_prepare",            "()V",                              (void *)android_media_MediaPlayer_prepare},
     {"prepareAsync",        "()V",                              (void *)android_media_MediaPlayer_prepareAsync},
     {"_start",              "()V",                              (void *)android_media_MediaPlayer_start},
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 6979995..25e1f16 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -80,16 +80,20 @@
 import java.io.FileNotFoundException;
 import java.io.PrintWriter;
 import java.nio.charset.StandardCharsets;
-import java.security.MessageDigest;
+import java.nio.ByteBuffer;
+import java.security.InvalidKeyException;
 import java.security.NoSuchAlgorithmException;
 import java.security.SecureRandom;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 import java.util.regex.Pattern;
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
 
 import static android.os.Process.ROOT_UID;
 import static android.os.Process.SHELL_UID;
@@ -996,7 +1000,7 @@
                     continue;
                 }
 
-                // As of Android O (API 24), the SSAID is read from an app-specific entry in table
+                // As of Android O, the SSAID is read from an app-specific entry in table
                 // SETTINGS_FILE_SSAID, unless accessed by a system process.
                 final Setting setting;
                 if (isNewSsaidSetting(name)) {
@@ -1035,7 +1039,7 @@
 
         // Get the value.
         synchronized (mLock) {
-            // As of Android O (API 24), the SSAID is read from an app-specific entry in table
+            // As of Android O, the SSAID is read from an app-specific entry in table
             // SETTINGS_FILE_SSAID, unless accessed by a system process.
             if (isNewSsaidSetting(name)) {
                 return getSsaidSettingLocked(owningUserId);
@@ -1978,12 +1982,12 @@
 
         private void generateUserKeyLocked(int userId) {
             // Generate a random key for each user used for creating a new ssaid.
-            final byte[] keyBytes = new byte[16];
+            final byte[] keyBytes = new byte[32];
             final SecureRandom rand = new SecureRandom();
             rand.nextBytes(keyBytes);
 
             // Convert to string for storage in settings table.
-            final String userKey = ByteStringUtils.toString(keyBytes);
+            final String userKey = ByteStringUtils.toHexString(keyBytes);
 
             // Store the key in the ssaid table.
             final SettingsState ssaidSettings = getSettingsLocked(SETTINGS_TYPE_SSAID, userId);
@@ -1995,6 +1999,10 @@
             }
         }
 
+        private byte[] getLengthPrefix(byte[] data) {
+            return ByteBuffer.allocate(4).putInt(data.length).array();
+        }
+
         public Setting generateSsaidLocked(String packageName, int userId) {
             final PackageInfo packageInfo;
             try {
@@ -2019,25 +2027,37 @@
             final String userKey = userKeySetting.getValue();
 
             // Convert the user's key back to a byte array.
-            final byte[] keyBytes = ByteStringUtils.toByteArray(userKey);
-            if (keyBytes == null || keyBytes.length != 16) {
+            final byte[] keyBytes = ByteStringUtils.fromHexToByteArray(userKey);
+
+            // Validate that the key is of expected length.
+            // Keys are currently 32 bytes, but were once 16 bytes during Android O development.
+            if (keyBytes == null || (keyBytes.length != 16 && keyBytes.length != 32)) {
                 throw new IllegalStateException("User key invalid");
             }
 
-            final MessageDigest md;
+            final Mac m;
             try {
-                // Hash package name and signature.
-                md = MessageDigest.getInstance("SHA-256");
+                m = Mac.getInstance("HmacSHA256");
+                m.init(new SecretKeySpec(keyBytes, m.getAlgorithm()));
             } catch (NoSuchAlgorithmException e) {
-                throw new IllegalStateException("HmacSHA256 is not available");
+                throw new IllegalStateException("HmacSHA256 is not available", e);
+            } catch (InvalidKeyException e) {
+                throw new IllegalStateException("Key is corrupted", e);
             }
-            md.update(keyBytes);
-            md.update(packageInfo.packageName.getBytes(StandardCharsets.UTF_8));
-            md.update(packageInfo.signatures[0].toByteArray());
+
+            // Mac the package name and each of the signatures.
+            byte[] packageNameBytes = packageInfo.packageName.getBytes(StandardCharsets.UTF_8);
+            m.update(getLengthPrefix(packageNameBytes), 0, 4);
+            m.update(packageNameBytes);
+            for (int i = 0; i < packageInfo.signatures.length; i++) {
+                byte[] sig = packageInfo.signatures[i].toByteArray();
+                m.update(getLengthPrefix(sig), 0, 4);
+                m.update(sig);
+            }
 
             // Convert result to a string for storage in settings table. Only want first 64 bits.
-            final String ssaid = ByteStringUtils.toString(md.digest()).substring(0, 16)
-                    .toLowerCase();
+            final String ssaid = ByteStringUtils.toHexString(m.doFinal()).substring(0, 16)
+                    .toLowerCase(Locale.US);
 
             // Save the ssaid in the ssaid table.
             final String uid = Integer.toString(packageInfo.applicationInfo.uid);
diff --git a/packages/SystemUI/res/xml/other_settings.xml b/packages/SystemUI/res/xml/other_settings.xml
index 18cb930..7719d5e 100644
--- a/packages/SystemUI/res/xml/other_settings.xml
+++ b/packages/SystemUI/res/xml/other_settings.xml
@@ -23,10 +23,5 @@
             android:key="power_notification_controls"
             android:title="@string/tuner_full_importance_settings"
             android:fragment="com.android.systemui.tuner.PowerNotificationControlsFragment"/>
-e
-    <com.android.systemui.tuner.ThemePreference
-        android:key="theme"
-        android:title="@string/theme"
-        android:summary="%s" />
 
 </PreferenceScreen>
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index 56947e5..964fefa 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -377,16 +377,18 @@
                 mCurrentPipBounds = mPipBounds;
                 break;
         }
-        try {
-            int animationDurationMs = -1;
-            if (wasRecentsShown
-                    && (mState == STATE_PIP_RECENTS || mState == STATE_PIP_RECENTS_FOCUSED)) {
-                animationDurationMs = mRecentsFocusChangedAnimationDurationMs;
+        if (mCurrentPipBounds != null) {
+            try {
+                int animationDurationMs = -1;
+                if (wasRecentsShown
+                        && (mState == STATE_PIP_RECENTS || mState == STATE_PIP_RECENTS_FOCUSED)) {
+                    animationDurationMs = mRecentsFocusChangedAnimationDurationMs;
+                }
+                mActivityManager.resizeStack(PINNED_STACK_ID, mCurrentPipBounds,
+                        true, true, true, animationDurationMs);
+            } catch (RemoteException e) {
+                Log.e(TAG, "resizeStack failed", e);
             }
-            mActivityManager.resizeStack(PINNED_STACK_ID, mCurrentPipBounds,
-                    true, true, true, animationDurationMs);
-        } catch (RemoteException e) {
-            Log.e(TAG, "resizeStack failed", e);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index 0bf3f15..1835afd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -60,7 +60,7 @@
 
     private AlertDialog mDialog;
     private QSTileHost mHost;
-    protected Handler mHandler;
+    protected H mHandler;
 
     private boolean mIsVisible;
     private boolean mIsIconVisible;
@@ -83,7 +83,7 @@
         mMainHandler = new Handler(Looper.getMainLooper());
         mActivityStarter = Dependency.get(ActivityStarter.class);
         mSecurityController = Dependency.get(SecurityController.class);
-        mHandler = new Handler((Looper) Dependency.get(Dependency.BG_LOOPER));
+        mHandler = new H(Dependency.get(Dependency.BG_LOOPER));
     }
 
     public void setHostEnvironment(QSTileHost host) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index d9298ed..926f610 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1524,8 +1524,9 @@
                 entry.notification.getUser().getIdentifier());
 
         final StatusBarNotification sbn = entry.notification;
+        boolean isLowPriority = mNotificationData.isAmbient(sbn.getKey());
         try {
-            entry.cacheContentViews(mContext, null);
+            entry.cacheContentViews(mContext, null, isLowPriority);
         } catch (RuntimeException e) {
             Log.e(TAG, "Unable to get notification remote views", e);
             return false;
@@ -1597,6 +1598,7 @@
 
         workAroundBadLayerDrawableOpacity(row);
         bindDismissRunnable(row);
+        row.setIsLowPriority(isLowPriority);
 
         // NB: the large icon is now handled entirely by the template
 
@@ -2283,7 +2285,8 @@
 
         boolean applyInPlace;
         try {
-            applyInPlace = entry.cacheContentViews(mContext, notification.getNotification());
+            applyInPlace = entry.cacheContentViews(mContext, notification.getNotification(),
+                    mNotificationData.isAmbient(key));
         } catch (RuntimeException e) {
             Log.e(TAG, "Unable to get notification remote views", e);
             applyInPlace = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 93c48f8..013554c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -22,6 +22,7 @@
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.ColorDrawable;
@@ -51,6 +52,7 @@
 import com.android.systemui.R;
 import com.android.systemui.classifier.FalsingManager;
 import com.android.systemui.statusbar.notification.HybridNotificationView;
+import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -201,6 +203,7 @@
     private boolean mShowAmbient;
     private boolean mIsLastChild;
     private Runnable mOnDismissRunnable;
+    private boolean mIsLowPriority;
 
     public boolean isGroupExpansionChanging() {
         if (isChildInGroup()) {
@@ -309,6 +312,18 @@
         mPublicLayout.updateExpandButtons(true);
         updateLimits();
         updateIconVisibilities();
+        updateShelfIconColor();
+    }
+
+    private void updateShelfIconColor() {
+        StatusBarIconView expandedIcon = mEntry.expandedIcon;
+        boolean isPreL = Boolean.TRUE.equals(expandedIcon.getTag(R.id.icon_is_pre_L));
+        boolean colorize = !isPreL || NotificationUtils.isGrayscale(expandedIcon,
+                NotificationColorUtil.getInstance(mContext));
+        if (colorize) {
+            int color = mEntry.getContrastedColor(mContext, mIsLowPriority && !isExpanded());
+            expandedIcon.setImageTintList(ColorStateList.valueOf(color));
+        }
     }
 
     private void updateLimits() {
@@ -943,6 +958,14 @@
         return mPrivateLayout.getTranslationY();
     }
 
+    public void setIsLowPriority(boolean isLowPriority) {
+        mIsLowPriority = isLowPriority;
+        mPrivateLayout.setIsLowPriority(isLowPriority);
+        if (mChildrenContainer != null) {
+            mChildrenContainer.setIsLowPriority(isLowPriority);
+        }
+    }
+
     public interface ExpansionLogger {
         public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
     }
@@ -1043,6 +1066,7 @@
             @Override
             public void onInflate(ViewStub stub, View inflated) {
                 mChildrenContainer = (NotificationChildrenContainer) inflated;
+                mChildrenContainer.setIsLowPriority(mIsLowPriority);
                 mChildrenContainer.setNotificationParent(ExpandableNotificationRow.this);
                 mChildrenContainer.onNotificationUpdated();
                 mTranslateableViews.add(mChildrenContainer);
@@ -1242,6 +1266,7 @@
      */
     public void setUserExpanded(boolean userExpanded) {
         setUserExpanded(userExpanded, false /* allowChildExpansion */);
+        updateShelfIconColor();
     }
 
     /**
@@ -1301,6 +1326,7 @@
         if (expand != mIsSystemExpanded) {
             final boolean wasExpanded = isExpanded();
             mIsSystemExpanded = expand;
+            updateShelfIconColor();
             notifyHeightChanged(false /* needsAnimation */);
             logExpansionEvent(false, wasExpanded);
             if (mIsSummaryWithChildren) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index b45cde8..4d0ce12 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -129,6 +129,7 @@
     private boolean mHeadsUpAnimatingAway;
     private boolean mIconsVisible;
     private int mClipBottomAmount;
+    private boolean mIsLowPriority;
 
 
     public NotificationContentView(Context context, AttributeSet attrs) {
@@ -163,20 +164,31 @@
         if (mExpandedChild != null) {
             int size = Math.min(maxSize, mNotificationMaxHeight);
             ViewGroup.LayoutParams layoutParams = mExpandedChild.getLayoutParams();
+            boolean useExactly = false;
             if (layoutParams.height >= 0) {
                 // An actual height is set
                 size = Math.min(maxSize, layoutParams.height);
+                useExactly = true;
             }
             int spec = size == Integer.MAX_VALUE
                     ? MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
-                    : MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST);
+                    : MeasureSpec.makeMeasureSpec(size, useExactly
+                            ? MeasureSpec.EXACTLY
+                            : MeasureSpec.AT_MOST);
             mExpandedChild.measure(widthMeasureSpec, spec);
             maxChildHeight = Math.max(maxChildHeight, mExpandedChild.getMeasuredHeight());
         }
         if (mContractedChild != null) {
             int heightSpec;
             int size = Math.min(maxSize, mSmallHeight);
-            if (shouldContractedBeFixedSize()) {
+            ViewGroup.LayoutParams layoutParams = mContractedChild.getLayoutParams();
+            boolean useExactly = false;
+            if (layoutParams.height >= 0) {
+                // An actual height is set
+                size = Math.min(size, layoutParams.height);
+                useExactly = true;
+            }
+            if (shouldContractedBeFixedSize() || useExactly) {
                 heightSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
             } else {
                 heightSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST);
@@ -202,12 +214,15 @@
         if (mHeadsUpChild != null) {
             int size = Math.min(maxSize, mHeadsUpHeight);
             ViewGroup.LayoutParams layoutParams = mHeadsUpChild.getLayoutParams();
+            boolean useExactly = false;
             if (layoutParams.height >= 0) {
                 // An actual height is set
                 size = Math.min(size, layoutParams.height);
+                useExactly = true;
             }
             mHeadsUpChild.measure(widthMeasureSpec,
-                    MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST));
+                    MeasureSpec.makeMeasureSpec(size, useExactly ? MeasureSpec.EXACTLY
+                            : MeasureSpec.AT_MOST));
             maxChildHeight = Math.max(maxChildHeight, mHeadsUpChild.getMeasuredHeight());
         }
         if (mSingleLineView != null) {
@@ -225,12 +240,15 @@
         if (mAmbientChild != null) {
             int size = Math.min(maxSize, mNotificationAmbientHeight);
             ViewGroup.LayoutParams layoutParams = mAmbientChild.getLayoutParams();
+            boolean useExactly = false;
             if (layoutParams.height >= 0) {
                 // An actual height is set
                 size = Math.min(size, layoutParams.height);
+                useExactly = true;
             }
             mAmbientChild.measure(widthMeasureSpec,
-                    MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST));
+                    MeasureSpec.makeMeasureSpec(size, useExactly ? MeasureSpec.EXACTLY
+                            : MeasureSpec.AT_MOST));
             maxChildHeight = Math.max(maxChildHeight, mAmbientChild.getMeasuredHeight());
         }
         int ownHeight = Math.min(maxChildHeight, maxSize);
@@ -606,7 +624,7 @@
     }
 
     public int getMinHeight(boolean likeGroupExpanded) {
-        if (likeGroupExpanded || !mIsChildInGroup || isGroupExpanded()) {
+        if (likeGroupExpanded || !mIsChildInGroup || isGroupExpanded() || mIsLowPriority) {
             return mContractedChild.getHeight();
         } else {
             return mSingleLineView.getHeight();
@@ -868,7 +886,7 @@
                 height = mContentHeight;
             }
             int expandedVisualType = getVisualTypeForHeight(height);
-            int collapsedVisualType = mIsChildInGroup && !isGroupExpanded()
+            int collapsedVisualType = mIsChildInGroup && !isGroupExpanded() && !mIsLowPriority
                     ? VISIBLE_TYPE_SINGLELINE
                     : getVisualTypeForHeight(mContainingNotification.getCollapsedHeight());
             return mTransformationStartVisibleType == collapsedVisualType
@@ -889,7 +907,7 @@
         if (!noExpandedChild && viewHeight == mExpandedChild.getHeight()) {
             return VISIBLE_TYPE_EXPANDED;
         }
-        if (!mUserExpanding && mIsChildInGroup && !isGroupExpanded()) {
+        if (!mUserExpanding && mIsChildInGroup && !isGroupExpanded() && !mIsLowPriority) {
             return VISIBLE_TYPE_SINGLELINE;
         }
 
@@ -976,16 +994,16 @@
         updateSingleLineView();
         applyRemoteInput(entry);
         if (mContractedChild != null) {
-            mContractedWrapper.notifyContentUpdated(entry.notification);
+            mContractedWrapper.notifyContentUpdated(entry.notification, mIsLowPriority);
         }
         if (mExpandedChild != null) {
-            mExpandedWrapper.notifyContentUpdated(entry.notification);
+            mExpandedWrapper.notifyContentUpdated(entry.notification, mIsLowPriority);
         }
         if (mHeadsUpChild != null) {
-            mHeadsUpWrapper.notifyContentUpdated(entry.notification);
+            mHeadsUpWrapper.notifyContentUpdated(entry.notification, mIsLowPriority);
         }
         if (mAmbientChild != null) {
-            mAmbientWrapper.notifyContentUpdated(entry.notification);
+            mAmbientWrapper.notifyContentUpdated(entry.notification, mIsLowPriority);
         }
         updateShowingLegacyBackground();
         mForceSelectNextLayout = true;
@@ -1282,4 +1300,8 @@
             }
         }
     }
+
+    public void setIsLowPriority(boolean isLowPriority) {
+        mIsLowPriority = isLowPriority;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 3a89186..8c04a1a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -117,14 +117,16 @@
             return row.getPublicLayout().getContractedChild();
         }
 
-        public boolean cacheContentViews(Context ctx, Notification updatedNotification) {
+        public boolean cacheContentViews(Context ctx, Notification updatedNotification,
+                boolean isLowPriority) {
             boolean applyInPlace = false;
             if (updatedNotification != null) {
                 final Notification.Builder updatedNotificationBuilder
                         = Notification.Builder.recoverBuilder(ctx, updatedNotification);
-                final RemoteViews newContentView = updatedNotificationBuilder.createContentView();
-                final RemoteViews newBigContentView =
-                        updatedNotificationBuilder.createBigContentView();
+                final RemoteViews newContentView = createContentView(updatedNotificationBuilder,
+                        isLowPriority);
+                final RemoteViews newBigContentView = createBigContentView(
+                        updatedNotificationBuilder, isLowPriority);
                 final RemoteViews newHeadsUpContentView =
                         updatedNotificationBuilder.createHeadsUpContentView();
                 final RemoteViews newPublicNotification
@@ -152,8 +154,8 @@
                 final Notification.Builder builder
                         = Notification.Builder.recoverBuilder(ctx, notification.getNotification());
 
-                cachedContentView = builder.createContentView();
-                cachedBigContentView = builder.createBigContentView();
+                cachedContentView = createContentView(builder, isLowPriority);
+                cachedBigContentView = createBigContentView(builder, isLowPriority);
                 cachedHeadsUpContentView = builder.createHeadsUpContentView();
                 cachedPublicContentView = builder.makePublicContentView();
                 cachedAmbientContentView = builder.makeAmbientNotification();
@@ -163,6 +165,28 @@
             return applyInPlace;
         }
 
+        private RemoteViews createBigContentView(Notification.Builder builder,
+                boolean isLowPriority) {
+            RemoteViews bigContentView = builder.createBigContentView();
+            if (bigContentView != null) {
+                return bigContentView;
+            }
+            if (isLowPriority) {
+                RemoteViews contentView = builder.createContentView();
+                Notification.Builder.makeHeaderExpanded(contentView);
+                return contentView;
+            }
+            return null;
+        }
+
+        private RemoteViews createContentView(Notification.Builder builder,
+                boolean isAmbient) {
+            if (isAmbient) {
+                return builder.makeLowPriorityContentView(false /* useRegularSubtext */);
+            }
+            return builder.createContentView();
+        }
+
         // Returns true if the RemoteViews are the same.
         private boolean compareRemoteViews(final RemoteViews a, final RemoteViews b) {
             return (a == null && b == null) ||
@@ -256,8 +280,9 @@
             }
         }
 
-        public int getContrastedColor(Context context) {
-            int rawColor = notification.getNotification().color;
+        public int getContrastedColor(Context context, boolean ambient) {
+            int rawColor = ambient ? Notification.COLOR_DEFAULT :
+                    notification.getNotification().color;
             if (mCachedContrastColorIsFor == rawColor && mCachedContrastColor != COLOR_INVALID) {
                 return mCachedContrastColor;
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/TransformableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/TransformableView.java
index dd7c4c7..063252f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/TransformableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/TransformableView.java
@@ -22,7 +22,7 @@
  * A view that can be transformed to and from.
  */
 public interface TransformableView {
-    int TRANSFORMING_VIEW_HEADER = 0;
+    int TRANSFORMING_VIEW_ICON = 0;
     int TRANSFORMING_VIEW_TITLE = 1;
     int TRANSFORMING_VIEW_TEXT = 2;
     int TRANSFORMING_VIEW_IMAGE = 3;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java
deleted file mode 100644
index 9501f90..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.notification;
-
-import android.util.Pools;
-import android.view.NotificationHeaderView;
-import android.view.View;
-
-import com.android.systemui.statusbar.CrossFadeHelper;
-
-/**
- * A transform state of a text view.
-*/
-public class HeaderTransformState extends TransformState {
-
-    private static Pools.SimplePool<HeaderTransformState> sInstancePool
-            = new Pools.SimplePool<>(40);
-    private View mExpandButton;
-    private View mWorkProfileIcon;
-    private TransformState mWorkProfileState;
-
-    @Override
-    public void initFrom(View view) {
-        super.initFrom(view);
-        if (view instanceof NotificationHeaderView) {
-            NotificationHeaderView header = (NotificationHeaderView) view;
-            mExpandButton = header.getExpandButton();
-            mWorkProfileState = TransformState.obtain();
-            mWorkProfileIcon = header.getWorkProfileIcon();
-            mWorkProfileState.initFrom(mWorkProfileIcon);
-        }
-    }
-
-    @Override
-    public boolean transformViewTo(TransformState otherState, float transformationAmount) {
-        // if the transforming notification has a header, we have ensured that it looks the same
-        // but the expand button, so lets fade just that one and transform the work profile icon.
-        if (!(mTransformedView instanceof NotificationHeaderView)) {
-            return false;
-        }
-        NotificationHeaderView header = (NotificationHeaderView) mTransformedView;
-        int childCount = header.getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View headerChild = header.getChildAt(i);
-            if (headerChild.getVisibility() == View.GONE) {
-                continue;
-            }
-            if (headerChild != mExpandButton) {
-                headerChild.setVisibility(View.INVISIBLE);
-            } else {
-                CrossFadeHelper.fadeOut(mExpandButton, transformationAmount);
-            }
-        }
-        return true;
-    }
-
-    @Override
-    public void transformViewFrom(TransformState otherState, float transformationAmount) {
-        // if the transforming notification has a header, we have ensured that it looks the same
-        // but the expand button, so lets fade just that one and transform the work profile icon.
-        if (!(mTransformedView instanceof NotificationHeaderView)) {
-            return;
-        }
-        NotificationHeaderView header = (NotificationHeaderView) mTransformedView;
-        header.setVisibility(View.VISIBLE);
-        header.setAlpha(1.0f);
-        int childCount = header.getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View headerChild = header.getChildAt(i);
-            if (headerChild.getVisibility() == View.GONE) {
-                continue;
-            }
-            if (headerChild == mExpandButton) {
-                CrossFadeHelper.fadeIn(mExpandButton, transformationAmount);
-            } else {
-                headerChild.setVisibility(View.VISIBLE);
-                if (headerChild == mWorkProfileIcon) {
-                    mWorkProfileState.transformViewFullyFrom(
-                            ((HeaderTransformState) otherState).mWorkProfileState,
-                            transformationAmount);
-                }
-            }
-        }
-        return;
-    }
-
-    public static HeaderTransformState obtain() {
-        HeaderTransformState instance = sInstancePool.acquire();
-        if (instance != null) {
-            return instance;
-        }
-        return new HeaderTransformState();
-    }
-
-    @Override
-    public void recycle() {
-        super.recycle();
-        sInstancePool.release(this);
-    }
-
-    @Override
-    protected void reset() {
-        super.reset();
-        mExpandButton = null;
-        mWorkProfileState = null;
-        if (mWorkProfileState != null) {
-            mWorkProfileState.recycle();
-            mWorkProfileState = null;
-        }
-    }
-
-    @Override
-    public void setVisible(boolean visible, boolean force) {
-        super.setVisible(visible, force);
-        if (!(mTransformedView instanceof NotificationHeaderView)) {
-            return;
-        }
-        NotificationHeaderView header = (NotificationHeaderView) mTransformedView;
-        int childCount = header.getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View headerChild = header.getChildAt(i);
-            if (!force && headerChild.getVisibility() == View.GONE) {
-                continue;
-            }
-            headerChild.animate().cancel();
-            if (headerChild.getVisibility() != View.GONE) {
-                headerChild.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
-            }
-            if (headerChild == mExpandButton) {
-                headerChild.setAlpha(visible ? 1.0f : 0.0f);
-            }
-            if (headerChild == mWorkProfileIcon) {
-                headerChild.setTranslationX(0);
-                headerChild.setTranslationY(0);
-            }
-        }
-    }
-
-    @Override
-    public void prepareFadeIn() {
-        super.prepareFadeIn();
-        if (!(mTransformedView instanceof NotificationHeaderView)) {
-            return;
-        }
-        NotificationHeaderView header = (NotificationHeaderView) mTransformedView;
-        int childCount = header.getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View headerChild = header.getChildAt(i);
-            if (headerChild.getVisibility() == View.GONE) {
-                continue;
-            }
-            headerChild.animate().cancel();
-            headerChild.setVisibility(View.VISIBLE);
-            headerChild.setAlpha(1.0f);
-            if (headerChild == mWorkProfileIcon) {
-                headerChild.setTranslationX(0);
-                headerChild.setTranslationY(0);
-            }
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigPictureTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigPictureTemplateViewWrapper.java
index 6084770..78b967a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigPictureTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigPictureTemplateViewWrapper.java
@@ -36,8 +36,8 @@
     }
 
     @Override
-    public void notifyContentUpdated(StatusBarNotification notification) {
-        super.notifyContentUpdated(notification);
+    public void notifyContentUpdated(StatusBarNotification notification, boolean isLowPriority) {
+        super.notifyContentUpdated(notification, isLowPriority);
         updateImageTag(notification);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigTextTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigTextTemplateViewWrapper.java
index 3f49125..39db243 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigTextTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigTextTemplateViewWrapper.java
@@ -41,11 +41,11 @@
     }
 
     @Override
-    public void notifyContentUpdated(StatusBarNotification notification) {
+    public void notifyContentUpdated(StatusBarNotification notification, boolean isLowPriority) {
         // Reinspect the notification. Before the super call, because the super call also updates
         // the transformation types and we need to have our values set by then.
         resolveViews(notification);
-        super.notifyContentUpdated(notification);
+        super.notifyContentUpdated(notification, isLowPriority);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
index 85e87dd..d564741 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
@@ -106,8 +106,8 @@
     }
 
     @Override
-    public void notifyContentUpdated(StatusBarNotification notification) {
-        super.notifyContentUpdated(notification);
+    public void notifyContentUpdated(StatusBarNotification notification, boolean isLowPriority) {
+        super.notifyContentUpdated(notification, isLowPriority);
         Drawable background = mView.getBackground();
         mBackgroundColor = 0;
         if (background instanceof ColorDrawable) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
index 3e4c758..e1f553c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
@@ -32,6 +32,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
+import android.widget.TextView;
 
 import com.android.systemui.R;
 import com.android.systemui.ViewInvertHelper;
@@ -60,6 +61,9 @@
 
     private ImageView mExpandButton;
     private NotificationHeaderView mNotificationHeader;
+    private TextView mHeaderText;
+    private ImageView mWorkProfileImage;
+    private boolean mIsLowPriority;
 
     protected NotificationHeaderViewWrapper(Context ctx, View view, ExpandableNotificationRow row) {
         super(view, row);
@@ -72,7 +76,9 @@
 
     protected void resolveHeaderViews() {
         mIcon = (ImageView) mView.findViewById(com.android.internal.R.id.icon);
+        mHeaderText = (TextView) mView.findViewById(com.android.internal.R.id.header_text);
         mExpandButton = (ImageView) mView.findViewById(com.android.internal.R.id.expand_button);
+        mWorkProfileImage = (ImageView) mView.findViewById(com.android.internal.R.id.profile_badge);
         mColor = resolveColor(mExpandButton);
         mNotificationHeader = (NotificationHeaderView) mView.findViewById(
                 com.android.internal.R.id.notification_header);
@@ -89,9 +95,9 @@
     }
 
     @Override
-    public void notifyContentUpdated(StatusBarNotification notification) {
-        super.notifyContentUpdated(notification);
-
+    public void notifyContentUpdated(StatusBarNotification notification, boolean isLowPriority) {
+        super.notifyContentUpdated(notification, isLowPriority);
+        mIsLowPriority = isLowPriority;
         ArraySet<View> previousViews = mTransformationHelper.getAllTransformingViews();
 
         // Reinspect the notification.
@@ -100,6 +106,11 @@
         updateTransformedTypes();
         addRemainingTransformTypes();
         updateCropToPaddingForImageViews();
+        mIcon.setTag(ImageTransformState.ICON_TAG, notification.getNotification().getSmallIcon());
+        // The work profile image is always the same lets just set the icon tag for it not to
+        // animate
+        mWorkProfileImage.setTag(ImageTransformState.ICON_TAG,
+                notification.getNotification().getSmallIcon());
 
         // We need to reset all views that are no longer transforming in case a view was previously
         // transformed, but now we decided to transform its container instead.
@@ -154,8 +165,11 @@
 
     protected void updateTransformedTypes() {
         mTransformationHelper.reset();
-        mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_HEADER,
-                mNotificationHeader);
+        mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_ICON, mIcon);
+        if (mIsLowPriority) {
+            mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TITLE,
+                    mHeaderText);
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
index 4ce330c..04ee6aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
@@ -40,11 +40,11 @@
     }
 
     @Override
-    public void notifyContentUpdated(StatusBarNotification notification) {
+    public void notifyContentUpdated(StatusBarNotification notification, boolean isLowPriority) {
         // Reinspect the notification. Before the super call, because the super call also updates
         // the transformation types and we need to have our values set by then.
         resolveViews(notification);
-        super.notifyContentUpdated(notification);
+        super.notifyContentUpdated(notification, isLowPriority);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMessagingTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMessagingTemplateViewWrapper.java
index 58f01c8..61457df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMessagingTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMessagingTemplateViewWrapper.java
@@ -59,11 +59,11 @@
     }
 
     @Override
-    public void notifyContentUpdated(StatusBarNotification notification) {
+    public void notifyContentUpdated(StatusBarNotification notification, boolean isLowPriority) {
         // Reinspect the notification. Before the super call, because the super call also updates
         // the transformation types and we need to have our values set by then.
         resolveViews();
-        super.notifyContentUpdated(notification);
+        super.notifyContentUpdated(notification, isLowPriority);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
index b984c0b..e9956ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
@@ -133,11 +133,11 @@
     }
 
     @Override
-    public void notifyContentUpdated(StatusBarNotification notification) {
+    public void notifyContentUpdated(StatusBarNotification notification, boolean isLowPriority) {
         // Reinspect the notification. Before the super call, because the super call also updates
         // the transformation types and we need to have our values set by then.
         resolveTemplateViews(notification);
-        super.notifyContentUpdated(notification);
+        super.notifyContentUpdated(notification, isLowPriority);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
index 16348dfe..8106223 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
@@ -80,9 +80,10 @@
 
     /**
      * Notifies this wrapper that the content of the view might have changed.
-     * @param notification
+     * @param notification the notification this is wrapped around
+     * @param isLowPriority is this notification low priority
      */
-    public void notifyContentUpdated(StatusBarNotification notification) {
+    public void notifyContentUpdated(StatusBarNotification notification, boolean isLowPriority) {
         mDarkInitialized = false;
     };
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
index 770ec95..6b3d25d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
@@ -402,11 +402,6 @@
             result.initFrom(view);
             return result;
         }
-        if (view instanceof NotificationHeaderView) {
-            HeaderTransformState result = HeaderTransformState.obtain();
-            result.initFrom(view);
-            return result;
-        }
         if (view instanceof ImageView) {
             ImageTransformState result = ImageTransformState.obtain();
             result.initFrom(view);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 345dcbd..32b9969 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -154,18 +154,6 @@
                 NotificationShelf.SHOW_AMBIENT_ICONS);
 
         applyNotificationIconsTint();
-        ArrayList<NotificationData.Entry> activeNotifications
-                = notificationData.getActiveNotifications();
-        for (int i = 0; i < activeNotifications.size(); i++) {
-            NotificationData.Entry entry = activeNotifications.get(i);
-            boolean isPreL = Boolean.TRUE.equals(entry.expandedIcon.getTag(R.id.icon_is_pre_L));
-            boolean colorize = !isPreL
-                    || NotificationUtils.isGrayscale(entry.expandedIcon, mNotificationColorUtil);
-            if (colorize) {
-                int color = entry.getContrastedColor(mContext);
-                entry.expandedIcon.setImageTintList(ColorStateList.valueOf(color));
-            }
-        }
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
index a706408..5536209 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -162,6 +162,10 @@
         BatteryMeterView battery = (BatteryMeterView) findViewById(R.id.battery);
         int colorSecondary = Utils.getColorAttr(getContext(), android.R.attr.textColorSecondary);
         battery.setRawColors(colorForeground, colorSecondary);
+
+        mNextAlarmController = Dependency.get(NextAlarmController.class);
+        mUserInfoController = Dependency.get(UserInfoController.class);
+        mActivityStarter = Dependency.get(ActivityStarter.class);
     }
 
     @Override
@@ -260,14 +264,6 @@
     }
 
     @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mNextAlarmController = Dependency.get(NextAlarmController.class);
-        mUserInfoController = Dependency.get(UserInfoController.class);
-        mActivityStarter = Dependency.get(ActivityStarter.class);
-    }
-
-    @Override
     @VisibleForTesting
     public void onDetachedFromWindow() {
         setListening(false);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index 1a2d778..e6a3add 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -78,6 +78,7 @@
     private NotificationHeaderUtil mHeaderUtil;
     private ViewState mHeaderViewState;
     private int mClipBottomAmount;
+    private boolean mIsLowPriority;
 
     public NotificationChildrenContainer(Context context) {
         this(context, null);
@@ -246,10 +247,13 @@
         return mChildren.size();
     }
 
-    public void recreateNotificationHeader(OnClickListener listener, StatusBarNotification notification) {
+    public void recreateNotificationHeader(OnClickListener listener,
+            StatusBarNotification notification) {
         final Notification.Builder builder = Notification.Builder.recoverBuilder(getContext(),
                 mNotificationParent.getStatusBarNotification().getNotification());
-        final RemoteViews header = builder.makeNotificationHeader();
+        final RemoteViews header = mIsLowPriority
+                ? builder.makeLowPriorityContentView(true /* useRegularSubtext */)
+                : builder.makeNotificationHeader();
         if (mNotificationHeader == null) {
             mNotificationHeader = (NotificationHeaderView) header.apply(getContext(), this);
             final View expandButton = mNotificationHeader.findViewById(
@@ -262,7 +266,7 @@
             invalidate();
         } else {
             header.reapply(getContext(), mNotificationHeader);
-            mNotificationHeaderWrapper.notifyContentUpdated(notification);
+            mNotificationHeaderWrapper.notifyContentUpdated(notification, mIsLowPriority);
         }
         updateChildrenHeaderAppearance();
     }
@@ -367,6 +371,9 @@
      * @return the intrinsic size of this children container, i.e the natural fully expanded state
      */
     public int getIntrinsicHeight() {
+        if (mIsLowPriority && !mChildrenExpanded) {
+            return mNotificationHeader.getHeight();
+        }
         int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren();
         return getIntrinsicHeight(maxAllowedVisibleChildren);
     }
@@ -480,7 +487,7 @@
             childState.clipTopAmount = 0;
             childState.alpha = 0;
             if (i < firstOverflowIndex) {
-                childState.alpha = 1;
+                childState.alpha = mIsLowPriority && !mChildrenExpanded ? expandFactor : 1.0f;
             } else if (expandFactor == 1.0f && i <= lastVisibleIndex) {
                 childState.alpha = (mActualHeight - childState.yTranslation) / childState.height;
                 childState.alpha = Math.max(0.0f, Math.min(1.0f, childState.alpha));
@@ -828,6 +835,9 @@
     }
 
     private int getMinHeight(int maxAllowedVisibleChildren) {
+        if (mIsLowPriority && !mChildrenExpanded) {
+            return mNotificationHeader.getHeight();
+        }
         int minExpandHeight = mNotificationHeaderMargin;
         int visibleChildren = 0;
         boolean firstChild = true;
@@ -922,4 +932,8 @@
         mClipBottomAmount = clipBottomAmount;
         updateChildrenClipping();
     }
+
+    public void setIsLowPriority(boolean isLowPriority) {
+        mIsLowPriority = isLowPriority;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ThemePreference.java b/packages/SystemUI/src/com/android/systemui/tuner/ThemePreference.java
deleted file mode 100644
index a068172..0000000
--- a/packages/SystemUI/src/com/android/systemui/tuner/ThemePreference.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.systemui.tuner;
-
-import android.app.AlertDialog;
-import android.app.UiModeManager;
-import android.content.Context;
-import android.os.SystemProperties;
-import android.support.v7.preference.ListPreference;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-
-import com.android.systemui.R;
-
-import libcore.util.Objects;
-
-import com.google.android.collect.Lists;
-
-import java.io.File;
-import java.util.ArrayList;
-
-public class ThemePreference extends ListPreference {
-
-    public ThemePreference(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    @Override
-    public void onAttached() {
-        super.onAttached();
-        String def = SystemProperties.get("ro.boot.vendor.overlay.theme");
-        if (TextUtils.isEmpty(def)) {
-            def = getContext().getString(R.string.default_theme);
-        }
-        String[] fileList = new File("/vendor/overlay").list();
-        ArrayList<String> options = fileList != null
-                ? Lists.newArrayList(fileList) : new ArrayList<>();
-        if (!options.contains(def)) {
-            options.add(0, def);
-        }
-        String[] list = options.toArray(new String[options.size()]);
-        setVisible(options.size() > 1);
-        setEntries(list);
-        setEntryValues(list);
-        updateValue();
-    }
-
-    private void updateValue() {
-        setValue(getContext().getSystemService(UiModeManager.class).getTheme());
-    }
-
-    @Override
-    protected void notifyChanged() {
-        super.notifyChanged();
-        if (!Objects.equal(getValue(),
-                getContext().getSystemService(UiModeManager.class).getTheme())) {
-            new AlertDialog.Builder(getContext())
-                    .setTitle(R.string.change_theme_reboot)
-                    .setPositiveButton(com.android.internal.R.string.global_action_restart, (d, i)
-                            -> getContext().getSystemService(UiModeManager.class)
-                            .setTheme(getValue()))
-                    .setNegativeButton(android.R.string.cancel, (d, i) -> updateValue())
-                    .show();
-        }
-    }
-}
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index 6516369..90e9321 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -30,6 +30,9 @@
     <uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
     <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
     <uses-permission android:name="android.permission.ACCESS_VR_MANAGER" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+    <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java b/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
index 973f1f2..fb4b6bd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
@@ -15,6 +15,7 @@
 package com.android.systemui;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
@@ -25,6 +26,8 @@
 
 import org.junit.Test;
 
+import java.io.PrintWriter;
+
 public class DependencyTest extends SysuiTestCase {
 
     @Test
@@ -46,8 +49,8 @@
         Dumpable d = mock(Dumpable.class);
         injectTestDependency("test", d);
         Dependency.get("test");
-        mDependency.dump(null, null, null);
-        verify(d).dump(eq(null), eq(null), eq(null));
+        mDependency.dump(null, mock(PrintWriter.class), null);
+        verify(d).dump(eq(null), any(), eq(null));
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index 5fe5174..f258e5d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -43,6 +43,7 @@
     public void SysuiSetup() throws Exception {
         System.setProperty("dexmaker.share_classloader", "true");
         mContext = new TestableContext(InstrumentationRegistry.getTargetContext(), this);
+        SystemUIFactory.createFromConfig(mContext);
         mDependency = new TestDependency();
         mDependency.mContext = mContext;
         mDependency.start();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index e3ee851..5345031 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -58,6 +58,7 @@
 
     @Before
     public void addLeakCheckDependencies() {
+        injectTestDependency(Dependency.BG_LOOPER, Looper.getMainLooper());
         injectMockDependency(UserSwitcherController.class);
         injectLeakCheckedDependencies(BluetoothController.class, LocationController.class,
                 RotationLockController.class, NetworkController.class, ZenModeController.class,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
index 9fcb5f7..525a361 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
@@ -40,6 +40,7 @@
         mContext.putComponent(PhoneStatusBar.class, mock(PhoneStatusBar.class));
         mContext.putComponent(Recents.class, mock(Recents.class));
         mContext.putComponent(Divider.class, mock(Divider.class));
+        mContext.addMockSystemService(Context.WINDOW_SERVICE, mock(WindowManager.class));
     }
 
     @Test
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 036b6c2..a474759 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3336,6 +3336,9 @@
     // OS: 8.0
     TTS_SLIDERS = 815;
 
+    // ACTION: Settings -> Display -> Theme
+    ACTION_THEME = 816;
+
     // ---- End O Constants, all O constants go above this line ----
 
     // Add new aosp constants above this line.
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
index 87eaf29..6779657 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
@@ -19,10 +19,6 @@
 import static android.Manifest.permission.MANAGE_AUTO_FILL;
 import static android.content.Context.AUTO_FILL_MANAGER_SERVICE;
 import static android.view.View.AUTO_FILL_FLAG_TYPE_FILL;
-import static android.view.View.AUTO_FILL_FLAG_TYPE_SAVE;
-
-import static com.android.server.autofill.AutoFillUI.MSG_SHOW_ALL_NOTIFICATIONS;
-import static com.android.server.autofill.AutoFillUI.SHOW_ALL_NOTIFICATIONS_DELAY_MS;
 
 import android.Manifest;
 import android.app.AppGlobals;
@@ -32,11 +28,13 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
 import android.database.ContentObserver;
+import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
@@ -51,9 +49,12 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.TimeUtils;
+import android.view.autofill.AutoFillId;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.os.BackgroundThread;
+import com.android.internal.os.HandlerCaller;
+import com.android.internal.os.SomeArgs;
 import com.android.server.FgThread;
 import com.android.server.SystemService;
 
@@ -70,13 +71,12 @@
 public final class AutoFillManagerService extends SystemService {
 
     private static final String TAG = "AutoFillManagerService";
-    static final boolean DEBUG = true; // TODO: change to false once stable
+    static final boolean DEBUG = true; // TODO(b/33197203): change to false once stable
 
     private static final long SERVICE_BINDING_LIFETIME_MS = 5 * DateUtils.MINUTE_IN_MILLIS;
 
-    private static final int ARG_NOT_USED = 0;
-
     protected static final int MSG_UNBIND = 1;
+    protected static final int MSG_SHOW_AUTO_FILL = 2;
 
     private final AutoFillManagerServiceStub mServiceStub;
     private final AutoFillUI mUi;
@@ -85,23 +85,28 @@
 
     private final Object mLock = new Object();
 
-    private final Handler mHandler = new Handler() {
+    private final HandlerCaller.Callback mHandlerCallback = new HandlerCaller.Callback() {
+
         @Override
-        public void handleMessage(Message msg) {
+        public void executeMessage(Message msg) {
             switch (msg.what) {
-                case MSG_UNBIND:
+                case MSG_UNBIND: {
                     removeStaleServiceForUser(msg.arg1);
                     return;
-                case MSG_SHOW_ALL_NOTIFICATIONS:
-                    mUi.showAllNotifications();
+                } case MSG_SHOW_AUTO_FILL: {
+                    final SomeArgs args = (SomeArgs) msg.obj;
+                    showAutoFillInput(msg.arg1, (AutoFillId) args.arg1, (Rect) args.arg2);
                     return;
-                default:
+                } default: {
                     Slog.w(TAG, "Invalid message: " + msg);
+                }
             }
         }
 
     };
 
+    private HandlerCaller mHandlerCaller;
+
     /**
      * Cache of {@link AutoFillManagerServiceImpl} per user id.
      * <p>
@@ -122,6 +127,8 @@
     public AutoFillManagerService(Context context) {
         super(context);
 
+        mHandlerCaller = new HandlerCaller(null, Looper.getMainLooper(), mHandlerCallback, true);
+
         mContext = context;
         mUi = new AutoFillUI(context, this, mLock);
         mResolver = context.getContentResolver();
@@ -139,14 +146,6 @@
         if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
             new SettingsObserver(BackgroundThread.getHandler());
         }
-        if (phase == PHASE_BOOT_COMPLETED) {
-            // TODO: if sent right away, the notification is not displayed. Since the notification
-            // mechanism is a temporary approach anyways, just delay it..
-            if (DEBUG)
-                Slog.d(TAG, "Showing notifications in " + SHOW_ALL_NOTIFICATIONS_DELAY_MS + "ms");
-            mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SHOW_ALL_NOTIFICATIONS),
-                    SHOW_ALL_NOTIFICATIONS_DELAY_MS);
-        }
     }
 
     private AutoFillManagerServiceImpl newServiceForUser(int userId) {
@@ -200,7 +199,7 @@
         }
         // Keep service connection alive for a while, in case user needs to interact with it
         // (for example, to save the data that was inputted in)
-        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_UNBIND, userId, ARG_NOT_USED),
+        mHandlerCaller.sendMessageDelayed(mHandlerCaller.obtainMessageI(MSG_UNBIND, userId),
                 SERVICE_BINDING_LIFETIME_MS);
         return service;
     }
@@ -245,18 +244,41 @@
 
     }
 
+
+    private void requestAutoFillLocked(IBinder activityToken, int userId, Bundle extras,
+            int flags) {
+        final AutoFillManagerServiceImpl service = getServiceForUserLocked(userId);
+        if (service != null) {
+            service.requestAutoFill(activityToken, extras, flags);
+        }
+    }
+
+    private void showAutoFillInput(int userId, AutoFillId id, Rect rect) {
+        if (DEBUG) Slog.d(TAG, "handler.showAutoFillInput(): id=" + id + ", rect=" + rect);
+
+        synchronized (mLock) {
+            requestAutoFillLocked(null, userId, null, AUTO_FILL_FLAG_TYPE_FILL);
+        }
+    }
+
     final class AutoFillManagerServiceStub extends IAutoFillManagerService.Stub {
 
         @Override
+        public void showAutoFillInput(AutoFillId id, Rect boundaries) {
+            if (DEBUG) Slog.d(TAG, "showAutoFillInput(): id=" + id + ", boundaries=" + boundaries);
+
+            // TODO(b/33197203): fail if it's not called by same uid as the top activity
+            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIOO(MSG_SHOW_AUTO_FILL,
+                    UserHandle.getCallingUserId(), id, boundaries));
+        }
+
+        @Override
         public void requestAutoFill(IBinder activityToken, int userId, Bundle extras, int flags) {
             if (DEBUG) Slog.d(TAG, "requestAutoFill: flags=" + flags + ", userId=" + userId);
             mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
 
             synchronized (mLock) {
-                final AutoFillManagerServiceImpl service = getServiceForUserLocked(userId);
-                if (service != null) {
-                    service.requestAutoFill(activityToken, extras, flags);
-                }
+                requestAutoFillLocked(activityToken, userId, extras, flags);
             }
         }
 
@@ -307,7 +329,6 @@
             if (DEBUG) Slog.d(TAG, "settings (" + uri + " changed for " + userId);
             synchronized (mLock) {
                 removeCachedServiceForUserLocked(userId);
-                mUi.updateNotification(userId);
             }
         }
     }
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
index ae21b07..83faf1b 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
@@ -163,7 +163,6 @@
             }
             final AssistStructure structure = resultData
                     .getParcelable(VoiceInteractionSession.KEY_STRUCTURE);
-            final Bundle data = resultData.getBundle(VoiceInteractionSession.KEY_RECEIVER_EXTRAS);
             final int flags = resultData.getInt(VoiceInteractionSession.KEY_FLAGS, 0);
 
             final ServerCallback serverCallback;
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/AutoFillUI.java
index 08e81d3..6fafd5d 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillUI.java
@@ -16,40 +16,29 @@
 package com.android.server.autofill;
 
 import static android.view.View.AUTO_FILL_FLAG_TYPE_SAVE;
-import static android.view.View.AUTO_FILL_FLAG_TYPE_FILL;
 
 import static com.android.server.autofill.AutoFillManagerService.DEBUG;
 
 import android.app.Activity;
-import android.app.AppGlobals;
 import android.app.Notification;
 import android.app.Notification.Action;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ServiceInfo;
-import android.content.pm.UserInfo;
 import android.os.Binder;
 import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.UserManager;
-import android.provider.Settings;
 import android.service.autofill.AutoFillService;
-import android.text.TextUtils;
 import android.util.Log;
 import android.util.Slog;
-import android.view.autofill.Dataset;
 import android.view.autofill.AutoFillId;
+import android.view.autofill.Dataset;
 import android.view.autofill.FillResponse;
 import android.widget.Toast;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.server.UiThread;
 
 import java.util.Arrays;
@@ -69,9 +58,10 @@
 
     AutoFillUI(Context context, AutoFillManagerService service, Object lock) {
         mContext = context;
-        mResolver = context.getContentResolver();
         mService = service;
         mLock = lock;
+
+        setNotificationListener();
     }
 
     /**
@@ -121,56 +111,60 @@
     private static final String EXTRA_FILL_RESPONSE = "fill_response";
     private static final String EXTRA_DATASET = "dataset";
 
-    private static final String TYPE_EMULATE = "emulate";
     private static final String TYPE_OPTIONS = "options";
     private static final String TYPE_DELETE_CALLBACK = "delete_callback";
     private static final String TYPE_PICK_DATASET = "pick_dataset";
     private static final String TYPE_SAVE = "save";
 
-    static final int MSG_SHOW_ALL_NOTIFICATIONS = 42;
-    static final int SHOW_ALL_NOTIFICATIONS_DELAY_MS = 5000;
-
+    @GuardedBy("mLock")
     private BroadcastReceiver mNotificationReceiver;
-    private final ContentResolver mResolver;
+    @GuardedBy("mLock")
     private final AutoFillManagerService mService;
     private final Object mLock;
 
     // Hack used to generate unique pending intents
     static int sResultCode = 0;
 
+    private void setNotificationListener() {
+        synchronized (mLock) {
+            if (mNotificationReceiver == null) {
+                mNotificationReceiver = new NotificationReceiver();
+                mContext.registerReceiver(mNotificationReceiver,
+                        new IntentFilter(NOTIFICATION_AUTO_FILL_INTENT));
+            }
+        }
+    }
+
     final class NotificationReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
             final int userId = intent.getIntExtra(EXTRA_USER_ID, -1);
 
-            final AutoFillManagerServiceImpl service = mService.getServiceForUserLocked(userId);
-            if (service == null) {
-                Slog.w(TAG, "no auto-fill service for user " + userId);
-                return;
-            }
-
-            final int callbackId = intent.getIntExtra(EXTRA_CALLBACK_ID, -1);
-            final String type = intent.getStringExtra(EXTRA_NOTIFICATION_TYPE);
-            if (type == null) {
-                Slog.wtf(TAG, "No extra " + EXTRA_NOTIFICATION_TYPE + " on intent " + intent);
-                return;
-            }
-            final FillResponse fillData = intent.getParcelableExtra(EXTRA_FILL_RESPONSE);
-            final Dataset dataset = intent.getParcelableExtra(EXTRA_DATASET);
-            final Bundle datasetArgs = dataset == null ? null : dataset.getExtras();
-            final Bundle fillDataArgs = fillData == null ? null : fillData.getExtras();
-
-            // Bundle sent on AutoFillService methods - only set if service provided a bundle
-            final Bundle extras = (datasetArgs == null && fillDataArgs == null)
-                    ? null : new Bundle();
-
-            if (DEBUG) Slog.d(TAG, "Notification received: type=" + type + ", userId=" + userId
-                    + ", callbackId=" + callbackId);
             synchronized (mLock) {
+                final AutoFillManagerServiceImpl service = mService.getServiceForUserLocked(userId);
+                if (service == null) {
+                    Slog.w(TAG, "no auto-fill service for user " + userId);
+                    return;
+                }
+
+                final int callbackId = intent.getIntExtra(EXTRA_CALLBACK_ID, -1);
+                final String type = intent.getStringExtra(EXTRA_NOTIFICATION_TYPE);
+                if (type == null) {
+                    Slog.wtf(TAG, "No extra " + EXTRA_NOTIFICATION_TYPE + " on intent " + intent);
+                    return;
+                }
+                final FillResponse fillData = intent.getParcelableExtra(EXTRA_FILL_RESPONSE);
+                final Dataset dataset = intent.getParcelableExtra(EXTRA_DATASET);
+                final Bundle datasetArgs = dataset == null ? null : dataset.getExtras();
+                final Bundle fillDataArgs = fillData == null ? null : fillData.getExtras();
+
+                // Bundle sent on AutoFillService methods - only set if service provided a bundle
+                final Bundle extras = (datasetArgs == null && fillDataArgs == null)
+                        ? null : new Bundle();
+
+                if (DEBUG) Slog.d(TAG, "Notification received: type=" + type + ", userId=" + userId
+                        + ", callbackId=" + callbackId);
                 switch (type) {
-                    case TYPE_EMULATE:
-                        service.requestAutoFill(null, extras, AUTO_FILL_FLAG_TYPE_FILL);
-                        break;
                     case TYPE_SAVE:
                         if (datasetArgs != null) {
                             if (DEBUG) Log.d(TAG, "filldata args on save notificataion: " +
@@ -210,54 +204,6 @@
         }
     }
 
-    private ComponentName getProviderForUser(int userId) {
-        ComponentName serviceComponent = null;
-        ServiceInfo serviceInfo = null;
-        final String componentName = Settings.Secure.getStringForUser(
-                mResolver, Settings.Secure.AUTO_FILL_SERVICE, userId);
-        if (!TextUtils.isEmpty(componentName)) {
-            try {
-                serviceComponent = ComponentName.unflattenFromString(componentName);
-                serviceInfo =
-                        AppGlobals.getPackageManager().getServiceInfo(serviceComponent, 0, userId);
-            } catch (RuntimeException | RemoteException e) {
-                Slog.wtf(TAG, "Bad auto-fill service name " + componentName, e);
-                return null;
-            }
-        }
-
-        if (DEBUG) Slog.d(TAG, "getServiceComponentForUser(" + userId + "): component="
-                + serviceComponent + ", info: " + serviceInfo);
-        if (serviceInfo == null) {
-            Slog.w(TAG, "no service info for " + serviceComponent);
-            return null;
-        }
-        return serviceComponent;
-    }
-
-    void showAllNotifications() {
-        final UserManager userManager =
-                (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-
-        final List<UserInfo> allUsers = userManager.getUsers(true);
-
-        for (UserInfo user : allUsers) {
-            final ComponentName serviceComponent = getProviderForUser(user.id);
-            if (serviceComponent != null) {
-                showMainNotification(serviceComponent, user.id);
-            }
-        }
-    }
-
-    void updateNotification(int userId) {
-        final ComponentName serviceComponent = getProviderForUser(userId);
-        if (serviceComponent == null) {
-            cancelMainNotification(userId);
-        } else {
-            showMainNotification(serviceComponent, userId);
-        }
-    }
-
     private static Intent newNotificationIntent(int userId, String type) {
         final Intent intent = new Intent(NOTIFICATION_AUTO_FILL_INTENT);
         intent.putExtra(EXTRA_USER_ID, userId);
@@ -296,65 +242,6 @@
     }
 
     /**
-     * Shows a permanent notification that triggers the auto-fill workflow for the given user.
-     *
-     * <p>It emulates calling the auto-fill service when the IME is shown.
-     */
-    private void showMainNotification(ComponentName serviceComponent, int userId) {
-        if (DEBUG) Log.d(TAG, "showNotification() for " + userId + ": " + serviceComponent);
-
-        synchronized (mLock) {
-            if (mNotificationReceiver == null) {
-                mNotificationReceiver = new NotificationReceiver();
-                mContext.registerReceiver(mNotificationReceiver,
-                        new IntentFilter(NOTIFICATION_AUTO_FILL_INTENT));
-            }
-        }
-
-        final Intent fillIntent = newNotificationIntent(userId, TYPE_EMULATE);
-        final PendingIntent fillPendingIntent = PendingIntent.getBroadcast(mContext,
-                -1, fillIntent, PendingIntent.FLAG_UPDATE_CURRENT);
-
-        final String packageName = serviceComponent.getPackageName();
-        String providerName = null;
-        final PackageManager pm = mContext.getPackageManager();
-        try {
-            final ApplicationInfo info = pm.getApplicationInfoAsUser(packageName, 0, userId);
-            if (info != null) {
-                providerName = pm.getApplicationLabel(info).toString();
-            }
-        } catch (Exception e) {
-            providerName = packageName;
-        }
-        final String title = "AutoFill IME Emulation";
-        final String subTitle = "Tap notification to start auto-fill workflow (by '" + providerName
-                + "' on top activity on user " + userId + ".\n"
-                + "Once provider replies, a new notification will show your options.";
-
-        final Notification notification = new Notification.Builder(mContext)
-                .setCategory(Notification.CATEGORY_SYSTEM)
-                .setOngoing(true)
-                .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
-                .setLocalOnly(true)
-                .setColor(mContext.getColor(
-                        com.android.internal.R.color.system_notification_accent_color))
-                .setContentTitle(title)
-                .setStyle(new Notification.BigTextStyle().bigText(subTitle))
-                .setContentIntent(fillPendingIntent)
-                .build();
-        NotificationManager.from(mContext).notify(TYPE_EMULATE, userId, notification);
-    }
-
-    /**
-     * Cancels the permament notification created by
-     * {@link #showMainNotification(ComponentName, int)}.
-     */
-    private void cancelMainNotification(int userId) {
-        if (DEBUG) Log.d(TAG, "cancelNotificationLocked(): " + userId);
-        NotificationManager.from(mContext).cancel(TYPE_EMULATE, userId);
-    }
-
-    /**
      * Shows a notification with the results of an auto-fill request, using notications actions
      * to emulate the auto-fill bar buttons displaying the dataset names.
      */
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 0e07ec0..b1560e6 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -275,7 +275,7 @@
                 } catch (IllegalArgumentException e) {
                     // Failed to parse the settings string, log this and move on
                     // with defaults.
-                    Slog.e(TAG, "Bad device idle settings", e);
+                    Slog.e(TAG, "Bad alarm manager settings", e);
                 }
 
                 MIN_FUTURITY = mParser.getLong(KEY_MIN_FUTURITY, DEFAULT_MIN_FUTURITY);
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 440ac90..8f99127 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -45,12 +45,16 @@
 import android.service.dreams.Sandman;
 import android.service.vr.IVrManager;
 import android.service.vr.IVrStateCallbacks;
+import android.text.TextUtils;
 import android.util.Slog;
 import android.view.WindowManagerInternal;
 import android.view.WindowManagerPolicy;
 
+import java.io.File;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
 
 import com.android.internal.R;
 import com.android.internal.app.DisableCarModeActivity;
@@ -343,6 +347,28 @@
         }
 
         @Override
+        public String[] getAvailableThemes() {
+            if (getContext().checkCallingOrSelfPermission(
+                    android.Manifest.permission.MODIFY_THEME_OVERLAY)
+                    != PackageManager.PERMISSION_GRANTED) {
+                Slog.e(TAG, "getAvailableThemes requires MODIFY_THEME_OVERLAY permission");
+                return null;
+            }
+            String def = SystemProperties.get("ro.boot.vendor.overlay.theme");
+            if (TextUtils.isEmpty(def)) {
+                def = null;
+            }
+            String[] fileList = new File("/vendor/overlay").list();
+            if (fileList == null) return new String[0];
+            ArrayList<String> options = new ArrayList(fileList.length + 1);
+            Collections.addAll(options, fileList);
+            if (!options.contains(def)) {
+                options.add(0, def);
+            }
+            return options.toArray(new String[options.size()]);
+        }
+
+        @Override
         public int getNightMode() {
             synchronized (mLock) {
                 return mNightMode;
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
new file mode 100644
index 0000000..3c90f93
--- /dev/null
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -0,0 +1,157 @@
+/*
+ * 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.
+ */
+
+package com.android.server.am;
+
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.SystemProperties;
+import android.provider.Settings;
+import android.util.KeyValueListParser;
+import android.util.Slog;
+
+import java.io.PrintWriter;
+
+/**
+ * Settings constants that can modify the activity manager's behavior.
+ */
+final class ActivityManagerConstants extends ContentObserver {
+    // Key names stored in the settings value.
+    private static final String KEY_ENFORCE_BG_CHECK = "enforce_bg_check";
+    private static final String KEY_MAX_CACHED_PROCESSES = "max_cached_processes";
+
+    private static final boolean DEFAULT_ENFORCE_BG_CHECK = SystemProperties.getBoolean(
+            "debug.bgcheck", false);
+    private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
+
+    // Enforce background check on apps targeting O?
+    public boolean ENFORCE_BG_CHECK = DEFAULT_ENFORCE_BG_CHECK;
+
+    // Maximum number of cached processes we will allow.
+    public int MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES;
+
+    private final ActivityManagerService mService;
+    private ContentResolver mResolver;
+    private final KeyValueListParser mParser = new KeyValueListParser(',');
+
+    private int mOverrideMaxCachedProcesses = -1;
+
+    // The maximum number of cached processes we will keep around before killing them.
+    // NOTE: this constant is *only* a control to not let us go too crazy with
+    // keeping around processes on devices with large amounts of RAM.  For devices that
+    // are tighter on RAM, the out of memory killer is responsible for killing background
+    // processes as RAM is needed, and we should *never* be relying on this limit to
+    // kill them.  Also note that this limit only applies to cached background processes;
+    // we have no limit on the number of service, visible, foreground, or other such
+    // processes and the number of those processes does not count against the cached
+    // process limit.
+    public int CUR_MAX_CACHED_PROCESSES;
+
+    // The maximum number of empty app processes we will let sit around.
+    public int CUR_MAX_EMPTY_PROCESSES;
+
+    // The number of empty apps at which we don't consider it necessary to do
+    // memory trimming.
+    public int CUR_TRIM_EMPTY_PROCESSES;
+
+    // The number of cached at which we don't consider it necessary to do
+    // memory trimming.
+    public int CUR_TRIM_CACHED_PROCESSES;
+
+    public ActivityManagerConstants(ActivityManagerService service, Handler handler) {
+        super(handler);
+        mService = service;
+        updateMaxCachedProcesses();
+    }
+
+    public void start(ContentResolver resolver) {
+        mResolver = resolver;
+        mResolver.registerContentObserver(Settings.Global.getUriFor(
+                Settings.Global.ACTIVITY_MANAGER_CONSTANTS), false, this);
+        updateConstants();
+    }
+
+    public void setOverrideMaxCachedProcesses(int value) {
+        mOverrideMaxCachedProcesses = value;
+        updateMaxCachedProcesses();
+    }
+
+    public int getOverrideMaxCachedProcesses() {
+        return mOverrideMaxCachedProcesses;
+    }
+
+    public static int computeEmptyProcessLimit(int totalProcessLimit) {
+        return totalProcessLimit/2;
+    }
+
+    @Override
+    public void onChange(boolean selfChange, Uri uri) {
+        updateConstants();
+    }
+
+    private void updateConstants() {
+        synchronized (mService) {
+            try {
+                mParser.setString(Settings.Global.getString(mResolver,
+                        Settings.Global.ACTIVITY_MANAGER_CONSTANTS));
+            } catch (IllegalArgumentException e) {
+                // Failed to parse the settings string, log this and move on
+                // with defaults.
+                Slog.e("ActivityManagerConstants", "Bad activity manager config settings", e);
+            }
+
+            ENFORCE_BG_CHECK = mParser.getBoolean(KEY_ENFORCE_BG_CHECK, DEFAULT_ENFORCE_BG_CHECK);
+            MAX_CACHED_PROCESSES = mParser.getInt(KEY_MAX_CACHED_PROCESSES,
+                    DEFAULT_MAX_CACHED_PROCESSES);
+            updateMaxCachedProcesses();
+        }
+    }
+
+    private void updateMaxCachedProcesses() {
+        CUR_MAX_CACHED_PROCESSES = mOverrideMaxCachedProcesses < 0
+                ? MAX_CACHED_PROCESSES : mOverrideMaxCachedProcesses;
+        CUR_MAX_EMPTY_PROCESSES = computeEmptyProcessLimit(CUR_MAX_CACHED_PROCESSES);
+
+        // Note the trim levels do NOT depend on the override process limit, we want
+        // to consider the same level the point where we do trimming regardless of any
+        // additional enforced limit.
+        final int rawMaxEmptyProcesses = computeEmptyProcessLimit(MAX_CACHED_PROCESSES);
+        CUR_TRIM_EMPTY_PROCESSES = rawMaxEmptyProcesses/2;
+        CUR_TRIM_CACHED_PROCESSES = (MAX_CACHED_PROCESSES-rawMaxEmptyProcesses)/3;
+    }
+
+    void dump(PrintWriter pw) {
+        pw.println("ACTIVITY MANAGER SETTINGS (dumpsys activity settings) "
+                + Settings.Global.ACTIVITY_MANAGER_CONSTANTS + ":");
+
+        pw.print("  "); pw.print(KEY_ENFORCE_BG_CHECK); pw.print("=");
+        pw.println(ENFORCE_BG_CHECK);
+
+        pw.print("  "); pw.print(KEY_MAX_CACHED_PROCESSES); pw.print("=");
+        pw.println(MAX_CACHED_PROCESSES);
+
+        pw.println();
+        if (mOverrideMaxCachedProcesses >= 0) {
+            pw.print("  mOverrideMaxCachedProcesses="); pw.println(mOverrideMaxCachedProcesses);
+        }
+        pw.print("  CUR_MAX_CACHED_PROCESSES="); pw.println(CUR_MAX_CACHED_PROCESSES);
+        pw.print("  CUR_MAX_EMPTY_PROCESSES="); pw.println(CUR_MAX_EMPTY_PROCESSES);
+        pw.print("  CUR_TRIM_EMPTY_PROCESSES="); pw.println(CUR_TRIM_EMPTY_PROCESSES);
+        pw.print("  CUR_TRIM_CACHED_PROCESSES="); pw.println(CUR_TRIM_CACHED_PROCESSES);
+    }
+}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a5742c2..43afbd1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -761,11 +761,6 @@
     ProcessRecord mHeavyWeightProcess = null;
 
     /**
-     * Are we enforcing background restrictions?
-     */
-    final boolean mEnforceBackgroundCheck;
-
-    /**
      * Non-persistent app uid whitelist for background restrictions
      */
     int[] mBackgroundUidWhitelist = new int[] {
@@ -1515,9 +1510,6 @@
      */
     boolean mBooted = false;
 
-    int mProcessLimit = ProcessList.MAX_CACHED_APPS;
-    int mProcessLimitOverride = -1;
-
     WindowManagerService mWindowManager;
     final ActivityThread mSystemThread;
 
@@ -1639,6 +1631,8 @@
     final MainHandler mHandler;
     final UiHandler mUiHandler;
 
+    final ActivityManagerConstants mConstants;
+
     PackageManagerInternal mPackageManagerInt;
 
     // VoiceInteraction session ID that changes for each new request except when
@@ -2620,10 +2614,9 @@
         mPermissionReviewRequired = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_permissionReviewRequired);
 
-        mEnforceBackgroundCheck = SystemProperties.getBoolean("debug.bgcheck", false);
         mBackgroundLaunchBroadcasts = SystemConfig.getInstance().getAllowImplicitBroadcasts();
         if (DEBUG_BACKGROUND_CHECK) {
-            Slog.d(TAG, "Enforcing O+ bg restrictions: " + mEnforceBackgroundCheck);
+            Slog.d(TAG, "Enforcing O+ bg restrictions: " + mConstants.ENFORCE_BG_CHECK);
             StringBuilder sb = new StringBuilder(200);
             sb.append("  ");
             for (String a : mBackgroundLaunchBroadcasts) {
@@ -2639,6 +2632,8 @@
         mHandler = new MainHandler(mHandlerThread.getLooper());
         mUiHandler = new UiHandler();
 
+        mConstants = new ActivityManagerConstants(this, mHandler);
+
         /* static; one-time init here */
         if (sKillHandler == null) {
             sKillThread = new ServiceThread(TAG + ":kill",
@@ -7276,9 +7271,6 @@
 
     /**
      * Whitelists {@code targetUid} to temporarily bypass Power Save mode.
-     *
-     * <p>{@code callerUid} must be allowed to request such whitelist by calling
-     * {@link #addTempPowerSaveWhitelistGrantorUid(int)}.
      */
     void tempWhitelistAppForPowerSave(int callerPid, int callerUid, int targetUid, long duration) {
         if (DEBUG_WHITELISTS) {
@@ -7470,8 +7462,7 @@
         enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
                 "setProcessLimit()");
         synchronized (this) {
-            mProcessLimit = max < 0 ? ProcessList.MAX_CACHED_APPS : max;
-            mProcessLimitOverride = max;
+            mConstants.setOverrideMaxCachedProcesses(max);
         }
         trimApplications();
     }
@@ -7479,7 +7470,7 @@
     @Override
     public int getProcessLimit() {
         synchronized (this) {
-            return mProcessLimitOverride;
+            return mConstants.getOverrideMaxCachedProcesses();
         }
     }
 
@@ -8034,7 +8025,7 @@
     // Unified app-op and target sdk check
     int appRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) {
         // Apps that target O+ are always subject to background check
-        if (mEnforceBackgroundCheck && packageTargetSdk >= Build.VERSION_CODES.O) {
+        if (mConstants.ENFORCE_BG_CHECK && packageTargetSdk >= Build.VERSION_CODES.O) {
             if (DEBUG_BACKGROUND_CHECK) {
                 Slog.i(TAG, "App " + uid + "/" + packageName + " targets O+, restricted");
             }
@@ -11559,6 +11550,7 @@
             mSystemThread.installSystemProviders(providers);
         }
 
+        mConstants.start(mContext.getContentResolver());
         mCoreSettingsObserver = new CoreSettingsObserver(this);
         mFontScaleSettingObserver = new FontScaleSettingObserver();
 
@@ -14493,6 +14485,10 @@
                 synchronized (this) {
                     dumpAssociationsLocked(fd, pw, args, opti, true, dumpClient, dumpPackage);
                 }
+            } else if ("settings".equals(cmd)) {
+                synchronized (this) {
+                    mConstants.dump(pw);
+                }
             } else if ("services".equals(cmd) || "s".equals(cmd)) {
                 if (dumpClient) {
                     ActiveServices.ServiceDumper dumper;
@@ -14533,6 +14529,11 @@
         } else if (dumpClient) {
             ActiveServices.ServiceDumper sdumper;
             synchronized (this) {
+                mConstants.dump(pw);
+                pw.println();
+                if (dumpAll) {
+                    pw.println("-------------------------------------------------------------------------------");
+                }
                 dumpPendingIntentsLocked(fd, pw, args, opti, dumpAll, dumpPackage);
                 pw.println();
                 if (dumpAll) {
@@ -14591,6 +14592,11 @@
 
         } else {
             synchronized (this) {
+                mConstants.dump(pw);
+                pw.println();
+                if (dumpAll) {
+                    pw.println("-------------------------------------------------------------------------------");
+                }
                 dumpPendingIntentsLocked(fd, pw, args, opti, dumpAll, dumpPackage);
                 pw.println();
                 if (dumpAll) {
@@ -21392,17 +21398,8 @@
         mNewNumServiceProcs = 0;
         mNewNumAServiceProcs = 0;
 
-        final int emptyProcessLimit;
-        final int cachedProcessLimit;
-        if (mProcessLimit <= 0) {
-            emptyProcessLimit = cachedProcessLimit = 0;
-        } else if (mProcessLimit == 1) {
-            emptyProcessLimit = 1;
-            cachedProcessLimit = 0;
-        } else {
-            emptyProcessLimit = ProcessList.computeEmptyProcessLimit(mProcessLimit);
-            cachedProcessLimit = mProcessLimit - emptyProcessLimit;
-        }
+        final int emptyProcessLimit = mConstants.CUR_MAX_EMPTY_PROCESSES;
+        final int cachedProcessLimit = mConstants.CUR_MAX_CACHED_PROCESSES - emptyProcessLimit;
 
         // Let's determine how many processes we have running vs.
         // how many slots we have for background processes; we may want
@@ -21510,7 +21507,7 @@
                         }
                         break;
                     case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
-                        if (numEmpty > ProcessList.TRIM_EMPTY_APPS
+                        if (numEmpty > mConstants.CUR_TRIM_EMPTY_PROCESSES
                                 && app.lastActivityTime < oldTime) {
                             app.kill("empty for "
                                     + ((oldTime + ProcessList.MAX_EMPTY_TIME - app.lastActivityTime)
@@ -21563,8 +21560,8 @@
         // memory they want.
         final int numCachedAndEmpty = numCached + numEmpty;
         int memFactor;
-        if (numCached <= ProcessList.TRIM_CACHED_APPS
-                && numEmpty <= ProcessList.TRIM_EMPTY_APPS) {
+        if (numCached <= mConstants.CUR_TRIM_CACHED_PROCESSES
+                && numEmpty <= mConstants.CUR_TRIM_EMPTY_PROCESSES) {
             if (numCachedAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) {
                 memFactor = ProcessStats.ADJ_MEM_FACTOR_CRITICAL;
             } else if (numCachedAndEmpty <= ProcessList.TRIM_LOW_THRESHOLD) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 1a2a31b..df8dd6b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -2406,6 +2406,7 @@
             pw.println("    provider [COMP_SPEC]: provider client-side state");
             pw.println("    s[ervices] [COMP_SPEC ...]: service state");
             pw.println("    as[sociations]: tracked app associations");
+            pw.println("    settings: currently applied config settings");
             pw.println("    service [COMP_SPEC]: service client-side state");
             pw.println("    package [PACKAGE_NAME]: all state related to given package");
             pw.println("    all: dump all activities");
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 973951e..98b5835c 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -557,6 +557,7 @@
     void getWindowContainerBounds(Rect outBounds) {
         if (mWindowContainerController != null) {
             mWindowContainerController.getBounds(outBounds);
+            return;
         }
         outBounds.setEmpty();
     }
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 1322ecf..40effff 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -138,31 +138,9 @@
     // without empty apps being able to push them out of memory.
     static final int MIN_CACHED_APPS = 2;
 
-    // The maximum number of cached processes we will keep around before killing them.
-    // NOTE: this constant is *only* a control to not let us go too crazy with
-    // keeping around processes on devices with large amounts of RAM.  For devices that
-    // are tighter on RAM, the out of memory killer is responsible for killing background
-    // processes as RAM is needed, and we should *never* be relying on this limit to
-    // kill them.  Also note that this limit only applies to cached background processes;
-    // we have no limit on the number of service, visible, foreground, or other such
-    // processes and the number of those processes does not count against the cached
-    // process limit.
-    static final int MAX_CACHED_APPS = 32;
-
     // We allow empty processes to stick around for at most 30 minutes.
     static final long MAX_EMPTY_TIME = 30*60*1000;
 
-    // The maximum number of empty app processes we will let sit around.
-    private static final int MAX_EMPTY_APPS = computeEmptyProcessLimit(MAX_CACHED_APPS);
-
-    // The number of empty apps at which we don't consider it necessary to do
-    // memory trimming.
-    static final int TRIM_EMPTY_APPS = MAX_EMPTY_APPS/2;
-
-    // The number of cached at which we don't consider it necessary to do
-    // memory trimming.
-    static final int TRIM_CACHED_APPS = (MAX_CACHED_APPS-MAX_EMPTY_APPS)/3;
-
     // Threshold of number of cached+empty where we consider memory critical.
     static final int TRIM_CRITICAL_THRESHOLD = 3;
 
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index 8d4f0a9..5fed397 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -40,6 +40,7 @@
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Slog;
@@ -50,18 +51,106 @@
 import java.util.HashSet;
 import java.util.List;
 
+import java.lang.Thread;
+import java.lang.Runnable;
+import java.lang.InterruptedException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+// The following class is Android Emulator specific. It is used to read and
+// write contents of the host system's clipboard.
+class HostClipboardMonitor implements Runnable {
+    public interface HostClipboardCallback {
+        void onHostClipboardUpdated(String contents);
+    }
+
+    private RandomAccessFile mPipe = null;
+    private HostClipboardCallback mHostClipboardCallback;
+    private static final String PIPE_NAME = "pipe:clipboard";
+    private static final String PIPE_DEVICE = "/dev/qemu_pipe";
+
+    private void openPipe() {
+        try {
+            // String.getBytes doesn't include the null terminator,
+            // but the QEMU pipe device requires the pipe service name
+            // to be null-terminated.
+            byte[] b = new byte[PIPE_NAME.length() + 1];
+            b[PIPE_NAME.length()] = 0;
+            System.arraycopy(
+                PIPE_NAME.getBytes(),
+                0,
+                b,
+                0,
+                PIPE_NAME.length());
+            mPipe = new RandomAccessFile(PIPE_DEVICE, "rw");
+            mPipe.write(b);
+        } catch (IOException e) {
+            try {
+                if (mPipe != null) mPipe.close();
+            } catch (IOException ee) {}
+            mPipe = null;
+        }
+    }
+
+    public HostClipboardMonitor(HostClipboardCallback cb) {
+        mHostClipboardCallback = cb;
+    }
+
+    @Override
+    public void run() {
+        while(!Thread.interrupted()) {
+            try {
+                // There's no guarantee that QEMU pipes will be ready at the moment
+                // this method is invoked. We simply try to get the pipe open and
+                // retry on failure indefinitely.
+                while (mPipe == null) {
+                    openPipe();
+                    Thread.sleep(100);
+                }
+                int size = mPipe.readInt();
+                size = Integer.reverseBytes(size);
+                byte[] receivedData = new byte[size];
+                mPipe.readFully(receivedData);
+                mHostClipboardCallback.onHostClipboardUpdated(
+                    new String(receivedData));
+            } catch (IOException e) {
+                try {
+                    mPipe.close();
+                } catch (IOException ee) {}
+                mPipe = null;
+            } catch (InterruptedException e) {}
+        }
+    }
+
+    public void setHostClipboard(String content) {
+        try {
+            if (mPipe != null) {
+                mPipe.writeInt(Integer.reverseBytes(content.getBytes().length));
+                mPipe.write(content.getBytes());
+            }
+        } catch(IOException e) {
+            Slog.e("HostClipboardMonitor",
+                   "Failed to set host clipboard " + e.getMessage());
+        }
+    }
+}
+
 /**
  * Implementation of the clipboard for copy and paste.
  */
 public class ClipboardService extends SystemService {
 
     private static final String TAG = "ClipboardService";
+    private static final boolean IS_EMULATOR =
+        SystemProperties.getBoolean("ro.kernel.qemu", false);
 
     private final IActivityManager mAm;
     private final IUserManager mUm;
     private final PackageManager mPm;
     private final AppOpsManager mAppOps;
     private final IBinder mPermissionOwner;
+    private HostClipboardMonitor mHostClipboardMonitor = null;
+    private Thread mHostMonitorThread = null;
 
     private final SparseArray<PerUserClipboard> mClipboards = new SparseArray<>();
 
@@ -82,6 +171,23 @@
             Slog.w("clipboard", "AM dead", e);
         }
         mPermissionOwner = permOwner;
+        if (IS_EMULATOR) {
+            mHostClipboardMonitor = new HostClipboardMonitor(
+                new HostClipboardMonitor.HostClipboardCallback() {
+                    @Override
+                    public void onHostClipboardUpdated(String contents){
+                        ClipData clip =
+                            new ClipData("host clipboard",
+                                         new String[]{"text/plain"},
+                                         new ClipData.Item(contents));
+                        synchronized(mClipboards) {
+                            setPrimaryClipInternal(getClipboard(0), clip);
+                        }
+                    }
+                });
+            mHostMonitorThread = new Thread(mHostClipboardMonitor);
+            mHostMonitorThread.start();
+        }
     }
 
     @Override
@@ -142,6 +248,11 @@
                 if (clip != null && clip.getItemCount() <= 0) {
                     throw new IllegalArgumentException("No items");
                 }
+                if (clip.getItemAt(0).getText() != null &&
+                    mHostClipboardMonitor != null) {
+                    mHostClipboardMonitor.setHostClipboard(
+                        clip.getItemAt(0).getText().toString());
+                }
                 final int callingUid = Binder.getCallingUid();
                 if (mAppOps.noteOp(AppOpsManager.OP_WRITE_CLIPBOARD, callingUid,
                         callingPackage) != AppOpsManager.MODE_ALLOWED) {
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index e1b6c87..238866a 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -57,6 +57,7 @@
 import android.service.vr.IVrManager;
 import android.service.vr.IVrStateCallbacks;
 import android.util.EventLog;
+import android.util.KeyValueListParser;
 import android.util.Log;
 import android.util.PrintWriterPrinter;
 import android.util.Slog;
@@ -522,6 +523,65 @@
     // True if we are currently in VR Mode.
     private boolean mIsVrModeEnabled;
 
+    /**
+     * All times are in milliseconds. These constants are kept synchronized with the system
+     * global Settings. Any access to this class or its fields should be done while
+     * holding the PowerManagerService.mLock lock.
+     */
+    private final class Constants extends ContentObserver {
+        // Key names stored in the settings value.
+        private static final String KEY_NO_CACHED_WAKE_LOCKS = "no_cached_wake_locks";
+
+        private static final boolean DEFAULT_NO_CACHED_WAKE_LOCKS = true;
+
+        // Prevent processes that are cached from holding wake locks?
+        public boolean NO_CACHED_WAKE_LOCKS = DEFAULT_NO_CACHED_WAKE_LOCKS;
+
+        private ContentResolver mResolver;
+        private final KeyValueListParser mParser = new KeyValueListParser(',');
+
+        public Constants(Handler handler) {
+            super(handler);
+        }
+
+        public void start(ContentResolver resolver) {
+            mResolver = resolver;
+            mResolver.registerContentObserver(Settings.Global.getUriFor(
+                    Settings.Global.POWER_MANAGER_CONSTANTS), false, this);
+            updateConstants();
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            updateConstants();
+        }
+
+        private void updateConstants() {
+            synchronized (mLock) {
+                try {
+                    mParser.setString(Settings.Global.getString(mResolver,
+                            Settings.Global.POWER_MANAGER_CONSTANTS));
+                } catch (IllegalArgumentException e) {
+                    // Failed to parse the settings string, log this and move on
+                    // with defaults.
+                    Slog.e(TAG, "Bad alarm manager settings", e);
+                }
+
+                NO_CACHED_WAKE_LOCKS = mParser.getBoolean(KEY_NO_CACHED_WAKE_LOCKS,
+                        DEFAULT_NO_CACHED_WAKE_LOCKS);
+            }
+        }
+
+        void dump(PrintWriter pw) {
+            pw.println("  Settings " + Settings.Global.POWER_MANAGER_CONSTANTS + ":");
+
+            pw.print("    "); pw.print(KEY_NO_CACHED_WAKE_LOCKS); pw.print("=");
+            pw.println(NO_CACHED_WAKE_LOCKS);
+        }
+    }
+
+    final Constants mConstants;
+
     private native void nativeInit();
 
     private static native void nativeAcquireSuspendBlocker(String name);
@@ -538,6 +598,7 @@
                 Process.THREAD_PRIORITY_DISPLAY, false /*allowIo*/);
         mHandlerThread.start();
         mHandler = new PowerManagerHandler(mHandlerThread.getLooper());
+        mConstants = new Constants(mHandler);
 
         synchronized (mLock) {
             mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService.WakeLocks");
@@ -616,6 +677,9 @@
                     mAppOps, createSuspendBlockerLocked("PowerManagerService.Broadcasts"),
                     mPolicy);
 
+            final ContentResolver resolver = mContext.getContentResolver();
+            mConstants.start(resolver);
+
             mWirelessChargerDetector = new WirelessChargerDetector(sensorManager,
                     createSuspendBlockerLocked("PowerManagerService.WirelessChargerDetector"),
                     mHandler);
@@ -629,7 +693,6 @@
                     mDisplayPowerCallbacks, mHandler, sensorManager);
 
             // Register for settings changes.
-            final ContentResolver resolver = mContext.getContentResolver();
             resolver.registerContentObserver(Settings.Secure.getUriFor(
                     Settings.Secure.SCREENSAVER_ENABLED),
                     false, mSettingsObserver, UserHandle.USER_ALL);
@@ -2795,7 +2858,7 @@
                             state.mProcState > ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
                         disabled = true;
                     }
-                } else {
+                } else if (mConstants.NO_CACHED_WAKE_LOCKS) {
                     disabled = !wakeLock.mUidState.mActive &&
                             wakeLock.mUidState.mProcState
                                     != ActivityManager.PROCESS_STATE_NONEXISTENT &&
@@ -3005,6 +3068,7 @@
         final WirelessChargerDetector wcd;
         synchronized (mLock) {
             pw.println("Power Manager State:");
+            mConstants.dump(pw);
             pw.println("  mDirty=0x" + Integer.toHexString(mDirty));
             pw.println("  mWakefulness=" + PowerManagerInternal.wakefulnessToString(mWakefulness));
             pw.println("  mWakefulnessChanging=" + mWakefulnessChanging);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 13358da8..5e458d4 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -3199,8 +3199,10 @@
         if (task == null) {
             return false;
         }
+        if (!StackId.isStackAffectedByDragResizing(getStackId())) {
+            return false;
+        }
         if (mAttrs.width != MATCH_PARENT || mAttrs.height != MATCH_PARENT) {
-
             // Floating windows never enter drag resize mode.
             return false;
         }
diff --git a/services/tests/servicestests/src/com/android/server/MockStorageManager.java b/services/tests/servicestests/src/com/android/server/MockStorageManager.java
index 9316516..031a3b3 100644
--- a/services/tests/servicestests/src/com/android/server/MockStorageManager.java
+++ b/services/tests/servicestests/src/com/android/server/MockStorageManager.java
@@ -32,6 +32,8 @@
 import android.util.ArrayMap;
 import android.util.Pair;
 
+import com.android.internal.os.AppFuseMount;
+
 import junit.framework.AssertionFailedError;
 
 import java.util.ArrayList;
@@ -463,12 +465,28 @@
     }
 
     @Override
-    public ParcelFileDescriptor mountAppFuse(String name) throws RemoteException {
+    public void fstrim(int flags) throws RemoteException {
         throw new UnsupportedOperationException();
     }
 
     @Override
-    public void fstrim(int flags) throws RemoteException {
+    public AppFuseMount mountProxyFileDescriptorBridge() throws RemoteException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ParcelFileDescriptor openProxyFileDescriptor(int mountPointId, int fileId, int mode)
+            throws RemoteException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public long getCacheQuotaBytes(String volumeUuid, int uid) throws RemoteException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public long getCacheSizeBytes(String volumeUuid, int uid) throws RemoteException {
         throw new UnsupportedOperationException();
     }