Merge "Correctly check expired jobs against active ones"
diff --git a/Android.mk b/Android.mk
index 0e5dfed..03b2533 100644
--- a/Android.mk
+++ b/Android.mk
@@ -944,27 +944,8 @@
 		-werror -hide 111 -hide 113 \
 		-overview $(LOCAL_PATH)/core/java/overview.html
 
-SUPPORT_API_DIR := ./frameworks/support/api
-
-# More API Level information for the Support Library, which is currently
-# included as part of the core framework docs build.
-framework_docs_LOCAL_DROIDDOC_OPTIONS += \
-    -since $(SUPPORT_API_DIR)/22.0.0.txt 22.0.0 \
-    -since $(SUPPORT_API_DIR)/22.0.0.txt 22.0.0 \
-    -since $(SUPPORT_API_DIR)/22.1.0.txt 22.1.0 \
-    -since $(SUPPORT_API_DIR)/22.2.0.txt 22.2.0 \
-    -since $(SUPPORT_API_DIR)/22.2.1.txt 22.2.1 \
-    -since $(SUPPORT_API_DIR)/23.0.0.txt 23.0.0 \
-    -since $(SUPPORT_API_DIR)/23.1.0.txt 23.1.0 \
-    -since $(SUPPORT_API_DIR)/23.1.1.txt 23.1.1 \
-    -since $(SUPPORT_API_DIR)/23.2.0.txt 23.2.0 \
-    -since $(SUPPORT_API_DIR)/23.2.1.txt 23.2.1 \
-    -since $(SUPPORT_API_DIR)/23.4.0.txt 23.4.0 \
-    -since $(SUPPORT_API_DIR)/24.0.0.txt 24.0.0 \
-    -since $(SUPPORT_API_DIR)/24.1.0.txt 24.1.0 \
-    -since $(SUPPORT_API_DIR)/24.2.0.txt 24.2.0 \
-    -since $(SUPPORT_API_DIR)/25.0.0.txt 25.0.0 \
-    -since $(SUPPORT_API_DIR)/25.1.0.txt 25.1.0
+# Allow the support library to add its own droiddoc options.
+include $(LOCAL_PATH)/../support/droiddoc.mk
 
 framework_docs_LOCAL_API_CHECK_ADDITIONAL_JAVA_DIR:= \
 	$(call intermediates-dir-for,JAVA_LIBRARIES,framework,,COMMON)
@@ -1472,10 +1453,6 @@
 LOCAL_SRC_FILES := \
     $(call all-proto-files-under, core/proto) \
     $(call all-proto-files-under, libs/incident/proto)
-LOCAL_C_INCLUDES := \
-    $(call generated-sources-dir-for,STATIC_LIBRARIES,libplatformprotos,)/proto
-LOCAL_EXPORT_C_INCLUDES := \
-    $(call generated-sources-dir-for,STATIC_LIBRARIES,libplatformprotos,)/proto
 include $(BUILD_STATIC_LIBRARY)
 
 # ====  c++ proto host library  ==============================
@@ -1490,10 +1467,6 @@
 LOCAL_SRC_FILES := \
     $(call all-proto-files-under, core/proto) \
     $(call all-proto-files-under, libs/incident/proto)
-LOCAL_C_INCLUDES := \
-    $(call generated-sources-dir-for,STATIC_LIBRARIES,libplatformprotos,)/proto
-LOCAL_EXPORT_C_INCLUDES := \
-    $(call generated-sources-dir-for,STATIC_LIBRARIES,libplatformprotos,)/proto
 include $(BUILD_HOST_SHARED_LIBRARY)
 
 
diff --git a/api/current.txt b/api/current.txt
index 477e346..aab29be 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -746,6 +746,7 @@
     field public static final int isAsciiCapable = 16843753; // 0x10103e9
     field public static final int isAuxiliary = 16843647; // 0x101037f
     field public static final int isDefault = 16843297; // 0x1010221
+    field public static final int isFeatureSplit = 16844126; // 0x101055e
     field public static final int isGame = 16843764; // 0x10103f4
     field public static final int isIndicator = 16843079; // 0x1010147
     field public static final int isModifier = 16843334; // 0x1010246
@@ -1790,6 +1791,7 @@
     field public static final int accessibilityActionSetProgress = 16908349; // 0x102003d
     field public static final int accessibilityActionShowOnScreen = 16908342; // 0x1020036
     field public static final int addToDictionary = 16908330; // 0x102002a
+    field public static final int autofill = 16908355; // 0x1020043
     field public static final int background = 16908288; // 0x1020000
     field public static final int button1 = 16908313; // 0x1020019
     field public static final int button2 = 16908314; // 0x102001a
@@ -5414,6 +5416,7 @@
     ctor public Notification.MessagingStyle.Message(java.lang.CharSequence, long, java.lang.CharSequence);
     method public java.lang.String getDataMimeType();
     method public android.net.Uri getDataUri();
+    method public android.os.Bundle getExtras();
     method public java.lang.CharSequence getSender();
     method public java.lang.CharSequence getText();
     method public long getTimestamp();
@@ -5493,7 +5496,6 @@
 
   public final class NotificationChannel implements android.os.Parcelable {
     ctor public NotificationChannel(java.lang.String, java.lang.CharSequence, int);
-    ctor public NotificationChannel(java.lang.String, int, int);
     ctor protected NotificationChannel(android.os.Parcel);
     method public boolean canBypassDnd();
     method public boolean canShowBadge();
@@ -5507,7 +5509,6 @@
     method public int getLightColor();
     method public int getLockscreenVisibility();
     method public java.lang.CharSequence getName();
-    method public int getNameResId();
     method public android.net.Uri getSound();
     method public long[] getVibrationPattern();
     method public void setBypassDnd(boolean);
@@ -5515,6 +5516,7 @@
     method public void setImportance(int);
     method public void setLightColor(int);
     method public void setLockscreenVisibility(int);
+    method public void setName(java.lang.CharSequence);
     method public void setShowBadge(boolean);
     method public void setSound(android.net.Uri, android.media.AudioAttributes);
     method public void setVibrationPattern(long[]);
@@ -5527,14 +5529,12 @@
 
   public final class NotificationChannelGroup implements android.os.Parcelable {
     ctor public NotificationChannelGroup(java.lang.String, java.lang.CharSequence);
-    ctor public NotificationChannelGroup(java.lang.String, int);
     ctor protected NotificationChannelGroup(android.os.Parcel);
     method public android.app.NotificationChannelGroup clone();
     method public int describeContents();
     method public java.util.List<android.app.NotificationChannel> getChannels();
     method public java.lang.String getId();
     method public java.lang.CharSequence getName();
-    method public int getNameResId();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.NotificationChannelGroup> CREATOR;
   }
@@ -5550,12 +5550,14 @@
     method public void createNotificationChannelGroups(java.util.List<android.app.NotificationChannelGroup>);
     method public void createNotificationChannels(java.util.List<android.app.NotificationChannel>);
     method public void deleteNotificationChannel(java.lang.String);
+    method public void deleteNotificationChannelGroup(java.lang.String);
     method public android.service.notification.StatusBarNotification[] getActiveNotifications();
     method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
     method public java.util.Map<java.lang.String, android.app.AutomaticZenRule> getAutomaticZenRules();
     method public final int getCurrentInterruptionFilter();
     method public int getImportance();
     method public android.app.NotificationChannel getNotificationChannel(java.lang.String);
+    method public java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups();
     method public java.util.List<android.app.NotificationChannel> getNotificationChannels();
     method public android.app.NotificationManager.Policy getNotificationPolicy();
     method public boolean isNotificationPolicyAccessGranted();
@@ -5717,6 +5719,8 @@
     method public java.lang.CharSequence getContentDescription();
     method public android.graphics.drawable.Icon getIcon();
     method public java.lang.CharSequence getTitle();
+    method public boolean isEnabled();
+    method public void setEnabled(boolean);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.RemoteAction> CREATOR;
   }
@@ -7122,6 +7126,7 @@
     method public android.bluetooth.le.BluetoothLeScanner getBluetoothLeScanner();
     method public java.util.Set<android.bluetooth.BluetoothDevice> getBondedDevices();
     method public static synchronized android.bluetooth.BluetoothAdapter getDefaultAdapter();
+    method public int getLeMaximumAdvertisingDataLength();
     method public java.lang.String getName();
     method public android.bluetooth.le.PeriodicAdvertisingManager getPeriodicAdvertisingManager();
     method public int getProfileConnectionState(int);
@@ -7933,7 +7938,7 @@
   }
 
   public final class AdvertisingSet {
-    method public void enableAdvertising(boolean);
+    method public void enableAdvertising(boolean, int);
     method public void periodicAdvertisingEnable(boolean);
     method public void setAdvertisingData(android.bluetooth.le.AdvertiseData);
     method public void setAdvertisingParameters(android.bluetooth.le.AdvertisingSetParameters);
@@ -7966,7 +7971,6 @@
     method public int getInterval();
     method public int getPrimaryPhy();
     method public int getSecondaryPhy();
-    method public int getTimeout();
     method public int getTxPowerLevel();
     method public boolean includeTxPower();
     method public boolean isAnonymous();
@@ -8000,7 +8004,6 @@
     method public android.bluetooth.le.AdvertisingSetParameters.Builder setLegacyMode(boolean);
     method public android.bluetooth.le.AdvertisingSetParameters.Builder setPrimaryPhy(int);
     method public android.bluetooth.le.AdvertisingSetParameters.Builder setSecondaryPhy(int);
-    method public android.bluetooth.le.AdvertisingSetParameters.Builder setTimeout(int);
     method public android.bluetooth.le.AdvertisingSetParameters.Builder setTxPowerLevel(int);
   }
 
@@ -8009,6 +8012,8 @@
     method public void startAdvertising(android.bluetooth.le.AdvertiseSettings, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseCallback);
     method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertisingSetCallback);
     method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertisingSetCallback, android.os.Handler);
+    method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, int, android.bluetooth.le.AdvertisingSetCallback);
+    method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, int, android.bluetooth.le.AdvertisingSetCallback, android.os.Handler);
     method public void stopAdvertising(android.bluetooth.le.AdvertiseCallback);
     method public void stopAdvertisingSet(android.bluetooth.le.AdvertisingSetCallback);
   }
@@ -10672,6 +10677,7 @@
     field public static final java.lang.String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory";
     field public static final java.lang.String FEATURE_USB_HOST = "android.hardware.usb.host";
     field public static final java.lang.String FEATURE_VERIFIED_BOOT = "android.software.verified_boot";
+    field public static final java.lang.String FEATURE_VR_HEADTRACKING = "android.hardware.vr.headtracking";
     field public static final java.lang.String FEATURE_VR_MODE = "android.software.vr.mode";
     field public static final java.lang.String FEATURE_VR_MODE_HIGH_PERFORMANCE = "android.hardware.vr.high_performance";
     field public static final java.lang.String FEATURE_VULKAN_HARDWARE_COMPUTE = "android.hardware.vulkan.compute";
@@ -12757,7 +12763,7 @@
   }
 
   public class ColorFilter {
-    ctor public ColorFilter();
+    ctor public deprecated ColorFilter();
   }
 
   public class ColorMatrix {
@@ -12781,6 +12787,9 @@
   public class ColorMatrixColorFilter extends android.graphics.ColorFilter {
     ctor public ColorMatrixColorFilter(android.graphics.ColorMatrix);
     ctor public ColorMatrixColorFilter(float[]);
+    method public void getColorMatrix(android.graphics.ColorMatrix);
+    method public void setColorMatrix(android.graphics.ColorMatrix);
+    method public void setColorMatrixArray(float[]);
   }
 
   public abstract class ColorSpace {
@@ -13004,6 +13013,10 @@
 
   public class LightingColorFilter extends android.graphics.ColorFilter {
     ctor public LightingColorFilter(int, int);
+    method public int getColorAdd();
+    method public int getColorMultiply();
+    method public void setColorAdd(int);
+    method public void setColorMultiply(int);
   }
 
   public class LinearGradient extends android.graphics.Shader {
@@ -13520,6 +13533,10 @@
 
   public class PorterDuffColorFilter extends android.graphics.ColorFilter {
     ctor public PorterDuffColorFilter(int, android.graphics.PorterDuff.Mode);
+    method public int getColor();
+    method public android.graphics.PorterDuff.Mode getMode();
+    method public void setColor(int);
+    method public void setMode(android.graphics.PorterDuff.Mode);
   }
 
   public class PorterDuffXfermode extends android.graphics.Xfermode {
@@ -21827,7 +21844,7 @@
     method public deprecated java.nio.ByteBuffer[] getInputBuffers();
     method public final android.media.MediaFormat getInputFormat();
     method public android.media.Image getInputImage(int);
-    method public android.os.Bundle getMetrics();
+    method public android.media.MediaMetricsSet getMetrics();
     method public final java.lang.String getName();
     method public java.nio.ByteBuffer getOutputBuffer(int);
     method public deprecated java.nio.ByteBuffer[] getOutputBuffers();
@@ -22379,7 +22396,7 @@
     method public boolean advance();
     method public long getCachedDuration();
     method public android.media.DrmInitData getDrmInitData();
-    method public android.os.Bundle getMetrics();
+    method public android.media.MediaMetricsSet getMetrics();
     method public java.util.Map<java.util.UUID, byte[]> getPsshInfo();
     method public boolean getSampleCryptoInfo(android.media.MediaCodec.CryptoInfo);
     method public int getSampleFlags();
@@ -22634,6 +22651,69 @@
     field public static final int OPTION_PREVIOUS_SYNC = 0; // 0x0
   }
 
+  public final class MediaMetricsSet {
+    method public double getDouble(java.lang.String, double);
+    method public int getInt(java.lang.String, int);
+    method public long getLong(java.lang.String, long);
+    method public java.lang.String getString(java.lang.String, java.lang.String);
+    method public boolean isEmpty();
+    method public java.util.Set<java.lang.String> keySet();
+    method public int size();
+  }
+
+  public static final class MediaMetricsSet.MediaCodec {
+    field public static final java.lang.String KEY_CODEC = "android.media.mediacodec.codec";
+    field public static final java.lang.String KEY_ENCODER = "android.media.mediacodec.encoder";
+    field public static final java.lang.String KEY_HEIGHT = "android.media.mediacodec.height";
+    field public static final java.lang.String KEY_MIME = "android.media.mediacodec.mime";
+    field public static final java.lang.String KEY_MODE = "android.media.mediacodec.mode";
+    field public static final java.lang.String KEY_ROTATION = "android.media.mediacodec.rotation";
+    field public static final java.lang.String KEY_SECURE = "android.media.mediacodec.secure";
+    field public static final java.lang.String KEY_WIDTH = "android.media.mediacodec.width";
+    field public static final java.lang.String MODE_AUDIO = "audio";
+    field public static final java.lang.String MODE_VIDEO = "video";
+  }
+
+  public static final class MediaMetricsSet.MediaExtractor {
+    field public static final java.lang.String KEY_FORMAT = "android.media.mediaextractor.fmt";
+    field public static final java.lang.String KEY_MIME = "android.media.mediaextractor.mime";
+    field public static final java.lang.String KEY_TRACKS = "android.media.mediaextractor.ntrk";
+  }
+
+  public static final class MediaMetricsSet.MediaPlayer {
+    field public static final java.lang.String KEY_CODEC_AUDIO = "android.media.mediaplayer.audio.codec";
+    field public static final java.lang.String KEY_CODEC_VIDEO = "android.media.mediaplayer.video.codec";
+    field public static final java.lang.String KEY_DURATION = "android.media.mediaplayer.durationMs";
+    field public static final java.lang.String KEY_ERRORS = "android.media.mediaplayer.err";
+    field public static final java.lang.String KEY_ERROR_CODE = "android.media.mediaplayer.errcode";
+    field public static final java.lang.String KEY_FRAMES = "android.media.mediaplayer.frames";
+    field public static final java.lang.String KEY_FRAMES_DROPPED = "android.media.mediaplayer.dropped";
+    field public static final java.lang.String KEY_HEIGHT = "android.media.mediaplayer.height";
+    field public static final java.lang.String KEY_MIME_AUDIO = "android.media.mediaplayer.audio.mime";
+    field public static final java.lang.String KEY_MIME_VIDEO = "android.media.mediaplayer.video.mime";
+    field public static final java.lang.String KEY_PLAYING = "android.media.mediaplayer.playingMs";
+    field public static final java.lang.String KEY_WIDTH = "android.media.mediaplayer.width";
+  }
+
+  public static final class MediaMetricsSet.MediaRecorder {
+    field public static final java.lang.String KEY_AUDIO_BITRATE = "android.media.mediarecorder.audio-bitrate";
+    field public static final java.lang.String KEY_AUDIO_CHANNELS = "android.media.mediarecorder.audio-channels";
+    field public static final java.lang.String KEY_AUDIO_SAMPLERATE = "android.media.mediarecorder.audio-samplerate";
+    field public static final java.lang.String KEY_AUDIO_TIMESCALE = "android.media.mediarecorder.audio-timescale";
+    field public static final java.lang.String KEY_CAPTURE_FPS = "android.media.mediarecorder.capture-fps";
+    field public static final java.lang.String KEY_CAPTURE_FPS_ENABLE = "android.media.mediarecorder.capture-fpsenable";
+    field public static final java.lang.String KEY_FRAMERATE = "android.media.mediarecorder.frame-rate";
+    field public static final java.lang.String KEY_HEIGHT = "android.media.mediarecorder.height";
+    field public static final java.lang.String KEY_MOVIE_TIMESCALE = "android.media.mediarecorder.movie-timescale";
+    field public static final java.lang.String KEY_ROTATION = "android.media.mediarecorder.rotation";
+    field public static final java.lang.String KEY_VIDEO_BITRATE = "android.media.mediarecorder.video-bitrate";
+    field public static final java.lang.String KEY_VIDEO_IFRAME_INTERVAL = "android.media.mediarecorder.video-iframe-interval";
+    field public static final java.lang.String KEY_VIDEO_LEVEL = "android.media.mediarecorder.video-encoder-level";
+    field public static final java.lang.String KEY_VIDEO_PROFILE = "android.media.mediarecorder.video-encoder-profile";
+    field public static final java.lang.String KEY_VIDEO_TIMESCALE = "android.media.mediarecorder.video-timescale";
+    field public static final java.lang.String KEY_WIDTH = "android.media.mediarecorder.width";
+  }
+
   public final class MediaMuxer {
     ctor public MediaMuxer(java.lang.String, int) throws java.io.IOException;
     ctor public MediaMuxer(java.io.FileDescriptor, int) throws java.io.IOException;
@@ -22674,7 +22754,7 @@
     method public java.lang.String getDrmPropertyString(java.lang.String) throws android.media.MediaPlayer.NoDrmSchemeException;
     method public int getDuration();
     method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException;
-    method public android.os.Bundle getMetrics();
+    method public android.media.MediaMetricsSet getMetrics();
     method public android.media.PlaybackParams getPlaybackParams();
     method public int getSelectedTrack(int) throws java.lang.IllegalStateException;
     method public android.media.SyncParams getSyncParams();
@@ -22842,7 +22922,7 @@
     ctor public MediaRecorder();
     method public static final int getAudioSourceMax();
     method public int getMaxAmplitude() throws java.lang.IllegalStateException;
-    method public android.os.Bundle getMetrics();
+    method public android.media.MediaMetricsSet getMetrics();
     method public android.view.Surface getSurface();
     method public void pause() throws java.lang.IllegalStateException;
     method public void prepare() throws java.io.IOException, java.lang.IllegalStateException;
@@ -36743,7 +36823,7 @@
     method public final android.os.IBinder onBind(android.content.Intent);
     method public void onConnected();
     method public void onDisconnected();
-    method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, android.os.CancellationSignal, android.service.autofill.FillCallback);
+    method public void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback);
     method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutofillService";
     field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
@@ -37094,11 +37174,11 @@
     field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
     field public static final int REASON_APP_CANCEL = 8; // 0x8
     field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9
+    field public static final int REASON_CANCEL = 2; // 0x2
+    field public static final int REASON_CANCEL_ALL = 3; // 0x3
     field public static final int REASON_CHANNEL_BANNED = 17; // 0x11
-    field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2
-    field public static final int REASON_DELEGATE_CANCEL_ALL = 3; // 0x3
-    field public static final int REASON_DELEGATE_CLICK = 1; // 0x1
-    field public static final int REASON_DELEGATE_ERROR = 4; // 0x4
+    field public static final int REASON_CLICK = 1; // 0x1
+    field public static final int REASON_ERROR = 4; // 0x4
     field public static final int REASON_GROUP_OPTIMIZATION = 13; // 0xd
     field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc
     field public static final int REASON_LISTENER_CANCEL = 10; // 0xa
@@ -45012,8 +45092,8 @@
     method public void addTouchables(java.util.ArrayList<android.view.View>);
     method public android.view.ViewPropertyAnimator animate();
     method public void announceForAccessibility(java.lang.CharSequence);
-    method public void autofill(android.view.autofill.AutofillValue);
-    method public void autofillVirtual(int, android.view.autofill.AutofillValue);
+    method public boolean autofill(android.view.autofill.AutofillValue);
+    method public boolean autofill(int, android.view.autofill.AutofillValue);
     method protected boolean awakenScrollBars();
     method protected boolean awakenScrollBars(int);
     method protected boolean awakenScrollBars(int, boolean);
@@ -45424,7 +45504,7 @@
     method public void setActivated(boolean);
     method public void setAlpha(float);
     method public void setAnimation(android.view.animation.Animation);
-    method public void setAutofillHint(java.lang.String[]);
+    method public void setAutofillHint(java.lang.String...);
     method public void setAutofillMode(int);
     method public void setBackground(android.graphics.drawable.Drawable);
     method public void setBackgroundColor(int);
@@ -46228,7 +46308,7 @@
     method public abstract int addChildCount(int);
     method public abstract void asyncCommit();
     method public abstract android.view.ViewStructure asyncNewChild(int);
-    method public abstract android.view.ViewStructure asyncNewChildForAutofill(int, int, int);
+    method public abstract android.view.ViewStructure asyncNewChild(int, int, int);
     method public abstract int getChildCount();
     method public abstract android.os.Bundle getExtras();
     method public abstract java.lang.CharSequence getHint();
@@ -46237,7 +46317,7 @@
     method public abstract int getTextSelectionStart();
     method public abstract boolean hasExtras();
     method public abstract android.view.ViewStructure newChild(int);
-    method public abstract android.view.ViewStructure newChildForAutofill(int, int, int);
+    method public abstract android.view.ViewStructure newChild(int, int, int);
     method public abstract void setAccessibilityFocused(boolean);
     method public abstract void setActivated(boolean);
     method public abstract void setAlpha(float);
@@ -47507,24 +47587,29 @@
   public final class AutofillManager {
     method public void cancel();
     method public void commit();
+    method public boolean isEnabled();
     method public void notifyValueChanged(android.view.View);
+    method public void notifyValueChanged(android.view.View, int, android.view.autofill.AutofillValue);
     method public void notifyViewEntered(android.view.View);
+    method public void notifyViewEntered(android.view.View, int, android.graphics.Rect);
     method public void notifyViewExited(android.view.View);
-    method public void notifyVirtualValueChanged(android.view.View, int, android.view.autofill.AutofillValue);
-    method public void notifyVirtualViewEntered(android.view.View, int, android.graphics.Rect);
-    method public void notifyVirtualViewExited(android.view.View, int);
+    method public void notifyViewExited(android.view.View, int);
     method public void registerCallback(android.view.autofill.AutofillManager.AutofillCallback);
+    method public void requestAutofill(android.view.View);
+    method public void requestAutofill(android.view.View, int, android.graphics.Rect);
     method public void unregisterCallback(android.view.autofill.AutofillManager.AutofillCallback);
     field public static final java.lang.String EXTRA_ASSIST_STRUCTURE = "android.view.autofill.extra.ASSIST_STRUCTURE";
     field public static final java.lang.String EXTRA_AUTHENTICATION_RESULT = "android.view.autofill.extra.AUTHENTICATION_RESULT";
+    field public static final int FLAG_MANUAL_REQUEST = 1; // 0x1
   }
 
   public static abstract class AutofillManager.AutofillCallback {
     ctor public AutofillManager.AutofillCallback();
     method public void onAutofillEvent(android.view.View, int);
-    method public void onAutofillEventVirtual(android.view.View, int, int);
+    method public void onAutofillEvent(android.view.View, int, int);
     field public static final int EVENT_INPUT_HIDDEN = 2; // 0x2
     field public static final int EVENT_INPUT_SHOWN = 1; // 0x1
+    field public static final int EVENT_INPUT_UNAVAILABLE = 3; // 0x3
   }
 
   public final class AutofillValue implements android.os.Parcelable {
diff --git a/api/system-current.txt b/api/system-current.txt
index 04dc632..0f42a54 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -859,6 +859,7 @@
     field public static final int isAsciiCapable = 16843753; // 0x10103e9
     field public static final int isAuxiliary = 16843647; // 0x101037f
     field public static final int isDefault = 16843297; // 0x1010221
+    field public static final int isFeatureSplit = 16844126; // 0x101055e
     field public static final int isGame = 16843764; // 0x10103f4
     field public static final int isIndicator = 16843079; // 0x1010147
     field public static final int isModifier = 16843334; // 0x1010246
@@ -1907,6 +1908,7 @@
     field public static final int accessibilityActionSetProgress = 16908349; // 0x102003d
     field public static final int accessibilityActionShowOnScreen = 16908342; // 0x1020036
     field public static final int addToDictionary = 16908330; // 0x102002a
+    field public static final int autofill = 16908355; // 0x1020043
     field public static final int background = 16908288; // 0x1020000
     field public static final int button1 = 16908313; // 0x1020019
     field public static final int button2 = 16908314; // 0x102001a
@@ -5588,6 +5590,7 @@
     ctor public Notification.MessagingStyle.Message(java.lang.CharSequence, long, java.lang.CharSequence);
     method public java.lang.String getDataMimeType();
     method public android.net.Uri getDataUri();
+    method public android.os.Bundle getExtras();
     method public java.lang.CharSequence getSender();
     method public java.lang.CharSequence getText();
     method public long getTimestamp();
@@ -5680,7 +5683,6 @@
 
   public final class NotificationChannel implements android.os.Parcelable {
     ctor public NotificationChannel(java.lang.String, java.lang.CharSequence, int);
-    ctor public NotificationChannel(java.lang.String, int, int);
     ctor protected NotificationChannel(android.os.Parcel);
     method public boolean canBypassDnd();
     method public boolean canShowBadge();
@@ -5694,19 +5696,17 @@
     method public int getLightColor();
     method public int getLockscreenVisibility();
     method public java.lang.CharSequence getName();
-    method public int getNameResId();
     method public android.net.Uri getSound();
     method public int getUserLockedFields();
     method public long[] getVibrationPattern();
     method public boolean isDeleted();
-    method public void lockFields(int);
     method public void populateFromXml(org.xmlpull.v1.XmlPullParser);
     method public void setBypassDnd(boolean);
-    method public void setDeleted(boolean);
     method public void setGroup(java.lang.String);
     method public void setImportance(int);
     method public void setLightColor(int);
     method public void setLockscreenVisibility(int);
+    method public void setName(java.lang.CharSequence);
     method public void setShowBadge(boolean);
     method public void setSound(android.net.Uri, android.media.AudioAttributes);
     method public void setVibrationPattern(long[]);
@@ -5731,18 +5731,14 @@
 
   public final class NotificationChannelGroup implements android.os.Parcelable {
     ctor public NotificationChannelGroup(java.lang.String, java.lang.CharSequence);
-    ctor public NotificationChannelGroup(java.lang.String, int);
     ctor protected NotificationChannelGroup(android.os.Parcel);
-    method public void addChannel(android.app.NotificationChannel);
     method public android.app.NotificationChannelGroup clone();
     method public int describeContents();
     method public java.util.List<android.app.NotificationChannel> getChannels();
     method public java.lang.String getId();
     method public java.lang.CharSequence getName();
-    method public int getNameResId();
     method public org.json.JSONObject toJson() throws org.json.JSONException;
     method public void writeToParcel(android.os.Parcel, int);
-    method public void writeXml(org.xmlpull.v1.XmlSerializer) throws java.io.IOException;
     field public static final android.os.Parcelable.Creator<android.app.NotificationChannelGroup> CREATOR;
   }
 
@@ -5757,12 +5753,14 @@
     method public void createNotificationChannelGroups(java.util.List<android.app.NotificationChannelGroup>);
     method public void createNotificationChannels(java.util.List<android.app.NotificationChannel>);
     method public void deleteNotificationChannel(java.lang.String);
+    method public void deleteNotificationChannelGroup(java.lang.String);
     method public android.service.notification.StatusBarNotification[] getActiveNotifications();
     method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
     method public java.util.Map<java.lang.String, android.app.AutomaticZenRule> getAutomaticZenRules();
     method public final int getCurrentInterruptionFilter();
     method public int getImportance();
     method public android.app.NotificationChannel getNotificationChannel(java.lang.String);
+    method public java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups();
     method public java.util.List<android.app.NotificationChannel> getNotificationChannels();
     method public android.app.NotificationManager.Policy getNotificationPolicy();
     method public boolean isNotificationPolicyAccessGranted();
@@ -5924,6 +5922,8 @@
     method public java.lang.CharSequence getContentDescription();
     method public android.graphics.drawable.Icon getIcon();
     method public java.lang.CharSequence getTitle();
+    method public boolean isEnabled();
+    method public void setEnabled(boolean);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.RemoteAction> CREATOR;
   }
@@ -7595,6 +7595,7 @@
     method public android.bluetooth.le.BluetoothLeScanner getBluetoothLeScanner();
     method public java.util.Set<android.bluetooth.BluetoothDevice> getBondedDevices();
     method public static synchronized android.bluetooth.BluetoothAdapter getDefaultAdapter();
+    method public int getLeMaximumAdvertisingDataLength();
     method public java.lang.String getName();
     method public android.bluetooth.le.PeriodicAdvertisingManager getPeriodicAdvertisingManager();
     method public int getProfileConnectionState(int);
@@ -8412,7 +8413,7 @@
   }
 
   public final class AdvertisingSet {
-    method public void enableAdvertising(boolean);
+    method public void enableAdvertising(boolean, int);
     method public void periodicAdvertisingEnable(boolean);
     method public void setAdvertisingData(android.bluetooth.le.AdvertiseData);
     method public void setAdvertisingParameters(android.bluetooth.le.AdvertisingSetParameters);
@@ -8445,7 +8446,6 @@
     method public int getInterval();
     method public int getPrimaryPhy();
     method public int getSecondaryPhy();
-    method public int getTimeout();
     method public int getTxPowerLevel();
     method public boolean includeTxPower();
     method public boolean isAnonymous();
@@ -8479,7 +8479,6 @@
     method public android.bluetooth.le.AdvertisingSetParameters.Builder setLegacyMode(boolean);
     method public android.bluetooth.le.AdvertisingSetParameters.Builder setPrimaryPhy(int);
     method public android.bluetooth.le.AdvertisingSetParameters.Builder setSecondaryPhy(int);
-    method public android.bluetooth.le.AdvertisingSetParameters.Builder setTimeout(int);
     method public android.bluetooth.le.AdvertisingSetParameters.Builder setTxPowerLevel(int);
   }
 
@@ -8488,6 +8487,8 @@
     method public void startAdvertising(android.bluetooth.le.AdvertiseSettings, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseCallback);
     method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertisingSetCallback);
     method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertisingSetCallback, android.os.Handler);
+    method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, int, android.bluetooth.le.AdvertisingSetCallback);
+    method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, int, android.bluetooth.le.AdvertisingSetCallback, android.os.Handler);
     method public void stopAdvertising(android.bluetooth.le.AdvertiseCallback);
     method public void stopAdvertisingSet(android.bluetooth.le.AdvertisingSetCallback);
   }
@@ -11334,6 +11335,7 @@
     field public static final java.lang.String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory";
     field public static final java.lang.String FEATURE_USB_HOST = "android.hardware.usb.host";
     field public static final java.lang.String FEATURE_VERIFIED_BOOT = "android.software.verified_boot";
+    field public static final java.lang.String FEATURE_VR_HEADTRACKING = "android.hardware.vr.headtracking";
     field public static final java.lang.String FEATURE_VR_MODE = "android.software.vr.mode";
     field public static final java.lang.String FEATURE_VR_MODE_HIGH_PERFORMANCE = "android.hardware.vr.high_performance";
     field public static final java.lang.String FEATURE_VULKAN_HARDWARE_COMPUTE = "android.hardware.vulkan.compute";
@@ -13495,7 +13497,7 @@
   }
 
   public class ColorFilter {
-    ctor public ColorFilter();
+    ctor public deprecated ColorFilter();
   }
 
   public class ColorMatrix {
@@ -13519,6 +13521,9 @@
   public class ColorMatrixColorFilter extends android.graphics.ColorFilter {
     ctor public ColorMatrixColorFilter(android.graphics.ColorMatrix);
     ctor public ColorMatrixColorFilter(float[]);
+    method public void getColorMatrix(android.graphics.ColorMatrix);
+    method public void setColorMatrix(android.graphics.ColorMatrix);
+    method public void setColorMatrixArray(float[]);
   }
 
   public abstract class ColorSpace {
@@ -13742,6 +13747,10 @@
 
   public class LightingColorFilter extends android.graphics.ColorFilter {
     ctor public LightingColorFilter(int, int);
+    method public int getColorAdd();
+    method public int getColorMultiply();
+    method public void setColorAdd(int);
+    method public void setColorMultiply(int);
   }
 
   public class LinearGradient extends android.graphics.Shader {
@@ -14258,6 +14267,10 @@
 
   public class PorterDuffColorFilter extends android.graphics.ColorFilter {
     ctor public PorterDuffColorFilter(int, android.graphics.PorterDuff.Mode);
+    method public int getColor();
+    method public android.graphics.PorterDuff.Mode getMode();
+    method public void setColor(int);
+    method public void setMode(android.graphics.PorterDuff.Mode);
   }
 
   public class PorterDuffXfermode extends android.graphics.Xfermode {
@@ -23623,7 +23636,7 @@
     method public deprecated java.nio.ByteBuffer[] getInputBuffers();
     method public final android.media.MediaFormat getInputFormat();
     method public android.media.Image getInputImage(int);
-    method public android.os.Bundle getMetrics();
+    method public android.media.MediaMetricsSet getMetrics();
     method public final java.lang.String getName();
     method public java.nio.ByteBuffer getOutputBuffer(int);
     method public deprecated java.nio.ByteBuffer[] getOutputBuffers();
@@ -24175,7 +24188,7 @@
     method public boolean advance();
     method public long getCachedDuration();
     method public android.media.DrmInitData getDrmInitData();
-    method public android.os.Bundle getMetrics();
+    method public android.media.MediaMetricsSet getMetrics();
     method public java.util.Map<java.util.UUID, byte[]> getPsshInfo();
     method public boolean getSampleCryptoInfo(android.media.MediaCodec.CryptoInfo);
     method public int getSampleFlags();
@@ -24430,6 +24443,69 @@
     field public static final int OPTION_PREVIOUS_SYNC = 0; // 0x0
   }
 
+  public final class MediaMetricsSet {
+    method public double getDouble(java.lang.String, double);
+    method public int getInt(java.lang.String, int);
+    method public long getLong(java.lang.String, long);
+    method public java.lang.String getString(java.lang.String, java.lang.String);
+    method public boolean isEmpty();
+    method public java.util.Set<java.lang.String> keySet();
+    method public int size();
+  }
+
+  public static final class MediaMetricsSet.MediaCodec {
+    field public static final java.lang.String KEY_CODEC = "android.media.mediacodec.codec";
+    field public static final java.lang.String KEY_ENCODER = "android.media.mediacodec.encoder";
+    field public static final java.lang.String KEY_HEIGHT = "android.media.mediacodec.height";
+    field public static final java.lang.String KEY_MIME = "android.media.mediacodec.mime";
+    field public static final java.lang.String KEY_MODE = "android.media.mediacodec.mode";
+    field public static final java.lang.String KEY_ROTATION = "android.media.mediacodec.rotation";
+    field public static final java.lang.String KEY_SECURE = "android.media.mediacodec.secure";
+    field public static final java.lang.String KEY_WIDTH = "android.media.mediacodec.width";
+    field public static final java.lang.String MODE_AUDIO = "audio";
+    field public static final java.lang.String MODE_VIDEO = "video";
+  }
+
+  public static final class MediaMetricsSet.MediaExtractor {
+    field public static final java.lang.String KEY_FORMAT = "android.media.mediaextractor.fmt";
+    field public static final java.lang.String KEY_MIME = "android.media.mediaextractor.mime";
+    field public static final java.lang.String KEY_TRACKS = "android.media.mediaextractor.ntrk";
+  }
+
+  public static final class MediaMetricsSet.MediaPlayer {
+    field public static final java.lang.String KEY_CODEC_AUDIO = "android.media.mediaplayer.audio.codec";
+    field public static final java.lang.String KEY_CODEC_VIDEO = "android.media.mediaplayer.video.codec";
+    field public static final java.lang.String KEY_DURATION = "android.media.mediaplayer.durationMs";
+    field public static final java.lang.String KEY_ERRORS = "android.media.mediaplayer.err";
+    field public static final java.lang.String KEY_ERROR_CODE = "android.media.mediaplayer.errcode";
+    field public static final java.lang.String KEY_FRAMES = "android.media.mediaplayer.frames";
+    field public static final java.lang.String KEY_FRAMES_DROPPED = "android.media.mediaplayer.dropped";
+    field public static final java.lang.String KEY_HEIGHT = "android.media.mediaplayer.height";
+    field public static final java.lang.String KEY_MIME_AUDIO = "android.media.mediaplayer.audio.mime";
+    field public static final java.lang.String KEY_MIME_VIDEO = "android.media.mediaplayer.video.mime";
+    field public static final java.lang.String KEY_PLAYING = "android.media.mediaplayer.playingMs";
+    field public static final java.lang.String KEY_WIDTH = "android.media.mediaplayer.width";
+  }
+
+  public static final class MediaMetricsSet.MediaRecorder {
+    field public static final java.lang.String KEY_AUDIO_BITRATE = "android.media.mediarecorder.audio-bitrate";
+    field public static final java.lang.String KEY_AUDIO_CHANNELS = "android.media.mediarecorder.audio-channels";
+    field public static final java.lang.String KEY_AUDIO_SAMPLERATE = "android.media.mediarecorder.audio-samplerate";
+    field public static final java.lang.String KEY_AUDIO_TIMESCALE = "android.media.mediarecorder.audio-timescale";
+    field public static final java.lang.String KEY_CAPTURE_FPS = "android.media.mediarecorder.capture-fps";
+    field public static final java.lang.String KEY_CAPTURE_FPS_ENABLE = "android.media.mediarecorder.capture-fpsenable";
+    field public static final java.lang.String KEY_FRAMERATE = "android.media.mediarecorder.frame-rate";
+    field public static final java.lang.String KEY_HEIGHT = "android.media.mediarecorder.height";
+    field public static final java.lang.String KEY_MOVIE_TIMESCALE = "android.media.mediarecorder.movie-timescale";
+    field public static final java.lang.String KEY_ROTATION = "android.media.mediarecorder.rotation";
+    field public static final java.lang.String KEY_VIDEO_BITRATE = "android.media.mediarecorder.video-bitrate";
+    field public static final java.lang.String KEY_VIDEO_IFRAME_INTERVAL = "android.media.mediarecorder.video-iframe-interval";
+    field public static final java.lang.String KEY_VIDEO_LEVEL = "android.media.mediarecorder.video-encoder-level";
+    field public static final java.lang.String KEY_VIDEO_PROFILE = "android.media.mediarecorder.video-encoder-profile";
+    field public static final java.lang.String KEY_VIDEO_TIMESCALE = "android.media.mediarecorder.video-timescale";
+    field public static final java.lang.String KEY_WIDTH = "android.media.mediarecorder.width";
+  }
+
   public final class MediaMuxer {
     ctor public MediaMuxer(java.lang.String, int) throws java.io.IOException;
     ctor public MediaMuxer(java.io.FileDescriptor, int) throws java.io.IOException;
@@ -24470,7 +24546,7 @@
     method public java.lang.String getDrmPropertyString(java.lang.String) throws android.media.MediaPlayer.NoDrmSchemeException;
     method public int getDuration();
     method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException;
-    method public android.os.Bundle getMetrics();
+    method public android.media.MediaMetricsSet getMetrics();
     method public android.media.PlaybackParams getPlaybackParams();
     method public int getSelectedTrack(int) throws java.lang.IllegalStateException;
     method public android.media.SyncParams getSyncParams();
@@ -24638,7 +24714,7 @@
     ctor public MediaRecorder();
     method public static final int getAudioSourceMax();
     method public int getMaxAmplitude() throws java.lang.IllegalStateException;
-    method public android.os.Bundle getMetrics();
+    method public android.media.MediaMetricsSet getMetrics();
     method public android.view.Surface getSurface();
     method public void pause() throws java.lang.IllegalStateException;
     method public void prepare() throws java.io.IOException, java.lang.IllegalStateException;
@@ -34358,6 +34434,7 @@
     method public deprecated void setUserRestrictions(android.os.Bundle);
     method public deprecated void setUserRestrictions(android.os.Bundle, android.os.UserHandle);
     method public static boolean supportsMultipleUsers();
+    field public static final java.lang.String ACTION_USER_RESTRICTIONS_CHANGED = "android.os.action.USER_RESTRICTIONS_CHANGED";
     field public static final java.lang.String ALLOW_PARENT_PROFILE_APP_LINKING = "allow_parent_profile_app_linking";
     field public static final java.lang.String DISALLOW_ADD_MANAGED_PROFILE = "no_add_managed_profile";
     field public static final java.lang.String DISALLOW_ADD_USER = "no_add_user";
@@ -39781,7 +39858,7 @@
     method public final android.os.IBinder onBind(android.content.Intent);
     method public void onConnected();
     method public void onDisconnected();
-    method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, android.os.CancellationSignal, android.service.autofill.FillCallback);
+    method public void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback);
     method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutofillService";
     field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
@@ -40169,11 +40246,11 @@
     field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
     field public static final int REASON_APP_CANCEL = 8; // 0x8
     field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9
+    field public static final int REASON_CANCEL = 2; // 0x2
+    field public static final int REASON_CANCEL_ALL = 3; // 0x3
     field public static final int REASON_CHANNEL_BANNED = 17; // 0x11
-    field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2
-    field public static final int REASON_DELEGATE_CANCEL_ALL = 3; // 0x3
-    field public static final int REASON_DELEGATE_CLICK = 1; // 0x1
-    field public static final int REASON_DELEGATE_ERROR = 4; // 0x4
+    field public static final int REASON_CLICK = 1; // 0x1
+    field public static final int REASON_ERROR = 4; // 0x4
     field public static final int REASON_GROUP_OPTIMIZATION = 13; // 0xd
     field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc
     field public static final int REASON_LISTENER_CANCEL = 10; // 0xa
@@ -48479,8 +48556,8 @@
     method public void addTouchables(java.util.ArrayList<android.view.View>);
     method public android.view.ViewPropertyAnimator animate();
     method public void announceForAccessibility(java.lang.CharSequence);
-    method public void autofill(android.view.autofill.AutofillValue);
-    method public void autofillVirtual(int, android.view.autofill.AutofillValue);
+    method public boolean autofill(android.view.autofill.AutofillValue);
+    method public boolean autofill(int, android.view.autofill.AutofillValue);
     method protected boolean awakenScrollBars();
     method protected boolean awakenScrollBars(int);
     method protected boolean awakenScrollBars(int, boolean);
@@ -48891,7 +48968,7 @@
     method public void setActivated(boolean);
     method public void setAlpha(float);
     method public void setAnimation(android.view.animation.Animation);
-    method public void setAutofillHint(java.lang.String[]);
+    method public void setAutofillHint(java.lang.String...);
     method public void setAutofillMode(int);
     method public void setBackground(android.graphics.drawable.Drawable);
     method public void setBackgroundColor(int);
@@ -49695,7 +49772,7 @@
     method public abstract int addChildCount(int);
     method public abstract void asyncCommit();
     method public abstract android.view.ViewStructure asyncNewChild(int);
-    method public abstract android.view.ViewStructure asyncNewChildForAutofill(int, int, int);
+    method public abstract android.view.ViewStructure asyncNewChild(int, int, int);
     method public abstract int getChildCount();
     method public abstract android.os.Bundle getExtras();
     method public abstract java.lang.CharSequence getHint();
@@ -49704,7 +49781,7 @@
     method public abstract int getTextSelectionStart();
     method public abstract boolean hasExtras();
     method public abstract android.view.ViewStructure newChild(int);
-    method public abstract android.view.ViewStructure newChildForAutofill(int, int, int);
+    method public abstract android.view.ViewStructure newChild(int, int, int);
     method public abstract void setAccessibilityFocused(boolean);
     method public abstract void setActivated(boolean);
     method public abstract void setAlpha(float);
@@ -50977,24 +51054,29 @@
   public final class AutofillManager {
     method public void cancel();
     method public void commit();
+    method public boolean isEnabled();
     method public void notifyValueChanged(android.view.View);
+    method public void notifyValueChanged(android.view.View, int, android.view.autofill.AutofillValue);
     method public void notifyViewEntered(android.view.View);
+    method public void notifyViewEntered(android.view.View, int, android.graphics.Rect);
     method public void notifyViewExited(android.view.View);
-    method public void notifyVirtualValueChanged(android.view.View, int, android.view.autofill.AutofillValue);
-    method public void notifyVirtualViewEntered(android.view.View, int, android.graphics.Rect);
-    method public void notifyVirtualViewExited(android.view.View, int);
+    method public void notifyViewExited(android.view.View, int);
     method public void registerCallback(android.view.autofill.AutofillManager.AutofillCallback);
+    method public void requestAutofill(android.view.View);
+    method public void requestAutofill(android.view.View, int, android.graphics.Rect);
     method public void unregisterCallback(android.view.autofill.AutofillManager.AutofillCallback);
     field public static final java.lang.String EXTRA_ASSIST_STRUCTURE = "android.view.autofill.extra.ASSIST_STRUCTURE";
     field public static final java.lang.String EXTRA_AUTHENTICATION_RESULT = "android.view.autofill.extra.AUTHENTICATION_RESULT";
+    field public static final int FLAG_MANUAL_REQUEST = 1; // 0x1
   }
 
   public static abstract class AutofillManager.AutofillCallback {
     ctor public AutofillManager.AutofillCallback();
     method public void onAutofillEvent(android.view.View, int);
-    method public void onAutofillEventVirtual(android.view.View, int, int);
+    method public void onAutofillEvent(android.view.View, int, int);
     field public static final int EVENT_INPUT_HIDDEN = 2; // 0x2
     field public static final int EVENT_INPUT_SHOWN = 1; // 0x1
+    field public static final int EVENT_INPUT_UNAVAILABLE = 3; // 0x3
   }
 
   public final class AutofillValue implements android.os.Parcelable {
diff --git a/api/test-current.txt b/api/test-current.txt
index 6962c45..f91bbb9 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -746,6 +746,7 @@
     field public static final int isAsciiCapable = 16843753; // 0x10103e9
     field public static final int isAuxiliary = 16843647; // 0x101037f
     field public static final int isDefault = 16843297; // 0x1010221
+    field public static final int isFeatureSplit = 16844126; // 0x101055e
     field public static final int isGame = 16843764; // 0x10103f4
     field public static final int isIndicator = 16843079; // 0x1010147
     field public static final int isModifier = 16843334; // 0x1010246
@@ -1790,6 +1791,7 @@
     field public static final int accessibilityActionSetProgress = 16908349; // 0x102003d
     field public static final int accessibilityActionShowOnScreen = 16908342; // 0x1020036
     field public static final int addToDictionary = 16908330; // 0x102002a
+    field public static final int autofill = 16908355; // 0x1020043
     field public static final int background = 16908288; // 0x1020000
     field public static final int button1 = 16908313; // 0x1020019
     field public static final int button2 = 16908314; // 0x102001a
@@ -5424,6 +5426,7 @@
     ctor public Notification.MessagingStyle.Message(java.lang.CharSequence, long, java.lang.CharSequence);
     method public java.lang.String getDataMimeType();
     method public android.net.Uri getDataUri();
+    method public android.os.Bundle getExtras();
     method public java.lang.CharSequence getSender();
     method public java.lang.CharSequence getText();
     method public long getTimestamp();
@@ -5503,7 +5506,6 @@
 
   public final class NotificationChannel implements android.os.Parcelable {
     ctor public NotificationChannel(java.lang.String, java.lang.CharSequence, int);
-    ctor public NotificationChannel(java.lang.String, int, int);
     ctor protected NotificationChannel(android.os.Parcel);
     method public boolean canBypassDnd();
     method public boolean canShowBadge();
@@ -5517,7 +5519,6 @@
     method public int getLightColor();
     method public int getLockscreenVisibility();
     method public java.lang.CharSequence getName();
-    method public int getNameResId();
     method public android.net.Uri getSound();
     method public long[] getVibrationPattern();
     method public void setBypassDnd(boolean);
@@ -5525,6 +5526,7 @@
     method public void setImportance(int);
     method public void setLightColor(int);
     method public void setLockscreenVisibility(int);
+    method public void setName(java.lang.CharSequence);
     method public void setShowBadge(boolean);
     method public void setSound(android.net.Uri, android.media.AudioAttributes);
     method public void setVibrationPattern(long[]);
@@ -5537,14 +5539,12 @@
 
   public final class NotificationChannelGroup implements android.os.Parcelable {
     ctor public NotificationChannelGroup(java.lang.String, java.lang.CharSequence);
-    ctor public NotificationChannelGroup(java.lang.String, int);
     ctor protected NotificationChannelGroup(android.os.Parcel);
     method public android.app.NotificationChannelGroup clone();
     method public int describeContents();
     method public java.util.List<android.app.NotificationChannel> getChannels();
     method public java.lang.String getId();
     method public java.lang.CharSequence getName();
-    method public int getNameResId();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.NotificationChannelGroup> CREATOR;
   }
@@ -5560,6 +5560,7 @@
     method public void createNotificationChannelGroups(java.util.List<android.app.NotificationChannelGroup>);
     method public void createNotificationChannels(java.util.List<android.app.NotificationChannel>);
     method public void deleteNotificationChannel(java.lang.String);
+    method public void deleteNotificationChannelGroup(java.lang.String);
     method public android.service.notification.StatusBarNotification[] getActiveNotifications();
     method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
     method public java.util.Map<java.lang.String, android.app.AutomaticZenRule> getAutomaticZenRules();
@@ -5567,6 +5568,7 @@
     method public android.content.ComponentName getEffectsSuppressor();
     method public int getImportance();
     method public android.app.NotificationChannel getNotificationChannel(java.lang.String);
+    method public java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups();
     method public java.util.List<android.app.NotificationChannel> getNotificationChannels();
     method public android.app.NotificationManager.Policy getNotificationPolicy();
     method public boolean isNotificationPolicyAccessGranted();
@@ -5728,6 +5730,8 @@
     method public java.lang.CharSequence getContentDescription();
     method public android.graphics.drawable.Icon getIcon();
     method public java.lang.CharSequence getTitle();
+    method public boolean isEnabled();
+    method public void setEnabled(boolean);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.RemoteAction> CREATOR;
   }
@@ -7149,6 +7153,7 @@
     method public android.bluetooth.le.BluetoothLeScanner getBluetoothLeScanner();
     method public java.util.Set<android.bluetooth.BluetoothDevice> getBondedDevices();
     method public static synchronized android.bluetooth.BluetoothAdapter getDefaultAdapter();
+    method public int getLeMaximumAdvertisingDataLength();
     method public java.lang.String getName();
     method public android.bluetooth.le.PeriodicAdvertisingManager getPeriodicAdvertisingManager();
     method public int getProfileConnectionState(int);
@@ -7960,7 +7965,7 @@
   }
 
   public final class AdvertisingSet {
-    method public void enableAdvertising(boolean);
+    method public void enableAdvertising(boolean, int);
     method public void periodicAdvertisingEnable(boolean);
     method public void setAdvertisingData(android.bluetooth.le.AdvertiseData);
     method public void setAdvertisingParameters(android.bluetooth.le.AdvertisingSetParameters);
@@ -7993,7 +7998,6 @@
     method public int getInterval();
     method public int getPrimaryPhy();
     method public int getSecondaryPhy();
-    method public int getTimeout();
     method public int getTxPowerLevel();
     method public boolean includeTxPower();
     method public boolean isAnonymous();
@@ -8027,7 +8031,6 @@
     method public android.bluetooth.le.AdvertisingSetParameters.Builder setLegacyMode(boolean);
     method public android.bluetooth.le.AdvertisingSetParameters.Builder setPrimaryPhy(int);
     method public android.bluetooth.le.AdvertisingSetParameters.Builder setSecondaryPhy(int);
-    method public android.bluetooth.le.AdvertisingSetParameters.Builder setTimeout(int);
     method public android.bluetooth.le.AdvertisingSetParameters.Builder setTxPowerLevel(int);
   }
 
@@ -8036,6 +8039,8 @@
     method public void startAdvertising(android.bluetooth.le.AdvertiseSettings, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseCallback);
     method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertisingSetCallback);
     method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertisingSetCallback, android.os.Handler);
+    method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, int, android.bluetooth.le.AdvertisingSetCallback);
+    method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, int, android.bluetooth.le.AdvertisingSetCallback, android.os.Handler);
     method public void stopAdvertising(android.bluetooth.le.AdvertiseCallback);
     method public void stopAdvertisingSet(android.bluetooth.le.AdvertisingSetCallback);
   }
@@ -10708,6 +10713,7 @@
     field public static final java.lang.String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory";
     field public static final java.lang.String FEATURE_USB_HOST = "android.hardware.usb.host";
     field public static final java.lang.String FEATURE_VERIFIED_BOOT = "android.software.verified_boot";
+    field public static final java.lang.String FEATURE_VR_HEADTRACKING = "android.hardware.vr.headtracking";
     field public static final java.lang.String FEATURE_VR_MODE = "android.software.vr.mode";
     field public static final java.lang.String FEATURE_VR_MODE_HIGH_PERFORMANCE = "android.hardware.vr.high_performance";
     field public static final java.lang.String FEATURE_VULKAN_HARDWARE_COMPUTE = "android.hardware.vulkan.compute";
@@ -12795,7 +12801,7 @@
   }
 
   public class ColorFilter {
-    ctor public ColorFilter();
+    ctor public deprecated ColorFilter();
   }
 
   public class ColorMatrix {
@@ -12819,6 +12825,9 @@
   public class ColorMatrixColorFilter extends android.graphics.ColorFilter {
     ctor public ColorMatrixColorFilter(android.graphics.ColorMatrix);
     ctor public ColorMatrixColorFilter(float[]);
+    method public void getColorMatrix(android.graphics.ColorMatrix);
+    method public void setColorMatrix(android.graphics.ColorMatrix);
+    method public void setColorMatrixArray(float[]);
   }
 
   public abstract class ColorSpace {
@@ -13042,6 +13051,10 @@
 
   public class LightingColorFilter extends android.graphics.ColorFilter {
     ctor public LightingColorFilter(int, int);
+    method public int getColorAdd();
+    method public int getColorMultiply();
+    method public void setColorAdd(int);
+    method public void setColorMultiply(int);
   }
 
   public class LinearGradient extends android.graphics.Shader {
@@ -13558,6 +13571,10 @@
 
   public class PorterDuffColorFilter extends android.graphics.ColorFilter {
     ctor public PorterDuffColorFilter(int, android.graphics.PorterDuff.Mode);
+    method public int getColor();
+    method public android.graphics.PorterDuff.Mode getMode();
+    method public void setColor(int);
+    method public void setMode(android.graphics.PorterDuff.Mode);
   }
 
   public class PorterDuffXfermode extends android.graphics.Xfermode {
@@ -21928,7 +21945,7 @@
     method public deprecated java.nio.ByteBuffer[] getInputBuffers();
     method public final android.media.MediaFormat getInputFormat();
     method public android.media.Image getInputImage(int);
-    method public android.os.Bundle getMetrics();
+    method public android.media.MediaMetricsSet getMetrics();
     method public final java.lang.String getName();
     method public java.nio.ByteBuffer getOutputBuffer(int);
     method public deprecated java.nio.ByteBuffer[] getOutputBuffers();
@@ -22480,7 +22497,7 @@
     method public boolean advance();
     method public long getCachedDuration();
     method public android.media.DrmInitData getDrmInitData();
-    method public android.os.Bundle getMetrics();
+    method public android.media.MediaMetricsSet getMetrics();
     method public java.util.Map<java.util.UUID, byte[]> getPsshInfo();
     method public boolean getSampleCryptoInfo(android.media.MediaCodec.CryptoInfo);
     method public int getSampleFlags();
@@ -22735,6 +22752,69 @@
     field public static final int OPTION_PREVIOUS_SYNC = 0; // 0x0
   }
 
+  public final class MediaMetricsSet {
+    method public double getDouble(java.lang.String, double);
+    method public int getInt(java.lang.String, int);
+    method public long getLong(java.lang.String, long);
+    method public java.lang.String getString(java.lang.String, java.lang.String);
+    method public boolean isEmpty();
+    method public java.util.Set<java.lang.String> keySet();
+    method public int size();
+  }
+
+  public static final class MediaMetricsSet.MediaCodec {
+    field public static final java.lang.String KEY_CODEC = "android.media.mediacodec.codec";
+    field public static final java.lang.String KEY_ENCODER = "android.media.mediacodec.encoder";
+    field public static final java.lang.String KEY_HEIGHT = "android.media.mediacodec.height";
+    field public static final java.lang.String KEY_MIME = "android.media.mediacodec.mime";
+    field public static final java.lang.String KEY_MODE = "android.media.mediacodec.mode";
+    field public static final java.lang.String KEY_ROTATION = "android.media.mediacodec.rotation";
+    field public static final java.lang.String KEY_SECURE = "android.media.mediacodec.secure";
+    field public static final java.lang.String KEY_WIDTH = "android.media.mediacodec.width";
+    field public static final java.lang.String MODE_AUDIO = "audio";
+    field public static final java.lang.String MODE_VIDEO = "video";
+  }
+
+  public static final class MediaMetricsSet.MediaExtractor {
+    field public static final java.lang.String KEY_FORMAT = "android.media.mediaextractor.fmt";
+    field public static final java.lang.String KEY_MIME = "android.media.mediaextractor.mime";
+    field public static final java.lang.String KEY_TRACKS = "android.media.mediaextractor.ntrk";
+  }
+
+  public static final class MediaMetricsSet.MediaPlayer {
+    field public static final java.lang.String KEY_CODEC_AUDIO = "android.media.mediaplayer.audio.codec";
+    field public static final java.lang.String KEY_CODEC_VIDEO = "android.media.mediaplayer.video.codec";
+    field public static final java.lang.String KEY_DURATION = "android.media.mediaplayer.durationMs";
+    field public static final java.lang.String KEY_ERRORS = "android.media.mediaplayer.err";
+    field public static final java.lang.String KEY_ERROR_CODE = "android.media.mediaplayer.errcode";
+    field public static final java.lang.String KEY_FRAMES = "android.media.mediaplayer.frames";
+    field public static final java.lang.String KEY_FRAMES_DROPPED = "android.media.mediaplayer.dropped";
+    field public static final java.lang.String KEY_HEIGHT = "android.media.mediaplayer.height";
+    field public static final java.lang.String KEY_MIME_AUDIO = "android.media.mediaplayer.audio.mime";
+    field public static final java.lang.String KEY_MIME_VIDEO = "android.media.mediaplayer.video.mime";
+    field public static final java.lang.String KEY_PLAYING = "android.media.mediaplayer.playingMs";
+    field public static final java.lang.String KEY_WIDTH = "android.media.mediaplayer.width";
+  }
+
+  public static final class MediaMetricsSet.MediaRecorder {
+    field public static final java.lang.String KEY_AUDIO_BITRATE = "android.media.mediarecorder.audio-bitrate";
+    field public static final java.lang.String KEY_AUDIO_CHANNELS = "android.media.mediarecorder.audio-channels";
+    field public static final java.lang.String KEY_AUDIO_SAMPLERATE = "android.media.mediarecorder.audio-samplerate";
+    field public static final java.lang.String KEY_AUDIO_TIMESCALE = "android.media.mediarecorder.audio-timescale";
+    field public static final java.lang.String KEY_CAPTURE_FPS = "android.media.mediarecorder.capture-fps";
+    field public static final java.lang.String KEY_CAPTURE_FPS_ENABLE = "android.media.mediarecorder.capture-fpsenable";
+    field public static final java.lang.String KEY_FRAMERATE = "android.media.mediarecorder.frame-rate";
+    field public static final java.lang.String KEY_HEIGHT = "android.media.mediarecorder.height";
+    field public static final java.lang.String KEY_MOVIE_TIMESCALE = "android.media.mediarecorder.movie-timescale";
+    field public static final java.lang.String KEY_ROTATION = "android.media.mediarecorder.rotation";
+    field public static final java.lang.String KEY_VIDEO_BITRATE = "android.media.mediarecorder.video-bitrate";
+    field public static final java.lang.String KEY_VIDEO_IFRAME_INTERVAL = "android.media.mediarecorder.video-iframe-interval";
+    field public static final java.lang.String KEY_VIDEO_LEVEL = "android.media.mediarecorder.video-encoder-level";
+    field public static final java.lang.String KEY_VIDEO_PROFILE = "android.media.mediarecorder.video-encoder-profile";
+    field public static final java.lang.String KEY_VIDEO_TIMESCALE = "android.media.mediarecorder.video-timescale";
+    field public static final java.lang.String KEY_WIDTH = "android.media.mediarecorder.width";
+  }
+
   public final class MediaMuxer {
     ctor public MediaMuxer(java.lang.String, int) throws java.io.IOException;
     ctor public MediaMuxer(java.io.FileDescriptor, int) throws java.io.IOException;
@@ -22775,7 +22855,7 @@
     method public java.lang.String getDrmPropertyString(java.lang.String) throws android.media.MediaPlayer.NoDrmSchemeException;
     method public int getDuration();
     method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException;
-    method public android.os.Bundle getMetrics();
+    method public android.media.MediaMetricsSet getMetrics();
     method public android.media.PlaybackParams getPlaybackParams();
     method public int getSelectedTrack(int) throws java.lang.IllegalStateException;
     method public android.media.SyncParams getSyncParams();
@@ -22943,7 +23023,7 @@
     ctor public MediaRecorder();
     method public static final int getAudioSourceMax();
     method public int getMaxAmplitude() throws java.lang.IllegalStateException;
-    method public android.os.Bundle getMetrics();
+    method public android.media.MediaMetricsSet getMetrics();
     method public android.view.Surface getSurface();
     method public void pause() throws java.lang.IllegalStateException;
     method public void prepare() throws java.io.IOException, java.lang.IllegalStateException;
@@ -31656,6 +31736,7 @@
     method public deprecated void setUserRestrictions(android.os.Bundle);
     method public deprecated void setUserRestrictions(android.os.Bundle, android.os.UserHandle);
     method public static boolean supportsMultipleUsers();
+    field public static final java.lang.String ACTION_USER_RESTRICTIONS_CHANGED = "android.os.action.USER_RESTRICTIONS_CHANGED";
     field public static final java.lang.String ALLOW_PARENT_PROFILE_APP_LINKING = "allow_parent_profile_app_linking";
     field public static final java.lang.String DISALLOW_ADD_MANAGED_PROFILE = "no_add_managed_profile";
     field public static final java.lang.String DISALLOW_ADD_USER = "no_add_user";
@@ -34940,6 +35021,7 @@
     field public static final java.lang.String SELECTED_INPUT_METHOD_SUBTYPE = "selected_input_method_subtype";
     field public static final java.lang.String SETTINGS_CLASSNAME = "settings_classname";
     field public static final java.lang.String SKIP_FIRST_USE_HINTS = "skip_first_use_hints";
+    field public static final java.lang.String SYNC_PARENT_SOUNDS = "sync_parent_sounds";
     field public static final java.lang.String TOUCH_EXPLORATION_ENABLED = "touch_exploration_enabled";
     field public static final deprecated java.lang.String TTS_DEFAULT_COUNTRY = "tts_default_country";
     field public static final deprecated java.lang.String TTS_DEFAULT_LANG = "tts_default_lang";
@@ -36887,7 +36969,7 @@
     method public final android.os.IBinder onBind(android.content.Intent);
     method public void onConnected();
     method public void onDisconnected();
-    method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, android.os.CancellationSignal, android.service.autofill.FillCallback);
+    method public void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback);
     method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutofillService";
     field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
@@ -37270,11 +37352,11 @@
     field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
     field public static final int REASON_APP_CANCEL = 8; // 0x8
     field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9
+    field public static final int REASON_CANCEL = 2; // 0x2
+    field public static final int REASON_CANCEL_ALL = 3; // 0x3
     field public static final int REASON_CHANNEL_BANNED = 17; // 0x11
-    field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2
-    field public static final int REASON_DELEGATE_CANCEL_ALL = 3; // 0x3
-    field public static final int REASON_DELEGATE_CLICK = 1; // 0x1
-    field public static final int REASON_DELEGATE_ERROR = 4; // 0x4
+    field public static final int REASON_CLICK = 1; // 0x1
+    field public static final int REASON_ERROR = 4; // 0x4
     field public static final int REASON_GROUP_OPTIMIZATION = 13; // 0xd
     field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc
     field public static final int REASON_LISTENER_CANCEL = 10; // 0xa
@@ -45372,8 +45454,8 @@
     method public void addTouchables(java.util.ArrayList<android.view.View>);
     method public android.view.ViewPropertyAnimator animate();
     method public void announceForAccessibility(java.lang.CharSequence);
-    method public void autofill(android.view.autofill.AutofillValue);
-    method public void autofillVirtual(int, android.view.autofill.AutofillValue);
+    method public boolean autofill(android.view.autofill.AutofillValue);
+    method public boolean autofill(int, android.view.autofill.AutofillValue);
     method protected boolean awakenScrollBars();
     method protected boolean awakenScrollBars(int);
     method protected boolean awakenScrollBars(int, boolean);
@@ -45787,7 +45869,7 @@
     method public void setActivated(boolean);
     method public void setAlpha(float);
     method public void setAnimation(android.view.animation.Animation);
-    method public void setAutofillHint(java.lang.String[]);
+    method public void setAutofillHint(java.lang.String...);
     method public void setAutofillMode(int);
     method public void setBackground(android.graphics.drawable.Drawable);
     method public void setBackgroundColor(int);
@@ -46595,7 +46677,7 @@
     method public abstract int addChildCount(int);
     method public abstract void asyncCommit();
     method public abstract android.view.ViewStructure asyncNewChild(int);
-    method public abstract android.view.ViewStructure asyncNewChildForAutofill(int, int, int);
+    method public abstract android.view.ViewStructure asyncNewChild(int, int, int);
     method public abstract int getChildCount();
     method public abstract android.os.Bundle getExtras();
     method public abstract java.lang.CharSequence getHint();
@@ -46604,7 +46686,7 @@
     method public abstract int getTextSelectionStart();
     method public abstract boolean hasExtras();
     method public abstract android.view.ViewStructure newChild(int);
-    method public abstract android.view.ViewStructure newChildForAutofill(int, int, int);
+    method public abstract android.view.ViewStructure newChild(int, int, int);
     method public abstract void setAccessibilityFocused(boolean);
     method public abstract void setActivated(boolean);
     method public abstract void setAlpha(float);
@@ -47876,24 +47958,29 @@
   public final class AutofillManager {
     method public void cancel();
     method public void commit();
+    method public boolean isEnabled();
     method public void notifyValueChanged(android.view.View);
+    method public void notifyValueChanged(android.view.View, int, android.view.autofill.AutofillValue);
     method public void notifyViewEntered(android.view.View);
+    method public void notifyViewEntered(android.view.View, int, android.graphics.Rect);
     method public void notifyViewExited(android.view.View);
-    method public void notifyVirtualValueChanged(android.view.View, int, android.view.autofill.AutofillValue);
-    method public void notifyVirtualViewEntered(android.view.View, int, android.graphics.Rect);
-    method public void notifyVirtualViewExited(android.view.View, int);
+    method public void notifyViewExited(android.view.View, int);
     method public void registerCallback(android.view.autofill.AutofillManager.AutofillCallback);
+    method public void requestAutofill(android.view.View);
+    method public void requestAutofill(android.view.View, int, android.graphics.Rect);
     method public void unregisterCallback(android.view.autofill.AutofillManager.AutofillCallback);
     field public static final java.lang.String EXTRA_ASSIST_STRUCTURE = "android.view.autofill.extra.ASSIST_STRUCTURE";
     field public static final java.lang.String EXTRA_AUTHENTICATION_RESULT = "android.view.autofill.extra.AUTHENTICATION_RESULT";
+    field public static final int FLAG_MANUAL_REQUEST = 1; // 0x1
   }
 
   public static abstract class AutofillManager.AutofillCallback {
     ctor public AutofillManager.AutofillCallback();
     method public void onAutofillEvent(android.view.View, int);
-    method public void onAutofillEventVirtual(android.view.View, int, int);
+    method public void onAutofillEvent(android.view.View, int, int);
     field public static final int EVENT_INPUT_HIDDEN = 2; // 0x2
     field public static final int EVENT_INPUT_SHOWN = 1; // 0x1
+    field public static final int EVENT_INPUT_UNAVAILABLE = 3; // 0x3
   }
 
   public final class AutofillValue implements android.os.Parcelable {
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 91520f1..827a77f 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -411,7 +411,8 @@
             if (file.isFile()) {
                 try {
                     ApkLite baseApk = PackageParser.parseApkLite(file, 0);
-                    PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null);
+                    PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null,
+                            null, null);
                     params.sessionParams.setSize(
                             PackageHelper.calculateInstalledSize(pkgLite, false,
                             params.sessionParams.abiOverride));
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index e5df278..75d4f32 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -21,8 +21,11 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
+import android.annotation.SdkConstant;
 import android.annotation.Size;
 import android.annotation.SystemApi;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.BroadcastBehavior;
 import android.app.Activity;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -335,6 +338,8 @@
      *
      * @deprecated use #addOnAccountsUpdatedListener to get account updates in runtime.
      */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @BroadcastBehavior(includeBackground = true)
     public static final String LOGIN_ACCOUNTS_CHANGED_ACTION =
         "android.accounts.LOGIN_ACCOUNTS_CHANGED";
 
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 86adbb0..5c7a12c 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -431,31 +431,28 @@
 
     // Force all the animations to end when the duration scale is 0.
     private void forceToEnd() {
-        if (mEndCanBeCalled) {
-            end();
+        // TODO: Below is commented out to temp work around b/36241584, uncomment this when it's
+        // fixed.
+//        if (mEndCanBeCalled) {
+//            end();
+//            return;
+//        }
+
+        // Note: we don't want to combine this case with the end() method below because in
+        // the case of developer calling end(), we still need to make sure end() is explicitly
+        // called on the child animators to maintain the old behavior.
+        if (mReversing) {
+            handleAnimationEvents(mLastEventId, 0, getTotalDuration());
         } else {
-            // Note: we don't want to combine this case with the end() method below because in
-            // the case of developer calling end(), we still need to make sure end() is explicitly
-            // called on the child animators to maintain the old behavior.
-            if (mReversing) {
-                mLastEventId = mLastEventId == -1 ? mEvents.size() : mLastEventId;
-                for (int j = mLastEventId - 1; j >= 0; j--) {
-                    AnimationEvent event = mEvents.get(j);
-                    if (event.mEvent == AnimationEvent.ANIMATION_END) {
-                        event.mNode.mAnimation.reverse();
-                    }
-                }
-            } else {
-                for (int j = mLastEventId + 1; j < mEvents.size(); j++) {
-                    AnimationEvent event = mEvents.get(j);
-                    if (event.mEvent == AnimationEvent.ANIMATION_START) {
-                        event.mNode.mAnimation.start();
-                    }
-                }
+            long zeroScalePlayTime = getTotalDuration();
+            if (zeroScalePlayTime == DURATION_INFINITE) {
+                // Use a large number for the play time.
+                zeroScalePlayTime = Integer.MAX_VALUE;
             }
-            mPlayingSet.clear();
-            endAnimation();
+            handleAnimationEvents(mLastEventId, mEvents.size() - 1, zeroScalePlayTime);
         }
+        mPlayingSet.clear();
+        endAnimation();
     }
 
     /**
@@ -730,7 +727,7 @@
         if (isEmptySet) {
             // In the case of empty AnimatorSet, or 0 duration scale, we will trigger the
             // onAnimationEnd() right away.
-            forceToEnd();
+            end();
         }
     }
 
@@ -1130,8 +1127,10 @@
      */
     private void pulseFrame(Node node, long animPlayTime) {
         if (!node.mEnded) {
+            float durationScale = ValueAnimator.getDurationScale();
+            durationScale = durationScale == 0  ? 1 : durationScale;
             node.mEnded = node.mAnimation.pulseAnimationFrame(
-                    (long) (animPlayTime * ValueAnimator.getDurationScale()));
+                    (long) (animPlayTime * durationScale));
         }
     }
 
diff --git a/core/java/android/annotation/BroadcastBehavior.java b/core/java/android/annotation/BroadcastBehavior.java
new file mode 100644
index 0000000..9b2ca31
--- /dev/null
+++ b/core/java/android/annotation/BroadcastBehavior.java
@@ -0,0 +1,56 @@
+/*
+ * 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.annotation;
+
+import android.content.Intent;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Description of how the annotated broadcast action behaves.
+ *
+ * @hide
+ */
+@Target({ ElementType.FIELD })
+@Retention(RetentionPolicy.SOURCE)
+public @interface BroadcastBehavior {
+    /**
+     * This broadcast will only be delivered to an explicit target.
+     *
+     * @see Intent#setPackage(String)
+     * @see Intent#setComponent(android.content.ComponentName)
+     */
+    boolean explicitOnly() default false;
+
+    /**
+     * This broadcast will only be delivered to registered receivers.
+     *
+     * @see Intent#FLAG_RECEIVER_REGISTERED_ONLY
+     */
+    boolean registeredOnly() default false;
+
+    /**
+     * This broadcast will include all {@code AndroidManifest.xml} receivers
+     * regardless of process state.
+     *
+     * @see Intent#FLAG_RECEIVER_INCLUDE_BACKGROUND
+     */
+    boolean includeBackground() default false;
+}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 78c29e8..37a11ec 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.metrics.LogMaker;
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillManager;
 import android.view.autofill.AutofillValue;
@@ -23,6 +24,8 @@
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.app.ToolbarActionBar;
 import com.android.internal.app.WindowDecorActionBar;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.internal.policy.PhoneWindow;
 
 import android.annotation.CallSuper;
@@ -765,6 +768,7 @@
     /*package*/ Configuration mCurrentConfig;
     private SearchManager mSearchManager;
     private MenuInflater mMenuInflater;
+    private final MetricsLogger mMetricsLogger = new MetricsLogger();
 
     static final class NonConfigurationInstances {
         Object activity;
@@ -7188,6 +7192,8 @@
     public void autofill(List<AutofillId> ids, List<AutofillValue> values) {
         final View root = getWindow().getDecorView();
         final int itemCount = ids.size();
+        int numApplied = 0;
+
         for (int i = 0; i < itemCount; i++) {
             final AutofillId id = ids.get(i);
             final AutofillValue value = values.get(i);
@@ -7197,12 +7203,22 @@
                 Log.w(TAG, "autofill(): no View with id " + viewId);
                 continue;
             }
+            final boolean wasApplied;
             if (id.isVirtual()) {
-                view.autofillVirtual(id.getVirtualChildId(), value);
+                wasApplied = view.autofill(id.getVirtualChildId(), value);
             } else {
-                view.autofill(value);
+                wasApplied = view.autofill(value);
+            }
+
+            if (wasApplied) {
+                numApplied++;
             }
         }
+
+        LogMaker log = new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_DATASET_APPLIED);
+        log.addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_VALUES, itemCount);
+        log.addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_VIEWS_FILLED, numApplied);
+        mMetricsLogger.write(log);
     }
 
     /** @hide */
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 44cc5b4..6b53cd8 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -50,6 +50,7 @@
 import android.database.sqlite.SQLiteDebug.DbStats;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Typeface;
 import android.hardware.display.DisplayManagerGlobal;
 import android.net.ConnectivityManager;
 import android.net.IConnectivityManager;
@@ -148,6 +149,7 @@
 import libcore.io.EventLogger;
 import libcore.io.IoUtils;
 import libcore.net.event.NetworkEventDispatcher;
+import dalvik.system.BaseDexClassLoader;
 import dalvik.system.CloseGuard;
 import dalvik.system.VMDebug;
 import dalvik.system.VMRuntime;
@@ -335,6 +337,8 @@
         Configuration overrideConfig;
         // Used for consolidating configs before sending on to Activity.
         private Configuration tmpConfig = new Configuration();
+        // Callback used for updating activity override config.
+        ViewRootImpl.ActivityConfigCallback configCallback;
         ActivityClientRecord nextIdle;
 
         ProfilerInfo profilerInfo;
@@ -370,6 +374,14 @@
             stopped = false;
             hideForNow = false;
             nextIdle = null;
+            configCallback = (Configuration overrideConfig, int newDisplayId) -> {
+                if (activity == null) {
+                    throw new IllegalStateException(
+                            "Received config update for non-existing activity");
+                }
+                activity.mMainThread.handleActivityConfigurationChanged(
+                        new ActivityConfigChangeData(token, overrideConfig), newDisplayId);
+            };
         }
 
         public boolean isPreHoneycomb() {
@@ -3679,6 +3691,12 @@
                 if (r.activity.mVisibleFromClient) {
                     r.activity.makeVisible();
                 }
+                final ViewRootImpl viewRoot = r.activity.mDecor.getViewRootImpl();
+                if (viewRoot != null) {
+                    // TODO: Figure out the best place to set the callback.
+                    // This looks like a place where decor view is already initialized.
+                    viewRoot.setActivityConfigCallback(r.configCallback);
+                }
             }
 
             if (!r.onlyLocalRequest) {
@@ -5027,7 +5045,7 @@
      * @param displayId Id of the display where activity was moved to, -1 if there was no move and
      *                  value didn't change.
      */
-    private void handleActivityConfigurationChanged(ActivityConfigChangeData data, int displayId) {
+    void handleActivityConfigurationChanged(ActivityConfigChangeData data, int displayId) {
         ActivityClientRecord r = mActivities.get(data.activityToken);
         // Check input params.
         if (r == null || r.activity == null) {
@@ -5044,6 +5062,7 @@
 
         // Perform updates.
         r.overrideConfig = data.overrideConfig;
+        final ViewRootImpl viewRoot = r.activity.mDecor.getViewRootImpl();
         if (movedToDifferentDisplay) {
             if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle activity moved to display, activity:"
                     + r.activityInfo.name + ", displayId=" + displayId
@@ -5051,13 +5070,15 @@
 
             performConfigurationChangedForActivity(r, mCompatConfiguration, displayId,
                     true /* movedToDifferentDisplay */);
-            final ViewRootImpl viewRoot = r.activity.mDecor.getViewRootImpl();
             viewRoot.onMovedToDisplay(displayId);
         } else {
             if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle activity config changed: "
                     + r.activityInfo.name + ", config=" + data.overrideConfig);
             performConfigurationChangedForActivity(r, mCompatConfiguration);
         }
+        // Notify the ViewRootImpl instance about configuration changes. It may have initiated this
+        // update to make sure that resources are updated before updating itself.
+        viewRoot.updateConfiguration();
         mSomeActivitiesChanged = true;
     }
 
@@ -5570,6 +5591,16 @@
             }
         }
 
+        // If we use profiles, setup the dex reporter to notify package manager
+        // of any relevant dex loads. The idle maintenance job will use the information
+        // reported to optimize the loaded dex files.
+        // Note that we only need one global reporter per app.
+        // Make sure we do this before calling onCreate so that we can capture the
+        // complete application startup.
+        if (SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false)) {
+            BaseDexClassLoader.setReporter(DexLoadReporter.getInstance());
+        }
+
         // Install the Network Security Config Provider. This must happen before the application
         // code is loaded to prevent issues with instances of TLS objects being created before
         // the provider is installed.
@@ -5665,6 +5696,7 @@
         }
 
         // Preload fonts resources
+        Typeface.setApplicationContext(appContext);
         try {
             final ApplicationInfo info =
                     getPackageManager().getApplicationInfo(
@@ -6282,35 +6314,26 @@
         // add dropbox logging to libcore
         DropBox.setReporter(new DropBoxReporter());
 
-        ViewRootImpl.addConfigCallback(new ComponentCallbacks2() {
-            @Override
-            public void onConfigurationChanged(Configuration newConfig) {
-                synchronized (mResourcesManager) {
-                    // We need to apply this change to the resources
-                    // immediately, because upon returning the view
-                    // hierarchy will be informed about it.
-                    if (mResourcesManager.applyConfigurationToResourcesLocked(newConfig, null)) {
-                        updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(),
-                                mResourcesManager.getConfiguration().getLocales());
+        ViewRootImpl.ConfigChangedCallback configChangedCallback
+                = (Configuration globalConfig) -> {
+            synchronized (mResourcesManager) {
+                // We need to apply this change to the resources immediately, because upon returning
+                // the view hierarchy will be informed about it.
+                if (mResourcesManager.applyConfigurationToResourcesLocked(globalConfig,
+                        null /* compat */)) {
+                    updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(),
+                            mResourcesManager.getConfiguration().getLocales());
 
-                        // This actually changed the resources!  Tell
-                        // everyone about it.
-                        if (mPendingConfiguration == null ||
-                                mPendingConfiguration.isOtherSeqNewer(newConfig)) {
-                            mPendingConfiguration = newConfig;
-
-                            sendMessage(H.CONFIGURATION_CHANGED, newConfig);
-                        }
+                    // This actually changed the resources! Tell everyone about it.
+                    if (mPendingConfiguration == null
+                            || mPendingConfiguration.isOtherSeqNewer(globalConfig)) {
+                        mPendingConfiguration = globalConfig;
+                        sendMessage(H.CONFIGURATION_CHANGED, globalConfig);
                     }
                 }
             }
-            @Override
-            public void onLowMemory() {
-            }
-            @Override
-            public void onTrimMemory(int level) {
-            }
-        });
+        };
+        ViewRootImpl.addConfigCallback(configChangedCallback);
     }
 
     public static ActivityThread systemMain() {
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 0f2ce3c..09e7595 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -362,6 +362,8 @@
     public static final String OPSTR_ANSWER_PHONE_CALLS
             = "android:answer_phone_calls";
 
+    // Warning: If an permission is added here it also has to be added to
+    // com.android.packageinstaller.permission.utils.EventLogger
     private static final int[] RUNTIME_AND_APPOP_PERMISSIONS_OPS = {
             // RUNTIME PERMISSIONS
             // Contacts
diff --git a/core/java/android/app/ApplicationErrorReport.java b/core/java/android/app/ApplicationErrorReport.java
index 9f1a539..e645261 100644
--- a/core/java/android/app/ApplicationErrorReport.java
+++ b/core/java/android/app/ApplicationErrorReport.java
@@ -22,6 +22,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.os.Binder;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.SystemProperties;
@@ -430,7 +431,7 @@
             dest.writeInt(throwLineNumber);
             dest.writeString(stackTrace);
             int total = dest.dataPosition()-start;
-            if (total > 20*1024) {
+            if (Binder.CHECK_PARCEL_SIZE && total > 20*1024) {
                 Slog.d("Error", "ERR: exClass=" + exceptionClassName);
                 Slog.d("Error", "ERR: exMsg=" + exceptionMessage);
                 Slog.d("Error", "ERR: file=" + throwFileName);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index ede9281..8a3d9b1 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -156,13 +156,13 @@
     @GuardedBy("ContextImpl.class")
     private ArrayMap<String, File> mSharedPrefsPaths;
 
-    final ActivityThread mMainThread;
-    final LoadedApk mPackageInfo;
-    private ClassLoader mClassLoader;
+    final @NonNull ActivityThread mMainThread;
+    final @NonNull LoadedApk mPackageInfo;
+    private @Nullable ClassLoader mClassLoader;
 
-    private final IBinder mActivityToken;
+    private final @Nullable IBinder mActivityToken;
 
-    private final UserHandle mUser;
+    private final @Nullable UserHandle mUser;
 
     private final ApplicationContentResolver mContentResolver;
 
@@ -181,6 +181,9 @@
     private PackageManager mPackageManager;
     private Context mReceiverRestrictedContext = null;
 
+    // The name of the split this Context is representing. May be null.
+    private @Nullable String mSplitName = null;
+
     private final Object mSync = new Object();
 
     @GuardedBy("mSync")
@@ -1914,17 +1917,25 @@
         }
     }
 
-    private static Resources createResources(IBinder activityToken, LoadedApk pi, int displayId,
-            Configuration overrideConfig, CompatibilityInfo compatInfo) {
+    private static Resources createResources(IBinder activityToken, LoadedApk pi, String splitName,
+            int displayId, Configuration overrideConfig, CompatibilityInfo compatInfo) {
+        final String[] splitResDirs;
+        final ClassLoader classLoader;
+        try {
+            splitResDirs = pi.getSplitPaths(splitName);
+            classLoader = pi.getSplitClassLoader(splitName);
+        } catch (NameNotFoundException e) {
+            throw new RuntimeException(e);
+        }
         return ResourcesManager.getInstance().getResources(activityToken,
                 pi.getResDir(),
-                pi.getSplitResDirs(),
+                splitResDirs,
                 pi.getOverlayDirs(),
                 pi.getApplicationInfo().sharedLibraryFiles,
                 displayId,
                 overrideConfig,
                 compatInfo,
-                pi.getClassLoader());
+                classLoader);
     }
 
     @Override
@@ -1933,14 +1944,13 @@
         LoadedApk pi = mMainThread.getPackageInfo(application, mResources.getCompatibilityInfo(),
                 flags | CONTEXT_REGISTER_PACKAGE);
         if (pi != null) {
-            ContextImpl c = new ContextImpl(this, mMainThread, pi, mActivityToken,
-                    new UserHandle(UserHandle.getUserId(application.uid)), flags,
-                    null);
+            ContextImpl c = new ContextImpl(this, mMainThread, pi, null, mActivityToken,
+                    new UserHandle(UserHandle.getUserId(application.uid)), flags, null);
 
             final int displayId = mDisplay != null
                     ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY;
 
-            c.setResources(createResources(mActivityToken, pi, displayId, null,
+            c.setResources(createResources(mActivityToken, pi, null, displayId, null,
                     getDisplayAdjustments(displayId).getCompatibilityInfo()));
             if (c.mResources != null) {
                 return c;
@@ -1964,20 +1974,20 @@
         if (packageName.equals("system") || packageName.equals("android")) {
             // The system resources are loaded in every application, so we can safely copy
             // the context without reloading Resources.
-            return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken, user, flags,
-                    null);
+            return new ContextImpl(this, mMainThread, mPackageInfo, null, mActivityToken, user,
+                    flags, null);
         }
 
         LoadedApk pi = mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(),
                 flags | CONTEXT_REGISTER_PACKAGE, user.getIdentifier());
         if (pi != null) {
-            ContextImpl c = new ContextImpl(this, mMainThread, pi, mActivityToken, user, flags,
-                    null);
+            ContextImpl c = new ContextImpl(this, mMainThread, pi, null, mActivityToken, user,
+                    flags, null);
 
             final int displayId = mDisplay != null
                     ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY;
 
-            c.setResources(createResources(mActivityToken, pi, displayId, null,
+            c.setResources(createResources(mActivityToken, pi, null, displayId, null,
                     getDisplayAdjustments(displayId).getCompatibilityInfo()));
             if (c.mResources != null) {
                 return c;
@@ -1999,7 +2009,7 @@
         final ClassLoader classLoader = mPackageInfo.getSplitClassLoader(splitName);
         final String[] paths = mPackageInfo.getSplitPaths(splitName);
 
-        final ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo,
+        final ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, splitName,
                 mActivityToken, mUser, mFlags, classLoader);
 
         final int displayId = mDisplay != null
@@ -2024,11 +2034,11 @@
             throw new IllegalArgumentException("overrideConfiguration must not be null");
         }
 
-        ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken,
-                mUser, mFlags, mClassLoader);
+        ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mSplitName,
+                mActivityToken, mUser, mFlags, mClassLoader);
 
         final int displayId = mDisplay != null ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY;
-        context.setResources(createResources(mActivityToken, mPackageInfo, displayId,
+        context.setResources(createResources(mActivityToken, mPackageInfo, mSplitName, displayId,
                 overrideConfiguration, getDisplayAdjustments(displayId).getCompatibilityInfo()));
         return context;
     }
@@ -2039,12 +2049,12 @@
             throw new IllegalArgumentException("display must not be null");
         }
 
-        ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken,
-                mUser, mFlags, mClassLoader);
+        ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mSplitName,
+                mActivityToken, mUser, mFlags, mClassLoader);
 
         final int displayId = display.getDisplayId();
-        context.setResources(createResources(mActivityToken, mPackageInfo, displayId, null,
-                getDisplayAdjustments(displayId).getCompatibilityInfo()));
+        context.setResources(createResources(mActivityToken, mPackageInfo, mSplitName, displayId,
+                null, getDisplayAdjustments(displayId).getCompatibilityInfo()));
         context.mDisplay = display;
         return context;
     }
@@ -2053,16 +2063,16 @@
     public Context createDeviceProtectedStorageContext() {
         final int flags = (mFlags & ~Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE)
                 | Context.CONTEXT_DEVICE_PROTECTED_STORAGE;
-        return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken, mUser, flags,
-                mClassLoader);
+        return new ContextImpl(this, mMainThread, mPackageInfo, mSplitName, mActivityToken, mUser,
+                flags, mClassLoader);
     }
 
     @Override
     public Context createCredentialProtectedStorageContext() {
         final int flags = (mFlags & ~Context.CONTEXT_DEVICE_PROTECTED_STORAGE)
                 | Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE;
-        return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken, mUser, flags,
-                mClassLoader);
+        return new ContextImpl(this, mMainThread, mPackageInfo, mSplitName, mActivityToken, mUser,
+                flags, mClassLoader);
     }
 
     @Override
@@ -2149,7 +2159,7 @@
 
     static ContextImpl createSystemContext(ActivityThread mainThread) {
         LoadedApk packageInfo = new LoadedApk(mainThread);
-        ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, 0,
+        ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0,
                 null);
         context.setResources(packageInfo.getResources());
         context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
@@ -2159,7 +2169,7 @@
 
     static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
         if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
-        ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, 0,
+        ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0,
                 null);
         context.setResources(packageInfo.getResources());
         return context;
@@ -2186,8 +2196,8 @@
             }
         }
 
-        ContextImpl context = new ContextImpl(null, mainThread, packageInfo, activityToken, null,
-                0, classLoader);
+        ContextImpl context = new ContextImpl(null, mainThread, packageInfo, activityInfo.splitName,
+                activityToken, null, 0, classLoader);
 
         // Clamp display ID to DEFAULT_DISPLAY if it is INVALID_DISPLAY.
         displayId = (displayId != Display.INVALID_DISPLAY) ? displayId : Display.DEFAULT_DISPLAY;
@@ -2214,9 +2224,10 @@
         return context;
     }
 
-    private ContextImpl(ContextImpl container, ActivityThread mainThread,
-            LoadedApk packageInfo, IBinder activityToken, UserHandle user, int flags,
-            ClassLoader classLoader) {
+    private ContextImpl(@Nullable ContextImpl container, @NonNull ActivityThread mainThread,
+            @NonNull LoadedApk packageInfo, @Nullable String splitName,
+            @Nullable IBinder activityToken, @Nullable UserHandle user, int flags,
+            @Nullable ClassLoader classLoader) {
         mOuterContext = this;
 
         // If creator didn't specify which storage to use, use the default
@@ -2241,6 +2252,7 @@
         mUser = user;
 
         mPackageInfo = packageInfo;
+        mSplitName = splitName;
         mClassLoader = classLoader;
         mResourcesManager = ResourcesManager.getInstance();
 
diff --git a/core/java/android/app/DexLoadReporter.java b/core/java/android/app/DexLoadReporter.java
new file mode 100644
index 0000000..13f288a
--- /dev/null
+++ b/core/java/android/app/DexLoadReporter.java
@@ -0,0 +1,168 @@
+/*
+ * 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.app;
+
+import android.os.FileUtils;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+
+import dalvik.system.BaseDexClassLoader;
+import dalvik.system.VMRuntime;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A dex load reporter which will notify package manager of any dex file loaded
+ * with {@code BaseDexClassLoader}.
+ * The goals are:
+ *     1) discover secondary dex files so that they can be optimized during the
+ *        idle maintenance job.
+ *     2) determine whether or not a dex file is used by an app which does not
+ *        own it (in order to select the optimal compilation method).
+ * @hide
+ */
+/*package*/ class DexLoadReporter implements BaseDexClassLoader.Reporter {
+    private static final String TAG = "DexLoadReporter";
+
+    private static final DexLoadReporter INSTANCE = new DexLoadReporter();
+
+    private static final boolean DEBUG = false;
+
+    // We must guard the access to the list of data directories because
+    // we might have concurrent accesses. Apps might load dex files while
+    // new data dirs are registered (due to creation of LoadedApks via
+    // create createApplicationContext).
+    @GuardedBy("mDataDirs")
+    private final Set<String> mDataDirs;
+
+    private DexLoadReporter() {
+        mDataDirs = new HashSet<>();
+    }
+
+    /*package*/ static DexLoadReporter getInstance() {
+        return INSTANCE;
+    }
+
+    /**
+     * Register an application data directory with the reporter.
+     * The data directories are used to determine if a dex file is secondary dex or not.
+     * Note that this method may be called multiple times for the same app, registering
+     * different data directories. This may happen when apps share the same user id
+     * ({@code android:sharedUserId}). For example, if app1 and app2 share the same user
+     * id, and app1 loads app2 apk, then both data directories will be registered.
+     */
+    /*package*/ void registerAppDataDir(String packageName, String dataDir) {
+        if (DEBUG) {
+            Slog.i(TAG, "Package " + packageName + " registering data dir: " + dataDir);
+        }
+        // TODO(calin): A few code paths imply that the data dir
+        // might be null. Investigate when that can happen.
+        if (dataDir != null) {
+            synchronized (mDataDirs) {
+                mDataDirs.add(dataDir);
+            }
+        }
+    }
+
+    @Override
+    public void report(List<String> dexPaths) {
+        if (dexPaths.isEmpty()) {
+            return;
+        }
+        // Notify the package manager about the dex loads unconditionally.
+        // The load might be for either a primary or secondary dex file.
+        notifyPackageManager(dexPaths);
+        // Check for secondary dex files and register them for profiling if
+        // possible.
+        registerSecondaryDexForProfiling(dexPaths);
+    }
+
+    private void notifyPackageManager(List<String> dexPaths) {
+        String packageName = ActivityThread.currentPackageName();
+        try {
+            ActivityThread.getPackageManager().notifyDexLoad(
+                    packageName, dexPaths, VMRuntime.getRuntime().vmInstructionSet());
+        } catch (RemoteException re) {
+            Slog.e(TAG, "Failed to notify PM about dex load for package " + packageName, re);
+        }
+    }
+
+    private void registerSecondaryDexForProfiling(List<String> dexPaths) {
+        if (!SystemProperties.getBoolean("dalvik.vm.dexopt.secondary", false)) {
+            return;
+        }
+        // Make a copy of the current data directories so that we don't keep the lock
+        // while registering for profiling. The registration will perform I/O to
+        // check for or create the profile.
+        String[] dataDirs;
+        synchronized (mDataDirs) {
+            dataDirs = mDataDirs.toArray(new String[0]);
+        }
+        for (String dexPath : dexPaths) {
+            registerSecondaryDexForProfiling(dexPath, dataDirs);
+        }
+    }
+
+    private void registerSecondaryDexForProfiling(String dexPath, String[] dataDirs) {
+        if (!isSecondaryDexFile(dexPath, dataDirs)) {
+            // The dex path is not a secondary dex file. Nothing to do.
+            return;
+        }
+        File secondaryProfile = getSecondaryProfileFile(dexPath);
+        try {
+            // Create the profile if not already there.
+            // Returns true if the file was created, false if the file already exists.
+            // or throws exceptions in case of errors.
+            boolean created = secondaryProfile.createNewFile();
+            if (DEBUG && created) {
+                Slog.i(TAG, "Created profile for secondary dex: " + secondaryProfile);
+            }
+        } catch (IOException ex) {
+            Slog.e(TAG, "Failed to create profile for secondary dex " + secondaryProfile +
+                    ":" + ex.getMessage());
+            // Don't move forward with the registration if we failed to create the profile.
+            return;
+        }
+
+        VMRuntime.registerAppInfo(secondaryProfile.getPath(), new String[] { dexPath });
+    }
+
+    // A dex file is a secondary dex file if it is in any of the registered app
+    // data directories.
+    private boolean isSecondaryDexFile(String dexPath, String[] dataDirs) {
+        for (String dataDir : dataDirs) {
+            if (FileUtils.contains(dataDir, dexPath)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    // Secondary dex profiles are stored next to the dex file and have the same
+    // name with '.prof' appended.
+    // NOTE: Keep in sync with installd.
+    private File getSecondaryProfileFile(String dexPath) {
+        return new File(dexPath + ".prof");
+    }
+}
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 5ab767b..5ea2480 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -66,6 +66,9 @@
     ParceledListSlice getNotificationChannels(String pkg);
     ParceledListSlice getNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted);
     int getNumNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted);
+    int getDeletedChannelCount(String pkg, int uid);
+    void deleteNotificationChannelGroup(String pkg, String channelGroupId);
+    ParceledListSlice getNotificationChannelGroups(String pkg);
 
     // TODO: Remove this when callers have been migrated to the equivalent
     // INotificationListener method.
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 77c4c7e..dbed1be 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -27,7 +27,8 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
-import android.content.pm.split.SplitDependencyLoaderHelper;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.split.SplitDependencyLoader;
 import android.content.res.AssetManager;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Resources;
@@ -49,13 +50,11 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
-import android.util.SparseIntArray;
 import android.view.Display;
 import android.view.DisplayAdjustments;
 
 import com.android.internal.util.ArrayUtils;
 
-import dalvik.system.BaseDexClassLoader;
 import dalvik.system.VMRuntime;
 
 import java.io.File;
@@ -305,7 +304,7 @@
                 final String[] splitPaths;
                 try {
                     splitPaths = getSplitPaths(null);
-                } catch (PackageManager.NameNotFoundException e) {
+                } catch (NameNotFoundException e) {
                     // This should NEVER fail.
                     throw new AssertionError("null split not found");
                 }
@@ -337,7 +336,7 @@
         mSplitResDirs = aInfo.uid == myUid ? aInfo.splitSourceDirs : aInfo.splitPublicSourceDirs;
 
         if (aInfo.requestsIsolatedSplitLoading() && !ArrayUtils.isEmpty(mSplitNames)) {
-            mSplitLoader = new SplitDependencyLoader(aInfo.splitDependencies);
+            mSplitLoader = new SplitDependencyLoaderImpl(aInfo.splitDependencies);
         }
     }
 
@@ -466,110 +465,88 @@
         }
     }
 
-    private class SplitDependencyLoader
-            extends SplitDependencyLoaderHelper<PackageManager.NameNotFoundException> {
-        private String[] mCachedBaseResourcePath;
+    /*
+     * All indices received by the super class should be shifted by 1 when accessing mSplitNames,
+     * etc. The super class assumes the base APK is index 0, while the PackageManager APIs don't
+     * include the base APK in the list of splits.
+     */
+    private class SplitDependencyLoaderImpl extends SplitDependencyLoader<NameNotFoundException> {
         private final String[][] mCachedResourcePaths;
-        private final ClassLoader[] mCachedSplitClassLoaders;
+        private final ClassLoader[] mCachedClassLoaders;
 
-        SplitDependencyLoader(SparseIntArray dependencies) {
+        SplitDependencyLoaderImpl(@NonNull SparseArray<int[]> dependencies) {
             super(dependencies);
-            mCachedResourcePaths = new String[mSplitNames.length][];
-            mCachedSplitClassLoaders = new ClassLoader[mSplitNames.length];
+            mCachedResourcePaths = new String[mSplitNames.length + 1][];
+            mCachedClassLoaders = new ClassLoader[mSplitNames.length + 1];
         }
 
         @Override
         protected boolean isSplitCached(int splitIdx) {
-            if (splitIdx != -1) {
-                return mCachedSplitClassLoaders[splitIdx] != null;
-            }
-            return mClassLoader != null && mCachedBaseResourcePath != null;
-        }
-
-        private void addAllConfigSplits(String splitName, ArrayList<String> outAssetPaths) {
-            for (int i = 0; i < mSplitNames.length; i++) {
-                if (isConfigurationSplitOf(mSplitNames[i], splitName)) {
-                    outAssetPaths.add(mSplitResDirs[i]);
-                }
-            }
+            return mCachedClassLoaders[splitIdx] != null;
         }
 
         @Override
-        protected void constructSplit(int splitIdx, int parentSplitIdx) throws
-                PackageManager.NameNotFoundException {
+        protected void constructSplit(int splitIdx, @NonNull int[] configSplitIndices,
+                int parentSplitIdx) throws NameNotFoundException {
             final ArrayList<String> splitPaths = new ArrayList<>();
-            if (splitIdx == -1) {
+            if (splitIdx == 0) {
                 createOrUpdateClassLoaderLocked(null);
-                addAllConfigSplits(null, splitPaths);
-                mCachedBaseResourcePath = splitPaths.toArray(new String[splitPaths.size()]);
+                mCachedClassLoaders[0] = mClassLoader;
+
+                // Never add the base resources here, they always get added no matter what.
+                for (int configSplitIdx : configSplitIndices) {
+                    splitPaths.add(mSplitResDirs[configSplitIdx - 1]);
+                }
+                mCachedResourcePaths[0] = splitPaths.toArray(new String[splitPaths.size()]);
                 return;
             }
 
-            final ClassLoader parent;
-            if (parentSplitIdx == -1) {
-                // The parent is the base APK, so use its ClassLoader as parent
-                // and its configuration splits as part of our own too.
-                parent = mClassLoader;
-                Collections.addAll(splitPaths, mCachedBaseResourcePath);
-            } else {
-                parent = mCachedSplitClassLoaders[parentSplitIdx];
-                Collections.addAll(splitPaths, mCachedResourcePaths[parentSplitIdx]);
+            // Since we handled the special base case above, parentSplitIdx is always valid.
+            final ClassLoader parent = mCachedClassLoaders[parentSplitIdx];
+            mCachedClassLoaders[splitIdx] = ApplicationLoaders.getDefault().getClassLoader(
+                    mSplitAppDirs[splitIdx - 1], getTargetSdkVersion(), false, null, null, parent);
+
+            Collections.addAll(splitPaths, mCachedResourcePaths[parentSplitIdx]);
+            splitPaths.add(mSplitResDirs[splitIdx - 1]);
+            for (int configSplitIdx : configSplitIndices) {
+                splitPaths.add(mSplitResDirs[configSplitIdx - 1]);
             }
-
-            mCachedSplitClassLoaders[splitIdx] = ApplicationLoaders.getDefault().getClassLoader(
-                    mSplitAppDirs[splitIdx], getTargetSdkVersion(), false, null, null, parent);
-
-            splitPaths.add(mSplitResDirs[splitIdx]);
-            addAllConfigSplits(mSplitNames[splitIdx], splitPaths);
             mCachedResourcePaths[splitIdx] = splitPaths.toArray(new String[splitPaths.size()]);
         }
 
-        private int ensureSplitLoaded(String splitName)
-                throws PackageManager.NameNotFoundException {
-            final int idx;
-            if (splitName == null) {
-                idx = -1;
-            } else {
+        private int ensureSplitLoaded(String splitName) throws NameNotFoundException {
+            int idx = 0;
+            if (splitName != null) {
                 idx = Arrays.binarySearch(mSplitNames, splitName);
                 if (idx < 0) {
                     throw new PackageManager.NameNotFoundException(
                             "Split name '" + splitName + "' is not installed");
                 }
+                idx += 1;
             }
-
             loadDependenciesForSplit(idx);
             return idx;
         }
 
-        ClassLoader getClassLoaderForSplit(String splitName)
-                throws PackageManager.NameNotFoundException {
-            final int idx = ensureSplitLoaded(splitName);
-            if (idx < 0) {
-                return mClassLoader;
-            }
-            return mCachedSplitClassLoaders[idx];
+        ClassLoader getClassLoaderForSplit(String splitName) throws NameNotFoundException {
+            return mCachedClassLoaders[ensureSplitLoaded(splitName)];
         }
 
-        String[] getSplitPathsForSplit(String splitName)
-                throws PackageManager.NameNotFoundException {
-            final int idx = ensureSplitLoaded(splitName);
-            if (idx < 0) {
-                return mCachedBaseResourcePath;
-            }
-            return mCachedResourcePaths[idx];
+        String[] getSplitPathsForSplit(String splitName) throws NameNotFoundException {
+            return mCachedResourcePaths[ensureSplitLoaded(splitName)];
         }
     }
 
-    private SplitDependencyLoader mSplitLoader;
+    private SplitDependencyLoaderImpl mSplitLoader;
 
-    ClassLoader getSplitClassLoader(String splitName) throws PackageManager.NameNotFoundException {
+    ClassLoader getSplitClassLoader(String splitName) throws NameNotFoundException {
         if (mSplitLoader == null) {
             return mClassLoader;
         }
         return mSplitLoader.getClassLoaderForSplit(splitName);
     }
 
-    String[] getSplitPaths(String splitName) throws PackageManager.NameNotFoundException {
+    String[] getSplitPaths(String splitName) throws NameNotFoundException {
         if (mSplitLoader == null) {
             return mSplitResDirs;
         }
@@ -752,39 +729,10 @@
         VMRuntime.registerAppInfo(profileFile.getPath(),
                 codePaths.toArray(new String[codePaths.size()]));
 
-        // Setup the reporter to notify package manager of any relevant dex loads.
-        // At this point the primary apk is loaded and will not be reported.
-        // Anything loaded from now on will be tracked as a potential secondary
-        // or foreign dex file. The goal is to enable:
-        //    1) monitoring and compilation of secondary dex file
-        //    2) track whether or not a dex file is used by other apps (used to
-        //       determined the compilation filter of apks).
-        if (BaseDexClassLoader.getReporter() != DexLoadReporter.INSTANCE) {
-            // Set the dex load reporter if not already set.
-            // Note that during the app's life cycle different LoadedApks may be
-            // created and loaded (e.g. if two different apps share the same runtime).
-            BaseDexClassLoader.setReporter(DexLoadReporter.INSTANCE);
-        }
-    }
-
-    private static class DexLoadReporter implements BaseDexClassLoader.Reporter {
-        private static final DexLoadReporter INSTANCE = new DexLoadReporter();
-
-        private DexLoadReporter() {}
-
-        @Override
-        public void report(List<String> dexPaths) {
-            if (dexPaths.isEmpty()) {
-                return;
-            }
-            String packageName = ActivityThread.currentPackageName();
-            try {
-                ActivityThread.getPackageManager().notifyDexLoad(
-                        packageName, dexPaths, VMRuntime.getRuntime().vmInstructionSet());
-            } catch (RemoteException re) {
-                Slog.e(TAG, "Failed to notify PM about dex load for package " + packageName, re);
-            }
-        }
+        // Register the app data directory with the reporter. It will
+        // help deciding whether or not a dex file is the primary apk or a
+        // secondary dex.
+        DexLoadReporter.getInstance().registerAppDataDir(mPackageName, mDataDir);
     }
 
     /**
@@ -955,7 +903,7 @@
             final String[] splitPaths;
             try {
                 splitPaths = getSplitPaths(null);
-            } catch (PackageManager.NameNotFoundException e) {
+            } catch (NameNotFoundException e) {
                 // This should never fail.
                 throw new AssertionError("null split not found");
             }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index a098591..aee9d386 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1935,7 +1935,9 @@
         if (this.actions != null) {
             that.actions = new Action[this.actions.length];
             for(int i=0; i<this.actions.length; i++) {
-                that.actions[i] = this.actions[i].clone();
+                if ( this.actions[i] != null) {
+                    that.actions[i] = this.actions[i].clone();
+                }
             }
         }
 
@@ -3432,7 +3434,9 @@
          * @param action The action to add.
          */
         public Builder addAction(Action action) {
-            mActions.add(action);
+            if (action != null) {
+                mActions.add(action);
+            }
             return this;
         }
 
@@ -3446,7 +3450,9 @@
         public Builder setActions(Action... actions) {
             mActions.clear();
             for (int i = 0; i < actions.length; i++) {
-                mActions.add(actions[i]);
+                if (actions[i] != null) {
+                    mActions.add(actions[i]);
+                }
             }
             return this;
         }
@@ -5651,11 +5657,13 @@
             static final String KEY_SENDER = "sender";
             static final String KEY_DATA_MIME_TYPE = "type";
             static final String KEY_DATA_URI= "uri";
+            static final String KEY_EXTRAS_BUNDLE = "extras";
 
             private final CharSequence mText;
             private final long mTimestamp;
             private final CharSequence mSender;
 
+            private Bundle mExtras = new Bundle();
             private String mDataMimeType;
             private Uri mDataUri;
 
@@ -5724,6 +5732,13 @@
             }
 
             /**
+             * Get the extras Bundle for this message.
+             */
+            public Bundle getExtras() {
+                return mExtras;
+            }
+
+            /**
              * Get the text used to display the contact's name in the messaging experience
              */
             public CharSequence getSender() {
@@ -5760,6 +5775,9 @@
                 if (mDataUri != null) {
                     bundle.putParcelable(KEY_DATA_URI, mDataUri);
                 }
+                if (mExtras != null) {
+                    bundle.putBundle(KEY_EXTRAS_BUNDLE, mExtras);
+                }
                 return bundle;
             }
 
@@ -5794,10 +5812,12 @@
                                 bundle.getLong(KEY_TIMESTAMP), bundle.getCharSequence(KEY_SENDER));
                         if (bundle.containsKey(KEY_DATA_MIME_TYPE) &&
                                 bundle.containsKey(KEY_DATA_URI)) {
-
                             message.setData(bundle.getString(KEY_DATA_MIME_TYPE),
                                     (Uri) bundle.getParcelable(KEY_DATA_URI));
                         }
+                        if (bundle.containsKey(KEY_EXTRAS_BUNDLE)) {
+                            message.getExtras().putAll(bundle.getBundle(KEY_EXTRAS_BUNDLE));
+                        }
                         return message;
                     }
                 } catch (ClassCastException e) {
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 16c85f5..29c4520 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -24,6 +24,7 @@
 import android.annotation.Nullable;
 import android.annotation.StringRes;
 import android.annotation.SystemApi;
+import android.content.Intent;
 import android.media.AudioAttributes;
 import android.net.Uri;
 import android.os.Parcel;
@@ -47,7 +48,6 @@
 
     private static final String TAG_CHANNEL = "channel";
     private static final String ATT_NAME = "name";
-    private static final String ATT_NAME_RES_ID = "name_res_id";
     private static final String ATT_ID = "id";
     private static final String ATT_DELETED = "deleted";
     private static final String ATT_PRIORITY = "priority";
@@ -141,7 +141,6 @@
 
     private final String mId;
     private CharSequence mName;
-    private int mNameResId = 0;
     private int mImportance = DEFAULT_IMPORTANCE;
     private boolean mBypassDnd;
     private int mLockscreenVisibility = DEFAULT_VISIBILITY;
@@ -162,7 +161,9 @@
      * @param id The id of the channel. Must be unique per package.
      * @param name The user visible name of the channel. Unchangeable once created; use this
      *             constructor if the channel represents a user-defined category that does not
-     *             need to be translated.
+     *             need to be translated. You can rename this channel when the system
+     *             locale changes by listening for the {@link Intent#ACTION_LOCALE_CHANGED}
+     *             broadcast.
      * @param importance The importance of the channel. This controls how interruptive notifications
      *                   posted to this channel are. See e.g.
      *                   {@link NotificationManager#IMPORTANCE_DEFAULT}.
@@ -173,21 +174,6 @@
         this.mImportance = importance;
     }
 
-    /**
-     * Creates a notification channel.
-     *
-     * @param id The id of the channel. Must be unique per package.
-     * @param nameResId The resource id of the string containing the channel name.
-     * @param importance The importance of the channel. This controls how interruptive notifications
-     *                   posted to this channel are. See e.g.
-     *                   {@link NotificationManager#IMPORTANCE_DEFAULT}.
-     */
-    public NotificationChannel(String id, @StringRes int nameResId, int importance) {
-        this.mId = id;
-        this.mNameResId = nameResId;
-        this.mImportance = importance;
-    }
-
     protected NotificationChannel(Parcel in) {
         if (in.readByte() != 0) {
             mId = in.readString();
@@ -195,7 +181,6 @@
             mId = null;
         }
         mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
-        mNameResId = in.readInt();
         mImportance = in.readInt();
         mBypassDnd = in.readByte() != 0;
         mLockscreenVisibility = in.readInt();
@@ -228,7 +213,6 @@
             dest.writeByte((byte) 0);
         }
         TextUtils.writeToParcel(mName, dest, flags);
-        dest.writeInt(mNameResId);
         dest.writeInt(mImportance);
         dest.writeByte(mBypassDnd ? (byte) 1 : (byte) 0);
         dest.writeInt(mLockscreenVisibility);
@@ -262,7 +246,6 @@
     /**
      * @hide
      */
-    @SystemApi
     public void lockFields(int field) {
         mUserLockedFields |= field;
     }
@@ -270,16 +253,15 @@
     /**
      * @hide
      */
-    @SystemApi
     public void setDeleted(boolean deleted) {
         mDeleted = deleted;
     }
 
     /**
-     * @hide
+     * Sets the name of this channel.
      */
-    public void setNameResId(@StringRes int nameResId) {
-        this.mNameResId = nameResId;
+    public void setName(CharSequence name) {
+        mName = name;
     }
 
     // Modifiable by a notification ranker.
@@ -417,13 +399,6 @@
     }
 
     /**
-     * Returns the resource id of the user visible name of this channel.
-     */
-    public int getNameResId() {
-        return mNameResId;
-    }
-
-    /**
      * Returns the user specified importance {e.g. @link NotificationManager#IMPORTANCE_LOW} for
      * notifications posted to this channel.
      */
@@ -556,7 +531,6 @@
         if (getName() != null) {
             out.attribute(null, ATT_NAME, getName().toString());
         }
-        out.attribute(null, ATT_NAME_RES_ID, Integer.toString(getNameResId()));
         if (getImportance() != DEFAULT_IMPORTANCE) {
             out.attribute(
                     null, ATT_IMPORTANCE, Integer.toString(getImportance()));
@@ -614,7 +588,6 @@
         JSONObject record = new JSONObject();
         record.put(ATT_ID, getId());
         record.put(ATT_NAME, getName());
-        record.put(ATT_NAME_RES_ID, getNameResId());
         if (getImportance() != DEFAULT_IMPORTANCE) {
             record.put(ATT_IMPORTANCE,
                     NotificationListenerService.Ranking.importanceToString(getImportance()));
@@ -732,7 +705,6 @@
 
         NotificationChannel that = (NotificationChannel) o;
 
-        if (getNameResId() != that.getNameResId()) return false;
         if (getImportance() != that.getImportance()) return false;
         if (mBypassDnd != that.mBypassDnd) return false;
         if (getLockscreenVisibility() != that.getLockscreenVisibility()) return false;
@@ -762,7 +734,6 @@
     public int hashCode() {
         int result = getId() != null ? getId().hashCode() : 0;
         result = 31 * result + (getName() != null ? getName().hashCode() : 0);
-        result = 31 * result + getNameResId();
         result = 31 * result + getImportance();
         result = 31 * result + (mBypassDnd ? 1 : 0);
         result = 31 * result + getLockscreenVisibility();
@@ -784,7 +755,6 @@
         return "NotificationChannel{" +
                 "mId='" + mId + '\'' +
                 ", mName=" + mName +
-                ", mNameResId=" + mNameResId +
                 ", mImportance=" + mImportance +
                 ", mBypassDnd=" + mBypassDnd +
                 ", mLockscreenVisibility=" + mLockscreenVisibility +
diff --git a/core/java/android/app/NotificationChannelGroup.java b/core/java/android/app/NotificationChannelGroup.java
index 288d39a..2b0cd04 100644
--- a/core/java/android/app/NotificationChannelGroup.java
+++ b/core/java/android/app/NotificationChannelGroup.java
@@ -17,6 +17,7 @@
 
 import android.annotation.StringRes;
 import android.annotation.SystemApi;
+import android.content.Intent;
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -41,38 +42,25 @@
 
     private static final String TAG_GROUP = "channelGroup";
     private static final String ATT_NAME = "name";
-    private static final String ATT_NAME_RES_ID = "name_res_id";
     private static final String ATT_ID = "id";
 
     private final String mId;
     private CharSequence mName;
-    private int mNameResId = 0;
     private List<NotificationChannel> mChannels = new ArrayList<>();
 
     /**
-     * Creates a notification channel.
+     * Creates a notification channel group.
      *
      * @param id The id of the group. Must be unique per package.
-     * @param name The user visible name of the group. Unchangeable once created; use this
-     *             constructor if the group represents something user-defined that does not
-     *             need to be translated.
+     * @param name The user visible name of the group. You can rename this group when the system
+     *             locale changes by listening for the {@link Intent#ACTION_LOCALE_CHANGED}
+     *             broadcast.
      */
     public NotificationChannelGroup(String id, CharSequence name) {
         this.mId = id;
         this.mName = name;
     }
 
-    /**
-     * Creates a notification channel.
-     *
-     * @param id The id of the group. Must be unique per package.
-     * @param nameResId String resource id of the user visible name of the group.
-     */
-    public NotificationChannelGroup(String id, @StringRes int nameResId) {
-        this.mId = id;
-        this.mNameResId = nameResId;
-    }
-
     protected NotificationChannelGroup(Parcel in) {
         if (in.readByte() != 0) {
             mId = in.readString();
@@ -80,7 +68,6 @@
             mId = null;
         }
         mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
-        mNameResId = in.readInt();
         in.readParcelableList(mChannels, NotificationChannel.class.getClassLoader());
     }
 
@@ -93,7 +80,6 @@
             dest.writeByte((byte) 0);
         }
         TextUtils.writeToParcel(mName, dest, flags);
-        dest.writeInt(mNameResId);
         dest.writeParcelableList(mChannels, flags);
     }
 
@@ -111,19 +97,11 @@
         return mName;
     }
 
-    /**
-     * Returns the resource id of the user visible name of this group.
-     */
-    public @StringRes int getNameResId() {
-        return mNameResId;
-    }
-
     /*
      * Returns the list of channels that belong to this group
      *
      * @hide
      */
-    @SystemApi
     public List<NotificationChannel> getChannels() {
         return mChannels;
     }
@@ -131,7 +109,6 @@
     /**
      * @hide
      */
-    @SystemApi
     public void addChannel(NotificationChannel channel) {
         mChannels.add(channel);
     }
@@ -139,7 +116,6 @@
     /**
      * @hide
      */
-    @SystemApi
     public void writeXml(XmlSerializer out) throws IOException {
         out.startTag(null, TAG_GROUP);
 
@@ -147,9 +123,6 @@
         if (getName() != null) {
             out.attribute(null, ATT_NAME, getName().toString());
         }
-        if (getNameResId() != 0) {
-            out.attribute(null, ATT_NAME_RES_ID, Integer.toString(getNameResId()));
-        }
 
         out.endTag(null, TAG_GROUP);
     }
@@ -162,7 +135,6 @@
         JSONObject record = new JSONObject();
         record.put(ATT_ID, getId());
         record.put(ATT_NAME, getName());
-        record.put(ATT_NAME_RES_ID, getNameResId());
         return record;
     }
 
@@ -191,31 +163,22 @@
 
         NotificationChannelGroup that = (NotificationChannelGroup) o;
 
-        if (getNameResId() != that.getNameResId()) return false;
         if (getId() != null ? !getId().equals(that.getId()) : that.getId() != null) return false;
         if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) {
             return false;
         }
-        return getChannels() != null ? getChannels().equals(that.getChannels())
-                : that.getChannels() == null;
-
+        return true;
     }
 
     @Override
     public NotificationChannelGroup clone() {
-        if (getName() != null) {
-            return new NotificationChannelGroup(getId(), getName());
-        } else {
-            return new NotificationChannelGroup(getId(), getNameResId());
-        }
+        return new NotificationChannelGroup(getId(), getName());
     }
 
     @Override
     public int hashCode() {
         int result = getId() != null ? getId().hashCode() : 0;
         result = 31 * result + (getName() != null ? getName().hashCode() : 0);
-        result = 31 * result + getNameResId();
-        result = 31 * result + (getChannels() != null ? getChannels().hashCode() : 0);
         return result;
     }
 
@@ -224,7 +187,6 @@
         return "NotificationChannelGroup{" +
                 "mId='" + mId + '\'' +
                 ", mName=" + mName +
-                ", mNameResId=" + mNameResId +
                 ", mChannels=" + mChannels +
                 '}';
     }
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 2296838..0379970 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -385,7 +385,7 @@
     /**
      * Creates a group container for {@link NotificationChannel} objects.
      *
-     * This is a no-op for groups that already exist.
+     * This can be used to rename an existing group.
      * <p>
      *     Group information is only used for presentation, not for behavior. Groups are optional
      *     for channels, and you can have a mix of channels that belong to groups and channels
@@ -421,21 +421,22 @@
     /**
      * Creates a notification channel that notifications can be posted to.
      *
-     * This is a no-op for channels that already exist.
+     * This can also be used to restore a deleted channel and to rename an existing channel. All
+     * other fields are ignored for channels that already exist.
      *
      * @param channel  the channel to create.  Note that the created channel may differ from this
      *                 value. If the provided channel is malformed, a RemoteException will be
-     *                 thrown. If the channel already exists, it will not be modified.
+     *                 thrown.
      */
     public void createNotificationChannel(@NonNull NotificationChannel channel) {
         createNotificationChannels(Arrays.asList(channel));
     }
 
     /**
-     * Creates multiple notification channels that different notifications can be posted to.
+     * Creates multiple notification channels that different notifications can be posted to. See
+     * {@link #createNotificationChannel(NotificationChannel)}.
      *
-     * @param channels the list of channels to attempt to create.  If any of these channels already
-     *                 exist, they will not be modified.
+     * @param channels the list of channels to attempt to create.
      */
     public void createNotificationChannels(@NonNull List<NotificationChannel> channels) {
         INotificationManager service = getService();
@@ -497,6 +498,30 @@
     }
 
     /**
+     * Returns all notification channel groups belonging to the calling app.
+     */
+    public List<NotificationChannelGroup> getNotificationChannelGroups() {
+        INotificationManager service = getService();
+        try {
+            return service.getNotificationChannelGroups(mContext.getPackageName()).getList();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Deletes the given notification channel group.
+     */
+    public void deleteNotificationChannelGroup(String groupId) {
+        INotificationManager service = getService();
+        try {
+            service.deleteNotificationChannelGroup(mContext.getPackageName(), groupId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * @hide
      */
     @TestApi
diff --git a/core/java/android/app/RemoteAction.java b/core/java/android/app/RemoteAction.java
index 5958bc1..e7fe407 100644
--- a/core/java/android/app/RemoteAction.java
+++ b/core/java/android/app/RemoteAction.java
@@ -41,12 +41,14 @@
     private final CharSequence mTitle;
     private final CharSequence mContentDescription;
     private final PendingIntent mActionIntent;
+    private boolean mEnabled;
 
     RemoteAction(Parcel in) {
         mIcon = Icon.CREATOR.createFromParcel(in);
         mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
         mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
         mActionIntent = PendingIntent.CREATOR.createFromParcel(in);
+        mEnabled = in.readBoolean();
     }
 
     public RemoteAction(@NonNull Icon icon, @NonNull CharSequence title,
@@ -59,6 +61,21 @@
         mTitle = title;
         mContentDescription = contentDescription;
         mActionIntent = intent;
+        mEnabled = true;
+    }
+
+    /**
+     * Sets whether this action is enabled.
+     */
+    public void setEnabled(boolean enabled) {
+        mEnabled = enabled;
+    }
+
+    /**
+     * Return whether this action is enabled.
+     */
+    public boolean isEnabled() {
+        return mEnabled;
     }
 
     /**
@@ -91,7 +108,9 @@
 
     @Override
     public RemoteAction clone() {
-        return new RemoteAction(mIcon, mTitle, mContentDescription, mActionIntent);
+        RemoteAction action = new RemoteAction(mIcon, mTitle, mContentDescription, mActionIntent);
+        action.setEnabled(mEnabled);
+        return action;
     }
 
     @Override
@@ -105,11 +124,13 @@
         TextUtils.writeToParcel(mTitle, out, flags);
         TextUtils.writeToParcel(mContentDescription, out, flags);
         mActionIntent.writeToParcel(out, flags);
+        out.writeBoolean(mEnabled);
     }
 
     public void dump(String prefix, PrintWriter pw) {
         pw.print(prefix);
         pw.print("title=" + mTitle);
+        pw.print(" enabled=" + mEnabled);
         pw.print(" contentDescription=" + mContentDescription);
         pw.print(" icon=" + mIcon);
         pw.print(" action=" + mActionIntent.getIntent());
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index 0fb5966..d9b6eed 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -17,6 +17,7 @@
 package android.app.admin;
 
 import android.accounts.AccountManager;
+import android.annotation.BroadcastBehavior;
 import android.annotation.IntDef;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
@@ -81,6 +82,7 @@
      * that other applications can not abuse it.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @BroadcastBehavior(explicitOnly = true)
     public static final String ACTION_DEVICE_ADMIN_ENABLED
             = "android.app.action.DEVICE_ADMIN_ENABLED";
 
@@ -94,6 +96,7 @@
      * to the user before they disable your admin.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @BroadcastBehavior(explicitOnly = true)
     public static final String ACTION_DEVICE_ADMIN_DISABLE_REQUESTED
             = "android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED";
 
@@ -115,6 +118,7 @@
      * its intent filter.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @BroadcastBehavior(explicitOnly = true)
     public static final String ACTION_DEVICE_ADMIN_DISABLED
             = "android.app.action.DEVICE_ADMIN_DISABLED";
 
@@ -131,6 +135,7 @@
      * this broadcast.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @BroadcastBehavior(explicitOnly = true)
     public static final String ACTION_PASSWORD_CHANGED
             = "android.app.action.ACTION_PASSWORD_CHANGED";
 
@@ -147,6 +152,7 @@
      * this broadcast.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @BroadcastBehavior(explicitOnly = true)
     public static final String ACTION_PASSWORD_FAILED
             = "android.app.action.ACTION_PASSWORD_FAILED";
 
@@ -160,6 +166,7 @@
      * this broadcast.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @BroadcastBehavior(explicitOnly = true)
     public static final String ACTION_PASSWORD_SUCCEEDED
             = "android.app.action.ACTION_PASSWORD_SUCCEEDED";
 
@@ -173,6 +180,7 @@
      * this broadcast.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @BroadcastBehavior(explicitOnly = true)
     public static final String ACTION_PASSWORD_EXPIRING
             = "android.app.action.ACTION_PASSWORD_EXPIRING";
 
@@ -187,6 +195,7 @@
      * @see DevicePolicyManager#isLockTaskPermitted(String)
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @BroadcastBehavior(explicitOnly = true)
     public static final String ACTION_LOCK_TASK_ENTERING
             = "android.app.action.LOCK_TASK_ENTERING";
 
@@ -200,6 +209,7 @@
      * @see DevicePolicyManager#isLockTaskPermitted(String)
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @BroadcastBehavior(explicitOnly = true)
     public static final String ACTION_LOCK_TASK_EXITING
             = "android.app.action.LOCK_TASK_EXITING";
 
@@ -232,6 +242,7 @@
      * <p>Output: Nothing</p>
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @BroadcastBehavior(explicitOnly = true)
     public static final String ACTION_PROFILE_PROVISIONING_COMPLETE =
             "android.app.action.PROFILE_PROVISIONING_COMPLETE";
 
@@ -244,6 +255,7 @@
      * @hide
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @BroadcastBehavior(explicitOnly = true)
     public static final String ACTION_BUGREPORT_SHARING_DECLINED =
             "android.app.action.BUGREPORT_SHARING_DECLINED";
 
@@ -256,6 +268,7 @@
      * @hide
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @BroadcastBehavior(explicitOnly = true)
     public static final String ACTION_BUGREPORT_FAILED = "android.app.action.BUGREPORT_FAILED";
 
     /**
@@ -266,6 +279,7 @@
      * @hide
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @BroadcastBehavior(explicitOnly = true)
     public static final String ACTION_BUGREPORT_SHARE =
             "android.app.action.BUGREPORT_SHARE";
 
@@ -274,6 +288,7 @@
      * @hide
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @BroadcastBehavior(explicitOnly = true)
     public static final String ACTION_SECURITY_LOGS_AVAILABLE
             = "android.app.action.SECURITY_LOGS_AVAILABLE";
 
@@ -283,6 +298,7 @@
      * @hide
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @BroadcastBehavior(explicitOnly = true)
     public static final String ACTION_NETWORK_LOGS_AVAILABLE
             = "android.app.action.NETWORK_LOGS_AVAILABLE";
 
@@ -314,7 +330,8 @@
      * @hide
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String ACTION_USER_ADDED  = "android.app.action.USER_ADDED";
+    @BroadcastBehavior(explicitOnly = true)
+    public static final String ACTION_USER_ADDED = "android.app.action.USER_ADDED";
 
     /**
      * Broadcast action: notify the device owner that a user or profile has been removed.
@@ -323,6 +340,7 @@
      * @hide
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @BroadcastBehavior(explicitOnly = true)
     public static final String ACTION_USER_REMOVED = "android.app.action.USER_REMOVED";
 
     /**
@@ -401,6 +419,7 @@
      * @hide
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @BroadcastBehavior(explicitOnly = true)
     public static final String ACTION_NOTIFY_PENDING_SYSTEM_UPDATE =
             "android.app.action.NOTIFY_PENDING_SYSTEM_UPDATE";
 
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index b1fbc8f..27bfb51 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -1612,9 +1612,8 @@
             return newChild(index, false, 0, 0);
         }
 
-        // TODO(b/33197203, b/33802548): add CTS/unit test
         @Override
-        public ViewStructure newChildForAutofill(int index, int virtualId, int flags) {
+        public ViewStructure newChild(int index, int virtualId, int flags) {
             return newChild(index, true, virtualId, flags);
         }
 
@@ -1624,7 +1623,7 @@
         }
 
         @Override
-        public ViewStructure asyncNewChildForAutofill(int index, int virtualId, int flags) {
+        public ViewStructure asyncNewChild(int index, int virtualId, int flags) {
             return asyncNewChild(index, true, virtualId);
         }
 
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 67c791d..74a39e8 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -16,8 +16,11 @@
 
 package android.appwidget;
 
+import android.annotation.BroadcastBehavior;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
 import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Context;
@@ -81,12 +84,14 @@
      *
      * @see #ACTION_APPWIDGET_CONFIGURE
      */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_APPWIDGET_PICK = "android.appwidget.action.APPWIDGET_PICK";
 
     /**
      * Similar to ACTION_APPWIDGET_PICK, but used from keyguard
      * @hide
      */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String
             ACTION_KEYGUARD_APPWIDGET_PICK = "android.appwidget.action.KEYGUARD_APPWIDGET_PICK";
 
@@ -133,6 +138,7 @@
      * @see #ACTION_APPWIDGET_CONFIGURE
      *
      */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_APPWIDGET_BIND = "android.appwidget.action.APPWIDGET_BIND";
 
     /**
@@ -157,6 +163,7 @@
      * and not display this AppWidget, and you will receive a {@link #ACTION_APPWIDGET_DELETED}
      * broadcast.
      */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_APPWIDGET_CONFIGURE = "android.appwidget.action.APPWIDGET_CONFIGURE";
 
     /**
@@ -290,6 +297,8 @@
      *
      * @see AppWidgetProvider#onUpdate AppWidgetProvider.onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
      */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @BroadcastBehavior(explicitOnly = true)
     public static final String ACTION_APPWIDGET_UPDATE = "android.appwidget.action.APPWIDGET_UPDATE";
 
     /**
@@ -302,6 +311,8 @@
      *      AppWidgetProvider.onAppWidgetOptionsChanged(Context context,
      *      AppWidgetManager appWidgetManager, int appWidgetId, Bundle newExtras)
      */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @BroadcastBehavior(explicitOnly = true)
     public static final String ACTION_APPWIDGET_OPTIONS_CHANGED = "android.appwidget.action.APPWIDGET_UPDATE_OPTIONS";
 
     /**
@@ -312,6 +323,8 @@
      *
      * @see AppWidgetProvider#onDeleted AppWidgetProvider.onDeleted(Context context, int[] appWidgetIds)
      */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @BroadcastBehavior(explicitOnly = true)
     public static final String ACTION_APPWIDGET_DELETED = "android.appwidget.action.APPWIDGET_DELETED";
 
     /**
@@ -322,6 +335,8 @@
      *
      * @see AppWidgetProvider#onEnabled AppWidgetProvider.onDisabled(Context context)
      */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @BroadcastBehavior(explicitOnly = true)
     public static final String ACTION_APPWIDGET_DISABLED = "android.appwidget.action.APPWIDGET_DISABLED";
 
     /**
@@ -334,6 +349,8 @@
      *
      * @see AppWidgetProvider#onEnabled AppWidgetProvider.onEnabled(Context context)
      */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @BroadcastBehavior(explicitOnly = true)
     public static final String ACTION_APPWIDGET_ENABLED = "android.appwidget.action.APPWIDGET_ENABLED";
 
     /**
@@ -365,6 +382,8 @@
      *
      * @see #ACTION_APPWIDGET_HOST_RESTORED
      */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @BroadcastBehavior(explicitOnly = true)
     public static final String ACTION_APPWIDGET_RESTORED
             = "android.appwidget.action.APPWIDGET_RESTORED";
 
@@ -402,6 +421,8 @@
      *
      * @see #ACTION_APPWIDGET_RESTORED
      */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @BroadcastBehavior(explicitOnly = true)
     public static final String ACTION_APPWIDGET_HOST_RESTORED
             = "android.appwidget.action.APPWIDGET_HOST_RESTORED";
 
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 488511b..4e1e42d 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1483,6 +1483,25 @@
     }
 
     /**
+     * Return the maximum LE advertising data length,
+     * if LE Extended Advertising feature is supported.
+     *
+     * @return the maximum LE advertising data length.
+     */
+    public int getLeMaximumAdvertisingDataLength() {
+        if (!getLeAccess()) return 0;
+        try {
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.getLeMaximumAdvertisingDataLength();
+        } catch (RemoteException e) {
+            Log.e(TAG, "failed to get getLeMaximumAdvertisingDataLength, error: ", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
+        return 0;
+    }
+
+    /**
      * Return true if hardware has entries available for matching beacons
      *
      * @return true if there are hw entries available for matching beacons
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index 76ca554..b337817 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -108,6 +108,7 @@
     boolean isLeCodedPhySupported();
     boolean isLeExtendedAdvertisingSupported();
     boolean isLePeriodicAdvertisingSupported();
+    int getLeMaximumAdvertisingDataLength();
     BluetoothActivityEnergyInfo reportActivityInfo();
 
     /**
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index 33fedc7..c281c7f 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -50,20 +50,12 @@
     void stopScan(in int scannerId);
     void flushPendingBatchResults(in int scannerId);
 
-    void registerAdvertiser(in IAdvertiserCallback callback);
-    void unregisterAdvertiser(in int advertiserId);
-    void startMultiAdvertising(in int advertiserId,
-                               in AdvertiseData advertiseData,
-                               in AdvertiseData scanResponse,
-                               in AdvertiseSettings settings);
-    void stopMultiAdvertising(in int advertiserId);
-
     void startAdvertisingSet(in AdvertisingSetParameters parameters, in AdvertiseData advertiseData,
                                 in AdvertiseData scanResponse, in PeriodicAdvertisingParameters periodicParameters,
-                                in AdvertiseData periodicData, in IAdvertisingSetCallback callback);
+                                in AdvertiseData periodicData, in int timeout, in IAdvertisingSetCallback callback);
     void stopAdvertisingSet(in IAdvertisingSetCallback callback);
 
-    void enableAdverisingSet(in int advertiserId, in boolean enable);
+    void enableAdverisingSet(in int advertiserId, in boolean enable, in int timeout);
     void setAdvertisingData(in int advertiserId, in AdvertiseData data);
     void setScanResponseData(in int advertiserId, in AdvertiseData data);
     void setAdvertisingParameters(in int advertiserId, in AdvertisingSetParameters parameters);
diff --git a/core/java/android/bluetooth/le/AdvertisingSet.java b/core/java/android/bluetooth/le/AdvertisingSet.java
index 1524022..5524a2b 100644
--- a/core/java/android/bluetooth/le/AdvertisingSet.java
+++ b/core/java/android/bluetooth/le/AdvertisingSet.java
@@ -63,9 +63,9 @@
      * Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
      *
      */
-    public void enableAdvertising(boolean enable) {
+    public void enableAdvertising(boolean enable, int timeout) {
         try {
-            gatt.enableAdverisingSet(this.advertiserId, enable);
+            gatt.enableAdverisingSet(this.advertiserId, enable, timeout);
         } catch (RemoteException e) {
             Log.e(TAG, "remote exception - ", e);
         }
diff --git a/core/java/android/bluetooth/le/AdvertisingSetParameters.java b/core/java/android/bluetooth/le/AdvertisingSetParameters.java
index 453dd70..59fef8d 100644
--- a/core/java/android/bluetooth/le/AdvertisingSetParameters.java
+++ b/core/java/android/bluetooth/le/AdvertisingSetParameters.java
@@ -118,13 +118,11 @@
     private final boolean connectable;
     private final int interval;
     private final int txPowerLevel;
-    private final int timeoutMillis;
 
     private AdvertisingSetParameters(boolean connectable, boolean isLegacy,
                                      boolean isAnonymous, boolean includeTxPower,
                                      int primaryPhy, int secondaryPhy,
-                                     int interval, int txPowerLevel,
-                                     int timeoutMillis) {
+                                     int interval, int txPowerLevel) {
         this.connectable = connectable;
         this.isLegacy = isLegacy;
         this.isAnonymous = isAnonymous;
@@ -133,7 +131,6 @@
         this.secondaryPhy = secondaryPhy;
         this.interval = interval;
         this.txPowerLevel = txPowerLevel;
-        this.timeoutMillis = timeoutMillis;
     }
 
     private AdvertisingSetParameters(Parcel in) {
@@ -145,7 +142,6 @@
         secondaryPhy = in.readInt();
         interval = in.readInt();
         txPowerLevel = in.readInt();
-        timeoutMillis = in.readInt();
     }
 
     /**
@@ -188,11 +184,6 @@
      */
     public int getTxPowerLevel() { return txPowerLevel; }
 
-    /**
-     * Returns the advertising time limit in milliseconds.
-     */
-    public int getTimeout() { return timeoutMillis; }
-
     @Override
     public String toString() {
         return "AdvertisingSetParameters [connectable=" + connectable
@@ -202,8 +193,7 @@
              + ", primaryPhy=" + primaryPhy
              + ", secondaryPhy=" + secondaryPhy
              + ", interval=" + interval
-             + ", txPowerLevel=" + txPowerLevel
-             + ", timeoutMillis=" + timeoutMillis + "]";
+             + ", txPowerLevel=" + txPowerLevel + "]";
     }
 
     @Override
@@ -221,7 +211,6 @@
         dest.writeInt(secondaryPhy);
         dest.writeInt(interval);
         dest.writeInt(txPowerLevel);
-        dest.writeInt(timeoutMillis);
     }
 
     public static final Parcelable.Creator<AdvertisingSetParameters> CREATOR =
@@ -250,7 +239,6 @@
         private int secondaryPhy = PHY_LE_1M;
         private int interval = INTERVAL_LOW;
         private int txPowerLevel = TX_POWER_MEDIUM;
-        private int timeoutMillis = 0;
 
         /**
          * Set whether the advertisement type should be connectable or
@@ -380,30 +368,12 @@
         }
 
         /**
-         * Limit advertising to a given amount of time.
-         * @param timeoutMillis Advertising time limit. May not exceed 180000
-         * milliseconds. A value of 0 will disable the time limit.
-         * @throws IllegalArgumentException If the provided timeout is over 180000
-         * ms.
-         */
-        public Builder setTimeout(int timeoutMillis) {
-            if (timeoutMillis < 0 || timeoutMillis > LIMITED_ADVERTISING_MAX_MILLIS) {
-                throw new IllegalArgumentException("timeoutMillis invalid (must be 0-" +
-                                                   LIMITED_ADVERTISING_MAX_MILLIS +
-                                                   " milliseconds)");
-            }
-            this.timeoutMillis = timeoutMillis;
-            return this;
-        }
-
-        /**
          * Build the {@link AdvertisingSetParameters} object.
          */
         public AdvertisingSetParameters build() {
             return new AdvertisingSetParameters(connectable, isLegacy, isAnonymous,
                                                 includeTxPower, primaryPhy,
-                                                secondaryPhy, interval, txPowerLevel,
-                                                timeoutMillis);
+                                                secondaryPhy, interval, txPowerLevel);
         }
     }
 }
\ No newline at end of file
diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index e03c947..67fd1c8 100644
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -28,6 +28,7 @@
 import android.os.RemoteException;
 import android.util.Log;
 
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.UUID;
@@ -60,11 +61,12 @@
     private final IBluetoothManager mBluetoothManager;
     private final Handler mHandler;
     private BluetoothAdapter mBluetoothAdapter;
-    private final Map<AdvertiseCallback, AdvertiseCallbackWrapper>
-            mLeAdvertisers = new HashMap<AdvertiseCallback, AdvertiseCallbackWrapper>();
+    private final Map<AdvertiseCallback, AdvertisingSetCallback>
+            mLegacyAdvertisers = new HashMap<>();
     private final Map<AdvertisingSetCallback, IAdvertisingSetCallback>
-            advertisingSetCallbackWrappers = new HashMap<>();
-    private final Map<Integer, AdvertisingSet> advertisingSets = new HashMap<>();
+            mCallbackWrappers = Collections.synchronizedMap(new HashMap<>());
+    private final Map<Integer, AdvertisingSet>
+            mAdvertisingSets = Collections.synchronizedMap(new HashMap<>());
 
     /**
      * Use BluetoothAdapter.getLeAdvertiser() instead.
@@ -109,7 +111,7 @@
     public void startAdvertising(AdvertiseSettings settings,
             AdvertiseData advertiseData, AdvertiseData scanResponse,
             final AdvertiseCallback callback) {
-        synchronized (mLeAdvertisers) {
+        synchronized (mLegacyAdvertisers) {
             BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter);
             if (callback == null) {
                 throw new IllegalArgumentException("callback cannot be null");
@@ -120,25 +122,64 @@
                 postStartFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_DATA_TOO_LARGE);
                 return;
             }
-            if (mLeAdvertisers.containsKey(callback)) {
+            if (mLegacyAdvertisers.containsKey(callback)) {
                 postStartFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_ALREADY_STARTED);
                 return;
             }
 
-            IBluetoothGatt gatt;
-            try {
-                gatt = mBluetoothManager.getBluetoothGatt();
-            } catch (RemoteException e) {
-                Log.e(TAG, "Failed to get Bluetooth gatt - ", e);
-                postStartFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR);
-                return;
+            AdvertisingSetParameters.Builder parameters = new AdvertisingSetParameters.Builder();
+            parameters.setLegacyMode(true);
+            parameters.setConnectable(isConnectable);
+            if (settings.getMode() == AdvertiseSettings.ADVERTISE_MODE_LOW_POWER) {
+                parameters.setInterval(1600); // 1s
+            } else if (settings.getMode() == AdvertiseSettings.ADVERTISE_MODE_BALANCED) {
+                parameters.setInterval(400); // 250ms
+            } else if (settings.getMode() == AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY) {
+                parameters.setInterval(160); // 100ms
             }
-            AdvertiseCallbackWrapper wrapper = new AdvertiseCallbackWrapper(callback, advertiseData,
-                    scanResponse, settings, gatt);
-            wrapper.startRegisteration();
+
+            if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_ULTRA_LOW) {
+                parameters.setTxPowerLevel(-21);
+            } else if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_LOW) {
+                parameters.setTxPowerLevel(-15);
+            } else if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM) {
+                parameters.setTxPowerLevel(-7);
+            } else if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_HIGH) {
+                parameters.setTxPowerLevel(1);
+            }
+
+            AdvertisingSetCallback wrapped = wrapOldCallback(callback, settings);
+            mLegacyAdvertisers.put(callback, wrapped);
+            startAdvertisingSet(parameters.build(), advertiseData, scanResponse, null, null,
+                                settings.getTimeout(), wrapped);
         }
     }
 
+    AdvertisingSetCallback wrapOldCallback(AdvertiseCallback callback, AdvertiseSettings settings) {
+        return new AdvertisingSetCallback() {
+            public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int status) {
+                if (status != AdvertisingSetCallback.ADVERTISE_SUCCESS) {
+                    postStartFailure(callback, status);
+                    return;
+                }
+
+                postStartSuccess(callback, settings);
+            }
+
+            /* Legacy advertiser is disabled on timeout */
+            public void onAdvertisingEnabled(int advertiserId, boolean enabled, int status) {
+                if (enabled == true) {
+                    Log.e(TAG, "Legacy advertiser should be only disabled on timeout," +
+                        " but was enabled!");
+                    return;
+                }
+
+                stopAdvertising(callback);
+            }
+
+        };
+    }
+
     /**
      * Stop Bluetooth LE advertising. The {@code callback} must be the same one use in
      * {@link BluetoothLeAdvertiser#startAdvertising}.
@@ -148,20 +189,21 @@
      * @param callback {@link AdvertiseCallback} identifies the advertising instance to stop.
      */
     public void stopAdvertising(final AdvertiseCallback callback) {
-        synchronized (mLeAdvertisers) {
+        synchronized (mLegacyAdvertisers) {
             if (callback == null) {
                 throw new IllegalArgumentException("callback cannot be null");
             }
-            AdvertiseCallbackWrapper wrapper = mLeAdvertisers.get(callback);
+            AdvertisingSetCallback wrapper = mLegacyAdvertisers.get(callback);
             if (wrapper == null) return;
-            wrapper.stopAdvertising();
+
+            stopAdvertisingSet(wrapper);
         }
     }
 
     /**
     * Creates a new advertising set. If operation succeed, device will start advertising. This
     * method returns immediately, the operation status is delivered through
-    * {@code callback.onNewAdvertisingSet()}.
+    * {@code callback.onAdvertisingSetStarted()}.
     * <p>
     * @param parameters advertising set parameters.
     * @param advertiseData Advertisement data to be broadcasted.
@@ -173,14 +215,14 @@
                                     AdvertiseData advertiseData, AdvertiseData scanResponse,
                                     PeriodicAdvertisingParameters periodicParameters,
                                     AdvertiseData periodicData, AdvertisingSetCallback callback) {
-        startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters,
-                            periodicData, callback, new Handler(Looper.getMainLooper()));
+            startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters,
+                            periodicData, 0, callback, new Handler(Looper.getMainLooper()));
     }
 
     /**
     * Creates a new advertising set. If operation succeed, device will start advertising. This
     * method returns immediately, the operation status is delivered through
-    * {@code callback.onNewAdvertisingSet()}.
+    * {@code callback.onAdvertisingSetStarted()}.
     * <p>
     * @param parameters advertising set parameters.
     * @param advertiseData Advertisement data to be broadcasted.
@@ -194,6 +236,49 @@
                                     PeriodicAdvertisingParameters periodicParameters,
                                     AdvertiseData periodicData, AdvertisingSetCallback callback,
                                     Handler handler) {
+        startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters,
+                            periodicData, 0, callback, handler);
+    }
+
+    /**
+    * Creates a new advertising set. If operation succeed, device will start advertising. This
+    * method returns immediately, the operation status is delivered through
+    * {@code callback.onAdvertisingSetStarted()}.
+    * <p>
+    * @param parameters advertising set parameters.
+    * @param advertiseData Advertisement data to be broadcasted.
+    * @param scanResponse Scan response associated with the advertisement data.
+    * @param periodicData Periodic advertising data.
+    * @param timeoutMillis Advertising time limit. May not exceed 180000
+    * @param callback Callback for advertising set.
+    */
+    public void startAdvertisingSet(AdvertisingSetParameters parameters,
+                                    AdvertiseData advertiseData, AdvertiseData scanResponse,
+                                    PeriodicAdvertisingParameters periodicParameters,
+                                    AdvertiseData periodicData, int timeoutMillis,
+                                    AdvertisingSetCallback callback) {
+        startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters,
+                            periodicData, timeoutMillis, callback, new Handler(Looper.getMainLooper()));
+    }
+
+    /**
+    * Creates a new advertising set. If operation succeed, device will start advertising. This
+    * method returns immediately, the operation status is delivered through
+    * {@code callback.onAdvertisingSetStarted()}.
+    * <p>
+    * @param parameters advertising set parameters.
+    * @param advertiseData Advertisement data to be broadcasted.
+    * @param scanResponse Scan response associated with the advertisement data.
+    * @param periodicData Periodic advertising data.
+    * @param timeoutMillis Advertising time limit. May not exceed 180000
+    * @param callback Callback for advertising set.
+    * @param handler thread upon which the callbacks will be invoked.
+    */
+    public void startAdvertisingSet(AdvertisingSetParameters parameters,
+                                    AdvertiseData advertiseData, AdvertiseData scanResponse,
+                                    PeriodicAdvertisingParameters periodicParameters,
+                                    AdvertiseData periodicData, int timeoutMillis,
+                                    AdvertisingSetCallback callback, Handler handler) {
         BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter);
 
         if (callback == null) {
@@ -209,11 +294,14 @@
         }
 
         IAdvertisingSetCallback wrapped = wrap(callback, handler);
-        advertisingSetCallbackWrappers.put(callback, wrapped);
+        if (mCallbackWrappers.putIfAbsent(callback, wrapped) != null) {
+            throw new IllegalArgumentException(
+                "callback instance already associated with advertising");
+        }
 
         try {
             gatt.startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters,
-                                     periodicData, wrapped);
+                                     periodicData, timeoutMillis, wrapped);
         } catch (RemoteException e) {
           Log.e(TAG, "Failed to start advertising set - ", e);
           throw new IllegalStateException("Failed to start advertising set");
@@ -229,10 +317,9 @@
           throw new IllegalArgumentException("callback cannot be null");
         }
 
-        IAdvertisingSetCallback wrapped = advertisingSetCallbackWrappers.remove(callback);
+        IAdvertisingSetCallback wrapped = mCallbackWrappers.remove(callback);
         if (wrapped == null) {
-            throw new IllegalArgumentException(
-                "callback does not represent valid registered callback.");
+            return;
         }
 
         IBluetoothGatt gatt;
@@ -251,7 +338,9 @@
      * @hide
      */
     public void cleanup() {
-        mLeAdvertisers.clear();
+        mLegacyAdvertisers.clear();
+        mCallbackWrappers.clear();
+        mAdvertisingSets.clear();
     }
 
     // Compute the size of advertisement data or scan resp
@@ -317,13 +406,13 @@
                     public void run() {
                         if (status != AdvertisingSetCallback.ADVERTISE_SUCCESS) {
                             callback.onAdvertisingSetStarted(null, status);
-                            advertisingSetCallbackWrappers.remove(callback);
+                            mCallbackWrappers.remove(callback);
                             return;
                         }
 
                         AdvertisingSet advertisingSet =
                             new AdvertisingSet(advertiserId, mBluetoothManager);
-                        advertisingSets.put(advertiserId, advertisingSet);
+                        mAdvertisingSets.put(advertiserId, advertisingSet);
                         callback.onAdvertisingSetStarted(advertisingSet, status);
                     }
                 });
@@ -333,10 +422,10 @@
                 handler.post(new Runnable() {
                     @Override
                     public void run() {
-                        AdvertisingSet advertisingSet = advertisingSets.get(advertiserId);
+                        AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
                         callback.onAdvertisingSetStopped(advertisingSet);
-                        advertisingSets.remove(advertiserId);
-                        advertisingSetCallbackWrappers.remove(callback);
+                        mAdvertisingSets.remove(advertiserId);
+                        mCallbackWrappers.remove(callback);
                     }
                 });
             }
@@ -345,7 +434,7 @@
                 handler.post(new Runnable() {
                     @Override
                     public void run() {
-                        AdvertisingSet advertisingSet = advertisingSets.get(advertiserId);
+                        AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
                         callback.onAdvertisingEnabled(advertisingSet, enabled, status);
                     }
                 });
@@ -355,7 +444,7 @@
                 handler.post(new Runnable() {
                     @Override
                     public void run() {
-                        AdvertisingSet advertisingSet = advertisingSets.get(advertiserId);
+                        AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
                         callback.onAdvertisingDataSet(advertisingSet, status);
                     }
                 });
@@ -365,7 +454,7 @@
                 handler.post(new Runnable() {
                     @Override
                     public void run() {
-                        AdvertisingSet advertisingSet = advertisingSets.get(advertiserId);
+                        AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
                         callback.onScanResponseDataSet(advertisingSet, status);
                     }
                 });
@@ -375,7 +464,7 @@
                 handler.post(new Runnable() {
                     @Override
                     public void run() {
-                        AdvertisingSet advertisingSet = advertisingSets.get(advertiserId);
+                        AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
                         callback.onAdvertisingParametersUpdated(advertisingSet, status);
                     }
                 });
@@ -385,7 +474,7 @@
                 handler.post(new Runnable() {
                     @Override
                     public void run() {
-                        AdvertisingSet advertisingSet = advertisingSets.get(advertiserId);
+                        AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
                         callback.onPeriodicAdvertisingParametersUpdated(advertisingSet, status);
                     }
                 });
@@ -395,7 +484,7 @@
                 handler.post(new Runnable() {
                     @Override
                     public void run() {
-                        AdvertisingSet advertisingSet = advertisingSets.get(advertiserId);
+                        AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
                         callback.onPeriodicAdvertisingDataSet(advertisingSet, status);
                     }
                 });
@@ -405,7 +494,7 @@
                 handler.post(new Runnable() {
                     @Override
                     public void run() {
-                        AdvertisingSet advertisingSet = advertisingSets.get(advertiserId);
+                        AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
                         callback.onPeriodicAdvertisingEnable(advertisingSet, enable, status);
                     }
                 });
@@ -413,144 +502,6 @@
         };
     }
 
-    /**
-     * Bluetooth GATT interface callbacks for advertising.
-     */
-    private class AdvertiseCallbackWrapper extends IAdvertiserCallback.Stub {
-        private static final int LE_CALLBACK_TIMEOUT_MILLIS = 2000;
-        private final AdvertiseCallback mAdvertiseCallback;
-        private final AdvertiseData mAdvertisement;
-        private final AdvertiseData mScanResponse;
-        private final AdvertiseSettings mSettings;
-        private final IBluetoothGatt mBluetoothGatt;
-
-        // mAdvertiserId -1: not registered
-        // -2: advertise stopped or registration timeout
-        // >=0: registered and advertising started
-        private int mAdvertiserId;
-        private boolean mIsAdvertising = false;
-        private int registrationError = AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR;
-
-        public AdvertiseCallbackWrapper(AdvertiseCallback advertiseCallback,
-                AdvertiseData advertiseData, AdvertiseData scanResponse,
-                AdvertiseSettings settings,
-                IBluetoothGatt bluetoothGatt) {
-            mAdvertiseCallback = advertiseCallback;
-            mAdvertisement = advertiseData;
-            mScanResponse = scanResponse;
-            mSettings = settings;
-            mBluetoothGatt = bluetoothGatt;
-            mAdvertiserId = -1;
-        }
-
-        public void startRegisteration() {
-            synchronized (this) {
-                if (mAdvertiserId == -2) return;
-
-                try {
-                    mBluetoothGatt.registerAdvertiser(this);
-                    wait(LE_CALLBACK_TIMEOUT_MILLIS);
-                } catch (InterruptedException | RemoteException e) {
-                    Log.e(TAG, "Failed to start registeration", e);
-                }
-                if (mAdvertiserId >= 0 && mIsAdvertising) {
-                    mLeAdvertisers.put(mAdvertiseCallback, this);
-                } else if (mAdvertiserId < 0) {
-
-                    // Registration timeout, reset mClientIf to -2 so no subsequent operations can
-                    // proceed.
-                    if (mAdvertiserId == -1) mAdvertiserId = -2;
-                    // Post internal error if registration failed.
-                    postStartFailure(mAdvertiseCallback, registrationError);
-                } else {
-                    // Unregister application if it's already registered but advertise failed.
-                    try {
-                        mBluetoothGatt.unregisterAdvertiser(mAdvertiserId);
-                        mAdvertiserId = -2;
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "remote exception when unregistering", e);
-                    }
-                }
-            }
-        }
-
-        public void stopAdvertising() {
-            synchronized (this) {
-                try {
-                    mBluetoothGatt.stopMultiAdvertising(mAdvertiserId);
-                    wait(LE_CALLBACK_TIMEOUT_MILLIS);
-                } catch (InterruptedException | RemoteException e) {
-                    Log.e(TAG, "Failed to stop advertising", e);
-                }
-                // Advertise callback should have been removed from LeAdvertisers when
-                // onMultiAdvertiseCallback was called. In case onMultiAdvertiseCallback is never
-                // invoked and wait timeout expires, remove callback here.
-                if (mLeAdvertisers.containsKey(mAdvertiseCallback)) {
-                    mLeAdvertisers.remove(mAdvertiseCallback);
-                }
-            }
-        }
-
-        /**
-         * Advertiser interface registered - app is ready to go
-         */
-        @Override
-        public void onAdvertiserRegistered(int status, int advertiserId) {
-            Log.d(TAG, "onAdvertiserRegistered() - status=" + status + " advertiserId=" + advertiserId);
-            synchronized (this) {
-                if (status == BluetoothGatt.GATT_SUCCESS) {
-                    try {
-                        if (mAdvertiserId == -2) {
-                            // Registration succeeds after timeout, unregister advertiser.
-                            mBluetoothGatt.unregisterAdvertiser(advertiserId);
-                        } else {
-                            mAdvertiserId = advertiserId;
-                            mBluetoothGatt.startMultiAdvertising(mAdvertiserId, mAdvertisement,
-                                    mScanResponse, mSettings);
-                        }
-                        return;
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "failed to start advertising", e);
-                    }
-                } else if (status == AdvertiseCallback.ADVERTISE_FAILED_TOO_MANY_ADVERTISERS) {
-                    registrationError = status;
-                }
-                // Registration failed.
-                mAdvertiserId = -2;
-                notifyAll();
-            }
-        }
-
-        @Override
-        public void onMultiAdvertiseCallback(int status, boolean isStart,
-                AdvertiseSettings settings) {
-            synchronized (this) {
-                if (isStart) {
-                    if (status == AdvertiseCallback.ADVERTISE_SUCCESS) {
-                        // Start success
-                        mIsAdvertising = true;
-                        postStartSuccess(mAdvertiseCallback, settings);
-                    } else {
-                        // Start failure.
-                        postStartFailure(mAdvertiseCallback, status);
-                    }
-                } else {
-                    // unregister advertiser for stop.
-                    try {
-                        mBluetoothGatt.unregisterAdvertiser(mAdvertiserId);
-                        mAdvertiserId = -2;
-                        mIsAdvertising = false;
-                        mLeAdvertisers.remove(mAdvertiseCallback);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "remote exception when unregistering", e);
-                    }
-                }
-                notifyAll();
-            }
-
-        }
-    }
-
     private void postStartFailure(final AdvertiseCallback callback, final int error) {
         mHandler.post(new Runnable() {
             @Override
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 1f01e28e..bd31b03 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -17,6 +17,7 @@
 package android.content;
 
 import android.annotation.AnyRes;
+import android.annotation.BroadcastBehavior;
 import android.annotation.IntDef;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
@@ -1103,18 +1104,7 @@
      * @hide
      */
     public static final String ACTION_CALL_PRIVILEGED = "android.intent.action.CALL_PRIVILEGED";
-    /**
-     * Activity action: Activate the current SIM card.  If SIM cards do not require activation,
-     * sending this intent is a no-op.
-     * <p>Input: No data should be specified.  get*Extra may have an optional
-     * {@link #EXTRA_SIM_ACTIVATION_RESPONSE} field containing a PendingIntent through which to
-     * send the activation result.
-     * <p>Output: nothing.
-     * @hide
-     */
-    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
-    public static final String ACTION_SIM_ACTIVATION_REQUEST =
-            "android.intent.action.SIM_ACTIVATION_REQUEST";
+
     /**
      * Activity Action: Main entry point for carrier setup apps.
      * <p>Carrier apps that provide an implementation for this action may be invoked to configure
@@ -1992,6 +1982,7 @@
      * This is a protected intent that can only be sent by the system.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @BroadcastBehavior(includeBackground = true)
     public static final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED";
 
     /**
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index b4d77a0..0b3742f 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -31,7 +31,7 @@
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.Printer;
-import android.util.SparseIntArray;
+import android.util.SparseArray;
 
 import com.android.internal.util.ArrayUtils;
 
@@ -656,13 +656,15 @@
      *
      * The keys and values are all indices into the {@link #splitNames}, {@link #splitSourceDirs},
      * and {@link #splitPublicSourceDirs} arrays.
-     * Each key represents a split and its value is its parent split.
+     * Each key represents a split and its value is an array of splits. The first element of this
+     * array is the parent split, and the rest are configuration splits. These configuration splits
+     * have no dependencies themselves.
      * Cycles do not exist because they are illegal and screened for during installation.
      *
      * May be null if no splits are installed, or if no dependencies exist between them.
      * @hide
      */
-    public SparseIntArray splitDependencies;
+    public SparseArray<int[]> splitDependencies;
 
     /**
      * Full paths to the locations of extra resource packages (runtime overlays)
@@ -1182,7 +1184,7 @@
         dest.writeStringArray(splitNames);
         dest.writeStringArray(splitSourceDirs);
         dest.writeStringArray(splitPublicSourceDirs);
-        dest.writeSparseIntArray(splitDependencies);
+        dest.writeSparseArray((SparseArray) splitDependencies);
         dest.writeString(nativeLibraryDir);
         dest.writeString(secondaryNativeLibraryDir);
         dest.writeString(nativeLibraryRootDir);
@@ -1244,7 +1246,7 @@
         splitNames = source.readStringArray();
         splitSourceDirs = source.readStringArray();
         splitPublicSourceDirs = source.readStringArray();
-        splitDependencies = source.readSparseIntArray();
+        splitDependencies = source.readSparseArray(null);
         nativeLibraryDir = source.readString();
         secondaryNativeLibraryDir = source.readString();
         nativeLibraryRootDir = source.readString();
diff --git a/core/java/android/content/pm/InstrumentationInfo.java b/core/java/android/content/pm/InstrumentationInfo.java
index 59c5307..f6f1be6 100644
--- a/core/java/android/content/pm/InstrumentationInfo.java
+++ b/core/java/android/content/pm/InstrumentationInfo.java
@@ -82,13 +82,15 @@
      *
      * The keys and values are all indices into the {@link #splitNames}, {@link #splitSourceDirs},
      * and {@link #splitPublicSourceDirs} arrays.
-     * Each key represents a split and its value is its parent split.
+     * Each key represents a split and its value is an array of splits. The first element of this
+     * array is the parent split, and the rest are configuration splits. These configuration splits
+     * have no dependencies themselves.
      * Cycles do not exist because they are illegal and screened for during installation.
      *
      * May be null if no splits are installed, or if no dependencies exist between them.
      * @hide
      */
-    public SparseIntArray splitDependencies;
+    public SparseArray<int[]> splitDependencies;
 
     /**
      * Full path to a directory assigned to the package for its persistent data.
@@ -155,7 +157,7 @@
         dest.writeStringArray(splitNames);
         dest.writeStringArray(splitSourceDirs);
         dest.writeStringArray(splitPublicSourceDirs);
-        dest.writeSparseIntArray(splitDependencies);
+        dest.writeSparseArray((SparseArray) splitDependencies);
         dest.writeString(dataDir);
         dest.writeString(deviceProtectedDataDir);
         dest.writeString(credentialProtectedDataDir);
@@ -185,7 +187,7 @@
         splitNames = source.readStringArray();
         splitSourceDirs = source.readStringArray();
         splitPublicSourceDirs = source.readStringArray();
-        splitDependencies = source.readSparseIntArray();
+        splitDependencies = source.readSparseArray(null);
         dataDir = source.readString();
         deviceProtectedDataDir = source.readString();
         credentialProtectedDataDir = source.readString();
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 33f57e0..10ffab2 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2355,6 +2355,13 @@
             = "android.hardware.vr.high_performance";
 
     /**
+     * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+     * The device implements headtracking suitable for a VR device.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_VR_HEADTRACKING = "android.hardware.vr.headtracking";
+
+    /**
      * Action to external storage service to clean out removed apps.
      * @hide
      */
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index e15a0e2..99aa1bc 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -76,7 +76,7 @@
 import android.util.Log;
 import android.util.Pair;
 import android.util.Slog;
-import android.util.SparseIntArray;
+import android.util.SparseArray;
 import android.util.TypedValue;
 import android.util.apk.ApkSignatureSchemeV2Verifier;
 import android.util.jar.StrictJarFile;
@@ -109,7 +109,6 @@
 import java.security.spec.X509EncodedKeySpec;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.BitSet;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Iterator;
@@ -211,6 +210,14 @@
         CHILD_PACKAGE_TAGS.add(TAG_EAT_COMMENT);
     }
 
+    private static final boolean LOG_UNSAFE_BROADCASTS = false;
+
+    // Set of broadcast actions that are safe for manifest receivers
+    private static final Set<String> SAFE_BROADCASTS = new ArraySet<>();
+    static {
+        SAFE_BROADCASTS.add(Intent.ACTION_BOOT_COMPLETED);
+    }
+
     /** @hide */
     public static class NewPermissionInfo {
         public final String name;
@@ -360,8 +367,12 @@
         /** Names of any split APKs, ordered by parsed splitName */
         public final String[] splitNames;
 
+        /** Names of any split APKs that are features. Ordered by splitName */
+        public final boolean[] isFeatureSplits;
+
         /** Dependencies of any split APKs, ordered by parsed splitName */
         public final String[] usesSplitNames;
+        public final String[] configForSplit;
 
         /**
          * Path where this package was found on disk. For monolithic packages
@@ -388,14 +399,16 @@
         public final boolean isolatedSplits;
 
         public PackageLite(String codePath, ApkLite baseApk, String[] splitNames,
-                String[] usesSplitNames, String[] splitCodePaths,
-                int[] splitRevisionCodes) {
+                boolean[] isFeatureSplits, String[] usesSplitNames, String[] configForSplit,
+                String[] splitCodePaths, int[] splitRevisionCodes) {
             this.packageName = baseApk.packageName;
             this.versionCode = baseApk.versionCode;
             this.installLocation = baseApk.installLocation;
             this.verifiers = baseApk.verifiers;
             this.splitNames = splitNames;
+            this.isFeatureSplits = isFeatureSplits;
             this.usesSplitNames = usesSplitNames;
+            this.configForSplit = configForSplit;
             this.codePath = codePath;
             this.baseCodePath = baseApk.codePath;
             this.splitCodePaths = splitCodePaths;
@@ -426,6 +439,8 @@
         public final String codePath;
         public final String packageName;
         public final String splitName;
+        public boolean isFeatureSplit;
+        public final String configForSplit;
         public final String usesSplitName;
         public final int versionCode;
         public final int revisionCode;
@@ -440,14 +455,17 @@
         public final boolean extractNativeLibs;
         public final boolean isolatedSplits;
 
-        public ApkLite(String codePath, String packageName, String splitName, String usesSplitName,
-                int versionCode, int revisionCode, int installLocation, List<VerifierInfo> verifiers,
-                Signature[] signatures, Certificate[][] certificates, boolean coreApp,
-                boolean debuggable, boolean multiArch, boolean use32bitAbi,
-                boolean extractNativeLibs, boolean isolatedSplits) {
+        public ApkLite(String codePath, String packageName, String splitName, boolean isFeatureSplit,
+                String configForSplit, String usesSplitName, int versionCode, int revisionCode,
+                int installLocation, List<VerifierInfo> verifiers, Signature[] signatures,
+                Certificate[][] certificates, boolean coreApp, boolean debuggable,
+                boolean multiArch, boolean use32bitAbi, boolean extractNativeLibs,
+                boolean isolatedSplits) {
             this.codePath = codePath;
             this.packageName = packageName;
             this.splitName = splitName;
+            this.isFeatureSplit = isFeatureSplit;
+            this.configForSplit = configForSplit;
             this.usesSplitName = usesSplitName;
             this.versionCode = versionCode;
             this.revisionCode = revisionCode;
@@ -803,10 +821,10 @@
         final ApkLite baseApk = parseApkLite(packageFile, flags);
         final String packagePath = packageFile.getAbsolutePath();
         Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-        return new PackageLite(packagePath, baseApk, null, null, null, null);
+        return new PackageLite(packagePath, baseApk, null, null, null, null, null, null);
     }
 
-    private static PackageLite parseClusterPackageLite(File packageDir, int flags)
+    static PackageLite parseClusterPackageLite(File packageDir, int flags)
             throws PackageParserException {
         final File[] files = packageDir.listFiles();
         if (ArrayUtils.isEmpty(files)) {
@@ -861,12 +879,16 @@
         final int size = apks.size();
 
         String[] splitNames = null;
+        boolean[] isFeatureSplits = null;
         String[] usesSplitNames = null;
+        String[] configForSplits = null;
         String[] splitCodePaths = null;
         int[] splitRevisionCodes = null;
         if (size > 0) {
             splitNames = new String[size];
+            isFeatureSplits = new boolean[size];
             usesSplitNames = new String[size];
+            configForSplits = new String[size];
             splitCodePaths = new String[size];
             splitRevisionCodes = new int[size];
 
@@ -876,14 +898,16 @@
             for (int i = 0; i < size; i++) {
                 final ApkLite apk = apks.get(splitNames[i]);
                 usesSplitNames[i] = apk.usesSplitName;
+                isFeatureSplits[i] = apk.isFeatureSplit;
+                configForSplits[i] = apk.configForSplit;
                 splitCodePaths[i] = apk.codePath;
                 splitRevisionCodes[i] = apk.revisionCode;
             }
         }
 
         final String codePath = packageDir.getAbsolutePath();
-        return new PackageLite(codePath, baseApk, splitNames, usesSplitNames, splitCodePaths,
-                splitRevisionCodes);
+        return new PackageLite(codePath, baseApk, splitNames, isFeatureSplits, usesSplitNames,
+                configForSplits, splitCodePaths, splitRevisionCodes);
     }
 
     /**
@@ -1061,42 +1085,6 @@
         }
     }
 
-    private static SparseIntArray buildSplitDependencyTree(PackageLite pkg)
-            throws PackageParserException {
-        SparseIntArray splitDependencies = new SparseIntArray();
-        for (int splitIdx = 0; splitIdx < pkg.splitNames.length; splitIdx++) {
-            final String splitDependency = pkg.usesSplitNames[splitIdx];
-            if (splitDependency != null) {
-                final int depIdx = Arrays.binarySearch(pkg.splitNames, splitDependency);
-                if (depIdx < 0) {
-                    throw new PackageParserException(
-                            PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
-                            "Split '" + pkg.splitNames[splitIdx] + "' requires split '"
-                                    + splitDependency + "', which is missing.");
-                }
-                splitDependencies.put(splitIdx, depIdx);
-            }
-        }
-
-        // Verify that there are no cycles.
-        final BitSet bitset = new BitSet();
-        for (int i = 0; i < splitDependencies.size(); i++) {
-            int splitIdx = splitDependencies.keyAt(i);
-
-            bitset.clear();
-            while (splitIdx != -1) {
-                if (bitset.get(splitIdx)) {
-                    throw new PackageParserException(
-                            PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
-                            "Cycle detected in split dependencies.");
-                }
-                bitset.set(splitIdx);
-                splitIdx = splitDependencies.get(splitIdx, -1);
-            }
-        }
-        return splitDependencies.size() != 0 ? splitDependencies : null;
-    }
-
     /**
      * Parse all APKs contained in the given directory, treating them as a
      * single package. This also performs sanity checking, such as requiring
@@ -1114,11 +1102,15 @@
         }
 
         // Build the split dependency tree.
-        SparseIntArray splitDependencies = null;
+        SparseArray<int[]> splitDependencies = null;
         final SplitAssetLoader assetLoader;
         if (lite.isolatedSplits && !ArrayUtils.isEmpty(lite.splitNames)) {
-            splitDependencies = buildSplitDependencyTree(lite);
-            assetLoader = new SplitAssetDependencyLoader(lite, splitDependencies, flags);
+            try {
+                splitDependencies = SplitAssetDependencyLoader.createDependenciesFromPackage(lite);
+                assetLoader = new SplitAssetDependencyLoader(lite, splitDependencies, flags);
+            } catch (SplitAssetDependencyLoader.IllegalDependencyException e) {
+                throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, e.getMessage());
+            }
         } else {
             assetLoader = new DefaultSplitAssetLoader(lite, flags);
         }
@@ -1754,6 +1746,8 @@
         boolean use32bitAbi = false;
         boolean extractNativeLibs = true;
         boolean isolatedSplits = false;
+        boolean isFeatureSplit = false;
+        String configForSplit = null;
         String usesSplitName = null;
 
         for (int i = 0; i < attrs.getAttributeCount(); i++) {
@@ -1769,6 +1763,10 @@
                 coreApp = attrs.getAttributeBooleanValue(i, false);
             } else if (attr.equals("isolatedSplits")) {
                 isolatedSplits = attrs.getAttributeBooleanValue(i, false);
+            } else if (attr.equals("configForSplit")) {
+                configForSplit = attrs.getAttributeValue(i);
+            } else if (attr.equals("isFeatureSplit")) {
+                isFeatureSplit = attrs.getAttributeBooleanValue(i, false);
             }
         }
 
@@ -1823,10 +1821,10 @@
             }
         }
 
-        return new ApkLite(codePath, packageSplit.first, packageSplit.second, usesSplitName,
-                versionCode, revisionCode, installLocation, verifiers, signatures,
-                certificates, coreApp, debuggable, multiArch, use32bitAbi, extractNativeLibs,
-                isolatedSplits);
+        return new ApkLite(codePath, packageSplit.first, packageSplit.second, isFeatureSplit,
+                configForSplit, usesSplitName, versionCode, revisionCode, installLocation,
+                verifiers, signatures, certificates, coreApp, debuggable, multiArch, use32bitAbi,
+                extractNativeLibs, isolatedSplits);
     }
 
     /**
@@ -4203,6 +4201,7 @@
                 sa.getBoolean(R.styleable.AndroidManifestActivity_visibleToInstantApps, false);
         if (visibleToEphemeral) {
             a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL;
+            owner.visibleToInstantApps = true;
         }
 
         sa.recycle();
@@ -4247,6 +4246,18 @@
                 if (intent.isVisibleToInstantApp()) {
                     a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL;
                 }
+                if (LOG_UNSAFE_BROADCASTS && receiver
+                        && (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.O)) {
+                    for (int i = 0; i < intent.countActions(); i++) {
+                        final String action = intent.getAction(i);
+                        if (action == null || !action.startsWith("android.")) continue;
+                        if (!SAFE_BROADCASTS.contains(action)) {
+                            Slog.w(TAG, "Broadcast " + action + " may never be delivered to "
+                                    + owner.packageName + " as requested at: "
+                                    + parser.getPositionDescription());
+                        }
+                    }
+                }
             } else if (!receiver && parser.getName().equals("preferred")) {
                 ActivityIntentInfo intent = new ActivityIntentInfo(a);
                 if (!parseIntent(res, parser, false /*allowGlobs*/, false /*allowAutoVerify*/,
@@ -4696,6 +4707,7 @@
                 sa.getBoolean(R.styleable.AndroidManifestProvider_visibleToInstantApps, false);
         if (visibleToEphemeral) {
             p.info.flags |= ProviderInfo.FLAG_VISIBLE_TO_EPHEMERAL;
+            owner.visibleToInstantApps = true;
         }
 
         sa.recycle();
@@ -5012,6 +5024,7 @@
                 sa.getBoolean(R.styleable.AndroidManifestService_visibleToInstantApps, false);
         if (visibleToEphemeral) {
             s.info.flags |= ServiceInfo.FLAG_VISIBLE_TO_EPHEMERAL;
+            owner.visibleToInstantApps = true;
         }
 
         sa.recycle();
@@ -5615,6 +5628,11 @@
 
         public byte[] restrictUpdateHash;
 
+        /**
+         * Set if the app or any of its components are visible to Instant Apps.
+         */
+        public boolean visibleToInstantApps;
+
         public Package(String packageName) {
             this.packageName = packageName;
             this.manifestPackageName = packageName;
diff --git a/core/java/android/content/pm/split/SplitAssetDependencyLoader.java b/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
index 4df90eb..16023f0 100644
--- a/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
+++ b/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
@@ -18,10 +18,11 @@
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
 
+import android.annotation.NonNull;
 import android.content.pm.PackageParser;
 import android.content.res.AssetManager;
 import android.os.Build;
-import android.util.SparseIntArray;
+import android.util.SparseArray;
 
 import libcore.io.IoUtils;
 
@@ -34,49 +35,31 @@
  * @hide
  */
 public class SplitAssetDependencyLoader
-        extends SplitDependencyLoaderHelper<PackageParser.PackageParserException>
+        extends SplitDependencyLoader<PackageParser.PackageParserException>
         implements SplitAssetLoader {
-    private static final int BASE_ASSET_PATH_IDX = -1;
-    private final String mBasePath;
-    private final String[] mSplitNames;
     private final String[] mSplitPaths;
     private final int mFlags;
 
-    private String[] mCachedBasePaths;
-    private AssetManager mCachedBaseAssetManager;
-
-    private String[][] mCachedSplitPaths;
+    private String[][] mCachedPaths;
     private AssetManager[] mCachedAssetManagers;
 
-    public SplitAssetDependencyLoader(PackageParser.PackageLite pkg, SparseIntArray dependencies,
-            int flags) {
+    public SplitAssetDependencyLoader(PackageParser.PackageLite pkg,
+            SparseArray<int[]> dependencies, int flags) {
         super(dependencies);
-        mBasePath = pkg.baseCodePath;
-        mSplitNames = pkg.splitNames;
-        mSplitPaths = pkg.splitCodePaths;
+
+        // The base is inserted into index 0, so we need to shift all the splits by 1.
+        mSplitPaths = new String[pkg.splitCodePaths.length + 1];
+        mSplitPaths[0] = pkg.baseCodePath;
+        System.arraycopy(pkg.splitCodePaths, 0, mSplitPaths, 1, pkg.splitCodePaths.length);
+
         mFlags = flags;
-        mCachedBasePaths = null;
-        mCachedBaseAssetManager = null;
-        mCachedSplitPaths = new String[mSplitNames.length][];
-        mCachedAssetManagers = new AssetManager[mSplitNames.length];
+        mCachedPaths = new String[mSplitPaths.length][];
+        mCachedAssetManagers = new AssetManager[mSplitPaths.length];
     }
 
     @Override
     protected boolean isSplitCached(int splitIdx) {
-        if (splitIdx != -1) {
-            return mCachedAssetManagers[splitIdx] != null;
-        }
-        return mCachedBaseAssetManager != null;
-    }
-
-    // Adds all non-code configuration splits for this split name. The split name is expected
-    // to represent a feature split.
-    private void addAllConfigSplits(String splitName, ArrayList<String> outAssetPaths) {
-        for (int i = 0; i < mSplitNames.length; i++) {
-            if (isConfigurationSplitOf(mSplitNames[i], splitName)) {
-                outAssetPaths.add(mSplitPaths[i]);
-            }
-        }
+        return mCachedAssetManagers[splitIdx] != null;
     }
 
     private static AssetManager createAssetManagerWithPaths(String[] assetPaths, int flags)
@@ -107,45 +90,38 @@
     }
 
     @Override
-    protected void constructSplit(int splitIdx, int parentSplitIdx) throws
-            PackageParser.PackageParserException {
+    protected void constructSplit(int splitIdx, @NonNull int[] configSplitIndices,
+            int parentSplitIdx) throws PackageParser.PackageParserException {
         final ArrayList<String> assetPaths = new ArrayList<>();
-        if (splitIdx == BASE_ASSET_PATH_IDX) {
-            assetPaths.add(mBasePath);
-            addAllConfigSplits(null, assetPaths);
-            mCachedBasePaths = assetPaths.toArray(new String[assetPaths.size()]);
-            mCachedBaseAssetManager = createAssetManagerWithPaths(mCachedBasePaths, mFlags);
-            return;
-        }
-
-        if (parentSplitIdx == BASE_ASSET_PATH_IDX) {
-            Collections.addAll(assetPaths, mCachedBasePaths);
-        } else {
-            Collections.addAll(assetPaths, mCachedSplitPaths[parentSplitIdx]);
+        if (parentSplitIdx >= 0) {
+            Collections.addAll(assetPaths, mCachedPaths[parentSplitIdx]);
         }
 
         assetPaths.add(mSplitPaths[splitIdx]);
-        addAllConfigSplits(mSplitNames[splitIdx], assetPaths);
-        mCachedSplitPaths[splitIdx] = assetPaths.toArray(new String[assetPaths.size()]);
-        mCachedAssetManagers[splitIdx] = createAssetManagerWithPaths(mCachedSplitPaths[splitIdx],
+        for (int configSplitIdx : configSplitIndices) {
+            assetPaths.add(mSplitPaths[configSplitIdx]);
+        }
+        mCachedPaths[splitIdx] = assetPaths.toArray(new String[assetPaths.size()]);
+        mCachedAssetManagers[splitIdx] = createAssetManagerWithPaths(mCachedPaths[splitIdx],
                 mFlags);
     }
 
     @Override
     public AssetManager getBaseAssetManager() throws PackageParser.PackageParserException {
-        loadDependenciesForSplit(BASE_ASSET_PATH_IDX);
-        return mCachedBaseAssetManager;
+        loadDependenciesForSplit(0);
+        return mCachedAssetManagers[0];
     }
 
     @Override
     public AssetManager getSplitAssetManager(int idx) throws PackageParser.PackageParserException {
-        loadDependenciesForSplit(idx);
-        return mCachedAssetManagers[idx];
+        // Since we insert the base at position 0, and PackageParser keeps splits separate from
+        // the base, we need to adjust the index.
+        loadDependenciesForSplit(idx + 1);
+        return mCachedAssetManagers[idx + 1];
     }
 
     @Override
     public void close() throws Exception {
-        IoUtils.closeQuietly(mCachedBaseAssetManager);
         for (AssetManager assets : mCachedAssetManagers) {
             IoUtils.closeQuietly(assets);
         }
diff --git a/core/java/android/content/pm/split/SplitDependencyLoader.java b/core/java/android/content/pm/split/SplitDependencyLoader.java
new file mode 100644
index 0000000..3586546
--- /dev/null
+++ b/core/java/android/content/pm/split/SplitDependencyLoader.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.content.pm.split;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.content.pm.PackageParser;
+import android.util.IntArray;
+import android.util.SparseArray;
+
+import libcore.util.EmptyArray;
+
+import java.util.Arrays;
+import java.util.BitSet;
+
+/**
+ * A helper class that implements the dependency tree traversal for splits. Callbacks
+ * are implemented by subclasses to notify whether a split has already been constructed
+ * and is cached, and to actually create the split requested.
+ *
+ * This helper is meant to be subclassed so as to reduce the number of allocations
+ * needed to make use of it.
+ *
+ * All inputs and outputs are assumed to be indices into an array of splits.
+ *
+ * @hide
+ */
+public abstract class SplitDependencyLoader<E extends Exception> {
+    private final @NonNull SparseArray<int[]> mDependencies;
+
+    /**
+     * Construct a new SplitDependencyLoader. Meant to be called from the
+     * subclass constructor.
+     * @param dependencies The dependency tree of splits.
+     */
+    protected SplitDependencyLoader(@NonNull SparseArray<int[]> dependencies) {
+        mDependencies = dependencies;
+    }
+
+    /**
+     * Traverses the dependency tree and constructs any splits that are not already
+     * cached. This routine short-circuits and skips the creation of splits closer to the
+     * root if they are cached, as reported by the subclass implementation of
+     * {@link #isSplitCached(int)}. The construction of splits is delegated to the subclass
+     * implementation of {@link #constructSplit(int, int[], int)}.
+     * @param splitIdx The index of the split to load. 0 represents the base Application.
+     */
+    protected void loadDependenciesForSplit(@IntRange(from = 0) int splitIdx) throws E {
+        // Quick check before any allocations are done.
+        if (isSplitCached(splitIdx)) {
+            return;
+        }
+
+        // Special case the base, since it has no dependencies.
+        if (splitIdx == 0) {
+            final int[] configSplitIndices = collectConfigSplitIndices(0);
+            constructSplit(0, configSplitIndices, -1);
+            return;
+        }
+
+        // Build up the dependency hierarchy.
+        final IntArray linearDependencies = new IntArray();
+        linearDependencies.add(splitIdx);
+
+        // Collect all the dependencies that need to be constructed.
+        // They will be listed from leaf to root.
+        while (true) {
+            // Only follow the first index into the array. The others are config splits and
+            // get loaded with the split.
+            final int[] deps = mDependencies.get(splitIdx);
+            if (deps != null && deps.length > 0) {
+                splitIdx = deps[0];
+            } else {
+                splitIdx = -1;
+            }
+
+            if (splitIdx < 0 || isSplitCached(splitIdx)) {
+                break;
+            }
+
+            linearDependencies.add(splitIdx);
+        }
+
+        // Visit each index, from right to left (root to leaf).
+        int parentIdx = splitIdx;
+        for (int i = linearDependencies.size() - 1; i >= 0; i--) {
+            final int idx = linearDependencies.get(i);
+            final int[] configSplitIndices = collectConfigSplitIndices(idx);
+            constructSplit(idx, configSplitIndices, parentIdx);
+            parentIdx = idx;
+        }
+    }
+
+    private @NonNull int[] collectConfigSplitIndices(int splitIdx) {
+        // The config splits appear after the first element.
+        final int[] deps = mDependencies.get(splitIdx);
+        if (deps == null || deps.length <= 1) {
+            return EmptyArray.INT;
+        }
+        return Arrays.copyOfRange(deps, 1, deps.length);
+    }
+
+    /**
+     * Subclass to report whether the split at `splitIdx` is cached and need not be constructed.
+     * It is assumed that if `splitIdx` is cached, any parent of `splitIdx` is also cached.
+     * @param splitIdx The index of the split to check for in the cache.
+     * @return true if the split is cached and does not need to be constructed.
+     */
+    protected abstract boolean isSplitCached(@IntRange(from = 0) int splitIdx);
+
+    /**
+     * Subclass to construct a split at index `splitIdx` with parent split `parentSplitIdx`.
+     * The result is expected to be cached by the subclass in its own structures.
+     * @param splitIdx The index of the split to construct. 0 represents the base Application.
+     * @param configSplitIndices The array of configuration splits to load along with this split.
+     *                           May be empty (length == 0) but never null.
+     * @param parentSplitIdx The index of the parent split. -1 if there is no parent.
+     * @throws E Subclass defined exception representing failure to construct a split.
+     */
+    protected abstract void constructSplit(@IntRange(from = 0) int splitIdx,
+            @NonNull @IntRange(from = 1) int[] configSplitIndices,
+            @IntRange(from = -1) int parentSplitIdx) throws E;
+
+    public static class IllegalDependencyException extends Exception {
+        private IllegalDependencyException(String message) {
+            super(message);
+        }
+    }
+
+    private static int[] append(int[] src, int elem) {
+        if (src == null) {
+            return new int[] { elem };
+        }
+        int[] dst = Arrays.copyOf(src, src.length + 1);
+        dst[src.length] = elem;
+        return dst;
+    }
+
+    public static @NonNull SparseArray<int[]> createDependenciesFromPackage(
+            PackageParser.PackageLite pkg) throws IllegalDependencyException {
+        // The data structure that holds the dependencies. In PackageParser, splits are stored
+        // in their own array, separate from the base. We treat all paths as equals, so
+        // we need to insert the base as index 0, and shift all other splits.
+        final SparseArray<int[]> splitDependencies = new SparseArray<>();
+
+        // The base depends on nothing.
+        splitDependencies.put(0, new int[] {-1});
+
+        // First write out the <uses-split> dependencies. These must appear first in the
+        // array of ints, as is convention in this class.
+        for (int splitIdx = 0; splitIdx < pkg.splitNames.length; splitIdx++) {
+            if (!pkg.isFeatureSplits[splitIdx]) {
+                // Non-feature splits don't have dependencies.
+                continue;
+            }
+
+            // Implicit dependency on the base.
+            final int targetIdx;
+            final String splitDependency = pkg.usesSplitNames[splitIdx];
+            if (splitDependency != null) {
+                final int depIdx = Arrays.binarySearch(pkg.splitNames, splitDependency);
+                if (depIdx < 0) {
+                    throw new IllegalDependencyException("Split '" + pkg.splitNames[splitIdx]
+                            + "' requires split '" + splitDependency + "', which is missing.");
+                }
+                targetIdx = depIdx + 1;
+            } else {
+                // Implicitly depend on the base.
+                targetIdx = 0;
+            }
+            splitDependencies.put(splitIdx + 1, new int[] {targetIdx});
+        }
+
+        // Write out the configForSplit reverse-dependencies. These appear after the <uses-split>
+        // dependencies and are considered leaves.
+        //
+        // At this point, all splits in splitDependencies have the first element in their array set.
+        for (int splitIdx = 0; splitIdx < pkg.splitNames.length; splitIdx++) {
+            if (pkg.isFeatureSplits[splitIdx]) {
+                // Feature splits are not configForSplits.
+                continue;
+            }
+
+            // Implicit feature for the base.
+            final int targetSplitIdx;
+            final String configForSplit = pkg.configForSplit[splitIdx];
+            if (configForSplit != null) {
+                final int depIdx = Arrays.binarySearch(pkg.splitNames, configForSplit);
+                if (depIdx < 0) {
+                    throw new IllegalDependencyException("Split '" + pkg.splitNames[splitIdx]
+                            + "' targets split '" + configForSplit + "', which is missing.");
+                }
+
+                if (!pkg.isFeatureSplits[depIdx]) {
+                    throw new IllegalDependencyException("Split '" + pkg.splitNames[splitIdx]
+                            + "' declares itself as configuration split for a non-feature split '"
+                            + pkg.splitNames[depIdx] + "'");
+                }
+                targetSplitIdx = depIdx + 1;
+            } else {
+                targetSplitIdx = 0;
+            }
+            splitDependencies.put(targetSplitIdx,
+                    append(splitDependencies.get(targetSplitIdx), splitIdx + 1));
+        }
+
+        // Verify that there are no cycles.
+        final BitSet bitset = new BitSet();
+        for (int i = 0, size = splitDependencies.size(); i < size; i++) {
+            int splitIdx = splitDependencies.keyAt(i);
+
+            bitset.clear();
+            while (splitIdx != -1) {
+                // Check if this split has been visited yet.
+                if (bitset.get(splitIdx)) {
+                    throw new IllegalDependencyException("Cycle detected in split dependencies.");
+                }
+
+                // Mark the split so that if we visit it again, we no there is a cycle.
+                bitset.set(splitIdx);
+
+                // Follow the first dependency only, the others are leaves by definition.
+                final int[] deps = splitDependencies.get(splitIdx);
+                splitIdx = deps != null ? deps[0] : -1;
+            }
+        }
+        return splitDependencies;
+    }
+}
diff --git a/core/java/android/content/pm/split/SplitDependencyLoaderHelper.java b/core/java/android/content/pm/split/SplitDependencyLoaderHelper.java
deleted file mode 100644
index b493480..0000000
--- a/core/java/android/content/pm/split/SplitDependencyLoaderHelper.java
+++ /dev/null
@@ -1,149 +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 android.content.pm.split;
-
-import android.annotation.Nullable;
-import android.util.IntArray;
-import android.util.SparseIntArray;
-
-/**
- * A helper class that implements the dependency tree traversal for splits. Callbacks
- * are implemented by subclasses to notify whether a split has already been constructed
- * and is cached, and to actually create the split requested.
- *
- * This helper is meant to be subclassed so as to reduce the number of allocations
- * needed to make use of it.
- *
- * All inputs and outputs are assumed to be indices into an array of splits.
- *
- * @hide
- */
-public abstract class SplitDependencyLoaderHelper<E extends Exception> {
-    @Nullable private final SparseIntArray mDependencies;
-
-    /**
-     * Construct a new SplitDependencyLoaderHelper. Meant to be called from the
-     * subclass constructor.
-     * @param dependencies The dependency tree of splits. Can be null, which leads to
-     *                     just the implicit dependency of all splits on the base.
-     */
-    protected SplitDependencyLoaderHelper(@Nullable SparseIntArray dependencies) {
-        mDependencies = dependencies;
-    }
-
-    /**
-     * Traverses the dependency tree and constructs any splits that are not already
-     * cached. This routine short-circuits and skips the creation of splits closer to the
-     * root if they are cached, as reported by the subclass implementation of
-     * {@link #isSplitCached(int)}. The construction of splits is delegated to the subclass
-     * implementation of {@link #constructSplit(int, int)}.
-     * @param splitIdx The index of the split to load. Can be -1, which represents the
-     *                 base Application.
-     */
-    protected void loadDependenciesForSplit(int splitIdx) throws E {
-        // Quick check before any allocations are done.
-        if (isSplitCached(splitIdx)) {
-            return;
-        }
-
-        final IntArray linearDependencies = new IntArray();
-        linearDependencies.add(splitIdx);
-
-        // Collect all the dependencies that need to be constructed.
-        // They will be listed from leaf to root.
-        while (splitIdx >= 0) {
-            splitIdx = mDependencies != null ? mDependencies.get(splitIdx, -1) : -1;
-            if (isSplitCached(splitIdx)) {
-                break;
-            }
-            linearDependencies.add(splitIdx);
-        }
-
-        // Visit each index, from right to left (root to leaf).
-        int parentIdx = splitIdx;
-        for (int i = linearDependencies.size() - 1; i >= 0; i--) {
-            final int idx = linearDependencies.get(i);
-            constructSplit(idx, parentIdx);
-            parentIdx = idx;
-        }
-    }
-
-    /**
-     * Subclass to report whether the split at `splitIdx` is cached and need not be constructed.
-     * It is assumed that if `splitIdx` is cached, any parent of `splitIdx` is also cached.
-     * @param splitIdx The index of the split to check for in the cache.
-     * @return true if the split is cached and does not need to be constructed.
-     */
-    protected abstract boolean isSplitCached(int splitIdx);
-
-    /**
-     * Subclass to construct a split at index `splitIdx` with parent split `parentSplitIdx`.
-     * The result is expected to be cached by the subclass in its own structures.
-     * @param splitIdx The index of the split to construct. Can be -1, which represents the
-     *                 base Application.
-     * @param parentSplitIdx The index of the parent split. Can be -1, which represents the
-     *                       base Application.
-     * @throws E
-     */
-    protected abstract void constructSplit(int splitIdx, int parentSplitIdx) throws E;
-
-    /**
-     * Returns true if `splitName` represents a Configuration split of `featureSplitName`.
-     *
-     * A Configuration split's name is prefixed with the associated Feature split's name
-     * or the empty string if the split is for the base Application APK. It is then followed by the
-     * dollar sign character "$" and some unique string that should represent the configurations
-     * the split contains.
-     *
-     * Example:
-     * <table>
-     *     <tr>
-     *         <th>Feature split name</th>
-     *         <th>Configuration split name: xhdpi</th>
-     *         <th>Configuration split name: fr-rFR</th>
-     *     </tr>
-     *     <tr>
-     *         <td>(base APK)</td>
-     *         <td><code>$xhdpi</code></td>
-     *         <td><code>$fr-rFR</code></td>
-     *     </tr>
-     *     <tr>
-     *         <td><code>Extras</code></td>
-     *         <td><code>Extras$xhdpi</code></td>
-     *         <td><code>Extras$fr-rFR</code></td>
-     *     </tr>
-     * </table>
-     *
-     * @param splitName The name of the split to check.
-     * @param featureSplitName The name of the Feature split. May be null or "" if checking
-     *                         the base Application APK.
-     * @return true if the splitName represents a Configuration split of featureSplitName.
-     */
-    protected static boolean isConfigurationSplitOf(String splitName, String featureSplitName) {
-        if (featureSplitName == null || featureSplitName.length() == 0) {
-            // We are looking for configuration splits of the base, which have some legacy support.
-            if (splitName.startsWith("config_")) {
-                return true;
-            } else if (splitName.startsWith("$")) {
-                return true;
-            } else {
-                return false;
-            }
-        } else {
-            return splitName.startsWith(featureSplitName + "$");
-        }
-    }
-}
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 8bc65af..e3b97e8 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -100,6 +100,8 @@
     private final CameraCharacteristics mCharacteristics;
     private final int mTotalPartialCount;
 
+    private static final long NANO_PER_SECOND = 1000000000; //ns
+
     /**
      * A list tracking request and its expected last regular frame number and last reprocess frame
      * number. Updated when calling ICameraDeviceUser methods.
@@ -1239,6 +1241,14 @@
         private final List<CaptureRequest> mRequestList;
         private final Handler mHandler;
         private final int mSessionId;
+        /**
+         * <p>Determine if the callback holder is for a constrained high speed request list that
+         * expects batched capture results. Capture results will be batched if the request list
+         * is interleaved with preview and video requests. Capture results won't be batched if the
+         * request list only contains preview requests, or if the request doesn't belong to a
+         * constrained high speed list.
+         */
+        private final boolean mHasBatchedOutputs;
 
         CaptureCallbackHolder(CaptureCallback callback, List<CaptureRequest> requestList,
                 Handler handler, boolean repeating, int sessionId) {
@@ -1251,6 +1261,25 @@
             mRequestList = new ArrayList<CaptureRequest>(requestList);
             mCallback = callback;
             mSessionId = sessionId;
+
+            // Check whether this callback holder is for batched outputs.
+            // The logic here should match createHighSpeedRequestList.
+            boolean hasBatchedOutputs = true;
+            for (int i = 0; i < requestList.size(); i++) {
+                CaptureRequest request = requestList.get(i);
+                if (!request.isPartOfCRequestList()) {
+                    hasBatchedOutputs = false;
+                    break;
+                }
+                if (i == 0) {
+                    Collection<Surface> targets = request.getTargets();
+                    if (targets.size() != 2) {
+                        hasBatchedOutputs = false;
+                        break;
+                    }
+                }
+            }
+            mHasBatchedOutputs = hasBatchedOutputs;
         }
 
         public boolean isRepeating() {
@@ -1288,6 +1317,14 @@
         public int getSessionId() {
             return mSessionId;
         }
+
+        public int getRequestCount() {
+            return mRequestList.size();
+        }
+
+        public boolean hasBatchedOutputs() {
+            return mHasBatchedOutputs;
+        }
     }
 
     /**
@@ -1777,10 +1814,27 @@
                         @Override
                         public void run() {
                             if (!CameraDeviceImpl.this.isClosed()) {
-                                holder.getCallback().onCaptureStarted(
-                                    CameraDeviceImpl.this,
-                                    holder.getRequest(resultExtras.getSubsequenceId()),
-                                    timestamp, frameNumber);
+                                final int subsequenceId = resultExtras.getSubsequenceId();
+                                final CaptureRequest request = holder.getRequest(subsequenceId);
+
+                                if (holder.hasBatchedOutputs()) {
+                                    // Send derived onCaptureStarted for requests within the batch
+                                    final Range<Integer> fpsRange =
+                                        request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE);
+                                    for (int i = 0; i < holder.getRequestCount(); i++) {
+                                        holder.getCallback().onCaptureStarted(
+                                            CameraDeviceImpl.this,
+                                            holder.getRequest(i),
+                                            timestamp - (subsequenceId - i) *
+                                            NANO_PER_SECOND/fpsRange.getUpper(),
+                                            frameNumber - (subsequenceId - i));
+                                    }
+                                } else {
+                                    holder.getCallback().onCaptureStarted(
+                                        CameraDeviceImpl.this,
+                                        holder.getRequest(resultExtras.getSubsequenceId()),
+                                        timestamp, frameNumber);
+                                }
                             }
                         }
                     });
@@ -1845,46 +1899,91 @@
                 Runnable resultDispatch = null;
 
                 CaptureResult finalResult;
+                // Make a copy of the native metadata before it gets moved to a CaptureResult
+                // object.
+                final CameraMetadataNative resultCopy;
+                if (holder.hasBatchedOutputs()) {
+                    resultCopy = new CameraMetadataNative(result);
+                } else {
+                    resultCopy = null;
+                }
 
                 // Either send a partial result or the final capture completed result
                 if (isPartialResult) {
                     final CaptureResult resultAsCapture =
                             new CaptureResult(result, request, resultExtras);
-
                     // Partial result
                     resultDispatch = new Runnable() {
                         @Override
                         public void run() {
-                            if (!CameraDeviceImpl.this.isClosed()){
-                                holder.getCallback().onCaptureProgressed(
-                                    CameraDeviceImpl.this,
-                                    request,
-                                    resultAsCapture);
+                            if (!CameraDeviceImpl.this.isClosed()) {
+                                if (holder.hasBatchedOutputs()) {
+                                    // Send derived onCaptureProgressed for requests within
+                                    // the batch.
+                                    for (int i = 0; i < holder.getRequestCount(); i++) {
+                                        CameraMetadataNative resultLocal =
+                                                new CameraMetadataNative(resultCopy);
+                                        CaptureResult resultInBatch = new CaptureResult(
+                                                resultLocal, holder.getRequest(i), resultExtras);
+
+                                        holder.getCallback().onCaptureProgressed(
+                                            CameraDeviceImpl.this,
+                                            holder.getRequest(i),
+                                            resultInBatch);
+                                    }
+                                } else {
+                                    holder.getCallback().onCaptureProgressed(
+                                        CameraDeviceImpl.this,
+                                        request,
+                                        resultAsCapture);
+                                }
                             }
                         }
                     };
-
                     finalResult = resultAsCapture;
                 } else {
                     List<CaptureResult> partialResults =
                             mFrameNumberTracker.popPartialResults(frameNumber);
 
+                    final long sensorTimestamp =
+                            result.get(CaptureResult.SENSOR_TIMESTAMP);
+                    final Range<Integer> fpsRange =
+                            request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE);
+                    final int subsequenceId = resultExtras.getSubsequenceId();
                     final TotalCaptureResult resultAsCapture = new TotalCaptureResult(result,
                             request, resultExtras, partialResults, holder.getSessionId());
-
                     // Final capture result
                     resultDispatch = new Runnable() {
                         @Override
                         public void run() {
                             if (!CameraDeviceImpl.this.isClosed()){
-                                holder.getCallback().onCaptureCompleted(
-                                    CameraDeviceImpl.this,
-                                    request,
-                                    resultAsCapture);
+                                if (holder.hasBatchedOutputs()) {
+                                    // Send derived onCaptureCompleted for requests within
+                                    // the batch.
+                                    for (int i = 0; i < holder.getRequestCount(); i++) {
+                                        resultCopy.set(CaptureResult.SENSOR_TIMESTAMP,
+                                                sensorTimestamp - (subsequenceId - i) *
+                                                NANO_PER_SECOND/fpsRange.getUpper());
+                                        CameraMetadataNative resultLocal =
+                                                new CameraMetadataNative(resultCopy);
+                                        TotalCaptureResult resultInBatch = new TotalCaptureResult(
+                                            resultLocal, holder.getRequest(i), resultExtras,
+                                            partialResults, holder.getSessionId());
+
+                                        holder.getCallback().onCaptureCompleted(
+                                            CameraDeviceImpl.this,
+                                            holder.getRequest(i),
+                                            resultInBatch);
+                                    }
+                                } else {
+                                    holder.getCallback().onCaptureCompleted(
+                                        CameraDeviceImpl.this,
+                                        request,
+                                        resultAsCapture);
+                                }
                             }
                         }
                     };
-
                     finalResult = resultAsCapture;
                 }
 
diff --git a/core/java/android/hardware/radio/RadioModule.java b/core/java/android/hardware/radio/RadioModule.java
index fc7d0d2..8964893 100644
--- a/core/java/android/hardware/radio/RadioModule.java
+++ b/core/java/android/hardware/radio/RadioModule.java
@@ -16,6 +16,8 @@
 
 package android.hardware.radio;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.content.Context;
 import android.content.Intent;
@@ -23,6 +25,7 @@
 import android.os.Looper;
 import android.os.Message;
 import java.lang.ref.WeakReference;
+import java.util.List;
 import java.util.UUID;
 
 /**
@@ -76,6 +79,8 @@
 
     public native int getProgramInformation(RadioManager.ProgramInfo[] info);
 
+    public native @NonNull List<RadioManager.ProgramInfo> getProgramList(@Nullable String filter);
+
     public native boolean isAntennaConnected();
 
     public native boolean hasControl();
diff --git a/core/java/android/hardware/radio/RadioTuner.java b/core/java/android/hardware/radio/RadioTuner.java
index 5c82555..c8034eb 100644
--- a/core/java/android/hardware/radio/RadioTuner.java
+++ b/core/java/android/hardware/radio/RadioTuner.java
@@ -16,6 +16,8 @@
 
 package android.hardware.radio;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.content.Context;
 import android.content.Intent;
@@ -23,6 +25,7 @@
 import android.os.Looper;
 import android.os.Message;
 import java.lang.ref.WeakReference;
+import java.util.List;
 import java.util.UUID;
 
 /**
@@ -209,6 +212,20 @@
     public abstract int getProgramInformation(RadioManager.ProgramInfo[] info);
 
     /**
+     * Get the list of discovered radio stations.
+     *
+     * To get the full list, set filter to null or empty string. Otherwise, client application
+     * must verify vendor product/name before setting this parameter to anything else.
+     *
+     * @param filter vendor-specific selector for radio stations.
+     * @return a list of radio stations.
+     * @throws IllegalStateException if the scan is in progress or has not been started.
+     * @throws IllegalArgumentException if the filter argument is not valid.
+     * @hide FutureFeature
+     */
+    public abstract @NonNull List<RadioManager.ProgramInfo> getProgramList(@Nullable String filter);
+
+    /**
      * Get current antenna connection state for current configuration.
      * Only valid if a configuration has been applied.
      * @return {@code true} if the antenna is connected, {@code false} otherwise.
diff --git a/core/java/android/net/ConnectivityMetricsEvent.java b/core/java/android/net/ConnectivityMetricsEvent.java
index 1b1b958..4faff62 100644
--- a/core/java/android/net/ConnectivityMetricsEvent.java
+++ b/core/java/android/net/ConnectivityMetricsEvent.java
@@ -19,20 +19,32 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
-/** {@hide} */
+/**
+ * Represents a core networking event defined in package android.net.metrics.
+ * Logged by IpConnectivityLog and managed by ConnectivityMetrics service.
+ * {@hide}
+ * */
 public final class ConnectivityMetricsEvent implements Parcelable {
 
-    /**  The time when this event was collected, as returned by System.currentTimeMillis(). */
+    /** Time when this event was collected, as returned by System.currentTimeMillis(). */
     public long timestamp;
-
+    /** Transports of the network associated with the event, as defined in NetworkCapabilities. */
+    public long transports;
+    /** Network id of the network associated with the event, or 0 if unspecified. */
+    public int netId;
+    /** Name of the network interface associated with the event, or null if unspecified. */
+    public String ifname;
     /** Opaque event-specific data. */
     public Parcelable data;
 
     public ConnectivityMetricsEvent() {
     }
 
-    public ConnectivityMetricsEvent(Parcel in) {
+    private ConnectivityMetricsEvent(Parcel in) {
         timestamp = in.readLong();
+        transports = in.readLong();
+        netId = in.readInt();
+        ifname = in.readString();
         data = in.readParcelable(null);
     }
 
@@ -56,11 +68,15 @@
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeLong(timestamp);
+        dest.writeLong(transports);
+        dest.writeInt(netId);
+        dest.writeString(ifname);
         dest.writeParcelable(data, 0);
     }
 
     @Override
     public String toString() {
+        // TODO: add transports, netId, ifname
         return String.format("ConnectivityMetricsEvent(%tT.%tL): %s", timestamp, timestamp, data);
     }
 }
diff --git a/core/java/android/net/metrics/IpConnectivityLog.java b/core/java/android/net/metrics/IpConnectivityLog.java
index aaad1fa..79094c0 100644
--- a/core/java/android/net/metrics/IpConnectivityLog.java
+++ b/core/java/android/net/metrics/IpConnectivityLog.java
@@ -60,23 +60,22 @@
     }
 
     /**
-     * Log an IpConnectivity event.
-     * @param timestamp is the epoch timestamp of the event in ms.
-     * @param data is a Parcelable instance representing the event.
+     * Log a ConnectivityMetricsEvent.
+     * @param ev the event to log. If the event timestamp is 0,
+     * the timestamp is set to the current time in milliseconds.
      * @return true if the event was successfully logged.
      */
-    public boolean log(long timestamp, Parcelable data) {
+    public boolean log(ConnectivityMetricsEvent ev) {
         if (!checkLoggerService()) {
             if (DBG) {
                 Log.d(TAG, SERVICE_NAME + " service was not ready");
             }
             return false;
         }
-
+        if (ev.timestamp == 0) {
+            ev.timestamp = System.currentTimeMillis();
+        }
         try {
-            ConnectivityMetricsEvent ev = new ConnectivityMetricsEvent();
-            ev.timestamp = timestamp;
-            ev.data = data;
             int left = mService.logEvent(ev);
             return left >= 0;
         } catch (RemoteException e) {
@@ -85,7 +84,31 @@
         }
     }
 
-    public void log(Parcelable event) {
-        log(System.currentTimeMillis(), event);
+    /**
+     * Log an IpConnectivity event.
+     * @param timestamp is the epoch timestamp of the event in ms.
+     * If the timestamp is 0, the timestamp is set to the current time in milliseconds.
+     * @param data is a Parcelable instance representing the event.
+     * @return true if the event was successfully logged.
+     */
+    public boolean log(long timestamp, Parcelable data) {
+        ConnectivityMetricsEvent ev = makeEv(data);
+        ev.timestamp = timestamp;
+        return log(ev);
+    }
+
+    /**
+     * Log an IpConnectivity event.
+     * @param data is a Parcelable instance representing the event.
+     * @return true if the event was successfully logged.
+     */
+    public boolean log(Parcelable data) {
+        return log(makeEv(data));
+    }
+
+    private static ConnectivityMetricsEvent makeEv(Parcelable data) {
+        ConnectivityMetricsEvent ev = new ConnectivityMetricsEvent();
+        ev.data = data;
+        return ev;
     }
 }
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index dc170ed..29884b1 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -2042,8 +2042,8 @@
 
     public static final String[] HISTORY_EVENT_NAMES = new String[] {
             "null", "proc", "fg", "top", "sync", "wake_lock_in", "job", "user", "userfg", "conn",
-            "active", "pkginst", "pkgunin", "alarm", "stats", "inactive", "active", "tmpwhitelist",
-            "screenwake", "wakeupap", "longwake", "est_capacity"
+            "active", "pkginst", "pkgunin", "alarm", "stats", "pkginactive", "pkgactive",
+            "tmpwhitelist", "screenwake", "wakeupap", "longwake", "est_capacity"
     };
 
     public static final String[] HISTORY_EVENT_CHECKIN_NAMES = new String[] {
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 0136979..7906707 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -66,7 +66,8 @@
      * of classes can potentially create leaks.
      */
     private static final boolean FIND_POTENTIAL_LEAKS = false;
-    private static final boolean CHECK_PARCEL_SIZE = false;
+    /** @hide */
+    public static final boolean CHECK_PARCEL_SIZE = false;
     static final String TAG = "Binder";
 
     /** @hide */
diff --git a/core/java/android/os/HwParcel.java b/core/java/android/os/HwParcel.java
index a265dd0..94fd5b0 100644
--- a/core/java/android/os/HwParcel.java
+++ b/core/java/android/os/HwParcel.java
@@ -219,6 +219,7 @@
     public native final void writeStatus(int status);
     public native final void verifySuccess();
     public native final void releaseTemporaryStorage();
+    public native final void release();
 
     public native final void send();
 
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index caea202..f503b3a 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -2638,7 +2638,7 @@
             dest.writeString(broadcastIntentAction);
             dest.writeStringArray(tags);
             int total = dest.dataPosition()-start;
-            if (total > 10*1024) {
+            if (Binder.CHECK_PARCEL_SIZE && total > 10*1024) {
                 Slog.d(TAG, "VIO: policy=" + policy + " dur=" + durationMillis
                         + " numLoop=" + violationNumThisLoop
                         + " anim=" + numAnimationsRunning
diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java
index b525193..8632194 100644
--- a/core/java/android/os/SystemProperties.java
+++ b/core/java/android/os/SystemProperties.java
@@ -35,6 +35,12 @@
     private static final String TAG = "SystemProperties";
     private static final boolean TRACK_KEY_ACCESS = false;
 
+    /**
+     * Android O removed the property name length limit, but com.amazon.kindle 7.8.1.5
+     * uses reflection to read this whenever text is selected (http://b/36095274).
+     */
+    public static final int PROP_NAME_MAX = Integer.MAX_VALUE;
+
     public static final int PROP_VALUE_MAX = 91;
 
     private static final ArrayList<Runnable> sChangeCallbacks = new ArrayList<Runnable>();
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index a638cd4..f6712f8 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -22,6 +22,7 @@
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.annotation.UserIdInt;
 import android.annotation.WorkerThread;
 import android.app.Activity;
@@ -763,6 +764,16 @@
     public static final int PIN_VERIFICATION_SUCCESS = -1;
 
     /**
+     * Sent when user restrictions have changed.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi // To allow seeing it from CTS.
+    public static final String ACTION_USER_RESTRICTIONS_CHANGED =
+            "android.os.action.USER_RESTRICTIONS_CHANGED";
+
+    /**
      * Error result indicating that this user is not allowed to add other users on this device.
      * This is a result code returned from the activity created by the intent
      * {@link #createUserCreationIntent(String, String, String, PersistableBundle)}.
diff --git a/core/java/android/provider/FontsContract.java b/core/java/android/provider/FontsContract.java
index 9f5d9d4..84443e9 100644
--- a/core/java/android/provider/FontsContract.java
+++ b/core/java/android/provider/FontsContract.java
@@ -138,12 +138,8 @@
     private HandlerThread mThread;
 
     /** @hide */
-    public FontsContract() {
-        // TODO: investigate if the system context is the best option here. ApplicationContext or
-        // the one passed by developer?
-        // TODO: Looks like ActivityThread.currentActivityThread() can return null. Check when it
-        // returns null and check if we need to handle null case.
-        mContext = ActivityThread.currentActivityThread().getSystemContext();
+    public FontsContract(Context context) {
+        mContext = context.getApplicationContext();
         mPackageManager = mContext.getPackageManager();
     }
 
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 391ee83..7b84f689 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6630,6 +6630,8 @@
          * This value is only used for managed profiles.
          * @hide
          */
+        @TestApi
+        @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
         public static final String SYNC_PARENT_SOUNDS = "sync_parent_sounds";
 
         /** @hide */
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 29e2073..709e5f9 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -30,6 +30,7 @@
 import android.os.ICancellationSignal;
 import android.os.Looper;
 import android.util.Log;
+import android.view.autofill.AutofillManager;
 
 import com.android.internal.os.SomeArgs;
 
@@ -90,6 +91,8 @@
     private static final int MSG_ON_FILL_REQUEST = 3;
     private static final int MSG_ON_SAVE_REQUEST = 4;
 
+    private static final int UNUSED_ARG = -1;
+
     private final IAutoFillService mInterface = new IAutoFillService.Stub() {
         @Override
         public void onInit(IAutoFillServiceConnection connection) {
@@ -102,14 +105,14 @@
 
         @Override
         public void onFillRequest(AssistStructure structure, Bundle extras,
-                IFillCallback callback) {
+                IFillCallback callback, int flags) {
             ICancellationSignal transport = CancellationSignal.createTransport();
             try {
                 callback.onCancellable(transport);
             } catch (RemoteException e) {
                 e.rethrowFromSystemServer();
             }
-            mHandlerCaller.obtainMessageOOOO(MSG_ON_FILL_REQUEST, structure,
+            mHandlerCaller.obtainMessageIIOOOO(MSG_ON_FILL_REQUEST, flags, UNUSED_ARG, structure,
                     CancellationSignal.fromTransport(transport), extras, callback)
                     .sendToTarget();
         }
@@ -135,8 +138,9 @@
                 final Bundle extras = (Bundle) args.arg3;
                 final IFillCallback callback = (IFillCallback) args.arg4;
                 final FillCallback fillCallback = new FillCallback(callback);
+                final int flags = msg.arg1;
                 args.recycle();
-                onFillRequest(structure, extras, cancellation, fillCallback);
+                onFillRequest(structure, extras, flags, cancellation, fillCallback);
                 break;
             } case MSG_ON_SAVE_REQUEST: {
                 final SomeArgs args = (SomeArgs) msg.obj;
@@ -188,7 +192,6 @@
      * <p>You should generally do initialization here rather than in {@link #onCreate}.
      */
     public void onConnected() {
-        //TODO(b/33197203): is not called anymore, fix it!
     }
 
     /**
@@ -206,11 +209,25 @@
      *     as well as when filling different sections of the UI as the system will try to
      *     aggressively unbind from the service to conserve resources. See {@link
      *     FillResponse} Javadoc for examples of multiple-sections requests.
+     * @param flags either {@code 0} or {@link AutofillManager#FLAG_MANUAL_REQUEST}.
      * @param cancellationSignal signal for observing cancellation requests. The system will use
      *     this to notify you that the fill result is no longer needed and you should stop
      *     handling this fill request in order to save resources.
      * @param callback object used to notify the result of the request.
      */
+    public void onFillRequest(@NonNull AssistStructure structure, @Nullable Bundle data, int flags,
+            @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback) {
+        //TODO(b/33197203): make non-abstract once older method is removed
+        onFillRequest(structure, data, cancellationSignal, callback);
+    }
+
+    /**
+     * @hide
+     * @deprecated - use {@link #onFillRequest(AssistStructure, Bundle, int,
+     * CancellationSignal, FillCallback)} instead
+     */
+    //TODO(b/33197203): remove once clients are not using anymore
+    @Deprecated
     public abstract void onFillRequest(@NonNull AssistStructure structure, @Nullable Bundle data,
             @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback);
 
@@ -238,7 +255,6 @@
      * <p> At this point this service may no longer be an active {@link AutofillService}.
      */
     public void onDisconnected() {
-        //TODO(b/33197203): is not called anymore, fix it!
     }
 
     /**
diff --git a/core/java/android/service/autofill/FillCallback.java b/core/java/android/service/autofill/FillCallback.java
index 00b206c..e8ad14f 100644
--- a/core/java/android/service/autofill/FillCallback.java
+++ b/core/java/android/service/autofill/FillCallback.java
@@ -37,7 +37,7 @@
     /**
      * Notifies the Android System that an
      * {@link AutofillService#onFillRequest(android.app.assist.AssistStructure, Bundle,
-     * android.os.CancellationSignal, FillCallback)} was successfully fulfilled by the service.
+     * int, android.os.CancellationSignal, FillCallback)} was successfully fulfilled by the service.
      *
      * @param response autofill information for that activity, or {@code null} when the activity
      * cannot be autofilled (for example, if it only contains read-only fields). See
@@ -56,7 +56,7 @@
     /**
      * Notifies the Android System that an
      * {@link AutofillService#onFillRequest(android.app.assist.AssistStructure,
-     * Bundle, android.os.CancellationSignal, FillCallback)}
+     * Bundle, int, android.os.CancellationSignal, FillCallback)}
      * could not be fulfilled by the service.
      *
      * @param message error message to be displayed to the user.
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index b808de7..c43019d 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -31,7 +31,7 @@
 /**
  * Response for a {@link
  * AutofillService#onFillRequest(android.app.assist.AssistStructure,
- * Bundle, android.os.CancellationSignal, FillCallback)}.
+ * Bundle, int, android.os.CancellationSignal, FillCallback)}.
  *
  * <p>The response typically contains one or more {@link Dataset}s, each representing a set of
  * fields that can be autofilled together, and the Android system displays a dataset picker UI
@@ -269,8 +269,8 @@
          * Sets a {@link Bundle} that will be passed to subsequent APIs that
          * manipulate this response. For example, they are passed to subsequent
          * calls to {@link AutofillService#onFillRequest(
-         * android.app.assist.AssistStructure, Bundle, android.os.CancellationSignal,
-         * FillCallback)} and {@link AutofillService#onSaveRequest(
+         * android.app.assist.AssistStructure, Bundle, int,
+         * android.os.CancellationSignal, FillCallback)} and {@link AutofillService#onSaveRequest(
          * android.app.assist.AssistStructure, Bundle, SaveCallback)}.
          *
          * @param extras The response extras.
diff --git a/core/java/android/service/autofill/IAutoFillService.aidl b/core/java/android/service/autofill/IAutoFillService.aidl
index 80685d8..9f296c6 100644
--- a/core/java/android/service/autofill/IAutoFillService.aidl
+++ b/core/java/android/service/autofill/IAutoFillService.aidl
@@ -31,7 +31,7 @@
 oneway interface IAutoFillService {
     void onInit(in IAutoFillServiceConnection connection);
     void onFillRequest(in AssistStructure structure, in Bundle extras,
-            in IFillCallback callback);
+            in IFillCallback callback, int flags);
     void onSaveRequest(in AssistStructure structure, in Bundle extras,
             in ISaveCallback callback);
 }
diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
index 6d368b5..6213d27 100644
--- a/core/java/android/service/autofill/SaveInfo.java
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -119,7 +119,6 @@
      */
     public static final int SAVE_DATA_TYPE_PASSWORD = 1;
 
-
     /**
      * Type used on when the {@link FillResponse} represents a physical address (such as street,
      * city, state, etc).
@@ -216,8 +215,10 @@
          * @throws IllegalArgumentException if {@code requiredIds} is {@code null} or empty.
          */
         public Builder(@SaveDataType int type, @NonNull AutofillId[] requiredIds) {
+            if (false) {// TODO(b/33197203): re-move when clients use it
             Preconditions.checkArgument(requiredIds != null && requiredIds.length > 0,
-                    "must have at least on required id: " + Arrays.toString(requiredIds));
+                    "must have at least one required id: " + Arrays.toString(requiredIds));
+            }
             switch (type) {
                 case SAVE_DATA_TYPE_PASSWORD:
                 case SAVE_DATA_TYPE_ADDRESS:
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 70e0461..f55c7cf 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -149,13 +149,13 @@
     // Notification cancellation reasons
 
     /** Notification was canceled by the status bar reporting a notification click. */
-    public static final int REASON_DELEGATE_CLICK = 1;
+    public static final int REASON_CLICK = 1;
     /** Notification was canceled by the status bar reporting a user dismissal. */
-    public static final int REASON_DELEGATE_CANCEL = 2;
+    public static final int REASON_CANCEL = 2;
     /** Notification was canceled by the status bar reporting a user dismiss all. */
-    public static final int REASON_DELEGATE_CANCEL_ALL = 3;
+    public static final int REASON_CANCEL_ALL = 3;
     /** Notification was canceled by the status bar reporting an inflation error. */
-    public static final int REASON_DELEGATE_ERROR = 4;
+    public static final int REASON_ERROR = 4;
     /** Notification was canceled by the package manager modifying the package. */
     public static final int REASON_PACKAGE_CHANGED = 5;
     /** Notification was canceled by the owning user context being stopped. */
diff --git a/core/java/android/service/vr/IVrManager.aidl b/core/java/android/service/vr/IVrManager.aidl
index 10e4177..6034c18 100644
--- a/core/java/android/service/vr/IVrManager.aidl
+++ b/core/java/android/service/vr/IVrManager.aidl
@@ -50,5 +50,13 @@
      * @param enabled true if the device should be placed in persistent VR mode.
      */
     void setPersistentVrModeEnabled(in boolean enabled);
+
+    /**
+     * Return current virtual display id.
+     *
+     * @return {@link android.view.Display.INVALID_DISPLAY} if there is no virtual display
+     * currently, else return the display id of the virtual display
+     */
+    int getCompatibilityDisplayId();
 }
 
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 483a49b..6bbb0ff 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -18,11 +18,11 @@
 
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
+import android.util.MergedConfiguration;
 import android.view.WindowInsets;
 
 import com.android.internal.R;
 import com.android.internal.os.HandlerCaller;
-import com.android.internal.util.ScreenShapeHelper;
 import com.android.internal.view.BaseIWindow;
 import com.android.internal.view.BaseSurfaceHolder;
 
@@ -32,7 +32,6 @@
 import android.app.WallpaperManager;
 import android.content.Context;
 import android.content.Intent;
-import android.content.res.Configuration;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.hardware.display.DisplayManager;
@@ -55,7 +54,6 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
-import android.view.WindowManager.LayoutParams;
 import android.view.WindowManagerGlobal;
 
 import java.io.FileDescriptor;
@@ -169,7 +167,7 @@
         final Rect mFinalSystemInsets = new Rect();
         final Rect mFinalStableInsets = new Rect();
         final Rect mBackdropFrame = new Rect();
-        final Configuration mConfiguration = new Configuration();
+        final MergedConfiguration mMergedConfiguration = new MergedConfiguration();
 
         final WindowManager.LayoutParams mLayout
                 = new WindowManager.LayoutParams();
@@ -288,7 +286,7 @@
             @Override
             public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
                     Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
-                    Configuration newConfig, Rect backDropRect, boolean forceLayout,
+                    MergedConfiguration mergedConfiguration, Rect backDropRect, boolean forceLayout,
                     boolean alwaysConsumeNavBar, int displayId) {
                 Message msg = mCaller.obtainMessageIO(MSG_WINDOW_RESIZED,
                         reportDraw ? 1 : 0, outsets);
@@ -568,7 +566,8 @@
                     out.print(mVisibleInsets.toShortString());
                     out.print(" mWinFrame="); out.print(mWinFrame.toShortString());
                     out.print(" mContentInsets="); out.println(mContentInsets.toShortString());
-            out.print(prefix); out.print("mConfiguration="); out.println(mConfiguration);
+            out.print(prefix); out.print("mConfiguration=");
+                    out.println(mMergedConfiguration.getMergedConfiguration());
             out.print(prefix); out.print("mLayout="); out.println(mLayout);
             synchronized (mLock) {
                 out.print(prefix); out.print("mPendingXOffset="); out.print(mPendingXOffset);
@@ -695,7 +694,7 @@
                         mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
                             View.VISIBLE, 0, mWinFrame, mOverscanInsets, mContentInsets,
                             mVisibleInsets, mStableInsets, mOutsets, mBackdropFrame,
-                            mConfiguration, mSurfaceHolder.mSurface);
+                            mMergedConfiguration, mSurfaceHolder.mSurface);
 
                     if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface
                             + ", frame=" + mWinFrame);
diff --git a/core/java/android/text/Emoji.java b/core/java/android/text/Emoji.java
index 83810b0..a07caf4 100644
--- a/core/java/android/text/Emoji.java
+++ b/core/java/android/text/Emoji.java
@@ -132,12 +132,11 @@
         0x1F910, 0x1F911, 0x1F912, 0x1F913, 0x1F914, 0x1F915, 0x1F916, 0x1F917, 0x1F918, 0x1F919,
         0x1F91A, 0x1F91B, 0x1F91C, 0x1F91D, 0x1F91E, 0x1F920, 0x1F921, 0x1F922, 0x1F923, 0x1F924,
         0x1F925, 0x1F926, 0x1F927, 0x1F930, 0x1F933, 0x1F934, 0x1F935, 0x1F936, 0x1F937, 0x1F938,
-        0x1F939, 0x1F93A, 0x1F93B, 0x1F93C, 0x1F93D, 0x1F93E, 0x1F940, 0x1F941, 0x1F942, 0x1F943,
-        0x1F944, 0x1F945, 0x1F946, 0x1F947, 0x1F948, 0x1F949, 0x1F94A, 0x1F94B, 0x1F950, 0x1F951,
-        0x1F952, 0x1F953, 0x1F954, 0x1F955, 0x1F956, 0x1F957, 0x1F958, 0x1F959, 0x1F95A, 0x1F95B,
-        0x1F95C, 0x1F95D, 0x1F95E, 0x1F980, 0x1F981, 0x1F982, 0x1F983, 0x1F984, 0x1F985, 0x1F986,
-        0x1F987, 0x1F988, 0x1F989, 0x1F98A, 0x1F98B, 0x1F98C, 0x1F98D, 0x1F98E, 0x1F98F, 0x1F990,
-        0x1F991, 0x1F9C0
+        0x1F939, 0x1F93A, 0x1F93C, 0x1F93D, 0x1F93E, 0x1F940, 0x1F941, 0x1F942, 0x1F943, 0x1F944,
+        0x1F945, 0x1F947, 0x1F948, 0x1F949, 0x1F94A, 0x1F94B, 0x1F950, 0x1F951, 0x1F952, 0x1F953,
+        0x1F954, 0x1F955, 0x1F956, 0x1F957, 0x1F958, 0x1F959, 0x1F95A, 0x1F95B, 0x1F95C, 0x1F95D,
+        0x1F95E, 0x1F980, 0x1F981, 0x1F982, 0x1F983, 0x1F984, 0x1F985, 0x1F986, 0x1F987, 0x1F988,
+        0x1F989, 0x1F98A, 0x1F98B, 0x1F98C, 0x1F98D, 0x1F98E, 0x1F98F, 0x1F990, 0x1F991, 0x1F9C0
     };
 
     // See http://www.unicode.org/Public/emoji/3.0/emoji-data.txt
@@ -150,7 +149,7 @@
         0x1F596, 0x1F645, 0x1F646, 0x1F647, 0x1F64B, 0x1F64C, 0x1F64D, 0x1F64E, 0x1F64F, 0x1F6A3,
         0x1F6B4, 0x1F6B5, 0x1F6B6, 0x1F6C0, 0x1F918, 0x1F919, 0x1F91A, 0x1F91B, 0x1F91C, 0x1F91D,
         0x1F91E, 0x1F926, 0x1F930, 0x1F933, 0x1F934, 0x1F935, 0x1F936, 0x1F937, 0x1F938, 0x1F939,
-        0x1F93B, 0x1F93C, 0x1F93D, 0x1F93E
+        0x1F93C, 0x1F93D, 0x1F93E
     };
 
     // See http://www.unicode.org/emoji/charts/emoji-zwj-sequences.html
diff --git a/core/java/android/util/LauncherIcons.java b/core/java/android/util/LauncherIcons.java
new file mode 100644
index 0000000..e5aa2b5
--- /dev/null
+++ b/core/java/android/util/LauncherIcons.java
@@ -0,0 +1,113 @@
+/*
+ * 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.util;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.PaintFlagsDrawFilter;
+import android.graphics.Path;
+import android.graphics.RectF;
+import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+
+/**
+ * Utility class to handle icon treatments (e.g., shadow generation) for the Launcher icons.
+ * @hide
+ */
+public final class LauncherIcons {
+
+    private final Paint mPaint = new Paint();
+    private final Canvas mCanvas = new Canvas();
+
+    private static final int KEY_SHADOW_ALPHA = 61;
+    private static final int AMBIENT_SHADOW_ALPHA = 30;
+    private static final float BLUR_FACTOR = 0.5f / 48;
+    private int mShadowInset;
+    private Bitmap mShadowBitmap;
+    private int mIconSize;
+    private Resources mRes;
+
+    public LauncherIcons(Context context) {
+        mRes = context.getResources();
+        DisplayMetrics metrics = mRes.getDisplayMetrics();
+        mShadowInset = (int) metrics.density / DisplayMetrics.DENSITY_DEFAULT;
+        mCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG,
+            Paint.FILTER_BITMAP_FLAG));
+        mIconSize = (int) mRes.getDimensionPixelSize(android.R.dimen.app_icon_size);
+    }
+
+    /**
+     * Draw the drawable into a bitmap.
+     */
+    public Bitmap createIconBitmap(Drawable icon) {
+        final Bitmap bitmap = Bitmap.createBitmap(mIconSize, mIconSize, Bitmap.Config.ARGB_8888);
+        mPaint.setAlpha(255);
+        mCanvas.setBitmap(bitmap);
+        int iconInset = 0;
+        if (mShadowBitmap != null) {
+            mCanvas.drawBitmap(mShadowBitmap, 0, 0, mPaint);
+            iconInset = mShadowInset;
+        }
+
+        icon.setBounds(iconInset, iconInset, mIconSize - iconInset,
+            mIconSize - iconInset);
+        icon.draw(mCanvas);
+        mCanvas.setBitmap(null);
+        return bitmap;
+    }
+
+    public Drawable wrapIconDrawableWithShadow(Drawable drawable) {
+        if (!(drawable instanceof AdaptiveIconDrawable)) {
+            return drawable;
+        }
+        AdaptiveIconDrawable d =
+            (AdaptiveIconDrawable) drawable.getConstantState().newDrawable().mutate();
+        getShadowBitmap(d);
+        Bitmap iconbitmap = createIconBitmap(d);
+        return new BitmapDrawable(mRes, iconbitmap);
+    }
+
+    private Bitmap getShadowBitmap(AdaptiveIconDrawable d) {
+        if (mShadowBitmap != null) {
+            return mShadowBitmap;
+        }
+
+        int shadowSize = mIconSize - mShadowInset;
+        mShadowBitmap = Bitmap.createBitmap(mIconSize, mIconSize, Bitmap.Config.ALPHA_8);
+        mCanvas.setBitmap(mShadowBitmap);
+
+        // Draw key shadow
+        mPaint.setColor(Color.TRANSPARENT);
+        float blur = BLUR_FACTOR * mIconSize;
+        mPaint.setShadowLayer(blur, 0, mShadowInset, KEY_SHADOW_ALPHA << 24);
+        d.setBounds(mShadowInset, mShadowInset, mIconSize - mShadowInset, mIconSize - mShadowInset);
+        mCanvas.drawPath(d.getIconMask(), mPaint);
+
+        // Draw ambient shadow
+        mPaint.setShadowLayer(blur, 0, 0, AMBIENT_SHADOW_ALPHA << 24);
+        d.setBounds(mShadowInset, 2 * mShadowInset, mIconSize - mShadowInset, mIconSize);
+        mCanvas.drawPath(d.getIconMask(), mPaint);
+        mPaint.clearShadowLayer();
+
+        return mShadowBitmap;
+    }
+}
diff --git a/core/java/android/util/MergedConfiguration.aidl b/core/java/android/util/MergedConfiguration.aidl
new file mode 100644
index 0000000..c24dbbe
--- /dev/null
+++ b/core/java/android/util/MergedConfiguration.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.util;
+
+parcelable MergedConfiguration;
\ No newline at end of file
diff --git a/core/java/android/util/MergedConfiguration.java b/core/java/android/util/MergedConfiguration.java
new file mode 100644
index 0000000..d94af8a
--- /dev/null
+++ b/core/java/android/util/MergedConfiguration.java
@@ -0,0 +1,122 @@
+/*
+ * 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.util;
+
+import android.annotation.NonNull;
+import android.content.res.Configuration;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Container that holds global and override config and their merge product.
+ * Merged configuration updates automatically whenever global or override configs are updated via
+ * setters.
+ *
+ * {@hide}
+ */
+public class MergedConfiguration implements Parcelable {
+
+    private Configuration mGlobalConfig = new Configuration();
+    private Configuration mOverrideConfig = new Configuration();
+    private Configuration mMergedConfig = new Configuration();
+
+    public MergedConfiguration() {
+    }
+
+    public MergedConfiguration(Configuration globalConfig, Configuration overrideConfig) {
+        setConfiguration(globalConfig, overrideConfig);
+    }
+
+    public MergedConfiguration(MergedConfiguration mergedConfiguration) {
+        setConfiguration(mergedConfiguration.getGlobalConfiguration(),
+                mergedConfiguration.getOverrideConfiguration());
+    }
+
+    private MergedConfiguration(Parcel in) {
+        readFromParcel(in);
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeParcelable(mGlobalConfig, flags);
+        dest.writeParcelable(mOverrideConfig, flags);
+        dest.writeParcelable(mMergedConfig, flags);
+    }
+
+    public void readFromParcel(Parcel source) {
+        mGlobalConfig = source.readParcelable(Configuration.class.getClassLoader());
+        mOverrideConfig = source.readParcelable(Configuration.class.getClassLoader());
+        mMergedConfig = source.readParcelable(Configuration.class.getClassLoader());
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final Creator<MergedConfiguration> CREATOR = new Creator<MergedConfiguration>() {
+        @Override
+        public MergedConfiguration createFromParcel(Parcel in) {
+            return new MergedConfiguration(in);
+        }
+
+        @Override
+        public MergedConfiguration[] newArray(int size) {
+            return new MergedConfiguration[size];
+        }
+    };
+
+    /**
+     * Update global and override configurations.
+     * Merged configuration will automatically be updated.
+     * @param globalConfig New global configuration.
+     * @param overrideConfig New override configuration.
+     */
+    public void setConfiguration(Configuration globalConfig, Configuration overrideConfig) {
+        mGlobalConfig.setTo(globalConfig);
+        mOverrideConfig.setTo(overrideConfig);
+        updateMergedConfig();
+    }
+
+    /**
+     * @return Stored global configuration value.
+     */
+    @NonNull
+    public Configuration getGlobalConfiguration() {
+        return mGlobalConfig;
+    }
+
+    /**
+     * @return Stored override configuration value.
+     */
+    public Configuration getOverrideConfiguration() {
+        return mOverrideConfig;
+    }
+
+    /**
+     * @return Stored merged configuration value.
+     */
+    public Configuration getMergedConfiguration() {
+        return mMergedConfig;
+    }
+
+    /** Update merged config when global or override config changes. */
+    private void updateMergedConfig() {
+        mMergedConfig.setTo(mGlobalConfig);
+        mMergedConfig.updateFrom(mOverrideConfig);
+    }
+}
diff --git a/core/java/android/view/AccessibilityIterators.java b/core/java/android/view/AccessibilityIterators.java
index e59937d..ca54bef 100644
--- a/core/java/android/view/AccessibilityIterators.java
+++ b/core/java/android/view/AccessibilityIterators.java
@@ -16,7 +16,6 @@
 
 package android.view;
 
-import android.content.ComponentCallbacks;
 import android.content.res.Configuration;
 
 import java.text.BreakIterator;
@@ -65,7 +64,7 @@
     }
 
     static class CharacterTextSegmentIterator extends AbstractTextSegmentIterator
-            implements ComponentCallbacks {
+            implements ViewRootImpl.ConfigChangedCallback {
         private static CharacterTextSegmentIterator sInstance;
 
         private Locale mLocale;
@@ -144,19 +143,14 @@
         }
 
         @Override
-        public void onConfigurationChanged(Configuration newConfig) {
-            Locale locale = newConfig.locale;
+        public void onConfigurationChanged(Configuration globalConfig) {
+            final Locale locale = globalConfig.getLocales().get(0);
             if (!mLocale.equals(locale)) {
                 mLocale = locale;
                 onLocaleChanged(locale);
             }
         }
 
-        @Override
-        public void onLowMemory() {
-            /* ignore */
-        }
-
         protected void onLocaleChanged(Locale locale) {
             mImpl = BreakIterator.getCharacterInstance(locale);
         }
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 14b2abe..611cc63 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -17,7 +17,6 @@
 
 package android.view;
 
-import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
@@ -26,6 +25,7 @@
 import android.view.MotionEvent;
 
 import com.android.internal.os.IResultReceiver;
+import android.util.MergedConfiguration;
 
 /**
  * API back to a client window that the Window Manager uses to inform it of
@@ -49,8 +49,8 @@
 
     void resized(in Rect frame, in Rect overscanInsets, in Rect contentInsets,
             in Rect visibleInsets, in Rect stableInsets, in Rect outsets, boolean reportDraw,
-            in Configuration newConfig, in Rect backDropFrame, boolean forceLayout,
-            boolean alwaysConsumeNavBar, int displayId);
+            in MergedConfiguration newMergedConfiguration, in Rect backDropFrame,
+            boolean forceLayout, boolean alwaysConsumeNavBar, int displayId);
     void moved(int newX, int newY);
     void dispatchAppVisibility(boolean visible);
     void dispatchGetNewSurface();
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 1facc10..51d6514 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -11,17 +11,17 @@
 ** 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 
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
 package android.view;
 
 import android.content.ClipData;
-import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.os.Bundle;
+import android.util.MergedConfiguration;
 import android.view.InputChannel;
 import android.view.IWindow;
 import android.view.IWindowId;
@@ -83,9 +83,9 @@
      * treat as real display. Example of such area is a chin in some models of wearable devices.
      * @param outBackdropFrame Rect which is used draw the resizing background during a resize
      * operation.
-     * @param outConfiguration New configuration of window, if it is now
-     * becoming visible and the global configuration has changed since it
-     * was last displayed.
+     * @param outMergedConfiguration New config container that holds global, override and merged
+     * config for window, if it is now becoming visible and the merged configuration has changed
+     * since it was last displayed.
      * @param outSurface Object in which is placed the new display surface.
      *
      * @return int Result flags: {@link WindowManagerGlobal#RELAYOUT_SHOW_FOCUS},
@@ -95,33 +95,8 @@
             int requestedWidth, int requestedHeight, int viewVisibility,
             int flags, out Rect outFrame, out Rect outOverscanInsets,
             out Rect outContentInsets, out Rect outVisibleInsets, out Rect outStableInsets,
-            out Rect outOutsets, out Rect outBackdropFrame, out Configuration outConfig,
-            out Surface outSurface);
-
-    /**
-     *  Position a window relative to it's parent (attached) window without triggering
-     *  a full relayout. This action may be deferred until a given frame number
-     *  for the parent window appears. This allows for synchronizing movement of a child
-     *  to repainting the contents of the parent.
-     *
-     *  "width" and "height" correspond to the width and height members of
-     *  WindowManager.LayoutParams in the {@link #relayout relayout()} case.
-     *  This may differ from the surface buffer size in the
-     *  case of {@link LayoutParams#FLAG_SCALED} and {@link #relayout relayout()}
-     *  must be used with requestedWidth/height if this must be changed.
-     *
-     *  @param window The window being modified. Must be attached to a parent window
-     *  or this call will fail.
-     *  @param left The new left position
-     *  @param top The new top position
-     *  @param right The new right position
-     *  @param bottom The new bottom position
-     *  @param deferTransactionUntilFrame Frame number from our parent (attached) to
-     *  defer this action until.
-     *  @param outFrame Rect in which is placed the new position/size on screen.
-     */
-    void repositionChild(IWindow childWindow, int left, int top, int right, int bottom,
-            long deferTransactionUntilFrame, out Rect outFrame);
+            out Rect outOutsets, out Rect outBackdropFrame,
+            out MergedConfiguration outMergedConfiguration, out Surface outSurface);
 
     /*
      * Notify the window manager that an application is relaunching and
@@ -134,12 +109,6 @@
     void prepareToReplaceWindows(IBinder appToken, boolean childrenOnly);
 
     /**
-     * If a call to relayout() asked to have the surface destroy deferred,
-     * it must call this once it is okay to destroy that surface.
-     */
-    void performDeferredDestroy(IWindow window);
-
-    /**
      * Called by a client to report that it ran out of graphics memory.
      */
     boolean outOfMemory(IWindow window);
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 6d320ef..824e035 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -16,8 +16,9 @@
 
 package android.view;
 
-import static android.view.WindowManagerPolicy.APPLICATION_MEDIA_SUBLAYER;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
 import static android.view.WindowManagerPolicy.APPLICATION_MEDIA_OVERLAY_SUBLAYER;
+import static android.view.WindowManagerPolicy.APPLICATION_MEDIA_SUBLAYER;
 import static android.view.WindowManagerPolicy.APPLICATION_PANEL_SUBLAYER;
 
 import android.content.Context;
@@ -28,6 +29,7 @@
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.Region;
+import android.os.Build;
 import android.os.Handler;
 import android.os.Message;
 import android.os.SystemClock;
@@ -777,6 +779,31 @@
     }
 
     /**
+     * This method still exists only for compatibility reasons because some applications have relied
+     * on this method via reflection. See Issue 36345857 for details.
+     *
+     * @deprecated No platform code is using this method anymore.
+     * @hide
+     */
+    @Deprecated
+    public void setWindowType(int type) {
+        if (getContext().getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.N_MR1) {
+            throw new UnsupportedOperationException(
+                    "SurfaceView#setWindowType() has never been a public API.");
+        }
+
+        if (type == TYPE_APPLICATION_PANEL) {
+            Log.e(TAG, "If you are calling SurfaceView#setWindowType(TYPE_APPLICATION_PANEL) "
+                    + "just to make the SurfaceView to be placed on top of its window, you must "
+                    + "call setZOrderOnTop(true) instead.", new Throwable());
+            setZOrderOnTop(true);
+            return;
+        }
+        Log.e(TAG, "SurfaceView#setWindowType(int) is deprecated and now does nothing. "
+                + "type=" + type, new Throwable());
+    }
+
+    /**
      * Check to see if the surface has fixed size dimensions or if the surface's
      * dimensions are dimensions are dependent on its current layout.
      *
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 80f6c32..583dad4 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2749,13 +2749,8 @@
      *                 x                 * NO LONGER NEEDED, SHOULD BE REUSED *
      *                1                  PFLAG3_FINGER_DOWN
      *               1                   PFLAG3_FOCUSED_BY_DEFAULT
-<<<<<<< HEAD
      *             11                    PFLAG3_AUTO_FILL_MODE_MASK
      *           11                      PFLAG3_IMPORTANT_FOR_AUTOFILL
-=======
-     *             11                    PFLAG3_AUTOFILL_MODE_MASK
-     *           xx                      * NO LONGER NEEDED, SHOULD BE REUSED *
->>>>>>> Replaced auto-fill by autofill to keep it consistent with API style.
      *          1                        PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE
      *         1                         PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED
      *        1                          PFLAG3_TEMPORARY_DETACH
@@ -7384,13 +7379,13 @@
      * <p>When implementing this method, subclasses must follow the rules below:
      *
      * <ol>
-     * <li>Also implement {@link #autofillVirtual(int, AutofillValue)} to autofill the virtual
+     * <li>Also implement {@link #autofill(int, AutofillValue)} to autofill the virtual
      * children.
      * <li>Call
-     * {@link android.view.autofill.AutofillManager#notifyVirtualViewEntered} and
-     * {@link android.view.autofill.AutofillManager#notifyVirtualViewExited(View, int)}
+     * {@link android.view.autofill.AutofillManager#notifyViewEntered} and
+     * {@link android.view.autofill.AutofillManager#notifyViewExited(View, int)}
      * when the focus inside the view changed.
-     * <li>Call {@link android.view.autofill.AutofillManager#notifyVirtualValueChanged(View, int,
+     * <li>Call {@link android.view.autofill.AutofillManager#notifyValueChanged(View, int,
      * AutofillValue)} when the value of a child changed.
      * <li>Call {@link AutofillManager#commit()} when the autofill context
      * of the view structure changed and you want the current autofill interaction if such
@@ -7445,8 +7440,11 @@
      * </pre>
      *
      * @param value value to be autofilled.
+     *
+     * @return {@code true} if the view was successfully autofilled, {@code false} otherwise
      */
-    public void autofill(@SuppressWarnings("unused") AutofillValue value) {
+    public boolean autofill(@SuppressWarnings("unused") AutofillValue value) {
+        return false;
     }
 
     /**
@@ -7457,14 +7455,17 @@
      *
      * @param value value to be autofilled.
      * @param virtualId id identifying the virtual child inside the custom view.
+     *
+     * @return {@code true} if the view was successfully autofilled, {@code false} otherwise
      */
-    public void autofillVirtual(@SuppressWarnings("unused") int virtualId,
+    public boolean autofill(@SuppressWarnings("unused") int virtualId,
             @SuppressWarnings("unused") AutofillValue value) {
+        return false;
     }
 
     /**
      * Describes the autofill type that should be used on calls to
-     * {@link #autofill(AutofillValue)} and {@link #autofillVirtual(int, AutofillValue)}.
+     * {@link #autofill(AutofillValue)} and {@link #autofill(int, AutofillValue)}.
      *
      * <p>By default returns {@link #AUTOFILL_TYPE_NONE}, but views should override it (and
      * {@link #autofill(AutofillValue)} to support the Autofill Framework.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index ed42385..1681787 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import static android.view.Display.INVALID_DISPLAY;
 import static android.view.View.PFLAG_DRAW_ANIMATION;
 import static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER;
 import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM;
@@ -28,10 +29,10 @@
 import android.animation.LayoutTransition;
 import android.annotation.NonNull;
 import android.app.ActivityManager;
+import android.app.ActivityThread;
 import android.app.ResourcesManager;
 import android.content.ClipData;
 import android.content.ClipDescription;
-import android.content.ComponentCallbacks;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.res.CompatibilityInfo;
@@ -67,6 +68,7 @@
 import android.util.AndroidRuntimeException;
 import android.util.DisplayMetrics;
 import android.util.Log;
+import android.util.MergedConfiguration;
 import android.util.Slog;
 import android.util.TimeUtils;
 import android.util.TypedValue;
@@ -161,7 +163,44 @@
     static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList();
     static boolean sFirstDrawComplete = false;
 
-    static final ArrayList<ComponentCallbacks> sConfigCallbacks = new ArrayList();
+    /**
+     * Callback for notifying about global configuration changes.
+     */
+    public interface ConfigChangedCallback {
+
+        /** Notifies about global config change. */
+        void onConfigurationChanged(Configuration globalConfig);
+    }
+
+    private static final ArrayList<ConfigChangedCallback> sConfigCallbacks = new ArrayList<>();
+
+    /**
+     * Callback for notifying activities about override configuration changes.
+     */
+    public interface ActivityConfigCallback {
+
+        /**
+         * Notifies about override config change and/or move to different display.
+         * @param overrideConfig New override config to apply to activity.
+         * @param newDisplayId New display id, {@link Display#INVALID_DISPLAY} if not changed.
+         */
+        void onConfigurationChanged(Configuration overrideConfig, int newDisplayId);
+    }
+
+    /**
+     * Callback used to notify corresponding activity about override configuration change and make
+     * sure that all resources are set correctly before updating the ViewRootImpl's internal state.
+     */
+    private ActivityConfigCallback mActivityConfigCallback;
+
+    /**
+     * Used when configuration change first updates the config of corresponding activity.
+     * In that case we receive a call back from {@link ActivityThread} and this flag is used to
+     * preserve the initial value.
+     *
+     * @see #performConfigurationChange(Configuration, Configuration, boolean, int)
+     */
+    private boolean mForceNextConfigUpdate;
 
     /**
      * Signals that compatibility booleans have been initialized according to
@@ -344,8 +383,12 @@
 
     private WindowInsets mLastWindowInsets;
 
-    final Configuration mLastConfiguration = new Configuration();
-    final Configuration mPendingConfiguration = new Configuration();
+    /** Last applied configuration obtained from resources. */
+    private final Configuration mLastConfigurationFromResources = new Configuration();
+    /** Last configuration reported from WM or via {@link #MSG_UPDATE_CONFIGURATION}. */
+    private final MergedConfiguration mLastReportedMergedConfiguration = new MergedConfiguration();
+    /** Configurations waiting to be applied. */
+    private final MergedConfiguration mPendingMergedConfiguration = new MergedConfiguration();
 
     boolean mScrollMayChange;
     @SoftInputModeFlags
@@ -464,7 +507,7 @@
         mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
 
         if (!sCompatibilityDone) {
-            sAlwaysAssignFocus = mTargetSdkVersion < Build.VERSION_CODES.O;
+            sAlwaysAssignFocus = true;
 
             sCompatibilityDone = true;
         }
@@ -480,12 +523,18 @@
         }
     }
 
-    public static void addConfigCallback(ComponentCallbacks callback) {
+    /** Add static config callback to be notified about global config changes. */
+    public static void addConfigCallback(ConfigChangedCallback callback) {
         synchronized (sConfigCallbacks) {
             sConfigCallbacks.add(callback);
         }
     }
 
+    /** Add activity config callback to be notified about override config changes. */
+    public void setActivityConfigCallback(ActivityConfigCallback callback) {
+        mActivityConfigCallback = callback;
+    }
+
     public void addWindowCallbacks(WindowCallbacks callback) {
         if (USE_MT_RENDERER) {
             synchronized (mWindowCallbacks) {
@@ -1558,6 +1607,7 @@
             mFullRedrawNeeded = true;
             mLayoutRequested = true;
 
+            final Configuration config = mContext.getResources().getConfiguration();
             if (shouldUseDisplaySize(lp)) {
                 // NOTE -- system code, won't try to do compat mode.
                 Point size = new Point();
@@ -1565,7 +1615,6 @@
                 desiredWindowWidth = size.x;
                 desiredWindowHeight = size.y;
             } else {
-                Configuration config = mContext.getResources().getConfiguration();
                 desiredWindowWidth = dipToPx(config.screenWidthDp);
                 desiredWindowHeight = dipToPx(config.screenHeightDp);
             }
@@ -1577,11 +1626,11 @@
             mAttachInfo.mHasWindowFocus = false;
             mAttachInfo.mWindowVisibility = viewVisibility;
             mAttachInfo.mRecomputeGlobalAttributes = false;
-            mLastConfiguration.setTo(host.getResources().getConfiguration());
+            mLastConfigurationFromResources.setTo(config);
             mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
             // Set the layout direction if it has not been set before (inherit is the default)
             if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
-                host.setLayoutDirection(mLastConfiguration.getLayoutDirection());
+                host.setLayoutDirection(config.getLayoutDirection());
             }
             host.dispatchAttachedToWindow(mAttachInfo, 0);
             mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
@@ -1826,11 +1875,14 @@
                         + " outsets=" + mPendingOutsets.toShortString()
                         + " surface=" + mSurface);
 
-                if (mPendingConfiguration.seq != 0) {
+                final Configuration pendingMergedConfig =
+                        mPendingMergedConfiguration.getMergedConfiguration();
+                if (pendingMergedConfig.seq != 0) {
                     if (DEBUG_CONFIGURATION) Log.v(mTag, "Visible with new config: "
-                            + mPendingConfiguration);
-                    updateConfiguration(new Configuration(mPendingConfiguration), !mFirst);
-                    mPendingConfiguration.seq = 0;
+                            + pendingMergedConfig);
+                    performConfigurationChange(mPendingMergedConfiguration, !mFirst,
+                            INVALID_DISPLAY /* same display */);
+                    pendingMergedConfig.seq = 0;
                     updatedConfiguration = true;
                 }
 
@@ -3388,43 +3440,82 @@
         unscheduleTraversals();
     }
 
-    void updateConfiguration(Configuration config, boolean force) {
-        if (DEBUG_CONFIGURATION) Log.v(mTag,
-                "Applying new config to window "
-                + mWindowAttributes.getTitle()
-                + ": " + config);
+    /**
+     * Notifies all callbacks that configuration and/or display has changed and updates internal
+     * state.
+     * @param mergedConfiguration New global and override config in {@link MergedConfiguration}
+     *                            container.
+     * @param force Flag indicating if we should force apply the config.
+     * @param newDisplayId Id of new display if moved, {@link Display#INVALID_DISPLAY} if not
+     *                     changed.
+     */
+    private void performConfigurationChange(MergedConfiguration mergedConfiguration, boolean force,
+            int newDisplayId) {
+        if (mergedConfiguration == null) {
+            throw new IllegalArgumentException("No merged config provided.");
+        }
 
-        CompatibilityInfo ci = mDisplay.getDisplayAdjustments().getCompatibilityInfo();
+        Configuration globalConfig = mergedConfiguration.getGlobalConfiguration();
+        final Configuration overrideConfig = mergedConfiguration.getOverrideConfiguration();
+        if (DEBUG_CONFIGURATION) Log.v(mTag,
+                "Applying new config to window " + mWindowAttributes.getTitle()
+                        + ", globalConfig: " + globalConfig
+                        + ", overrideConfig: " + overrideConfig);
+
+        final CompatibilityInfo ci = mDisplay.getDisplayAdjustments().getCompatibilityInfo();
         if (!ci.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) {
-            config = new Configuration(config);
-            ci.applyToConfiguration(mNoncompatDensity, config);
+            globalConfig = new Configuration(globalConfig);
+            ci.applyToConfiguration(mNoncompatDensity, globalConfig);
         }
 
         synchronized (sConfigCallbacks) {
             for (int i=sConfigCallbacks.size()-1; i>=0; i--) {
-                sConfigCallbacks.get(i).onConfigurationChanged(config);
+                sConfigCallbacks.get(i).onConfigurationChanged(globalConfig);
             }
         }
-        if (mView != null) {
-            // At this point the resources have been updated to
-            // have the most recent config, whatever that is.  Use
-            // the one in them which may be newer.
-            final Resources localResources = mView.getResources();
-            config = localResources.getConfiguration();
-            if (force || mLastConfiguration.diff(config) != 0) {
-                // Update the display with new DisplayAdjustments.
-                mDisplay = ResourcesManager.getInstance().getAdjustedDisplay(
-                        mDisplay.getDisplayId(), localResources);
 
-                final int lastLayoutDirection = mLastConfiguration.getLayoutDirection();
-                final int currentLayoutDirection = config.getLayoutDirection();
-                mLastConfiguration.setTo(config);
-                if (lastLayoutDirection != currentLayoutDirection &&
-                        mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
-                    mView.setLayoutDirection(currentLayoutDirection);
-                }
-                mView.dispatchConfigurationChanged(config);
+        mLastReportedMergedConfiguration.setConfiguration(globalConfig, overrideConfig);
+
+        mForceNextConfigUpdate = force;
+        if (mActivityConfigCallback != null) {
+            // An activity callback is set - notify it about override configuration update.
+            // This basically initiates a round trip to ActivityThread and back, which will ensure
+            // that corresponding activity and resources are updated before updating inner state of
+            // ViewRootImpl. Eventually it will call #updateConfiguration().
+            mActivityConfigCallback.onConfigurationChanged(overrideConfig, newDisplayId);
+        } else {
+            // There is no activity callback - update the configuration right away.
+            updateConfiguration();
+        }
+        mForceNextConfigUpdate = false;
+    }
+
+    /**
+     * Update display and views if last applied merged configuration changed.
+     */
+    public void updateConfiguration() {
+        if (mView == null) {
+            return;
+        }
+
+        // At this point the resources have been updated to
+        // have the most recent config, whatever that is.  Use
+        // the one in them which may be newer.
+        final Resources localResources = mView.getResources();
+        final Configuration config = localResources.getConfiguration();
+        if (mForceNextConfigUpdate || mLastConfigurationFromResources.diff(config) != 0) {
+            // Update the display with new DisplayAdjustments.
+            mDisplay = ResourcesManager.getInstance().getAdjustedDisplay(
+                    mDisplay.getDisplayId(), localResources);
+
+            final int lastLayoutDirection = mLastConfigurationFromResources.getLayoutDirection();
+            final int currentLayoutDirection = config.getLayoutDirection();
+            mLastConfigurationFromResources.setTo(config);
+            if (lastLayoutDirection != currentLayoutDirection
+                    && mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
+                mView.setLayoutDirection(currentLayoutDirection);
             }
+            mView.dispatchConfigurationChanged(config);
         }
     }
 
@@ -3582,13 +3673,16 @@
                 if (mAdded) {
                     SomeArgs args = (SomeArgs) msg.obj;
 
-                    if (mDisplay.getDisplayId() != args.argi3) {
-                        onMovedToDisplay(args.argi3);
+                    final int displayId = args.argi3;
+                    final boolean displayChanged = mDisplay.getDisplayId() != displayId;
+                    if (displayChanged) {
+                        onMovedToDisplay(displayId);
                     }
 
-                    Configuration config = (Configuration) args.arg4;
-                    if (config != null) {
-                        updateConfiguration(config, false);
+                    final MergedConfiguration mergedConfiguration = (MergedConfiguration) args.arg4;
+                    if (mergedConfiguration != null) {
+                        performConfigurationChange(mergedConfiguration, false /* force */,
+                                displayChanged ? displayId : INVALID_DISPLAY /* same display */);
                     }
 
                     final boolean framesChanged = !mWinFrame.equals(args.arg1)
@@ -3759,11 +3853,19 @@
                 handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo) msg.obj);
             } break;
             case MSG_UPDATE_CONFIGURATION: {
-                Configuration config = (Configuration)msg.obj;
-                if (config.isOtherSeqNewer(mLastConfiguration)) {
-                    config = mLastConfiguration;
+                Configuration config = (Configuration) msg.obj;
+                if (config.isOtherSeqNewer(
+                        mLastReportedMergedConfiguration.getMergedConfiguration())) {
+                    // If we already have a newer merged config applied - use its global part.
+                    config = mLastReportedMergedConfiguration.getGlobalConfiguration();
                 }
-                updateConfiguration(config, false);
+
+                // Use the newer global config and last reported override config.
+                mPendingMergedConfiguration.setConfiguration(config,
+                        mLastReportedMergedConfiguration.getOverrideConfiguration());
+
+                performConfigurationChange(mPendingMergedConfiguration, false /* force */,
+                        INVALID_DISPLAY /* same display */);
             } break;
             case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
                 setAccessibilityFocus(null, null);
@@ -5902,7 +6004,7 @@
         if (params != null) {
             if (DBG) Log.d(mTag, "WindowLayout in layoutWindow:" + params);
         }
-        mPendingConfiguration.seq = 0;
+        mPendingMergedConfiguration.getMergedConfiguration().seq = 0;
         //Log.d(mTag, ">>>>>> CALLING relayout");
         if (params != null && mOrigWindowType != params.type) {
             // For compatibility with old apps, don't crash here.
@@ -5918,8 +6020,8 @@
                 (int) (mView.getMeasuredHeight() * appScale + 0.5f),
                 viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
                 mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
-                mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingConfiguration,
-                mSurface);
+                mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame,
+                mPendingMergedConfiguration, mSurface);
 
         mPendingAlwaysConsumeNavBar =
                 (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_NAV_BAR) != 0;
@@ -6199,9 +6301,9 @@
         }
     }
 
-    public void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
+    private void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
             Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
-            Configuration newConfig, Rect backDropFrame, boolean forceLayout,
+            MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
             boolean alwaysConsumeNavBar, int displayId) {
         if (DEBUG_LAYOUT) Log.v(mTag, "Resizing " + this + ": frame=" + frame.toShortString()
                 + " contentInsets=" + contentInsets.toShortString()
@@ -6233,7 +6335,8 @@
         args.arg1 = sameProcessCall ? new Rect(frame) : frame;
         args.arg2 = sameProcessCall ? new Rect(contentInsets) : contentInsets;
         args.arg3 = sameProcessCall ? new Rect(visibleInsets) : visibleInsets;
-        args.arg4 = sameProcessCall && newConfig != null ? new Configuration(newConfig) : newConfig;
+        args.arg4 = sameProcessCall && mergedConfiguration != null
+                ? new MergedConfiguration(mergedConfiguration) : null;
         args.arg5 = sameProcessCall ? new Rect(overscanInsets) : overscanInsets;
         args.arg6 = sameProcessCall ? new Rect(stableInsets) : stableInsets;
         args.arg7 = sameProcessCall ? new Rect(outsets) : outsets;
@@ -7243,13 +7346,13 @@
         @Override
         public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
                 Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
-                Configuration newConfig, Rect backDropFrame, boolean forceLayout,
+                MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
                 boolean alwaysConsumeNavBar, int displayId) {
             final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
                 viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
-                        visibleInsets, stableInsets, outsets, reportDraw, newConfig, backDropFrame,
-                        forceLayout, alwaysConsumeNavBar, displayId);
+                        visibleInsets, stableInsets, outsets, reportDraw, mergedConfiguration,
+                        backDropFrame, forceLayout, alwaysConsumeNavBar, displayId);
             }
         }
 
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index a71b899..4168756 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -275,13 +275,12 @@
      *            {@link #addChildCount(int)} and {@link #setChildCount(int)}.
      * @param virtualId an opaque ID to the Android System (although it could be meaningful to the
      *            {@link View} creating the {@link ViewStructure}), but it's the same id used on
-     *            {@link View#autofillVirtual(int, AutofillValue)}.
+     *            {@link View#autofill(int, AutofillValue)}.
      * @param flags currently {@code 0}.
      *
      * @return Returns an fresh {@link ViewStructure} ready to be filled in.
      */
-    // TODO(b/33197203, b/33802548): add CTS/unit test
-    public abstract ViewStructure newChildForAutofill(int index, int virtualId, int flags);
+    public abstract ViewStructure newChild(int index, int virtualId, int flags);
 
     /**
      * Like {@link #newChild}, but allows the caller to asynchronously populate the returned
@@ -294,7 +293,7 @@
     public abstract ViewStructure asyncNewChild(int index);
 
     /**
-     * Like {@link #newChildForAutofill(int, int, int)}, but allows the caller to asynchronously
+     * Like {@link #newChild(int, int, int)}, but allows the caller to asynchronously
      * populate the returned child.
      *
      * <p>It can transfer the returned {@link ViewStructure} to another thread for it to build its
@@ -307,13 +306,12 @@
      *            {@link #addChildCount(int)} and {@link #setChildCount(int)}.
      * @param virtualId an opaque ID to the Android System (although it could be meaningful to the
      *            {@link View} creating the {@link ViewStructure}), but it's the same id used on
-     *            {@link View#autofillVirtual(int, AutofillValue)}.
+     *            {@link View#autofill(int, AutofillValue)}.
      * @param flags currently {@code 0}.
      *
      * @return Returns an fresh {@link ViewStructure} ready to be filled in.
      */
-    // TODO(b/33197203, b/33802548): add CTS/unit test
-    public abstract ViewStructure asyncNewChildForAutofill(int index, int virtualId, int flags);
+    public abstract ViewStructure asyncNewChild(int index, int virtualId, int flags);
 
     /**
      * Sets the {@link View#getAutofillType()} that can be used to autofill this node.
@@ -350,7 +348,7 @@
      * Sets whether the data on this node is sensitive; if it is, then its content (text, autofill
      * value, etc..) is striped before calls to {@link
      * android.service.autofill.AutofillService#onFillRequest(android.app.assist.AssistStructure,
-     * Bundle, android.os.CancellationSignal, android.service.autofill.FillCallback)}.
+     * Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback)}.
      *
      * <p>By default, all nodes are assumed to be sensitive, and only nodes that does not have PII
      * (Personally Identifiable Information - sensitive data such as email addresses, credit card
@@ -360,8 +358,8 @@
      * <p>Notice that the content of even sensitive nodes are sent to the service (through the
      * {@link
      * android.service.autofill.AutofillService#onSaveRequest(android.app.assist.AssistStructure,
-     * Bundle, android.service.autofill.SaveCallback)} call) when the user consented to save the
-     * data, so it is important to set the content of sensitive nodes as well, but mark them as
+     * Bundle, android.service.autofill.SaveCallback)} call) when the user consented to save
+     * thedata, so it is important to set the content of sensitive nodes as well, but mark them as
      * sensitive.
      *
      * <p>Should only be set when the node is used for autofill purposes - it will be ignored
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index c4f90dc..9ed6371 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -71,12 +71,19 @@
     public static final String EXTRA_AUTHENTICATION_RESULT =
             "android.view.autofill.extra.AUTHENTICATION_RESULT";
 
-    /** @hide */ public static final int FLAG_START_SESSION = 0x1;
-    /** @hide */ public static final int FLAG_VIEW_ENTERED = 0x2;
-    /** @hide */ public static final int FLAG_VIEW_EXITED = 0x4;
-    /** @hide */ public static final int FLAG_VALUE_CHANGED = 0x8;
+    // Public flags start from the lowest bit
+    /**
+     * Indicates autofill was explicitly requested by the user.
+     */
+    public static final int FLAG_MANUAL_REQUEST = 0x1;
 
-    private final Rect mTempRect = new Rect();
+    // Private flags start from the highest bit
+    /** @hide */ public static final int FLAG_START_SESSION = 0x80000000;
+    /** @hide */ public static final int FLAG_VIEW_ENTERED =  0x40000000;
+    /** @hide */ public static final int FLAG_VIEW_EXITED =   0x20000000;
+    /** @hide */ public static final int FLAG_VALUE_CHANGED = 0x10000000;
+
+    @NonNull private final Rect mTempRect = new Rect();
 
     private final IAutoFillManager mService;
     private IAutoFillManagerClient mServiceClient;
@@ -121,11 +128,28 @@
     }
 
     /**
-     * Called when a {@link View} that supports autofill is entered.
+     * Checkes whether autofill is enabled for the current user.
      *
-     * @param view {@link View} that was entered.
+     * <p>Typically used to determine whether the option to explicitly request autofill should
+     * be offered - see {@link #requestAutofill(View)}.
+     *
+     * @return whether autofill is enabled for the current user.
      */
-    public void notifyViewEntered(@NonNull View view) {
+    public boolean isEnabled() {
+        ensureServiceClientAddedIfNeeded();
+        return mEnabled;
+    }
+
+    /**
+     * Explicitly requests a new autofill context.
+     *
+     * <p>Normally, the autofill context is automatically started when autofillable views are
+     * focused, but this method should be used in the cases where it must be explicitly requested,
+     * like a view that provides a contextual menu allowing users to autofill the activity.
+     *
+     * @param view view requesting the new autofill context.
+     */
+    public void requestAutofill(@NonNull View view) {
         ensureServiceClientAddedIfNeeded();
 
         if (!mEnabled) {
@@ -137,9 +161,55 @@
         final AutofillId id = getAutofillId(view);
         final AutofillValue value = view.getAutofillValue();
 
+        startSession(id, view.getWindowToken(), bounds, value, FLAG_MANUAL_REQUEST);
+    }
+
+    /**
+     * Explicitly requests a new autofill context for virtual views.
+     *
+     * <p>Normally, the autofill context is automatically started when autofillable views are
+     * focused, but this method should be used in the cases where it must be explicitly requested,
+     * like a virtual view that provides a contextual menu allowing users to autofill the activity.
+     *
+     * @param view the {@link View} whose descendant is the virtual view.
+     * @param childId id identifying the virtual child inside the view.
+     * @param bounds child boundaries, relative to the top window.
+     */
+    public void requestAutofill(@NonNull View view, int childId, @NonNull Rect bounds) {
+        ensureServiceClientAddedIfNeeded();
+
+        if (!mEnabled) {
+            return;
+        }
+
+        final AutofillId id = getAutofillId(view, childId);
+        startSession(id, view.getWindowToken(), bounds, null, FLAG_MANUAL_REQUEST);
+    }
+
+
+    /**
+     * Called when a {@link View} that supports autofill is entered.
+     *
+     * @param view {@link View} that was entered.
+     */
+    public void notifyViewEntered(@NonNull View view) {
+        ensureServiceClientAddedIfNeeded();
+
+        if (!mEnabled) {
+            if (mCallback != null) {
+                mCallback.onAutofillEvent(view, AutofillCallback.EVENT_INPUT_UNAVAILABLE);
+            }
+            return;
+        }
+
+        final Rect bounds = mTempRect;
+        view.getBoundsOnScreen(bounds);
+        final AutofillId id = getAutofillId(view);
+        final AutofillValue value = view.getAutofillValue();
+
         if (!mHasSession) {
             // Starts new session.
-            startSession(id, view.getWindowToken(), bounds, value);
+            startSession(id, view.getWindowToken(), bounds, value, 0);
         } else {
             // Update focus on existing session.
             updateSession(id, bounds, value, FLAG_VIEW_ENTERED);
@@ -169,11 +239,13 @@
      * @param childId id identifying the virtual child inside the view.
      * @param bounds child boundaries, relative to the top window.
      */
-    public void notifyVirtualViewEntered(@NonNull View view, int childId,
-            @NonNull Rect bounds) {
+    public void notifyViewEntered(@NonNull View view, int childId, @NonNull Rect bounds) {
         ensureServiceClientAddedIfNeeded();
 
         if (!mEnabled) {
+            if (mCallback != null) {
+                mCallback.onAutofillEvent(view, childId, AutofillCallback.EVENT_INPUT_UNAVAILABLE);
+            }
             return;
         }
 
@@ -181,7 +253,7 @@
 
         if (!mHasSession) {
             // Starts new session.
-            startSession(id, view.getWindowToken(), bounds, null);
+            startSession(id, view.getWindowToken(), bounds, null, 0);
         } else {
             // Update focus on existing session.
             updateSession(id, bounds, null, FLAG_VIEW_ENTERED);
@@ -194,7 +266,7 @@
      * @param view the {@link View} whose descendant is the virtual view.
      * @param childId id identifying the virtual child inside the view.
      */
-    public void notifyVirtualViewExited(@NonNull View view, int childId) {
+    public void notifyViewExited(@NonNull View view, int childId) {
         ensureServiceClientAddedIfNeeded();
 
         if (mEnabled && mHasSession) {
@@ -224,16 +296,16 @@
     /**
      * Called to indicate the value of an autofillable virtual {@link View} changed.
      *
-     * @param parent parent view whose value changed.
+     * @param view the {@link View} whose descendant is the virtual view.
      * @param childId id identifying the virtual child inside the parent view.
      * @param value new value of the child.
      */
-    public void notifyVirtualValueChanged(View parent, int childId, AutofillValue value) {
+    public void notifyValueChanged(View view, int childId, AutofillValue value) {
         if (!mEnabled || !mHasSession) {
             return;
         }
 
-        final AutofillId id = getAutofillId(parent, childId);
+        final AutofillId id = getAutofillId(view, childId);
         updateSession(id, null, value, FLAG_VALUE_CHANGED);
     }
 
@@ -304,17 +376,18 @@
         return new AutofillId(parent.getAccessibilityViewId(), childId);
     }
 
-    private void startSession(AutofillId id, IBinder windowToken, Rect bounds,
-            AutofillValue value) {
+    private void startSession(@NonNull AutofillId id, @NonNull IBinder windowToken,
+            @NonNull Rect bounds, @NonNull AutofillValue value, int flags) {
         if (DEBUG) {
-            Log.d(TAG, "startSession(): id=" + id + ", bounds=" + bounds + ", value=" + value);
+            Log.d(TAG, "startSession(): id=" + id + ", bounds=" + bounds + ", value=" + value
+                    + ", flags=" + flags);
         }
 
         try {
             mService.startSession(mContext.getActivityToken(), windowToken,
                     mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
-                    mCallback != null);
-            final AutofillClient client = getClient();
+                    mCallback != null, flags, mContext.getOpPackageName());
+            AutofillClient client = getClient();
             if (client != null) {
                 client.resetableStateAvailable();
             }
@@ -435,7 +508,7 @@
             return;
         }
         if (id.isVirtual()) {
-            mCallback.onAutofillEventVirtual(view, id.getVirtualChildId(), event);
+            mCallback.onAutofillEvent(view, id.getVirtualChildId(), event);
         } else {
             mCallback.onAutofillEvent(view, event);
         }
@@ -471,13 +544,23 @@
         public static final int EVENT_INPUT_HIDDEN = 2;
 
         /**
+         * The auto-fill input UI affordance associated with the view won't be shown because
+         * autofill is not available.
+         *
+         * <p>If the view provides its own auto-complete UI affordance but was not displaying it
+         * to avoid flickering, it could shown it upon receiving this event.
+         */
+        public static final int EVENT_INPUT_UNAVAILABLE = 3;
+
+        /**
          * Called after a change in the autofill state associated with a view.
          *
          * @param view view associated with the change.
          *
          * @param event currently either {@link #EVENT_INPUT_SHOWN} or {@link #EVENT_INPUT_HIDDEN}.
          */
-        public void onAutofillEvent(@NonNull View view, @AutofillEventType int event) {}
+        public void onAutofillEvent(@NonNull View view, @AutofillEventType int event) {
+        }
 
         /**
          * Called after a change in the autofill state associated with a virtual view.
@@ -487,8 +570,8 @@
          *
          * @param event currently either {@link #EVENT_INPUT_SHOWN} or {@link #EVENT_INPUT_HIDDEN}.
          */
-        public void onAutofillEventVirtual(@NonNull View view, int childId,
-                @AutofillEventType int event) {}
+        public void onAutofillEvent(@NonNull View view, int childId, @AutofillEventType int event) {
+        }
     }
 
     private static final class AutofillManagerClient extends IAutoFillManagerClient.Stub {
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index 86a4965..97210cc 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -32,7 +32,7 @@
     boolean addClient(in IAutoFillManagerClient client, int userId);
     oneway void startSession(in IBinder activityToken, IBinder windowToken, in IBinder appCallback,
             in AutofillId autoFillId, in Rect bounds, in AutofillValue value, int userId,
-            boolean hasCallback);
+            boolean hasCallback, int flags, String packageName);
     oneway void updateSession(in IBinder activityToken, in AutofillId id, in Rect bounds,
             in AutofillValue value, int flags, int userId);
     oneway void finishSession(in IBinder activityToken, int userId);
diff --git a/core/java/android/widget/AbsSpinner.java b/core/java/android/widget/AbsSpinner.java
index 020e80a..fae5742 100644
--- a/core/java/android/widget/AbsSpinner.java
+++ b/core/java/android/widget/AbsSpinner.java
@@ -514,14 +514,15 @@
     }
 
     @Override
-    public void autofill(AutofillValue value) {
-        if (!isEnabled()) return;
+    public boolean autofill(AutofillValue value) {
+        if (!isEnabled()) return false;
 
         if (value.isList()) {
             setSelection(value.getListValue());
         } else {
             Log.w(LOG_TAG, value + " could not be autofilled into " + this);
         }
+        return true;
     }
 
     @Override
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 899a824..9dc61ab 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -584,14 +584,16 @@
     }
 
     @Override
-    public void autofill(AutofillValue value) {
-        if (!isEnabled()) return;
+    public boolean autofill(AutofillValue value) {
+        if (!isEnabled()) return false;
 
         if (value.isToggle()) {
             setChecked(value.getToggleValue());
         } else {
             Log.w(LOG_TAG, value + " could not be autofilled into " + this);
         }
+
+        return true;
     }
 
     @Override
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index f63573f..7d04f35 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -775,14 +775,16 @@
     }
 
     @Override
-    public void autofill(AutofillValue value) {
-        if (!isEnabled()) return;
+    public boolean autofill(AutofillValue value) {
+        if (!isEnabled()) return false;
 
         if (value.isDate()) {
             mDelegate.updateDate(value.getDateValue());
         } else {
             Log.w(LOG_TAG, value + " could not be autofilled into " + this);
         }
+
+        return true;
     }
 
     @Override
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index ade03e1..faa2310 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -157,6 +157,7 @@
     private static final int MENU_ITEM_ORDER_SELECT_ALL = 9;
     private static final int MENU_ITEM_ORDER_REPLACE = 10;
     private static final int MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START = 11;
+    private static final int MENU_ITEM_ORDER_AUTOFILL = 12;
 
     // Each Editor manages its own undo stack.
     private final UndoManager mUndoManager = new UndoManager();
@@ -2644,6 +2645,10 @@
                 .setAlphabeticShortcut('a')
                 .setEnabled(mTextView.canSelectAllText())
                 .setOnMenuItemClickListener(mOnContextMenuItemClickListener);
+        menu.add(Menu.NONE, TextView.ID_AUTOFILL, MENU_ITEM_ORDER_AUTOFILL,
+                com.android.internal.R.string.autofill)
+                .setEnabled(mTextView.canRequestAutofill())
+                .setOnMenuItemClickListener(mOnContextMenuItemClickListener);
 
         mPreserveSelection = true;
     }
@@ -3828,6 +3833,12 @@
                         .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
             }
 
+            if (mTextView.canRequestAutofill()) {
+                menu.add(Menu.NONE, TextView.ID_AUTOFILL, MENU_ITEM_ORDER_AUTOFILL,
+                        com.android.internal.R.string.autofill)
+                        .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+            }
+
             updateSelectAllItem(menu);
             updateReplaceItem(menu);
         }
diff --git a/core/java/android/widget/RadioGroup.java b/core/java/android/widget/RadioGroup.java
index 5e8279a..a7574c7 100644
--- a/core/java/android/widget/RadioGroup.java
+++ b/core/java/android/widget/RadioGroup.java
@@ -426,23 +426,24 @@
     }
 
     @Override
-    public void autofill(AutofillValue value) {
-        if (!isEnabled()) return;
+    public boolean autofill(AutofillValue value) {
+        if (!isEnabled()) return false;
 
         int index;
         if (value.isList()) {
             index = value.getListValue();
         } else {
             Log.w(LOG_TAG, value + " could not be autofilled into " + this);
-            return;
+            return false;
         }
 
         final View child = getChildAt(index);
         if (child == null) {
             Log.w(VIEW_LOG_TAG, "RadioGroup.autoFill(): no child with index " + index);
-            return;
+            return false;
         }
         check(child.getId());
+        return true;
     }
 
     @Override
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 3822138..519a7dd 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -58,6 +58,7 @@
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.AdapterView.OnItemSelectedListener;
@@ -159,20 +160,6 @@
     private SearchableInfo mSearchable;
     private Bundle mAppSearchData;
 
-    /*
-     * SearchView can be set expanded before the IME is ready to be shown during
-     * initial UI setup. The show operation is asynchronous to account for this.
-     */
-    private Runnable mShowImeRunnable = new Runnable() {
-        public void run() {
-            InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
-
-            if (imm != null) {
-                imm.showSoftInputUnchecked(0, null);
-            }
-        }
-    };
-
     private Runnable mUpdateDrawableStateRunnable = new Runnable() {
         public void run() {
             updateFocusedState();
@@ -497,9 +484,9 @@
     @Override
     public void clearFocus() {
         mClearingFocus = true;
-        setImeVisibility(false);
         super.clearFocus();
         mSearchSrcTextView.clearFocus();
+        mSearchSrcTextView.setImeVisibility(false);
         mClearingFocus = false;
     }
 
@@ -967,19 +954,6 @@
         super.onDetachedFromWindow();
     }
 
-    private void setImeVisibility(final boolean visible) {
-        if (visible) {
-            post(mShowImeRunnable);
-        } else {
-            removeCallbacks(mShowImeRunnable);
-            InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
-
-            if (imm != null) {
-                imm.hideSoftInputFromWindow(getWindowToken(), 0);
-            }
-        }
-    }
-
     /**
      * Called by the SuggestionsAdapter
      * @hide
@@ -1286,7 +1260,7 @@
                 if (mSearchable != null) {
                     launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null, query.toString());
                 }
-                setImeVisibility(false);
+                mSearchSrcTextView.setImeVisibility(false);
                 dismissSuggestions();
             }
         }
@@ -1311,7 +1285,7 @@
         } else {
             mSearchSrcTextView.setText("");
             mSearchSrcTextView.requestFocus();
-            setImeVisibility(true);
+            mSearchSrcTextView.setImeVisibility(true);
         }
 
     }
@@ -1319,7 +1293,7 @@
     private void onSearchClicked() {
         updateViewsVisibility(false);
         mSearchSrcTextView.requestFocus();
-        setImeVisibility(true);
+        mSearchSrcTextView.setImeVisibility(true);
         if (mOnSearchClickListener != null) {
             mOnSearchClickListener.onClick(this);
         }
@@ -1477,7 +1451,7 @@
         if (mOnSuggestionListener == null
                 || !mOnSuggestionListener.onSuggestionClick(position)) {
             launchSuggestion(position, KeyEvent.KEYCODE_UNKNOWN, null);
-            setImeVisibility(false);
+            mSearchSrcTextView.setImeVisibility(false);
             dismissSuggestions();
             return true;
         }
@@ -1910,6 +1884,9 @@
         private int mThreshold;
         private SearchView mSearchView;
 
+        private boolean mHasPendingShowSoftInputRequest;
+        final Runnable mRunShowSoftInputIfNecessary = () -> showSoftInputIfNecessary();
+
         public SearchAutoComplete(Context context) {
             super(context);
             mThreshold = getThreshold();
@@ -1983,11 +1960,13 @@
             super.onWindowFocusChanged(hasWindowFocus);
 
             if (hasWindowFocus && mSearchView.hasFocus() && getVisibility() == VISIBLE) {
-                InputMethodManager inputManager =
-                        getContext().getSystemService(InputMethodManager.class);
-                inputManager.showSoftInput(this, 0);
-                // If in landscape mode, then make sure that
-                // the ime is in front of the dropdown.
+                // Since InputMethodManager#onPostWindowFocus() will be called after this callback,
+                // it is a bit too early to call InputMethodManager#showSoftInput() here. We still
+                // need to wait until the system calls back onCreateInputConnection() to call
+                // InputMethodManager#showSoftInput().
+                mHasPendingShowSoftInputRequest = true;
+
+                // If in landscape mode, then make sure that the ime is in front of the dropdown.
                 if (isLandscapeMode(getContext())) {
                     ensureImeVisible(true);
                 }
@@ -2027,7 +2006,7 @@
                     }
                     if (event.isTracking() && !event.isCanceled()) {
                         mSearchView.clearFocus();
-                        mSearchView.setImeVisibility(false);
+                        setImeVisibility(false);
                         return true;
                     }
                 }
@@ -2051,5 +2030,51 @@
             };
             return 160;
         }
+
+        /**
+         * We override {@link View#onCreateInputConnection(EditorInfo)} as a signal to schedule a
+         * pending {@link InputMethodManager#showSoftInput(View, int)} request (if any).
+         */
+        @Override
+        public InputConnection onCreateInputConnection(EditorInfo editorInfo) {
+            final InputConnection ic = super.onCreateInputConnection(editorInfo);
+            if (mHasPendingShowSoftInputRequest) {
+                removeCallbacks(mRunShowSoftInputIfNecessary);
+                post(mRunShowSoftInputIfNecessary);
+            }
+            return ic;
+        }
+
+        private void showSoftInputIfNecessary() {
+            if (mHasPendingShowSoftInputRequest) {
+                final InputMethodManager imm =
+                        getContext().getSystemService(InputMethodManager.class);
+                imm.showSoftInput(this, 0);
+                mHasPendingShowSoftInputRequest = false;
+            }
+        }
+
+        private void setImeVisibility(final boolean visible) {
+            final InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
+            if (!visible) {
+                mHasPendingShowSoftInputRequest = false;
+                removeCallbacks(mRunShowSoftInputIfNecessary);
+                imm.hideSoftInputFromWindow(getWindowToken(), 0);
+                return;
+            }
+
+            if (imm.isActive(this)) {
+                // This means that SearchAutoComplete is already connected to the IME.
+                // InputMethodManager#showSoftInput() is guaranteed to pass client-side focus check.
+                mHasPendingShowSoftInputRequest = false;
+                removeCallbacks(mRunShowSoftInputIfNecessary);
+                imm.showSoftInput(this, 0);
+                return;
+            }
+
+            // Otherwise, InputMethodManager#showSoftInput() should be deferred after
+            // onCreateInputConnection().
+            mHasPendingShowSoftInputRequest = true;
+        }
     }
 }
diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java
index a6a9db4..59881b5 100644
--- a/core/java/android/widget/TextClock.java
+++ b/core/java/android/widget/TextClock.java
@@ -132,7 +132,7 @@
 
     private CharSequence mDescFormat;
 
-    private boolean mRegistered;
+    private boolean mAttached;
 
     private Calendar mTime;
     private String mTimeZone;
@@ -252,7 +252,7 @@
         }
 
         createTime(mTimeZone);
-        // Wait until registering for events to handle the ticker
+        // Wait until onAttachedToWindow() to handle the ticker
         chooseFormat(false);
     }
 
@@ -503,9 +503,12 @@
         boolean hadSeconds = mHasSeconds;
         mHasSeconds = DateFormat.hasSeconds(mFormat);
 
-        if (handleTicker && mRegistered && hadSeconds != mHasSeconds) {
-            if (hadSeconds) getHandler().removeCallbacks(mTicker);
-            else mTicker.run();
+        if (handleTicker && mAttached && hadSeconds != mHasSeconds) {
+            if (hadSeconds) {
+                getHandler().removeCallbacks(mTicker);
+            } else if (getVisibility() == VISIBLE) {
+                mTicker.run();
+            }
         }
     }
 
@@ -517,27 +520,50 @@
     }
 
     @Override
-    public void onVisibilityAggregated(boolean isVisible) {
-        if (!mRegistered && isVisible) {
-            mRegistered = true;
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        if (!mAttached) {
+            mAttached = true;
 
             registerReceiver();
             registerObserver();
 
             createTime(mTimeZone);
 
-            if (mHasSeconds) {
-                mTicker.run();
-            } else {
-                onTimeChanged();
+            if (getVisibility() == VISIBLE) {
+                if (mHasSeconds) {
+                    mTicker.run();
+                } else {
+                    onTimeChanged();
+                }
             }
-        } else if (mRegistered && !isVisible) {
+        }
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+
+        if (mAttached) {
             unregisterReceiver();
             unregisterObserver();
 
             getHandler().removeCallbacks(mTicker);
 
-            mRegistered = false;
+            mAttached = false;
+        }
+    }
+
+    @Override
+    public void onVisibilityAggregated(boolean isVisible) {
+        if (mAttached) {
+            if (isVisible && mHasSeconds) {
+                mTicker.run();
+            } else {
+                getHandler().removeCallbacks(mTicker);
+            }
+            onTimeChanged();
         }
     }
 
@@ -560,7 +586,7 @@
     }
 
     private void registerObserver() {
-        if (mRegistered) {
+        if (mAttached) {
             if (mFormatChangeObserver == null) {
                 mFormatChangeObserver = new FormatChangeObserver(getHandler());
             }
@@ -587,9 +613,11 @@
     }
 
     private void onTimeChanged() {
-        mTime.setTimeInMillis(System.currentTimeMillis());
-        setText(DateFormat.format(mFormat, mTime));
-        setContentDescription(DateFormat.format(mDescFormat, mTime));
+        if (getVisibility() == VISIBLE) {
+            mTime.setTimeInMillis(System.currentTimeMillis());
+            setText(DateFormat.format(mFormat, mTime));
+            setContentDescription(DateFormat.format(mDescFormat, mTime));
+        }
     }
 
     /** @hide */
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index d04f70f..26edc43 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -10012,15 +10012,33 @@
 
     // TODO(b/33197203): add unit/CTS tests for autofill methods
 
+    boolean canRequestAutofill() {
+        final AutofillManager afm = mContext.getSystemService(AutofillManager.class);
+        if (afm != null) {
+            return afm.isEnabled();
+        }
+        return false;
+    }
+
+    private void requestAutofill() {
+        final AutofillManager afm = mContext.getSystemService(AutofillManager.class);
+        if (afm != null) {
+            afm.requestAutofill(this);
+        }
+    }
+
     @Override
-    public void autofill(AutofillValue value) {
+    public boolean autofill(AutofillValue value) {
         if (value.isText()) {
             if (isTextEditable()) {
                 setText(value.getTextValue(), mBufferType, true, 0);
+                return true;
             }
         } else {
             Log.w(LOG_TAG, value + " could not be autofilled into " + this);
         }
+
+        return false;
     }
 
     @Override
@@ -10481,6 +10499,7 @@
     static final int ID_PASTE_AS_PLAIN_TEXT = android.R.id.pasteAsPlainText;
     static final int ID_REPLACE = android.R.id.replaceText;
     static final int ID_ASSIST = android.R.id.textAssist;
+    static final int ID_AUTOFILL = android.R.id.autofill;
 
     /**
      * Called when a context menu option for the text view is selected.  Currently
@@ -10545,6 +10564,11 @@
             case ID_SHARE:
                 shareSelectedText();
                 return true;
+
+            case ID_AUTOFILL:
+                requestAutofill();
+                stopTextActionMode();
+                return true;
         }
         return false;
     }
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index cfa78b5..1e97e3b 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -530,14 +530,16 @@
     }
 
     @Override
-    public void autofill(AutofillValue value) {
-        if (!isEnabled()) return;
+    public boolean autofill(AutofillValue value) {
+        if (!isEnabled()) return false;
 
         if (value.isDate()) {
             mDelegate.setDate(value.getDateValue());
         } else {
             Log.w(LOG_TAG, value + " could not be autofilled into " + this);
         }
+
+        return true;
     }
 
     @Override
diff --git a/core/java/com/android/internal/notification/SystemNotificationChannels.java b/core/java/com/android/internal/notification/SystemNotificationChannels.java
index ec3aac2..c840f26 100644
--- a/core/java/com/android/internal/notification/SystemNotificationChannels.java
+++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java
@@ -48,12 +48,12 @@
         List<NotificationChannel> channelsList = new ArrayList<NotificationChannel>();
         channelsList.add(new NotificationChannel(
                 VIRTUAL_KEYBOARD,
-                R.string.notification_channel_virtual_keyboard,
+                context.getString(R.string.notification_channel_virtual_keyboard),
                 NotificationManager.IMPORTANCE_LOW));
 
         final NotificationChannel physicalKeyboardChannel = new NotificationChannel(
                 PHYSICAL_KEYBOARD,
-                R.string.notification_channel_physical_keyboard,
+                context.getString(R.string.notification_channel_physical_keyboard),
                 NotificationManager.IMPORTANCE_DEFAULT);
         physicalKeyboardChannel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI,
                 Notification.AUDIO_ATTRIBUTES_DEFAULT);
@@ -61,32 +61,32 @@
 
         channelsList.add(new NotificationChannel(
                 SECURITY,
-                R.string.notification_channel_security,
+                context.getString(R.string.notification_channel_security),
                 NotificationManager.IMPORTANCE_LOW));
 
         channelsList.add(new NotificationChannel(
                 CAR_MODE,
-                R.string.notification_channel_car_mode,
+                context.getString(R.string.notification_channel_car_mode),
                 NotificationManager.IMPORTANCE_LOW));
 
         channelsList.add(new NotificationChannel(
                 DEVELOPER,
-                R.string.notification_channel_developer,
+                context.getString(R.string.notification_channel_developer),
                 NotificationManager.IMPORTANCE_LOW));
 
         channelsList.add(new NotificationChannel(
                 UPDATES,
-                R.string.notification_channel_updates,
+                context.getString(R.string.notification_channel_updates),
                 NotificationManager.IMPORTANCE_LOW));
 
         channelsList.add(new NotificationChannel(
                 NETWORK_STATUS,
-                R.string.notification_channel_network_status,
+                context.getString(R.string.notification_channel_network_status),
                 NotificationManager.IMPORTANCE_LOW));
 
         final NotificationChannel networkAlertsChannel = new NotificationChannel(
                 NETWORK_ALERTS,
-                R.string.notification_channel_network_alerts,
+                context.getString(R.string.notification_channel_network_alerts),
                 NotificationManager.IMPORTANCE_HIGH);
         networkAlertsChannel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI,
                 Notification.AUDIO_ATTRIBUTES_DEFAULT);
@@ -94,17 +94,17 @@
 
         channelsList.add(new NotificationChannel(
                 VPN,
-                R.string.notification_channel_vpn,
+                context.getString(R.string.notification_channel_vpn),
                 NotificationManager.IMPORTANCE_LOW));
 
         channelsList.add(new NotificationChannel(
                 DEVICE_ADMIN,
-                R.string.notification_channel_device_admin,
+                context.getString(R.string.notification_channel_device_admin),
                 NotificationManager.IMPORTANCE_LOW));
 
         final NotificationChannel alertsChannel = new NotificationChannel(
                 ALERTS,
-                R.string.notification_channel_alerts,
+                context.getString(R.string.notification_channel_alerts),
                 NotificationManager.IMPORTANCE_DEFAULT);
         alertsChannel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI,
                 Notification.AUDIO_ATTRIBUTES_DEFAULT);
@@ -112,12 +112,12 @@
 
         channelsList.add(new NotificationChannel(
                 RETAIL_MODE,
-                R.string.notification_channel_retail_mode,
+                context.getString(R.string.notification_channel_retail_mode),
                 NotificationManager.IMPORTANCE_LOW));
 
         channelsList.add(new NotificationChannel(
                 USB,
-                R.string.notification_channel_usb,
+                context.getString(R.string.notification_channel_usb),
                 NotificationManager.IMPORTANCE_MIN));
 
         nm.createNotificationChannels(channelsList);
@@ -128,7 +128,7 @@
         final NotificationManager nm = context.getSystemService(NotificationManager.class);
         nm.createNotificationChannelsForPackage(pkg, Arrays.asList(new NotificationChannel(
                 ACCOUNT,
-                R.string.notification_channel_account,
+                context.getString(R.string.notification_channel_account),
                 NotificationManager.IMPORTANCE_LOW)));
     }
 
diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java
index 96468ab..0a9faa1 100644
--- a/core/java/com/android/internal/os/WrapperInit.java
+++ b/core/java/com/android/internal/os/WrapperInit.java
@@ -142,6 +142,21 @@
             Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from wrapper");
         }
 
-        RuntimeInit.applicationInit(targetSdkVersion, argv, null);
+        // Check whether the first argument is a "-cp" in argv, and assume the next argument is the
+        // classpath. If found, create a PathClassLoader and use it for applicationInit.
+        ClassLoader classLoader = null;
+        if (argv != null && argv.length > 2 && argv[0].equals("-cp")) {
+            classLoader = ZygoteInit.createPathClassLoader(argv[1], targetSdkVersion);
+
+            // Install this classloader as the context classloader, too.
+            Thread.currentThread().setContextClassLoader(classLoader);
+
+            // Remove the classpath from the arguments.
+            String removedArgs[] = new String[argv.length - 2];
+            System.arraycopy(argv, 2, removedArgs, 0, argv.length - 2);
+            argv = removedArgs;
+        }
+
+        RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
     }
 }
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 76d8af1..b2a2fec 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -468,7 +468,8 @@
                 String[] amendedArgs = new String[args.length + 2];
                 amendedArgs[0] = "-cp";
                 amendedArgs[1] = systemServerClasspath;
-                System.arraycopy(parsedArgs.remainingArgs, 0, amendedArgs, 2, parsedArgs.remainingArgs.length);
+                System.arraycopy(args, 0, amendedArgs, 2, args.length);
+                args = amendedArgs;
             }
 
             WrapperInit.execApplication(parsedArgs.invokeWith,
@@ -477,8 +478,7 @@
         } else {
             ClassLoader cl = null;
             if (systemServerClasspath != null) {
-                cl = createSystemServerClassLoader(systemServerClasspath,
-                                                   parsedArgs.targetSdkVersion);
+                cl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion);
 
                 Thread.currentThread().setContextClassLoader(cl);
             }
@@ -493,15 +493,14 @@
     }
 
     /**
-     * Creates a PathClassLoader for the system server. It also creates
-     * a shared namespace associated with the classloader to let it access
-     * platform-private native libraries.
+     * Creates a PathClassLoader for the given class path that is associated with a shared
+     * namespace, i.e., this classloader can access platform-private native libraries. The
+     * classloader will use java.library.path as the native library path.
      */
-    private static PathClassLoader createSystemServerClassLoader(String systemServerClasspath,
-                                                                 int targetSdkVersion) {
+    static PathClassLoader createPathClassLoader(String classPath, int targetSdkVersion) {
       String libraryPath = System.getProperty("java.library.path");
 
-      return PathClassLoaderFactory.createClassLoader(systemServerClasspath,
+      return PathClassLoaderFactory.createClassLoader(classPath,
                                                       libraryPath,
                                                       libraryPath,
                                                       ClassLoader.getSystemClassLoader(),
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index ce51dc4..361fd3da 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -16,12 +16,12 @@
 
 package com.android.internal.view;
 
-import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.hardware.input.InputManager;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
+import android.util.MergedConfiguration;
 import android.view.DragEvent;
 import android.view.IWindow;
 import android.view.IWindowSession;
@@ -39,8 +39,9 @@
 
     @Override
     public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
-            Rect stableInsets, Rect outsets, boolean reportDraw, Configuration newConfig,
-            Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeNavBar, int displayId) {
+            Rect stableInsets, Rect outsets, boolean reportDraw,
+            MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
+            boolean alwaysConsumeNavBar, int displayId) {
         if (reportDraw) {
             try {
                 mSession.finishDrawing(this);
diff --git a/core/java/com/android/internal/widget/ImageFloatingTextView.java b/core/java/com/android/internal/widget/ImageFloatingTextView.java
index 80207ee..e86932c 100644
--- a/core/java/com/android/internal/widget/ImageFloatingTextView.java
+++ b/core/java/com/android/internal/widget/ImageFloatingTextView.java
@@ -115,6 +115,7 @@
         // Lets calculate how many lines the given measurement allows us.
         int availableHeight = height - mPaddingTop - mPaddingBottom;
         int maxLines = availableHeight / getLineHeight();
+        maxLines = Math.max(1, maxLines);
         if (getMaxLines() > 0) {
             maxLines = Math.min(getMaxLines(), maxLines);
         }
diff --git a/core/java/com/android/internal/widget/MessagingLinearLayout.java b/core/java/com/android/internal/widget/MessagingLinearLayout.java
index b259ad1..1104318 100644
--- a/core/java/com/android/internal/widget/MessagingLinearLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLinearLayout.java
@@ -16,8 +16,6 @@
 
 package com.android.internal.widget;
 
-import com.android.internal.R;
-
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.TypedArray;
@@ -28,6 +26,8 @@
 import android.view.ViewGroup;
 import android.widget.RemoteViews;
 
+import com.android.internal.R;
+
 /**
  * A custom-built layout for the Notification.MessagingStyle.
  *
@@ -119,23 +119,30 @@
                 }
                 final View child = getChildAt(i);
                 LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
-
+                ImageFloatingTextView textChild = null;
                 if (child instanceof ImageFloatingTextView) {
                     // Pretend we need the image padding for all views, we don't know which
                     // one will end up needing to do this (might end up not using all the space,
                     // but calculating this exactly would be more expensive).
-                    ((ImageFloatingTextView) child).setNumIndentLines(
-                            mIndentLines == 2 ? 3 : mIndentLines);
+                    textChild = (ImageFloatingTextView) child;
+                    textChild.setNumIndentLines(mIndentLines == 2 ? 3 : mIndentLines);
                 }
 
-                measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
+                int spacing = first ? 0 : mSpacing;
+                measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, totalHeight
+                        - mPaddingTop - mPaddingBottom + spacing);
 
                 final int childHeight = child.getMeasuredHeight();
                 int newHeight = Math.max(totalHeight, totalHeight + childHeight + lp.topMargin +
-                        lp.bottomMargin + (first ? 0 : mSpacing));
+                        lp.bottomMargin + spacing);
                 first = false;
+                boolean measuredTooSmall = false;
+                if (textChild != null) {
+                    measuredTooSmall = childHeight < textChild.getLayout().getHeight()
+                            + textChild.getPaddingTop() + textChild.getPaddingBottom();
+                }
 
-                if (newHeight <= targetHeight) {
+                if (newHeight <= targetHeight && !measuredTooSmall) {
                     totalHeight = newHeight;
                     lp.hide = false;
                 } else {
@@ -168,7 +175,15 @@
                 }
                 boolean changed = textChild.setNumIndentLines(Math.max(0, imageLines));
                 if (changed || !recalculateVisibility) {
-                    measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
+                    final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
+                            mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin,
+                            lp.width);
+                    // we want to measure it at most as high as it is currently, otherwise we'll
+                    // drop later lines
+                    final int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
+                            targetHeight - child.getMeasuredHeight(), lp.height);
+
+                    child.measure(childWidthMeasureSpec, childHeightMeasureSpec);;
                 }
                 imageLines -= textChild.getLineCount();
             }
diff --git a/core/jni/android/graphics/ColorFilter.cpp b/core/jni/android/graphics/ColorFilter.cpp
index 79439e2..5553a3e 100644
--- a/core/jni/android/graphics/ColorFilter.cpp
+++ b/core/jni/android/graphics/ColorFilter.cpp
@@ -30,7 +30,7 @@
 
 class SkColorFilterGlue {
 public:
-    static void finalizer(JNIEnv* env, jobject clazz, jlong skFilterHandle) {
+    static void SafeUnref(JNIEnv* env, jobject clazz, jlong skFilterHandle) {
         SkColorFilter* filter = reinterpret_cast<SkColorFilter *>(skFilterHandle);
         SkSafeUnref(filter);
     }
@@ -57,19 +57,19 @@
 };
 
 static const JNINativeMethod colorfilter_methods[] = {
-    {"destroyFilter", "(J)V", (void*) SkColorFilterGlue::finalizer}
+    {"nSafeUnref", "(J)V", (void*) SkColorFilterGlue::SafeUnref}
 };
 
 static const JNINativeMethod porterduff_methods[] = {
-    { "native_CreatePorterDuffFilter", "(II)J", (void*) SkColorFilterGlue::CreatePorterDuffFilter   },
+    { "native_CreatePorterDuffFilter", "(II)J", (void*) SkColorFilterGlue::CreatePorterDuffFilter },
 };
 
 static const JNINativeMethod lighting_methods[] = {
-    { "native_CreateLightingFilter", "(II)J", (void*) SkColorFilterGlue::CreateLightingFilter   },
+    { "native_CreateLightingFilter", "(II)J", (void*) SkColorFilterGlue::CreateLightingFilter },
 };
 
 static const JNINativeMethod colormatrix_methods[] = {
-    { "nativeColorMatrixFilter", "([F)J", (void*) SkColorFilterGlue::CreateColorMatrixFilter   },
+    { "nativeColorMatrixFilter", "([F)J", (void*) SkColorFilterGlue::CreateColorMatrixFilter },
 };
 
 int register_android_graphics_ColorFilter(JNIEnv* env) {
diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp
index 1bd2333..678041f 100644
--- a/core/jni/android_os_HwParcel.cpp
+++ b/core/jni/android_os_HwParcel.cpp
@@ -404,6 +404,11 @@
     signalExceptionForError(env, err);
 }
 
+static void JHwParcel_native_release(
+        JNIEnv *env, jobject thiz) {
+    JHwParcel::GetNativeContext(env, thiz)->setParcel(NULL, false /* assumeOwnership */);
+}
+
 static void JHwParcel_native_releaseTemporaryStorage(
         JNIEnv *env, jobject thiz) {
     JHwParcel::GetNativeContext(env, thiz)->getStorage()->release(env);
@@ -955,6 +960,10 @@
 
     { "writeBuffer", "(L" PACKAGE_PATH "/HwBlob;)V",
         (void *)JHwParcel_native_writeBuffer },
+
+    { "release", "()V",
+        (void *)JHwParcel_native_release },
+
 };
 
 namespace android {
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 9660de4..956b724 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -26,7 +26,9 @@
 #include <sys/un.h>
 #include <unistd.h>
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 
 // Static whitelist of open paths that the zygote is allowed to keep open.
@@ -65,9 +67,10 @@
       return true;
   }
 
-  static const std::string kFrameworksPrefix = "/system/framework/";
-  static const std::string kJarSuffix = ".jar";
-  if (StartsWith(path, kFrameworksPrefix) && EndsWith(path, kJarSuffix)) {
+  static const char* kFrameworksPrefix = "/system/framework/";
+  static const char* kJarSuffix = ".jar";
+  if (android::base::StartsWith(path, kFrameworksPrefix)
+      && android::base::EndsWith(path, kJarSuffix)) {
     return true;
   }
 
@@ -79,28 +82,31 @@
   // /data/resource-cache/system@vendor@overlay@framework-res.apk@idmap
   // /data/resource-cache/system@vendor@overlay-subdir@pg@framework-res.apk@idmap
   // See AssetManager.cpp for more details on overlay-subdir.
-  static const std::string kOverlayDir = "/system/vendor/overlay/";
-  static const std::string kVendorOverlayDir = "/vendor/overlay";
-  static const std::string kOverlaySubdir = "/system/vendor/overlay-subdir/";
-  static const std::string kApkSuffix = ".apk";
+  static const char* kOverlayDir = "/system/vendor/overlay/";
+  static const char* kVendorOverlayDir = "/vendor/overlay";
+  static const char* kOverlaySubdir = "/system/vendor/overlay-subdir/";
+  static const char* kApkSuffix = ".apk";
 
-  if ((StartsWith(path, kOverlayDir) || StartsWith(path, kOverlaySubdir)
-       || StartsWith(path, kVendorOverlayDir))
-      && EndsWith(path, kApkSuffix)
+  if ((android::base::StartsWith(path, kOverlayDir)
+       || android::base::StartsWith(path, kOverlaySubdir)
+       || android::base::StartsWith(path, kVendorOverlayDir))
+      && android::base::EndsWith(path, kApkSuffix)
       && path.find("/../") == std::string::npos) {
     return true;
   }
 
-  static const std::string kOverlayIdmapPrefix = "/data/resource-cache/";
-  static const std::string kOverlayIdmapSuffix = ".apk@idmap";
-  if (StartsWith(path, kOverlayIdmapPrefix) && EndsWith(path, kOverlayIdmapSuffix)
+  static const char* kOverlayIdmapPrefix = "/data/resource-cache/";
+  static const char* kOverlayIdmapSuffix = ".apk@idmap";
+  if (android::base::StartsWith(path, kOverlayIdmapPrefix)
+      && android::base::EndsWith(path, kOverlayIdmapSuffix)
       && path.find("/../") == std::string::npos) {
     return true;
   }
 
   // All regular files that are placed under this path are whitelisted automatically.
-  static const std::string kZygoteWhitelistPath = "/vendor/zygote_whitelist/";
-  if (StartsWith(path, kZygoteWhitelistPath) && path.find("/../") == std::string::npos) {
+  static const char* kZygoteWhitelistPath = "/vendor/zygote_whitelist/";
+  if (android::base::StartsWith(path, kZygoteWhitelistPath)
+      && path.find("/../") == std::string::npos) {
     return true;
   }
 
@@ -111,24 +117,6 @@
     : whitelist_() {
 }
 
-// TODO: Call android::base::StartsWith instead of copying the code here.
-// static
-bool FileDescriptorWhitelist::StartsWith(const std::string& str,
-                                         const std::string& prefix) {
-  return str.compare(0, prefix.size(), prefix) == 0;
-}
-
-// TODO: Call android::base::EndsWith instead of copying the code here.
-// static
-bool FileDescriptorWhitelist::EndsWith(const std::string& str,
-                                       const std::string& suffix) {
-  if (suffix.size() > str.size()) {
-    return false;
-  }
-
-  return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
-}
-
 FileDescriptorWhitelist* FileDescriptorWhitelist::instance_ = nullptr;
 
 // static
@@ -174,7 +162,8 @@
   }
 
   std::string file_path;
-  if (!Readlink(fd, &file_path)) {
+  const std::string fd_path = android::base::StringPrintf("/proc/self/fd/%d", fd);
+  if (!android::base::Readlink(fd_path, &file_path)) {
     return NULL;
   }
 
@@ -299,30 +288,6 @@
   is_sock(false) {
 }
 
-// TODO: Call android::base::Readlink instead of copying the code here.
-// static
-bool FileDescriptorInfo::Readlink(const int fd, std::string* result) {
-  char path[64];
-  snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
-
-  // Code copied from android::base::Readlink starts here :
-
-  // Annoyingly, the readlink system call returns EINVAL for a zero-sized buffer,
-  // and truncates to whatever size you do supply, so it can't be used to query.
-  // We could call lstat first, but that would introduce a race condition that
-  // we couldn't detect.
-  // ext2 and ext4 both have PAGE_SIZE limitations, so we assume that here.
-  char buf[4096];
-  ssize_t len = readlink(path, buf, sizeof(buf));
-  if (len == -1) {
-    PLOG(ERROR) << "Readlink on " << fd << " failed.";
-    return false;
-  }
-
-  result->assign(buf, len);
-  return true;
-}
-
 // static
 bool FileDescriptorInfo::GetSocketName(const int fd, std::string* result) {
   sockaddr_storage ss;
diff --git a/core/jni/fd_utils.h b/core/jni/fd_utils.h
index 03298c3..a39e387 100644
--- a/core/jni/fd_utils.h
+++ b/core/jni/fd_utils.h
@@ -59,10 +59,6 @@
  private:
   FileDescriptorWhitelist();
 
-  static bool StartsWith(const std::string& str, const std::string& prefix);
-
-  static bool EndsWith(const std::string& str, const std::string& suffix);
-
   static FileDescriptorWhitelist* instance_;
 
   std::vector<std::string> whitelist_;
@@ -99,8 +95,6 @@
   FileDescriptorInfo(struct stat stat, const std::string& file_path, int fd, int open_flags,
                      int fd_flags, int fs_flags, off_t offset);
 
-  static bool Readlink(const int fd, std::string* result);
-
   // Returns the locally-bound name of the socket |fd|. Returns true
   // iff. all of the following hold :
   //
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c991f22..58e4051 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3593,7 +3593,7 @@
                  android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
 
-        <service android:name="com.android.server.BackgroundDexOptJobService"
+        <service android:name="com.android.server.pm.BackgroundDexOptService"
                  android:exported="true"
                  android:permission="android.permission.BIND_JOB_SERVICE">
         </service>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 67050f7..cf6bd9e 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1014,6 +1014,15 @@
          <p>The default value of this attribute is <code>false</code>. -->
     <attr name="isolatedSplits" format="boolean" />
 
+    <!-- If set to <code>true</code>, indicates to the platform that this APK is
+         a 'feature' split and that it implicitly depends on the base APK. This distinguishes
+         this split APK from a 'configuration' split, which provides resource overrides
+         for a particular 'feature' split. Only useful when the base APK specifies
+         <code>android:isolatedSplits="true"</code>.
+
+         <p>The default value of this attribute is <code>false</code>. -->
+    <attr name="isFeatureSplit" format="boolean" />
+
     <!-- Extra options for an activity's UI. Applies to either the {@code <activity>} or
          {@code <application>} tag. If specified on the {@code <application>}
          tag these will be considered defaults for all activities in the
@@ -1286,6 +1295,7 @@
         <attr name="sharedUserLabel" />
         <attr name="installLocation" />
         <attr name="isolatedSplits" />
+        <attr name="isFeatureSplit" />
         <attr name="targetSandboxVersion" />
     </declare-styleable>
 
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 6e0d9dc..385f256 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1386,6 +1386,9 @@
     <!-- Boolean indicating if current platform supports BLE peripheral mode -->
     <bool name="config_bluetooth_le_peripheral_mode_supported">false</bool>
 
+    <!-- Boolean indicating if current platform supports HFP inband ringing -->
+    <bool name="config_bluetooth_hfp_inband_ringing_support">false</bool>
+
     <!-- Max number of scan filters supported by blutooth controller. 0 if the
          device does not support hardware scan filters-->
     <integer translatable="false" name="config_bluetooth_max_scan_filters">0</integer>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index f8a071d..cd3624d 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -138,4 +138,8 @@
 
   <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_MOVE_WINDOW}. -->
   <item type="id" name="accessibilityActionMoveWindow" />
+
+  <!-- Action used to manually trigger an autofill request -->
+  <item type="id" name="autofill" />
+
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 59432cd..f965c69 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2807,6 +2807,7 @@
         <public name="importantForAutofill" />
         <public name="recycleEnabled"/>
         <public name="isStatic" />
+        <public name="isFeatureSplit" />
     </public-group>
 
     <public-group type="style" first-id="0x010302e0">
@@ -2815,6 +2816,7 @@
     <public-group type="id" first-id="0x01020041">
         <public name="textAssist" />
         <public name="accessibilityActionMoveWindow" />
+        <public name="autofill" />
     </public-group>
 
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d1d406d..d1c14e9 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2640,6 +2640,9 @@
     <!-- Item on EditText context menu. This action is used to redo a text edit operation. -->
     <string name="redo">Redo</string>
 
+    <!-- Item on EditText context menu. This action is used to request autofill. -->
+    <string name="autofill">Autofill</string>
+
     <!-- Text selection contextual mode title, displayed in the CAB. [CHAR LIMIT=20] -->
     <string name="textSelectionCABTitle">Text selection</string>
 
@@ -4564,22 +4567,25 @@
     <!-- Accessibility string used for describing the button in time picker that changes the dialog to circular clock mode. [CHAR LIMIT=NONE] -->
     <string name="time_picker_radial_mode_description">Switch to clock mode for the time input.</string>
 
-    <!-- Title for the auto-fill save dialog shown when the the contents of the activity can be saved
-         by an auto-fill service, but the service does not know what the activity represents [CHAR LIMIT=NONE] -->
+    <!-- Accessibility title for the autofill dialog used to select a list of options to autofill an activity. [CHAR LIMIT=NONE] -->
+    <string name="autofill_picker_accessibility_title">Autofill options</string>
+
+    <!-- Title for the autofill save dialog shown when the the contents of the activity can be saved
+         by an autofill service, but the service does not know what the activity represents [CHAR LIMIT=NONE] -->
     <string name="autofill_save_title">Save to <xliff:g id="label" example="MyPass">%1$s</xliff:g>?</string>
-    <!-- Title for the auto-fill save dialog shown when the the contents of the activity can be saved
-         by an auto-fill service, and the service does knows what the activity represents (for example, credit card info) [CHAR LIMIT=NONE] -->
+    <!-- Title for the autofill save dialog shown when the the contents of the activity can be saved
+         by an autofill service, and the service does knows what the activity represents (for example, credit card info) [CHAR LIMIT=NONE] -->
     <string name="autofill_save_title_with_type">Save <xliff:g id="type" example="Credit Card">%1$s</xliff:g> to <xliff:g id="label" example="MyPass">%2$s</xliff:g>?</string>
-    <!-- Label for the auto-fill save button [CHAR LIMIT=NONE] -->
+    <!-- Label for the autofill save button [CHAR LIMIT=NONE] -->
     <string name="autofill_save_yes">Save</string>
-    <!-- Label for the auto-fill cancel button [CHAR LIMIT=NONE] -->
+    <!-- Label for the autofill cancel button [CHAR LIMIT=NONE] -->
     <string name="autofill_save_no">No thanks</string>
 
-    <!-- Label for the type of data being saved for auto-fill when it represent user credentials with a password [CHAR LIMIT=NONE] -->
+    <!-- Label for the type of data being saved for autofill when it represent user credentials with a password [CHAR LIMIT=NONE] -->
     <string name="autofill_save_type_password">password</string>
-    <!-- Label for the type of data being saved for auto-fill when it represent an address (street, city, etc.) [CHAR LIMIT=NONE] -->
+    <!-- Label for the type of data being saved for autofill when it represent an address (street, city, etc.) [CHAR LIMIT=NONE] -->
     <string name="autofill_save_type_address">address</string>
-    <!-- Label for the type of data being saved for auto-fill when it represents a credit card [CHAR LIMIT=NONE] -->
+    <!-- Label for the type of data being saved for autofill when it represents a credit card [CHAR LIMIT=NONE] -->
     <string name="autofill_save_type_credit_card">credit card</string>
 
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 26d71c3..0d4a407 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -242,6 +242,7 @@
   <java-symbol type="bool" name="config_bluetooth_address_validation" />
   <java-symbol type="bool" name="config_bluetooth_sco_off_call" />
   <java-symbol type="bool" name="config_bluetooth_le_peripheral_mode_supported" />
+  <java-symbol type="bool" name="config_bluetooth_hfp_inband_ringing_support" />
   <java-symbol type="bool" name="config_cellBroadcastAppLinks" />
   <java-symbol type="bool" name="config_duplicate_port_omadm_wappush" />
   <java-symbol type="bool" name="config_enableAutoPowerModes" />
@@ -2841,11 +2842,14 @@
   <java-symbol type="dimen" name="autofill_fill_min_margin" />
   <java-symbol type="layout" name="autofill_save"/>
   <java-symbol type="layout" name="autofill_dataset_picker"/>
+  <java-symbol type="id" name="autofill" />
   <java-symbol type="id" name="autofill_save_title" />
   <java-symbol type="id" name="autofill_save_subtitle" />
   <java-symbol type="id" name="autofill_save_no" />
   <java-symbol type="id" name="autofill_save_yes" />
   <java-symbol type="id" name="autofill_save_close" />
+  <java-symbol type="string" name="autofill" />
+  <java-symbol type="string" name="autofill_picker_accessibility_title " />
   <java-symbol type="string" name="autofill_save_title" />
   <java-symbol type="string" name="autofill_save_title_with_type" />
   <java-symbol type="string" name="autofill_save_yes" />
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index fba8e23..dbc9e5d 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -40,6 +40,7 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner conscrypt telephony-common org.apache.http.legacy
 LOCAL_PACKAGE_NAME := FrameworksCoreTests
+LOCAL_COMPATIBILITY_SUITE := device-tests
 
 LOCAL_CERTIFICATE := platform
 
diff --git a/docs/html/topic/libraries/support-library/revisions.jd b/docs/html/topic/libraries/support-library/revisions.jd
index 9a24d15..adb1af5 100644
--- a/docs/html/topic/libraries/support-library/revisions.jd
+++ b/docs/html/topic/libraries/support-library/revisions.jd
@@ -316,14 +316,13 @@
   implementations, as well as any calls to this method, should be removed.
   </li>
 
-  <li>{@link android.support.v4.media.session.MediaSessionCompat#obtain
+  <li>{@code
   MediaSessionCompat.obtain()} has been deprecated and replaced with the more
   appropriately-named method
   <a href="/reference/android/support/v4/media/session/MediaSessionCompat.html#fromMediaSession"><code>fromMediaSession()</code></a>.
   </li>
 
-  <li>{@link
-  android.support.v4.media.session.MediaSessionCompat.QueueItem#obtain
+  <li>{@code
   MediaSessionCompat.QueueItem.obtain()} has been deprecated and replaced with
   the more appropriately-named method
   <a href="/reference/android/support/v4/media/session/MediaSessionCompat.QueueItem.html#fromQueueItem"><code>fromQueueItem()</code></a>.
diff --git a/drm/java/android/drm/DrmManagerClient.java b/drm/java/android/drm/DrmManagerClient.java
index 704f0ce..5973d3e 100644
--- a/drm/java/android/drm/DrmManagerClient.java
+++ b/drm/java/android/drm/DrmManagerClient.java
@@ -275,6 +275,10 @@
      * the {@link DrmManagerClient} object is no longer needed in your
      * application. After this method is called, {@link DrmManagerClient} is no
      * longer usable since it has lost all of its required resource.
+     *
+     * This method was added in API 24. In API versions 16 through 23, release()
+     * should be called instead. There is no need to do anything for API
+     * versions prior to 16.
      */
     @Override
     public void close() {
diff --git a/graphics/java/android/graphics/ColorFilter.java b/graphics/java/android/graphics/ColorFilter.java
index ac62bf4..0ca3729 100644
--- a/graphics/java/android/graphics/ColorFilter.java
+++ b/graphics/java/android/graphics/ColorFilter.java
@@ -28,21 +28,51 @@
  */
 public class ColorFilter {
     /**
-     * Holds the pointer to the native SkColorFilter instance.
-     *
-     * @hide
+     * @deprecated Use subclass constructors directly instead.
      */
-    public long native_instance;
+    @Deprecated
+    public ColorFilter() {}
+
+    /**
+     * Holds the pointer to the native SkColorFilter instance.
+     */
+    private long mNativeInstance;
+
+    long createNativeInstance() {
+        return 0;
+    }
+
+    void discardNativeInstance() {
+        if (mNativeInstance != 0) {
+            nSafeUnref(mNativeInstance);
+            mNativeInstance = 0;
+        }
+    }
 
     @Override
     protected void finalize() throws Throwable {
         try {
-            super.finalize();
+            if (mNativeInstance != 0) {
+                nSafeUnref(mNativeInstance);
+            }
+            mNativeInstance = -1;
         } finally {
-            destroyFilter(native_instance);
-            native_instance = 0;
+            super.finalize();
         }
     }
 
-    static native void destroyFilter(long native_instance);
+    /** @hide */
+    public long getNativeInstance() {
+        if (mNativeInstance == -1) {
+            throw new IllegalStateException("attempting to use a finalized ColorFilter");
+        }
+
+        if (mNativeInstance == 0) {
+            mNativeInstance = createNativeInstance();
+        }
+        return mNativeInstance;
+
+    }
+
+    static native void nSafeUnref(long native_instance);
 }
diff --git a/graphics/java/android/graphics/ColorMatrix.java b/graphics/java/android/graphics/ColorMatrix.java
index 1b1849e..6299b2c 100644
--- a/graphics/java/android/graphics/ColorMatrix.java
+++ b/graphics/java/android/graphics/ColorMatrix.java
@@ -268,4 +268,21 @@
         m[5] = 1;   m[6] = -0.34414f;   m[7] = -0.71414f;
         m[10] = 1;  m[11] = 1.772f;     m[12] = 0;
     }
+
+    @Override
+    public boolean equals(Object obj) {
+        // if (obj == this) return true; -- NaN value would mean matrix != itself
+        if (!(obj instanceof ColorMatrix)) {
+            return false;
+        }
+
+        // we don't use Arrays.equals(), since that considers NaN == NaN
+        final float[] other = ((ColorMatrix) obj).mArray;
+        for (int i = 0; i < 20; i++) {
+            if (other[i] != mArray[i]) {
+                return false;
+            }
+        }
+        return true;
+    }
 }
diff --git a/graphics/java/android/graphics/ColorMatrixColorFilter.java b/graphics/java/android/graphics/ColorMatrixColorFilter.java
index 291c8ff..61f6cc5 100644
--- a/graphics/java/android/graphics/ColorMatrixColorFilter.java
+++ b/graphics/java/android/graphics/ColorMatrixColorFilter.java
@@ -16,6 +16,9 @@
 
 package android.graphics;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
 /**
  * A color filter that transforms colors through a 4x5 color matrix. This filter
  * can be used to change the saturation of pixels, convert from YUV to RGB, etc.
@@ -32,9 +35,8 @@
      *               the filter, so changes made to the matrix after the filter
      *               is constructed will not be reflected in the filter.
      */
-    public ColorMatrixColorFilter(ColorMatrix matrix) {
+    public ColorMatrixColorFilter(@NonNull ColorMatrix matrix) {
         mMatrix.set(matrix);
-        update();
     }
 
     /**
@@ -44,84 +46,76 @@
      *              matrix. The first 20 entries of the array are copied into
      *              the filter. See ColorMatrix.
      */
-    public ColorMatrixColorFilter(float[] array) {
+    public ColorMatrixColorFilter(@NonNull float[] array) {
         if (array.length < 20) {
             throw new ArrayIndexOutOfBoundsException();
         }
         mMatrix.set(array);
-        update();
     }
 
     /**
-     * Returns the {@link ColorMatrix} used by this filter. The returned
-     * value is never null. Modifying the returned matrix does not have
-     * any effect until you call {@link #setColorMatrix(ColorMatrix)}.
+     * Copies the ColorMatrix from the filter into the passed ColorMatrix.
      *
-     * @see #setColorMatrix(ColorMatrix)
-     *
-     * @hide
+     * @param colorMatrix Set to the current value of the filter's ColorMatrix.
      */
-    public ColorMatrix getColorMatrix() {
-        return mMatrix;
+    public void getColorMatrix(ColorMatrix colorMatrix) {
+        colorMatrix.set(mMatrix);
     }
 
     /**
-     * Specifies the color matrix used by this filter. If the specified
-     * color matrix is null, this filter's color matrix will be reset to
-     * the identity matrix.
+     * Copies the provided color matrix to be used by this filter.
+     *
+     * If the specified color matrix is null, this filter's color matrix will be reset to the
+     * identity matrix.
      *
      * @param matrix A {@link ColorMatrix} or null
      *
-     * @see #getColorMatrix()
-     * @see android.graphics.ColorMatrix#reset()
-     * @see #setColorMatrix(float[])
-     *
-     * @hide
+     * @see #getColorMatrix(ColorMatrix)
+     * @see #setColorMatrixArray(float[])
+     * @see ColorMatrix#reset()
      */
-    public void setColorMatrix(ColorMatrix matrix) {
+    public void setColorMatrix(@Nullable ColorMatrix matrix) {
+        discardNativeInstance();
         if (matrix == null) {
             mMatrix.reset();
-        } else if (matrix != mMatrix) {
+        } else {
             mMatrix.set(matrix);
         }
-        update();
     }
 
     /**
-     * Specifies the color matrix used by this filter. If the specified
-     * color matrix is null, this filter's color matrix will be reset to
-     * the identity matrix.
+     * Copies the provided color matrix to be used by this filter.
+     *
+     * If the specified color matrix is null, this filter's color matrix will be reset to the
+     * identity matrix.
      *
      * @param array Array of floats used to transform colors, treated as a 4x5
      *              matrix. The first 20 entries of the array are copied into
      *              the filter. See {@link ColorMatrix}.
      *
-     * @see #getColorMatrix()
-     * @see android.graphics.ColorMatrix#reset()
+     * @see #getColorMatrix(ColorMatrix)
      * @see #setColorMatrix(ColorMatrix)
+     * @see ColorMatrix#reset()
      *
      * @throws ArrayIndexOutOfBoundsException if the specified array's
      *         length is < 20
-     *
-     * @hide
      */
-    public void setColorMatrix(float[] array) {
+    public void setColorMatrixArray(@Nullable float[] array) {
+        // called '...Array' so that passing null isn't ambiguous
+        discardNativeInstance();
         if (array == null) {
             mMatrix.reset();
         } else {
             if (array.length < 20) {
                 throw new ArrayIndexOutOfBoundsException();
             }
-
             mMatrix.set(array);
         }
-        update();
     }
 
-    private void update() {
-        final float[] colorMatrix = mMatrix.getArray();
-        destroyFilter(native_instance);
-        native_instance = nativeColorMatrixFilter(colorMatrix);
+    @Override
+    long createNativeInstance() {
+        return nativeColorMatrixFilter(mMatrix.getArray());
     }
 
     private static native long nativeColorMatrixFilter(float[] array);
diff --git a/graphics/java/android/graphics/LightingColorFilter.java b/graphics/java/android/graphics/LightingColorFilter.java
index ad78430..b0c145b 100644
--- a/graphics/java/android/graphics/LightingColorFilter.java
+++ b/graphics/java/android/graphics/LightingColorFilter.java
@@ -21,6 +21,8 @@
 
 package android.graphics;
 
+import android.annotation.ColorInt;
+
 /**
  * A color filter that can be used to simulate simple lighting effects.
  * A <code>LightingColorFilter</code> is defined by two parameters, one
@@ -37,7 +39,9 @@
  * The result is pinned to the <code>[0..255]</code> range for each channel.
  */
 public class LightingColorFilter extends ColorFilter {
+    @ColorInt
     private int mMul;
+    @ColorInt
     private int mAdd;
 
     /**
@@ -45,10 +49,9 @@
      * and then adds a second color. The alpha components of the mul and add
      * arguments are ignored.
      */
-    public LightingColorFilter(int mul, int add) {
+    public LightingColorFilter(@ColorInt int mul, @ColorInt int add) {
         mMul = mul;
         mAdd = add;
-        update();
     }
 
     /**
@@ -56,9 +59,8 @@
      * color filter is applied.
      *
      * @see #setColorMultiply(int)
-     *
-     * @hide
      */
+    @ColorInt
     public int getColorMultiply() {
         return mMul;
     }
@@ -69,12 +71,12 @@
      * The alpha channel of this color is ignored.
      *
      * @see #getColorMultiply()
-     *
-     * @hide
      */
-    public void setColorMultiply(int mul) {
-        mMul = mul;
-        update();
+    public void setColorMultiply(@ColorInt int mul) {
+        if (mMul != mul) {
+            mMul = mul;
+            discardNativeInstance();
+        }
     }
 
     /**
@@ -82,9 +84,8 @@
      * when the color filter is applied.
      *
      * @see #setColorAdd(int)
-     *
-     * @hide
      */
+    @ColorInt
     public int getColorAdd() {
         return mAdd;
     }
@@ -95,17 +96,17 @@
      * The alpha channel of this color is ignored.
      *
      * @see #getColorAdd()
-     *
-     * @hide
      */
-    public void setColorAdd(int add) {
-        mAdd = add;
-        update();
+    public void setColorAdd(@ColorInt int add) {
+        if (mAdd != add) {
+            mAdd = add;
+            discardNativeInstance();
+        }
     }
 
-    private void update() {
-        destroyFilter(native_instance);
-        native_instance = native_CreateLightingFilter(mMul, mAdd);
+    @Override
+    long createNativeInstance() {
+        return native_CreateLightingFilter(mMul, mAdd);
     }
 
     private static native long native_CreateLightingFilter(int mul, int add);
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 7ca4615..5d6aa8a 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -42,7 +42,8 @@
 public class Paint {
 
     private long mNativePaint;
-    private long mNativeShader = 0;
+    private long mNativeShader;
+    private long mNativeColorFilter;
 
     // The approximate size of a native paint object.
     private static final long NATIVE_PAINT_SIZE = 98;
@@ -584,6 +585,11 @@
             mNativeShader = newNativeShader;
             nSetShader(mNativePaint, mNativeShader);
         }
+        long newNativeColorFilter = mColorFilter == null ? 0 : mColorFilter.getNativeInstance();
+        if (newNativeColorFilter != mNativeColorFilter) {
+            mNativeColorFilter = newNativeColorFilter;
+            nSetColorFilter(mNativePaint, mNativeColorFilter);
+        }
         return mNativePaint;
     }
 
@@ -1044,10 +1050,13 @@
      * @return       filter
      */
     public ColorFilter setColorFilter(ColorFilter filter) {
-        long filterNative = 0;
-        if (filter != null)
-            filterNative = filter.native_instance;
-        nSetColorFilter(mNativePaint, filterNative);
+        // If mColorFilter changes, cached value of native shader aren't valid, since
+        // old shader's pointer may be reused by another shader allocation later
+        if (mColorFilter != filter) {
+            mNativeColorFilter = -1;
+        }
+
+        // Defer setting the filter natively until getNativeInstance() is called
         mColorFilter = filter;
         return filter;
     }
diff --git a/graphics/java/android/graphics/PorterDuffColorFilter.java b/graphics/java/android/graphics/PorterDuffColorFilter.java
index 69d6891..ccc6ead 100644
--- a/graphics/java/android/graphics/PorterDuffColorFilter.java
+++ b/graphics/java/android/graphics/PorterDuffColorFilter.java
@@ -24,6 +24,7 @@
  * color and a specific {@link PorterDuff Porter-Duff composite mode}.
  */
 public class PorterDuffColorFilter extends ColorFilter {
+    @ColorInt
     private int mColor;
     private PorterDuff.Mode mMode;
 
@@ -40,7 +41,6 @@
     public PorterDuffColorFilter(@ColorInt int color, @NonNull PorterDuff.Mode mode) {
         mColor = color;
         mMode = mode;
-        update();
     }
 
     /**
@@ -49,9 +49,8 @@
      *
      * @see Color
      * @see #setColor(int)
-     *
-     * @hide
      */
+    @ColorInt
     public int getColor() {
         return mColor;
     }
@@ -65,12 +64,12 @@
      * @see Color
      * @see #getColor()
      * @see #getMode()
-     *
-     * @hide
      */
-    public void setColor(int color) {
-        mColor = color;
-        update();
+    public void setColor(@ColorInt int color) {
+        if (mColor != color) {
+            mColor = color;
+            discardNativeInstance();
+        }
     }
 
     /**
@@ -79,8 +78,6 @@
      *
      * @see PorterDuff
      * @see #setMode(android.graphics.PorterDuff.Mode)
-     *
-     * @hide
      */
     public PorterDuff.Mode getMode() {
         return mMode;
@@ -93,17 +90,18 @@
      * @see PorterDuff
      * @see #getMode()
      * @see #getColor()
-     *
-     * @hide
      */
     public void setMode(@NonNull PorterDuff.Mode mode) {
+        if (mode == null) {
+            throw new IllegalArgumentException("mode must be non-null");
+        }
         mMode = mode;
-        update();
+        discardNativeInstance();
     }
 
-    private void update() {
-        destroyFilter(native_instance);
-        native_instance = native_CreatePorterDuffFilter(mColor, mMode.nativeInt);
+    @Override
+    long createNativeInstance() {
+        return native_CreatePorterDuffFilter(mColor, mMode.nativeInt);
     }
 
     @Override
@@ -115,10 +113,7 @@
             return false;
         }
         final PorterDuffColorFilter other = (PorterDuffColorFilter) object;
-        if (mColor != other.mColor || mMode != other.mMode) {
-            return false;
-        }
-        return true;
+        return (mColor == other.mColor && mMode.nativeInt == other.mMode.nativeInt);
     }
 
     @Override
diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java
index b584e0d..8410ab2 100644
--- a/graphics/java/android/graphics/Shader.java
+++ b/graphics/java/android/graphics/Shader.java
@@ -106,8 +106,10 @@
     }
 
     void discardNativeInstance() {
-        nativeSafeUnref(mNativeInstance);
-        mNativeInstance = 0;
+        if (mNativeInstance != 0) {
+            nativeSafeUnref(mNativeInstance);
+            mNativeInstance = 0;
+        }
     }
 
     /**
@@ -120,7 +122,9 @@
     @Override
     protected void finalize() throws Throwable {
         try {
-            nativeSafeUnref(mNativeInstance);
+            if (mNativeInstance != 0) {
+                nativeSafeUnref(mNativeInstance);
+            }
             mNativeInstance = -1;
         } finally {
             super.finalize();
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 95577ca..3416401 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -24,6 +24,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.Context;
 import android.content.res.AssetManager;
 import android.graphics.fonts.FontRequest;
 import android.graphics.fonts.FontResult;
@@ -88,7 +89,7 @@
     @GuardedBy("sLock")
     private static FontsContract sFontsContract;
     @GuardedBy("sLock")
-    private static Handler mHandler;
+    private static Handler sHandler;
 
     /**
      * Cache for Typeface objects dynamically loaded from assets. Currently max size is 16.
@@ -226,6 +227,20 @@
     }
 
     /**
+     * Set the application context so we can generate font requests from the provider. This should
+     * be called from ActivityThread when the application binds, as we preload fonts.
+     * @hide
+     */
+    public static void setApplicationContext(Context context) {
+        synchronized (sLock) {
+            if (sFontsContract == null) {
+                sFontsContract = new FontsContract(context);
+                sHandler = new Handler();
+            }
+        }
+    }
+
+    /**
      * Create a typeface object given a font request. The font will be asynchronously fetched,
      * therefore the result is delivered to the given callback. See {@link FontRequest}.
      * Only one of the methods in callback will be invoked, depending on whether the request
@@ -241,18 +256,17 @@
         Typeface cachedTypeface = findFromCache(
                 request.getProviderAuthority(), request.getQuery());
         if (cachedTypeface != null) {
-            mHandler.post(() -> callback.onTypefaceRetrieved(cachedTypeface));
+            sHandler.post(() -> callback.onTypefaceRetrieved(cachedTypeface));
             return;
         }
         synchronized (sLock) {
             if (sFontsContract == null) {
-                sFontsContract = new FontsContract();
-                mHandler = new Handler();
+                throw new RuntimeException("Context not initialized, can't query provider");
             }
             final ResultReceiver receiver = new ResultReceiver(null) {
                 @Override
                 public void onReceiveResult(int resultCode, Bundle resultData) {
-                    mHandler.post(() -> receiveResult(request, callback, resultCode, resultData));
+                    sHandler.post(() -> receiveResult(request, callback, resultCode, resultData));
                 }
             };
             sFontsContract.getFont(request, receiver);
diff --git a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
index 0722c18..c6c9271 100644
--- a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
+++ b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
@@ -218,6 +218,8 @@
     }
 
     /**
+     * Only call this method after bound is set on this drawable.
+     *
      * @return the mask path object used to clip the drawable
      */
     public Path getIconMask() {
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 3a12419..a1539b8 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -333,7 +333,7 @@
         // Color filters always override tint filters.
         final ColorFilter colorFilter = (mColorFilter == null ? mTintFilter : mColorFilter);
         final long colorFilterNativeInstance = colorFilter == null ? 0 :
-                colorFilter.native_instance;
+                colorFilter.getNativeInstance();
         boolean canReuseCache = mVectorState.canReuseCache();
         int pixelCount = nDraw(mVectorState.getNativeRenderer(), canvas.getNativeCanvasWrapper(),
                 colorFilterNativeInstance, mTmpBounds, needMirroring(),
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index b8d95e4..359cfac 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -4765,7 +4765,6 @@
                     && (targetTypeLen = attrPrivate.size())
             );
         }
-        break;
     }
     return 0;
 }
diff --git a/libs/androidfw/tests/data/basic/R.h b/libs/androidfw/tests/data/basic/R.h
index 8e9741e..94a2a14 100644
--- a/libs/androidfw/tests/data/basic/R.h
+++ b/libs/androidfw/tests/data/basic/R.h
@@ -44,8 +44,8 @@
       density = 0x7f030002,
 
       // From feature
-      test3 = 0x7f080000,
-      test4 = 0x7f080001,
+      test3 = 0x80020000,
+      test4 = 0x80020001,
     };
   };
 
@@ -57,7 +57,7 @@
       ref2 = 0x7f040003,
 
       // From feature
-      number3 = 0x7f090000,
+      number3 = 0x80030000,
     };
   };
 
diff --git a/libs/androidfw/tests/data/feature/AndroidManifest.xml b/libs/androidfw/tests/data/feature/AndroidManifest.xml
index c972372..12ca5b6 100644
--- a/libs/androidfw/tests/data/feature/AndroidManifest.xml
+++ b/libs/androidfw/tests/data/feature/AndroidManifest.xml
@@ -15,5 +15,6 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.basic">
+    package="com.android.basic"
+    featureName="feature">
 </manifest>
diff --git a/libs/androidfw/tests/data/feature/build b/libs/androidfw/tests/data/feature/build
index 6ed3e41..aa2f716 100755
--- a/libs/androidfw/tests/data/feature/build
+++ b/libs/androidfw/tests/data/feature/build
@@ -19,4 +19,10 @@
 
 PATH_TO_FRAMEWORK_RES=${ANDROID_BUILD_TOP}/prebuilts/sdk/current/android.jar
 
-aapt package -M AndroidManifest.xml -S res -I $PATH_TO_FRAMEWORK_RES --feature-of ../basic/basic.apk -F feature.apk -f
+aapt2 compile --dir res -o compiled.flata
+aapt2 link -o feature.apk \
+    --manifest AndroidManifest.xml \
+    -I $PATH_TO_FRAMEWORK_RES \
+    -I ../basic/basic.apk \
+    --package-id 0x80 \
+    compiled.flata
diff --git a/libs/androidfw/tests/data/feature/feature.apk b/libs/androidfw/tests/data/feature/feature.apk
index 767fed6..a0dae38 100644
--- a/libs/androidfw/tests/data/feature/feature.apk
+++ b/libs/androidfw/tests/data/feature/feature.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/feature/res/values/values.xml b/libs/androidfw/tests/data/feature/res/values/values.xml
index 59f7d93..43e1517 100644
--- a/libs/androidfw/tests/data/feature/res/values/values.xml
+++ b/libs/androidfw/tests/data/feature/res/values/values.xml
@@ -15,13 +15,12 @@
 -->
 
 <resources>
-    <!-- Features are offset, so 7f020000 will become 7f080000 at runtime. -->
-    <public type="string" name="test3" id="0x7f020000" />
+    <public type="string" name="test3" id="0x80020000" />
     <string name="test3">test3</string>
 
-    <public type="string" name="test4" id="0x7f020001" />
+    <public type="string" name="test4" id="0x80020001" />
     <string name="test4">test4</string>
 
-    <public type="integer" name="number3" id="0x7f030000" />
+    <public type="integer" name="number3" id="0x80030000" />
     <integer name="number3">200</integer>
 </resources>
diff --git a/libs/common_time/Android.mk b/libs/common_time/Android.mk
index 1fec504..636f057 100644
--- a/libs/common_time/Android.mk
+++ b/libs/common_time/Android.mk
@@ -15,7 +15,8 @@
     clock_recovery.cpp \
     common_clock.cpp \
     main.cpp \
-    utils.cpp
+    utils.cpp \
+    LinearTransform.cpp
 
 # Uncomment to enable vesbose logging and debug service.
 #TIME_SERVICE_DEBUG=true
diff --git a/libs/common_time/LinearTransform.cpp b/libs/common_time/LinearTransform.cpp
new file mode 100644
index 0000000..6730855
--- /dev/null
+++ b/libs/common_time/LinearTransform.cpp
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#define __STDC_LIMIT_MACROS
+
+#include "LinearTransform.h"
+#include <assert.h>
+
+
+// disable sanitize as these functions may intentionally overflow (see comments below).
+// the ifdef can be removed when host builds use clang.
+#if defined(__clang__)
+#define ATTRIBUTE_NO_SANITIZE_INTEGER __attribute__((no_sanitize("integer")))
+#else
+#define ATTRIBUTE_NO_SANITIZE_INTEGER
+#endif
+
+namespace android {
+
+// sanitize failure with T = int32_t and x = 0x80000000
+template<class T>
+ATTRIBUTE_NO_SANITIZE_INTEGER
+static inline T ABS(T x) { return (x < 0) ? -x : x; }
+
+// Static math methods involving linear transformations
+// remote sanitize failure on overflow case.
+ATTRIBUTE_NO_SANITIZE_INTEGER
+static bool scale_u64_to_u64(
+        uint64_t val,
+        uint32_t N,
+        uint32_t D,
+        uint64_t* res,
+        bool round_up_not_down) {
+    uint64_t tmp1, tmp2;
+    uint32_t r;
+
+    assert(res);
+    assert(D);
+
+    // Let U32(X) denote a uint32_t containing the upper 32 bits of a 64 bit
+    // integer X.
+    // Let L32(X) denote a uint32_t containing the lower 32 bits of a 64 bit
+    // integer X.
+    // Let X[A, B] with A <= B denote bits A through B of the integer X.
+    // Let (A | B) denote the concatination of two 32 bit ints, A and B.
+    // IOW X = (A | B) => U32(X) == A && L32(X) == B
+    //
+    // compute M = val * N (a 96 bit int)
+    // ---------------------------------
+    // tmp2 = U32(val) * N (a 64 bit int)
+    // tmp1 = L32(val) * N (a 64 bit int)
+    // which means
+    // M = val * N = (tmp2 << 32) + tmp1
+    tmp2 = (val >> 32) * N;
+    tmp1 = (val & UINT32_MAX) * N;
+
+    // compute M[32, 95]
+    // tmp2 = tmp2 + U32(tmp1)
+    //      = (U32(val) * N) + U32(L32(val) * N)
+    //      = M[32, 95]
+    tmp2 += tmp1 >> 32;
+
+    // if M[64, 95] >= D, then M/D has bits > 63 set and we have
+    // an overflow.
+    if ((tmp2 >> 32) >= D) {
+        *res = UINT64_MAX;
+        return false;
+    }
+
+    // Divide.  Going in we know
+    // tmp2 = M[32, 95]
+    // U32(tmp2) < D
+    r = tmp2 % D;
+    tmp2 /= D;
+
+    // At this point
+    // tmp1      = L32(val) * N
+    // tmp2      = M[32, 95] / D
+    //           = (M / D)[32, 95]
+    // r         = M[32, 95] % D
+    // U32(tmp2) = 0
+    //
+    // compute tmp1 = (r | M[0, 31])
+    tmp1 = (tmp1 & UINT32_MAX) | ((uint64_t)r << 32);
+
+    // Divide again.  Keep the remainder around in order to round properly.
+    r = tmp1 % D;
+    tmp1 /= D;
+
+    // At this point
+    // tmp2      = (M / D)[32, 95]
+    // tmp1      = (M / D)[ 0, 31]
+    // r         =  M % D
+    // U32(tmp1) = 0
+    // U32(tmp2) = 0
+
+    // Pack the result and deal with the round-up case (As well as the
+    // remote possiblility over overflow in such a case).
+    *res = (tmp2 << 32) | tmp1;
+    if (r && round_up_not_down) {
+        ++(*res);
+        if (!(*res)) {
+            *res = UINT64_MAX;
+            return false;
+        }
+    }
+
+    return true;
+}
+
+// at least one known sanitize failure (see comment below)
+ATTRIBUTE_NO_SANITIZE_INTEGER
+static bool linear_transform_s64_to_s64(
+        int64_t  val,
+        int64_t  basis1,
+        int32_t  N,
+        uint32_t D,
+        bool     invert_frac,
+        int64_t  basis2,
+        int64_t* out) {
+    uint64_t scaled, res;
+    uint64_t abs_val;
+    bool is_neg;
+
+    if (!out)
+        return false;
+
+    // Compute abs(val - basis_64). Keep track of whether or not this delta
+    // will be negative after the scale opertaion.
+    if (val < basis1) {
+        is_neg = true;
+        abs_val = basis1 - val;
+    } else {
+        is_neg = false;
+        abs_val = val - basis1;
+    }
+
+    if (N < 0)
+        is_neg = !is_neg;
+
+    if (!scale_u64_to_u64(abs_val,
+                          invert_frac ? D : ABS(N),
+                          invert_frac ? ABS(N) : D,
+                          &scaled,
+                          is_neg))
+        return false; // overflow/undeflow
+
+    // if scaled is >= 0x8000<etc>, then we are going to overflow or
+    // underflow unless ABS(basis2) is large enough to pull us back into the
+    // non-overflow/underflow region.
+    if (scaled & INT64_MIN) {
+        if (is_neg && (basis2 < 0))
+            return false; // certain underflow
+
+        if (!is_neg && (basis2 >= 0))
+            return false; // certain overflow
+
+        if (ABS(basis2) <= static_cast<int64_t>(scaled & INT64_MAX))
+            return false; // not enough
+
+        // Looks like we are OK
+        *out = (is_neg ? (-scaled) : scaled) + basis2;
+    } else {
+        // Scaled fits within signed bounds, so we just need to check for
+        // over/underflow for two signed integers.  Basically, if both scaled
+        // and basis2 have the same sign bit, and the result has a different
+        // sign bit, then we have under/overflow.  An easy way to compute this
+        // is
+        // (scaled_signbit XNOR basis_signbit) &&
+        // (scaled_signbit XOR res_signbit)
+        // ==
+        // (scaled_signbit XOR basis_signbit XOR 1) &&
+        // (scaled_signbit XOR res_signbit)
+
+        if (is_neg)
+            scaled = -scaled; // known sanitize failure
+        res = scaled + basis2;
+
+        if ((scaled ^ basis2 ^ INT64_MIN) & (scaled ^ res) & INT64_MIN)
+            return false;
+
+        *out = res;
+    }
+
+    return true;
+}
+
+bool LinearTransform::doForwardTransform(int64_t a_in, int64_t* b_out) const {
+    if (0 == a_to_b_denom)
+        return false;
+
+    return linear_transform_s64_to_s64(a_in,
+                                       a_zero,
+                                       a_to_b_numer,
+                                       a_to_b_denom,
+                                       false,
+                                       b_zero,
+                                       b_out);
+}
+
+bool LinearTransform::doReverseTransform(int64_t b_in, int64_t* a_out) const {
+    if (0 == a_to_b_numer)
+        return false;
+
+    return linear_transform_s64_to_s64(b_in,
+                                       b_zero,
+                                       a_to_b_numer,
+                                       a_to_b_denom,
+                                       true,
+                                       a_zero,
+                                       a_out);
+}
+
+template <class T> void LinearTransform::reduce(T* N, T* D) {
+    T a, b;
+    if (!N || !D || !(*D)) {
+        assert(false);
+        return;
+    }
+
+    a = *N;
+    b = *D;
+
+    if (a == 0) {
+        *D = 1;
+        return;
+    }
+
+    // This implements Euclid's method to find GCD.
+    if (a < b) {
+        T tmp = a;
+        a = b;
+        b = tmp;
+    }
+
+    while (1) {
+        // a is now the greater of the two.
+        const T remainder = a % b;
+        if (remainder == 0) {
+            *N /= b;
+            *D /= b;
+            return;
+        }
+        // by swapping remainder and b, we are guaranteeing that a is
+        // still the greater of the two upon entrance to the loop.
+        a = b;
+        b = remainder;
+    }
+};
+
+template void LinearTransform::reduce<uint64_t>(uint64_t* N, uint64_t* D);
+template void LinearTransform::reduce<uint32_t>(uint32_t* N, uint32_t* D);
+
+// sanitize failure if *N = 0x80000000
+ATTRIBUTE_NO_SANITIZE_INTEGER
+void LinearTransform::reduce(int32_t* N, uint32_t* D) {
+    if (N && D && *D) {
+        if (*N < 0) {
+            *N = -(*N);
+            reduce(reinterpret_cast<uint32_t*>(N), D);
+            *N = -(*N);
+        } else {
+            reduce(reinterpret_cast<uint32_t*>(N), D);
+        }
+    }
+}
+
+}  // namespace android
diff --git a/libs/common_time/LinearTransform.h b/libs/common_time/LinearTransform.h
new file mode 100644
index 0000000..bf6ab8e
--- /dev/null
+++ b/libs/common_time/LinearTransform.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2011 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 _LINEAR_TRANSFORM_H
+#define _LINEAR_TRANSFORM_H
+
+#include <stdint.h>
+
+namespace android {
+
+// LinearTransform defines a structure which hold the definition of a
+// transformation from single dimensional coordinate system A into coordinate
+// system B (and back again).  Values in A and in B are 64 bit, the linear
+// scale factor is expressed as a rational number using two 32 bit values.
+//
+// Specifically, let
+// f(a) = b
+// F(b) = f^-1(b) = a
+// then
+//
+// f(a) = (((a - a_zero) * a_to_b_numer) / a_to_b_denom) + b_zero;
+//
+// and
+//
+// F(b) = (((b - b_zero) * a_to_b_denom) / a_to_b_numer) + a_zero;
+//
+struct LinearTransform {
+  int64_t  a_zero;
+  int64_t  b_zero;
+  int32_t  a_to_b_numer;
+  uint32_t a_to_b_denom;
+
+  // Transform from A->B
+  // Returns true on success, or false in the case of a singularity or an
+  // overflow.
+  bool doForwardTransform(int64_t a_in, int64_t* b_out) const;
+
+  // Transform from B->A
+  // Returns true on success, or false in the case of a singularity or an
+  // overflow.
+  bool doReverseTransform(int64_t b_in, int64_t* a_out) const;
+
+  // Helpers which will reduce the fraction N/D using Euclid's method.
+  template <class T> static void reduce(T* N, T* D);
+  static void reduce(int32_t* N, uint32_t* D);
+};
+
+
+}
+
+#endif  // _LINEAR_TRANSFORM_H
diff --git a/libs/common_time/clock_recovery.h b/libs/common_time/clock_recovery.h
index 278a75e..8066a39 100644
--- a/libs/common_time/clock_recovery.h
+++ b/libs/common_time/clock_recovery.h
@@ -19,9 +19,10 @@
 
 #include <stdint.h>
 #include <common_time/ICommonClock.h>
-#include <utils/LinearTransform.h>
 #include <utils/threads.h>
 
+#include "LinearTransform.h"
+
 #ifdef TIME_SERVICE_DEBUG
 #include "diag_thread.h"
 #endif
diff --git a/libs/common_time/common_clock.cpp b/libs/common_time/common_clock.cpp
index ee326e1..aed52f1 100644
--- a/libs/common_time/common_clock.cpp
+++ b/libs/common_time/common_clock.cpp
@@ -23,7 +23,6 @@
 #include <stdint.h>
 
 #include <utils/Errors.h>
-#include <utils/LinearTransform.h>
 
 #include "common_clock.h"
 
diff --git a/libs/common_time/common_clock.h b/libs/common_time/common_clock.h
index b786fdc..5e4e5f5 100644
--- a/libs/common_time/common_clock.h
+++ b/libs/common_time/common_clock.h
@@ -20,9 +20,10 @@
 #include <stdint.h>
 
 #include <utils/Errors.h>
-#include <utils/LinearTransform.h>
 #include <utils/threads.h>
 
+#include "LinearTransform.h"
+
 namespace android {
 
 class CommonClock {
diff --git a/libs/hwui/FloatColor.h b/libs/hwui/FloatColor.h
index d8afa35..a738ba4 100644
--- a/libs/hwui/FloatColor.h
+++ b/libs/hwui/FloatColor.h
@@ -38,13 +38,14 @@
     }
 
     // "color" is a gamma-encoded sRGB color
-    // After calling this method, the color is stored as a linear color. The color
-    // is not pre-multiplied.
-    void setUnPreMultipliedSRGB(uint32_t color) {
+    // After calling this method, the color is stored as a un-premultiplied linear color
+    // if linear blending is enabled. Otherwise, the color is stored as a un-premultiplied
+    // gamma-encoded sRGB color
+    void setUnPreMultiplied(uint32_t color) {
         a = ((color >> 24) & 0xff) / 255.0f;
-        r = EOCF_sRGB(((color >> 16) & 0xff) / 255.0f);
-        g = EOCF_sRGB(((color >>  8) & 0xff) / 255.0f);
-        b = EOCF_sRGB(((color      ) & 0xff) / 255.0f);
+        r = EOCF(((color >> 16) & 0xff) / 255.0f);
+        g = EOCF(((color >>  8) & 0xff) / 255.0f);
+        b = EOCF(((color      ) & 0xff) / 255.0f);
     }
 
     bool isNotBlack() {
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index 18bfcc2..dceb285 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -189,9 +189,9 @@
         float amount, uint8_t*& dst) const {
     float oppAmount = 1.0f - amount;
     float a = start.a * oppAmount + end.a * amount;
-    *dst++ = uint8_t(a * OECF_sRGB((start.r * oppAmount + end.r * amount)) * 255.0f);
-    *dst++ = uint8_t(a * OECF_sRGB((start.g * oppAmount + end.g * amount)) * 255.0f);
-    *dst++ = uint8_t(a * OECF_sRGB((start.b * oppAmount + end.b * amount)) * 255.0f);
+    *dst++ = uint8_t(a * OECF(start.r * oppAmount + end.r * amount) * 255.0f);
+    *dst++ = uint8_t(a * OECF(start.g * oppAmount + end.g * amount) * 255.0f);
+    *dst++ = uint8_t(a * OECF(start.b * oppAmount + end.b * amount) * 255.0f);
     *dst++ = uint8_t(a * 255.0f);
 }
 
@@ -201,17 +201,14 @@
     float a = start.a * oppAmount + end.a * amount;
     float* d = (float*) dst;
 #ifdef ANDROID_ENABLE_LINEAR_BLENDING
+    // We want to stay linear
     *d++ = a * (start.r * oppAmount + end.r * amount);
     *d++ = a * (start.g * oppAmount + end.g * amount);
     *d++ = a * (start.b * oppAmount + end.b * amount);
 #else
-    // What we're doing to the alpha channel here is technically incorrect
-    // but reproduces Android's old behavior when the alpha was pre-multiplied
-    // with gamma-encoded colors
-    a = EOCF_sRGB(a);
-    *d++ = a * OECF_sRGB(start.r * oppAmount + end.r * amount);
-    *d++ = a * OECF_sRGB(start.g * oppAmount + end.g * amount);
-    *d++ = a * OECF_sRGB(start.b * oppAmount + end.b * amount);
+    *d++ = a * OECF(start.r * oppAmount + end.r * amount);
+    *d++ = a * OECF(start.g * oppAmount + end.g * amount);
+    *d++ = a * OECF(start.b * oppAmount + end.b * amount);
 #endif
     *d++ = a;
     dst += 4 * sizeof(float);
@@ -232,10 +229,10 @@
     ChannelMixer mix = gMixers[mUseFloatTexture];
 
     FloatColor start;
-    start.setUnPreMultipliedSRGB(colors[0]);
+    start.setUnPreMultiplied(colors[0]);
 
     FloatColor end;
-    end.setUnPreMultipliedSRGB(colors[1]);
+    end.setUnPreMultiplied(colors[1]);
 
     int currentPos = 1;
     float startPos = positions[0];
@@ -250,7 +247,7 @@
 
             currentPos++;
 
-            end.setUnPreMultipliedSRGB(colors[currentPos]);
+            end.setUnPreMultiplied(colors[currentPos]);
             distance = positions[currentPos] - startPos;
         }
 
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 40ab778..38c23e4 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -190,7 +190,7 @@
 // Dithering must be done in the quantization space
 // When we are writing to an sRGB framebuffer, we must do the following:
 //     EOTF(OETF(color) + dither)
-// The dithering pattern is generated with a triangle noise generator in the range [-0.0,1.0]
+// The dithering pattern is generated with a triangle noise generator in the range [-1.0,1.0]
 // TODO: Handle linear fp16 render targets
 const char* gFS_Gradient_Functions = R"__SHADER__(
         float triangleNoise(const highp vec2 n) {
@@ -202,23 +202,26 @@
 )__SHADER__";
 const char* gFS_Gradient_Preamble[2] = {
         // Linear framebuffer
-        "\nvec4 dither(const vec4 color) {\n"
-        "    return vec4(color.rgb + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0), color.a);\n"
-        "}\n"
-        "\nvec4 gammaMix(const vec4 a, const vec4 b, float v) {\n"
-        "    vec4 c = mix(a, b, v);\n"
-        "    c.a = EOTF_sRGB(c.a);\n" // This is technically incorrect but preserves compatibility
-        "    return vec4(OETF_sRGB(c.rgb) * c.a, c.a);\n"
-        "}\n",
+        R"__SHADER__(
+        vec4 dither(const vec4 color) {
+            return color + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0);
+        }
+        vec4 gradientMix(const vec4 a, const vec4 b, float v) {
+            vec4 c = mix(a, b, v);
+            return vec4(c.rgb * c.a, c.a);
+        }
+        )__SHADER__",
         // sRGB framebuffer
-        "\nvec4 dither(const vec4 color) {\n"
-        "    vec3 dithered = sqrt(color.rgb) + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0);\n"
-        "    return vec4(dithered * dithered, color.a);\n"
-        "}\n"
-        "\nvec4 gammaMix(const vec4 a, const vec4 b, float v) {\n"
-        "    vec4 c = mix(a, b, v);\n"
-        "    return vec4(c.rgb * c.a, c.a);\n"
-        "}\n"
+        R"__SHADER__(
+        vec4 dither(const vec4 color) {
+            vec3 dithered = sqrt(color.rgb) + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0);
+            return vec4(dithered * dithered, color.a);
+        }
+        vec4 gradientMixMix(const vec4 a, const vec4 b, float v) {
+            vec4 c = mix(a, b, v);
+            return vec4(c.rgb * c.a, c.a);
+        }
+        )__SHADER__",
 };
 
 // Uses luminance coefficients from Rec.709 to choose the appropriate gamma
@@ -272,19 +275,19 @@
         // Linear
         "    vec4 gradientColor = texture2D(gradientSampler, linear);\n",
 
-        "    vec4 gradientColor = gammaMix(startColor, endColor, clamp(linear, 0.0, 1.0));\n",
+        "    vec4 gradientColor = gradientMix(startColor, endColor, clamp(linear, 0.0, 1.0));\n",
 
         // Circular
         "    vec4 gradientColor = texture2D(gradientSampler, vec2(length(circular), 0.5));\n",
 
-        "    vec4 gradientColor = gammaMix(startColor, endColor, clamp(length(circular), 0.0, 1.0));\n",
+        "    vec4 gradientColor = gradientMix(startColor, endColor, clamp(length(circular), 0.0, 1.0));\n",
 
         // Sweep
         "    highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
         "    vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n",
 
         "    highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
-        "    vec4 gradientColor = gammaMix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n"
+        "    vec4 gradientColor = gradientMix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n"
 };
 const char* gFS_Main_FetchBitmap =
         "    vec4 bitmapColor = OETF(texture2D(bitmapSampler, outBitmapTexCoords));\n";
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 760c10c..4f7f9d7 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -173,8 +173,8 @@
         outData->gradientSampler = 0;
         outData->gradientTexture = nullptr;
 
-        outData->startColor.setUnPreMultipliedSRGB(gradInfo.fColors[0]);
-        outData->endColor.setUnPreMultipliedSRGB(gradInfo.fColors[1]);
+        outData->startColor.setUnPreMultiplied(gradInfo.fColors[0]);
+        outData->endColor.setUnPreMultiplied(gradInfo.fColors[1]);
     }
 
     return true;
diff --git a/libs/hwui/VkLayer.cpp b/libs/hwui/VkLayer.cpp
index 537b3ea..ef4784b 100644
--- a/libs/hwui/VkLayer.cpp
+++ b/libs/hwui/VkLayer.cpp
@@ -29,7 +29,7 @@
     SkImageInfo info = SkImageInfo::MakeS32(mWidth, mHeight, kPremul_SkAlphaType);
     surface = SkSurface::MakeRenderTarget(mRenderState.getGrContext(), SkBudgeted::kNo, info);
     surface->getCanvas()->clear(SK_ColorBLUE);
-    mImage = surface->makeImageSnapshot(SkBudgeted::kNo);
+    mImage = surface->makeImageSnapshot();
 }
 
 void VkLayer::onVkContextDestroyed() {
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index d264127..13a22b4 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -23,6 +23,7 @@
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
 import android.media.MediaCodecInfo.CodecCapabilities;
+import android.media.MediaMetricsSet;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -3186,59 +3187,22 @@
     public native final String getName();
 
     /**
-     *  Returns Analytics/Metrics data about the current content being
+     *  Return Metrics data about the current codec instance.
      *
-     * @return a Bundle containing the set of attributes and values available
-     * for the media being handled by this instance of MediaCodec
+     * @return a MediaMetricsSet containing the set of attributes and values
+     * available for the media being handled by this instance of MediaCodec
+     * The attributes are descibed in {@link MediaMetricsSet.MediaCodec}.
      *
-     *  <table style="width: 0%">
-     *   <thead>
-     *    <tr>
-     *     <th>Key</th>
-     *     <th>Type</th>
-     *     <th>Description</th>
-     *    </tr>
-     *   </thead>
-     *   <tbody>
-     *    <tr>
-     *     <td>{@code "codec"}</td>
-     *     <td>String</td>
-     *     <td>Identifies the particular codec in use</td>
-     *    </tr><tr>
-     *     <td>{@code "mime"}</td>
-     *     <td>String</td>
-     *     <td>Mime type of the media being encoded/decoded</td>
-     *    </tr><tr>
-     *     <td>{@code "mode"}</td>
-     *     <td>String</td>
-     *     <td>"Audio" or "Video"</td>
-     *    </tr><tr>
-     *     <td>{@code "secure"}</td>
-     *     <td>Integer</td>
-     *     <td>Indicates whether the code is operating on secure content and
-     *         may also use capabilities in android.media.MediaCrypto</td>
-     *    </tr><tr>
-     *     <td>{@code "height"}</td>
-     *     <td>Integer</td>
-     *     <td>Height (pixels); valid only when mode=video</td>
-     *    </tr><tr>
-     *     <td>{@code "width"}</td>
-     *     <td>Integer</td>
-     *     <td>Width (pixels); valid only when mode=video</td>
-     *    </tr><tr>
-     *     <td>{@code "rotation"}</td>
-     *     <td>Integer</td>
-     *     <td>rotation (degrees) to orient the video onto the target surface;
-     *         valid only when mode=video. Note there may be additional
-     *         rotations applied when the surface is mapped to the screen.</td>
-     *    </tr>
-     *   </tbody>
-     *  </table>
-     *
-     *  Additional fields specific to individual codecs will also appear in
+     *  Additional vendor-specific fields may also be present in
      *  the return value.
      */
-    public native Bundle getMetrics();
+    public MediaMetricsSet getMetrics() {
+        Bundle bundle = native_getMetrics();
+	MediaMetricsSet mSet = new MediaMetricsSet(bundle);
+	return mSet;
+    }
+
+    private native Bundle native_getMetrics();
 
     /**
      * Change a video encoder's target bitrate on the fly. The value is an
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index b9e409d..2ed6668 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -25,6 +25,7 @@
 import android.media.MediaCodec;
 import android.media.MediaFormat;
 import android.media.MediaHTTPService;
+import android.media.MediaMetricsSet;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -651,41 +652,24 @@
     public native boolean hasCacheReachedEndOfStream();
 
     /**
-     *  Returns Analytics/Metrics data about the current media container.
+     *  Return Metrics data about the current media container.
      *
-     * @return the set of keys and values available for the media being
-     * handled by this instance of MediaExtractor
+     * @return a MediaMetricsSet containing the set of attributes and values
+     * available for the media container being handled by this instance
+     * of MediaExtractor.
+     * The attributes are descibed in {@link MediaMetricsSet.MediaExtractor}.
      *
-     *  <table style="width: 0%">
-     *   <thead>
-     *    <tr>
-     *     <th>Key</th>
-     *     <th>Type</th>
-     *     <th>Description</th>
-     *    </tr>
-     *   </thead>
-     *   <tbody>
-     *    <tr>
-     *     <td>{@code "fmt"}</td>
-     *     <td>String</td>
-     *     <td>The container format (which determines the handler)</td>
-     *    </tr><tr>
-     *     <td>{@code "mime"}</td>
-     *     <td>String</td>
-     *     <td>Mime type of the container.</td>
-     *    </tr><tr>
-     *     <td>{@code "ntrk"}</td>
-     *     <td>Integer</td>
-     *     <td>Number of tracks in the container</td>
-     *    </tr>
-     *   </tbody>
-     *  </table>
-     *
-     *  Additional fields specific to individual codecs will also appear in
+     *  Additional vendor-specific fields may also be present in
      *  the return value.
      */
-    public native Bundle getMetrics();
 
+    public MediaMetricsSet getMetrics() {
+        Bundle bundle = native_getMetrics();
+	MediaMetricsSet mSet = new MediaMetricsSet(bundle);
+	return mSet;
+    }
+
+    private native Bundle native_getMetrics();
 
     private static native final void native_init();
     private native final void native_setup();
diff --git a/media/java/android/media/MediaMetricsSet.java b/media/java/android/media/MediaMetricsSet.java
new file mode 100644
index 0000000..5ecbee2
--- /dev/null
+++ b/media/java/android/media/MediaMetricsSet.java
@@ -0,0 +1,491 @@
+/*
+ * 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.media;
+
+import android.os.Bundle;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.Runnable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
+import java.net.HttpCookie;
+import java.net.HttpURLConnection;
+import java.net.InetSocketAddress;
+import java.net.URL;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Scanner;
+import java.util.Set;
+import java.util.UUID;
+import java.util.Vector;
+
+
+/**
+ * MediaMetricsSet contains the results returned by the getMetrics()
+ * methods defined in other Media classes such as
+ * {@link MediaCodec}, {@link MediaExtractor}, {@link MediaPlayer},
+ * and {@link MediaRecorder}.
+ *
+ * MediaMetricsSet behaves similarly to a {@link Bundle}. It contains
+ * a set of keys and values.
+ * Methods such as {@link #getInt} and {@link #getString} are provided
+ * to extract values of the corresponding types.
+ * The {@link #keySet} method can be used to discover all of the keys
+ * that are present in the particular instance.
+ *
+ */
+public final class MediaMetricsSet
+{
+
+    /**
+     * This MediaCodec class holds the constants defining keys related to
+     * the metrics for a MediaCodec.
+     */
+    public final static class MediaCodec
+    {
+        private MediaCodec() {}
+
+        /**
+         * Key to extract the codec being used
+         * from the {@link MediaCodec#getMetrics} return value.
+         * The value is a String.
+         */
+        public static final String KEY_CODEC = "android.media.mediacodec.codec";
+
+        /**
+         * Key to extract the MIME type
+         * from the {@link MediaCodec#getMetrics} return value.
+         * The value is a String.
+         */
+        public static final String KEY_MIME = "android.media.mediacodec.mime";
+
+        /**
+         * Key to extract what the codec mode
+         * from the {@link MediaCodec#getMetrics} return value.
+         * The value is a String. Values will be one of the constants
+	 * MODE_AUDIO or MODE_VIDEO.
+         */
+        public static final String KEY_MODE = "android.media.mediacodec.mode";
+
+	/**
+	 * The value returned for the key {@link #KEY_MODE} when the
+	 * codec is a audio codec.
+	 */
+        public static final String MODE_AUDIO = "audio";
+
+	/**
+	 * The value returned for the key {@link #KEY_MODE} when the
+	 * codec is a video codec.
+	 */
+        public static final String MODE_VIDEO = "video";
+
+        /**
+         * Key to extract the flag indicating whether the codec is running
+         * as an encoder or decoder from the {@link MediaCodec#getMetrics} return value.
+         * The value is an integer.
+         * A 0 indicates decoder; 1 indicates encoder.
+         */
+        public static final String KEY_ENCODER = "android.media.mediacodec.encoder";
+
+        /**
+         * Key to extract the flag indicating whether the codec is running
+         * in secure (DRM) mode from the {@link MediaCodec#getMetrics} return value.
+         * The value is an integer.
+         */
+        public static final String KEY_SECURE = "android.media.mediacodec.secure";
+
+        /**
+         * Key to extract the width (in pixels) of the video track
+         * from the {@link MediaCodec#getMetrics} return value.
+         * The value is an integer.
+         */
+        public static final String KEY_WIDTH = "android.media.mediacodec.width";
+
+        /**
+         * Key to extract the height (in pixels) of the video track
+         * from the {@link MediaCodec#getMetrics} return value.
+         * The value is an integer.
+         */
+        public static final String KEY_HEIGHT = "android.media.mediacodec.height";
+
+        /**
+         * Key to extract the rotation (in degrees) to properly orient the video
+         * from the {@link MediaCodec#getMetrics} return.
+         * The value is a integer.
+         */
+        public static final String KEY_ROTATION = "android.media.mediacodec.rotation";
+
+    }
+
+    /**
+     * This class holds the constants defining keys related to
+     * the metrics for a MediaExtractor.
+     */
+    public final static class MediaExtractor
+    {
+        private MediaExtractor() {}
+
+        /**
+         * Key to extract the container format
+         * from the {@link MediaExtractor#getMetrics} return value.
+         * The value is a String.
+         */
+        public static final String KEY_FORMAT = "android.media.mediaextractor.fmt";
+
+        /**
+         * Key to extract the container MIME type
+         * from the {@link MediaExtractor#getMetrics} return value.
+         * The value is a String.
+         */
+        public static final String KEY_MIME = "android.media.mediaextractor.mime";
+
+        /**
+         * Key to extract the number of tracks in the container
+         * from the {@link MediaExtractor#getMetrics} return value.
+         * The value is an integer.
+         */
+        public static final String KEY_TRACKS = "android.media.mediaextractor.ntrk";
+
+    }
+
+    /**
+     * This class holds the constants defining keys related to
+     * the metrics for a MediaPlayer.
+     */
+    public final static class MediaPlayer
+    {
+        private MediaPlayer() {}
+
+        /**
+         * Key to extract the MIME type of the video track
+         * from the {@link MediaPlayer#getMetrics} return value.
+         * The value is a String.
+         */
+        public static final String KEY_MIME_VIDEO = "android.media.mediaplayer.video.mime";
+
+        /**
+         * Key to extract the codec being used to decode the video track
+         * from the {@link MediaPlayer#getMetrics} return value.
+         * The value is a String.
+         */
+        public static final String KEY_CODEC_VIDEO = "android.media.mediaplayer.video.codec";
+
+        /**
+         * Key to extract the width (in pixels) of the video track
+         * from the {@link MediaPlayer#getMetrics} return value.
+         * The value is an integer.
+         */
+        public static final String KEY_WIDTH = "android.media.mediaplayer.width";
+
+        /**
+         * Key to extract the height (in pixels) of the video track
+         * from the {@link MediaPlayer#getMetrics} return value.
+         * The value is an integer.
+         */
+        public static final String KEY_HEIGHT = "android.media.mediaplayer.height";
+
+        /**
+         * Key to extract the count of video frames played
+         * from the {@link MediaPlayer#getMetrics} return value.
+         * The value is an integer.
+         */
+        public static final String KEY_FRAMES = "android.media.mediaplayer.frames";
+
+        /**
+         * Key to extract the count of video frames dropped
+         * from the {@link MediaPlayer#getMetrics} return value.
+         * The value is an integer.
+         */
+        public static final String KEY_FRAMES_DROPPED = "android.media.mediaplayer.dropped";
+
+        /**
+         * Key to extract the MIME type of the audio track
+         * from the {@link MediaPlayer#getMetrics} return value.
+         * The value is a String.
+         */
+        public static final String KEY_MIME_AUDIO = "android.media.mediaplayer.audio.mime";
+
+        /**
+         * Key to extract the codec being used to decode the audio track
+         * from the {@link MediaPlayer#getMetrics} return value.
+         * The value is a String.
+         */
+        public static final String KEY_CODEC_AUDIO = "android.media.mediaplayer.audio.codec";
+
+        /**
+         * Key to extract the duration (in milliseconds) of the
+         * media being played
+         * from the {@link MediaPlayer#getMetrics} return value.
+         * The value is a long.
+         */
+        public static final String KEY_DURATION = "android.media.mediaplayer.durationMs";
+
+        /**
+         * Key to extract the playing time (in milliseconds) of the
+         * media being played
+         * from the {@link MediaPlayer#getMetrics} return value.
+         * The value is a long.
+         */
+        public static final String KEY_PLAYING = "android.media.mediaplayer.playingMs";
+
+        /**
+         * Key to extract the count of errors encountered while
+         * playing the media
+         * from the {@link MediaPlayer#getMetrics} return value.
+         * The value is an integer.
+         */
+        public static final String KEY_ERRORS = "android.media.mediaplayer.err";
+
+        /**
+         * Key to extract an (optional) error code detected while
+         * playing the media
+         * from the {@link MediaPlayer#getMetrics} return value.
+         * The value is an integer.
+         */
+        public static final String KEY_ERROR_CODE = "android.media.mediaplayer.errcode";
+
+    }
+
+    /**
+     * This class holds the constants defining keys related to
+     * the metrics for a MediaRecorder.
+     */
+    public final static class MediaRecorder
+    {
+        private MediaRecorder() {}
+
+        /**
+         * Key to extract the audio bitrate
+         * from the {@link MediaRecorder#getMetrics} return.
+         * The value is an integer.
+         */
+        public static final String KEY_AUDIO_BITRATE = "android.media.mediarecorder.audio-bitrate";
+
+        /**
+         * Key to extract the number of audio channels
+         * from the {@link MediaRecorder#getMetrics} return.
+         * The value is an integer.
+         */
+        public static final String KEY_AUDIO_CHANNELS = "android.media.mediarecorder.audio-channels";
+
+        /**
+         * Key to extract the audio samplerate
+         * from the {@link MediaRecorder#getMetrics} return.
+         * The value is an integer.
+         */
+        public static final String KEY_AUDIO_SAMPLERATE = "android.media.mediarecorder.audio-samplerate";
+
+        /**
+         * Key to extract the audio timescale
+         * from the {@link MediaRecorder#getMetrics} return.
+         * The value is an integer.
+         */
+        public static final String KEY_AUDIO_TIMESCALE = "android.media.mediarecorder.audio-timescale";
+
+        /**
+         * Key to extract the video capture frame rate
+         * from the {@link MediaRecorder#getMetrics} return.
+         * The value is a double.
+         */
+        public static final String KEY_CAPTURE_FPS = "android.media.mediarecorder.capture-fps";
+
+        /**
+         * Key to extract the video capture framerate enable value
+         * from the {@link MediaRecorder#getMetrics} return.
+         * The value is an integer.
+         */
+        public static final String KEY_CAPTURE_FPS_ENABLE = "android.media.mediarecorder.capture-fpsenable";
+
+        /**
+         * Key to extract the intended playback frame rate
+         * from the {@link MediaRecorder#getMetrics} return.
+         * The value is an integer.
+         */
+        public static final String KEY_FRAMERATE = "android.media.mediarecorder.frame-rate";
+
+        /**
+         * Key to extract the height (in pixels) of the captured video
+         * from the {@link MediaRecorder#getMetrics} return.
+         * The value is an integer.
+         */
+        public static final String KEY_HEIGHT = "android.media.mediarecorder.height";
+
+        /**
+         * Key to extract the recorded movies time units
+         * from the {@link MediaRecorder#getMetrics} return.
+         * The value is an integer.
+         * A value of 1000 indicates that the movie's timing is in milliseconds.
+         */
+        public static final String KEY_MOVIE_TIMESCALE = "android.media.mediarecorder.movie-timescale";
+
+        /**
+         * Key to extract the rotation (in degrees) to properly orient the video
+         * from the {@link MediaRecorder#getMetrics} return.
+         * The value is an integer.
+         */
+        public static final String KEY_ROTATION = "android.media.mediarecorder.rotation";
+
+        /**
+         * Key to extract the video bitrate from being used
+         * from the {@link MediaRecorder#getMetrics} return.
+         * The value is an integer.
+         */
+        public static final String KEY_VIDEO_BITRATE = "android.media.mediarecorder.video-bitrate";
+
+        /**
+         * Key to extract the value for how often video iframes are generated
+         * from the {@link MediaRecorder#getMetrics} return.
+         * The value is an integer.
+         */
+        public static final String KEY_VIDEO_IFRAME_INTERVAL = "android.media.mediarecorder.video-iframe-interval";
+
+        /**
+         * Key to extract the video encoding level
+         * from the {@link MediaRecorder#getMetrics} return.
+         * The value is an integer.
+         */
+        public static final String KEY_VIDEO_LEVEL = "android.media.mediarecorder.video-encoder-level";
+
+        /**
+         * Key to extract the video encoding profile
+         * from the {@link MediaRecorder#getMetrics} return.
+         * The value is an integer.
+         */
+        public static final String KEY_VIDEO_PROFILE = "android.media.mediarecorder.video-encoder-profile";
+
+        /**
+         * Key to extract the recorded video time units
+         * from the {@link MediaRecorder#getMetrics} return.
+         * The value is an integer.
+         * A value of 1000 indicates that the video's timing is in milliseconds.
+         */
+        public static final String KEY_VIDEO_TIMESCALE = "android.media.mediarecorder.video-timescale";
+
+        /**
+         * Key to extract the width (in pixels) of the captured video
+         * from the {@link MediaRecorder#getMetrics} return.
+         * The value is an integer.
+         */
+        public static final String KEY_WIDTH = "android.media.mediarecorder.width";
+
+    }
+
+    /*
+     * Methods that we want
+     */
+
+    private Bundle mBundle;
+
+    MediaMetricsSet(Bundle bundle) {
+        mBundle = bundle;
+    }
+
+    /**
+     * Returns the number of mappings contained in this Bundle.
+     *
+     * @return the number of mappings as an int.
+     */
+    public int size() {
+        return mBundle.size();
+    }
+
+    /**
+     * Returns true if the mapping of this MediaMetricsSet is empty,
+     * false otherwise.
+     */
+    public boolean isEmpty() {
+        return mBundle.isEmpty();
+    }
+
+    /**
+     * Returns the value associated with the given key, or defaultValue if
+     * no mapping of the desired type exists for the given key.
+     *
+     * @param key a String
+     * @param defaultValue Value to return if key does not exist
+     * @return a double value
+     */
+    public double getDouble(String key, double defaultValue) {
+        return mBundle.getDouble(key, defaultValue);
+    }
+
+    /**
+     * Returns the value associated with the given key, or defaultValue if
+     * no mapping of the desired type exists for the given key.
+     *
+     * @param key a String
+     * @param defaultValue Value to return if key does not exist
+     * @return an int value
+     */
+    public int getInt(String key, int defaultValue) {
+        return mBundle.getInt(key, defaultValue);
+    }
+
+    /**
+     * Returns the value associated with the given key, or defaultValue if
+     * no mapping of the desired type exists for the given key.
+     *
+     * @param key a String
+     * @param defaultValue Value to return if key does not exist
+     * @return a long value
+     */
+    public long getLong(String key, long defaultValue) {
+        return mBundle.getLong(key, defaultValue);
+    }
+
+    /**
+     * Returns the value associated with the given key, or defaultValue if
+     * no mapping of the desired type exists for the given key or if a null
+     * value is explicitly associated with the given key.
+     *
+     * @param key a String
+     * @param defaultValue Value to return if key does not exist or if a null
+     *     value is associated with the given key.
+     * @return the String value associated with the given key, or defaultValue
+     *     if no valid String object is currently mapped to that key.
+     */
+    public String getString(String key, String defaultValue) {
+        return mBundle.getString(key, defaultValue);
+    }
+
+    /**
+     * Returns a Set containing the Strings used as keys in this Bundle.
+     *
+     * @return a Set of String keys
+     */
+    public Set<String> keySet() {
+        return mBundle.keySet();
+    }
+
+
+
+    public String toString() {
+        return mBundle.toString();
+    }
+
+}
+
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index b85c911..1ee05b8 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -49,6 +49,7 @@
 import android.media.BufferingParams;
 import android.media.MediaDrm;
 import android.media.MediaFormat;
+import android.media.MediaMetricsSet;
 import android.media.MediaTimeProvider;
 import android.media.PlaybackParams;
 import android.media.SubtitleController;
@@ -1494,70 +1495,22 @@
     public native int getVideoHeight();
 
     /**
-     *  Returns Analytics/Metrics data about the current video in this player.
+     * Return Metrics data about the current player.
      *
-     * @return the a map of attributes and values available for this video
-     * player or null if no metrics are available.
+     * @return a MediaMetricsSet containing the set of attributes and values
+     * available for the media being handled by this instance of MediaPlayer
+     * The attributes are descibed in {@link MediaMetricsSet.MediaPlayer}.
      *
-     *  <table style="width: 0%">
-     *   <thead>
-     *    <tr>
-     *     <th>Key</th>
-     *     <th>Type</th>
-     *     <th>Description</th>
-     *    </tr>
-     *   </thead>
-     *   <tbody>
-     *    <tr>
-     *     <td>{@code "video/codec"}</td>
-     *     <td>String</td>
-     *     <td>Identifies the video codec in use</td>
-     *    </tr><tr>
-     *     <td>{@code "video/mime"}</td>
-     *     <td>String</td>
-     *     <td>Mime type of the video being encoded/decoded</td>
-     *    </tr><tr>
-     *     <td>{@code "audio/codec"}</td>
-     *     <td>String</td>
-     *     <td>Identifies the audio codec in use</td>
-     *    </tr><tr>
-     *     <td>{@code "audio/mime"}</td>
-     *     <td>String</td>
-     *     <td>Mime type of the audio being encoded/decoded</td>
-     *    </tr><tr>
-     *     <td>{@code "ht"}</td>
-     *     <td>Integer</td>
-     *     <td>Height (pixels); valid only when mode=video</td>
-     *    </tr><tr>
-     *     <td>{@code "wid"}</td>
-     *     <td>Integer</td>
-     *     <td>Width (pixels); valid only when mode=video</td>
-     *    </tr><tr>
-     *     <td>{@code "frame"}</td>
-     *     <td>Integer</td>
-     *     <td>Number of decoded video frames sent to the display</td>
-     *    </tr><tr>
-     *     <td>{@code "dropped"}</td>
-     *     <td>Integer</td>
-     *     <td>Number of decoded video frames that were not sent to display.
-     *         These frames were dropped by the player.</td>
-     *    </tr><tr>
-     *     <td>{@code "durationMs"}</td>
-     *     <td>Integer</td>
-     *     <td>The length of the media being played (in ms), e.g. "This video lasts for 30000 milliseconds". </td>
-     *    </tr><tr>
-     *     <td>{@code "playingMs"}</td>
-     *     <td>Integer</td>
-     *     <td>The time the media has been played (in ms). If you watch a
-     *         30 second twice through, this will report 60000 ms.</td>
-     *    </tr>
-     *   </tbody>
-     *  </table>
-     *
-     *  Additional fields specific to individual codecs will also appear in
+     *  Additional vendor-specific fields may also be present in
      *  the return value.
      */
-    public native Bundle getMetrics();
+    public MediaMetricsSet getMetrics() {
+        Bundle bundle = native_getMetrics();
+	MediaMetricsSet mSet = new MediaMetricsSet(bundle);
+	return mSet;
+    }
+
+    private native Bundle native_getMetrics();
 
     /**
      * Checks whether the MediaPlayer is playing.
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 075a84f..cdc1d60 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -20,6 +20,7 @@
 import android.annotation.SystemApi;
 import android.app.ActivityThread;
 import android.hardware.Camera;
+import android.media.MediaMetricsSet;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -1259,91 +1260,23 @@
     private native void setParameter(String nameValuePair);
 
     /**
-     * Returns Metrics data about the current media container.
+     *  Return Metrics data about the current Mediarecorder instance.
      *
-     * @return the set of keys and values available for the media being
-     * handled by this instance of MediaExtractor. The keys, data types,
-     * and meaning are described in the following table.
+     * @return a MediaMetricsSet containing the set of attributes and values
+     * available for the media being generated by this instance of
+     * MediaRecorder.
+     * The attributes are descibed in {@link MediaMetricsSet.MediaRecorder}.
      *
-     *  <table style="width: 0%">
-     *   <thead>
-     *    <tr>
-     *     <th>Key</th>
-     *     <th>Type</th>
-     *     <th>Description</th>
-     *    </tr>
-     *   </thead>
-     *   <tbody>
-     *    <tr>
-     *     <td>{@code "ht"}</td>
-     *     <td>Integer</td>
-     *     <td>Height of the recorded video (pixels)</td>
-     *    </tr><tr>
-     *     <td>{@code "wid"}</td>
-     *     <td>Integer</td>
-     *     <td>Width of the recorded video (pixels)</td>
-     *    </tr><tr>
-     *     <td>{@code "frame-rate"}</td>
-     *     <td>Integer</td>
-     *     <td>Framerate of captured Video (frames per second)</td>
-     *    </tr><tr>
-     *     <td>{@code "video-bitrate"}</td>
-     *     <td>Integer</td>
-     *     <td>Bit rate of encoded video (bits per second)</td>
-     *    </tr><tr>
-     *     <td>{@code "video-iframe-interval"}</td>
-     *     <td>Integer</td>
-     *     <td>Interval between encoded IFrames (seconds)</td>
-     *    </tr><tr>
-     *     <td>{@code "video-timescale"}</td>
-     *     <td>Integer</td>
-     *     <td></td>
-     *    </tr><tr>
-     *     <td>{@code "video-encoder-profile"}</td>
-     *     <td>Integer</td>
-     *     <td>Video Encoder Profile, as defined in OpenMAX IL</td>
-     *    </tr><tr>
-     *     <td>{@code "video-encoder-level"}</td>
-     *     <td>Integer</td>
-     *     <td>Video Encoder Level, as defined in OpenMAX IL</td>
-     *    </tr><tr>
-     *     <td>{@code "audio-bitrate"}</td>
-     *     <td>Integer</td>
-     *     <td>Bitrate of encoded audio (bits per second)</td>
-     *    </tr><tr>
-     *     <td>{@code "audio-samplerate"}</td>
-     *     <td>Integer</td>
-     *     <td></td>
-     *    </tr><tr>
-     *     <td>{@code "audio-channels"}</td>
-     *     <td>Integer</td>
-     *     <td>Number of Audio Channels Captured</td>
-     *    </tr><tr>
-     *     <td>{@code "audio-timescale"}</td>
-     *     <td>Integer</td>
-     *     <td></td>
-     *    </tr><tr>
-     *     <td>{@code "movie-timescale"}</td>
-     *     <td>Integer</td>
-     *     <td></td>
-     *    </tr><tr>
-     *     <td>{@code "movie-timescale"}</td>
-     *     <td>Integer</td>
-     *     <td></td>
-     *    </tr><tr>
-     *     <td>{@code "capture-fps"}</td>
-     *     <td>Integer</td>
-     *     <td></td>
-     *    </tr><tr>
-     *     <td>{@code "rotation"}</td>
-     *     <td>Integer</td>
-     *     <td>Orientation of the Video (degrees)</td>
-     *    </tr>
-     *   </tbody>
-     *  </table>
+     *  Additional vendor-specific fields may also be present in
+     *  the return value.
      */
+    public MediaMetricsSet getMetrics() {
+        Bundle bundle = native_getMetrics();
+	MediaMetricsSet mSet = new MediaMetricsSet(bundle);
+	return mSet;
+    }
 
-    public native Bundle getMetrics();
+    private native Bundle native_getMetrics();
 
     @Override
     protected void finalize() { native_finalize(); }
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 62fd395..c28aa5e 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -1807,6 +1807,9 @@
          * {@link #TYPE_S_DMB}, and
          * {@link #TYPE_T_DMB}.
          *
+         * <p>This value cannot be changed once it's set. Trying to modify it will make the update
+         * fail.
+         *
          * <p>This is a required field.
          *
          * <p>Type: TEXT
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 293e5dd..a8dd313 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -624,7 +624,7 @@
     return OK;
 }
 
-status_t JMediaCodec::getMetrics(JNIEnv *, Parcel *reply) const {
+status_t JMediaCodec::getMetrics(JNIEnv *, MediaAnalyticsItem * &reply) const {
 
     status_t status = mCodec->getMetrics(reply);
     return status;
@@ -1666,9 +1666,9 @@
 }
 
 static jobject
-android_media_MediaCodec_getMetrics(JNIEnv *env, jobject thiz)
+android_media_MediaCodec_native_getMetrics(JNIEnv *env, jobject thiz)
 {
-    ALOGV("android_media_MediaCodec_getMetrics");
+    ALOGV("android_media_MediaCodec_native_getMetrics");
 
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
     if (codec == NULL ) {
@@ -1677,16 +1677,14 @@
     }
 
     // get what we have for the metrics from the codec
-    Parcel reply;
-    status_t err = codec->getMetrics(env, &reply);
+    MediaAnalyticsItem *item = NULL;
+
+    status_t err = codec->getMetrics(env, item);
     if (err != OK) {
         ALOGE("getMetrics failed");
         return (jobject) NULL;
     }
 
-    // build and return the Bundle
-    MediaAnalyticsItem *item = new MediaAnalyticsItem;
-    item->readFromParcel(reply);
     jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL);
 
     // housekeeping
@@ -2004,8 +2002,8 @@
     { "getName", "()Ljava/lang/String;",
       (void *)android_media_MediaCodec_getName },
 
-    { "getMetrics", "()Landroid/os/Bundle;",
-      (void *)android_media_MediaCodec_getMetrics},
+    { "native_getMetrics", "()Landroid/os/Bundle;",
+      (void *)android_media_MediaCodec_native_getMetrics},
 
     { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V",
       (void *)android_media_MediaCodec_setParameters },
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index a8c76c5..c9a1700 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -19,6 +19,7 @@
 
 #include "jni.h"
 
+#include <media/MediaAnalyticsItem.h>
 #include <media/hardware/CryptoAPI.h>
 #include <media/stagefright/foundation/ABase.h>
 #include <media/stagefright/foundation/AHandler.h>
@@ -116,7 +117,7 @@
 
     status_t getName(JNIEnv *env, jstring *name) const;
 
-    status_t getMetrics(JNIEnv *env, Parcel *reply) const;
+    status_t getMetrics(JNIEnv *env, MediaAnalyticsItem * &reply) const;
 
     status_t setParameters(const sp<AMessage> &params);
 
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index 3c33493..c2cfed9 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -811,9 +811,9 @@
 }
 
 static jobject
-android_media_MediaExtractor_getMetrics(JNIEnv * env, jobject thiz)
+android_media_MediaExtractor_native_getMetrics(JNIEnv * env, jobject thiz)
 {
-    ALOGV("android_media_MediaExtractor_getMetrics");
+    ALOGV("android_media_MediaExtractor_native_getMetrics");
 
     sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
     if (extractor == NULL ) {
@@ -905,8 +905,8 @@
     { "hasCacheReachedEndOfStream", "()Z",
       (void *)android_media_MediaExtractor_hasCacheReachedEOS },
 
-    {"getMetrics",          "()Landroid/os/Bundle;",
-      (void *)android_media_MediaExtractor_getMetrics},
+    {"native_getMetrics",          "()Landroid/os/Bundle;",
+      (void *)android_media_MediaExtractor_native_getMetrics},
 };
 
 int register_android_media_MediaExtractor(JNIEnv *env) {
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 27724a1..1b52cf5 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -708,7 +708,7 @@
 }
 
 static jobject
-android_media_MediaPlayer_getMetrics(JNIEnv *env, jobject thiz)
+android_media_MediaPlayer_native_getMetrics(JNIEnv *env, jobject thiz)
 {
     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
     if (mp == NULL ) {
@@ -1393,7 +1393,7 @@
     {"_stop",               "()V",                              (void *)android_media_MediaPlayer_stop},
     {"getVideoWidth",       "()I",                              (void *)android_media_MediaPlayer_getVideoWidth},
     {"getVideoHeight",      "()I",                              (void *)android_media_MediaPlayer_getVideoHeight},
-    {"getMetrics",          "()Landroid/os/Bundle;",            (void *)android_media_MediaPlayer_getMetrics},
+    {"native_getMetrics",          "()Landroid/os/Bundle;",            (void *)android_media_MediaPlayer_native_getMetrics},
     {"setPlaybackParams", "(Landroid/media/PlaybackParams;)V", (void *)android_media_MediaPlayer_setPlaybackParams},
     {"getPlaybackParams", "()Landroid/media/PlaybackParams;", (void *)android_media_MediaPlayer_getPlaybackParams},
     {"setSyncParams",     "(Landroid/media/SyncParams;)V",  (void *)android_media_MediaPlayer_setSyncParams},
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 77544eb..7a63e00 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -628,9 +628,9 @@
 }
 
 static jobject
-android_media_MediaRecorder_getMetrics(JNIEnv *env, jobject thiz)
+android_media_MediaRecorder_native_getMetrics(JNIEnv *env, jobject thiz)
 {
-    ALOGV("android_media_MediaRecorder_getMetrics");
+    ALOGV("android_media_MediaRecorder_native_getMetrics");
 
     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
     if (mr == NULL) {
@@ -688,7 +688,7 @@
     {"native_finalize",      "()V",                             (void *)android_media_MediaRecorder_native_finalize},
     {"native_setInputSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaRecorder_setInputSurface },
 
-    {"getMetrics",          "()Landroid/os/Bundle;",            (void *)android_media_MediaRecorder_getMetrics},
+    {"native_getMetrics",          "()Landroid/os/Bundle;",            (void *)android_media_MediaRecorder_native_getMetrics},
 };
 
 // This function only registers the native methods, and is called from
diff --git a/packages/MtpDocumentsProvider/tests/Android.mk b/packages/MtpDocumentsProvider/tests/Android.mk
index e50d6fb..148cd0d 100644
--- a/packages/MtpDocumentsProvider/tests/Android.mk
+++ b/packages/MtpDocumentsProvider/tests/Android.mk
@@ -8,5 +8,6 @@
 LOCAL_PACKAGE_NAME := MtpDocumentsProviderTests
 LOCAL_INSTRUMENTATION_FOR := MtpDocumentsProvider
 LOCAL_CERTIFICATE := media
+LOCAL_COMPATIBILITY_SUITE := device-tests
 
 include $(BUILD_PACKAGE)
diff --git a/packages/PrintSpooler/tests/outofprocess/Android.mk b/packages/PrintSpooler/tests/outofprocess/Android.mk
index d1d0ee4..3c02453 100644
--- a/packages/PrintSpooler/tests/outofprocess/Android.mk
+++ b/packages/PrintSpooler/tests/outofprocess/Android.mk
@@ -24,5 +24,6 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ub-uiautomator mockito-target-minus-junit4
 
 LOCAL_PACKAGE_NAME := PrintSpoolerOutOfProcessTests
+LOCAL_COMPATIBILITY_SUITE := device-tests
 
 include $(BUILD_PACKAGE)
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index f77d466..1010a8a 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -422,11 +422,11 @@
     <!-- Setting Checkbox title whether to enable WiFi Verbose Logging. [CHAR LIMIT=40] -->
     <string name="wifi_verbose_logging">Enable Wi\u2011Fi Verbose Logging</string>
     <!-- Setting Checkbox title whether to enable WiFi Aggressive Handover. [CHAR LIMIT=40] -->
-    <string name="wifi_aggressive_handover">Aggressive Wi\u2011Fi to Cellular handover</string>
+    <string name="wifi_aggressive_handover">Aggressive Wi\u2011Fi to mobile handover</string>
     <!-- Setting Checkbox title whether to enable WiFi Scanning in the presence of traffic. [CHAR LIMIT=80] -->
     <string name="wifi_allow_scan_with_traffic">Always allow Wi\u2011Fi Roam Scans</string>
-    <!-- Setting Checkbox title whether to always keep cellular data active. [CHAR LIMIT=80] -->
-    <string name="mobile_data_always_on">Cellular data always active</string>
+    <!-- Setting Checkbox title whether to always keep mobile data active. [CHAR LIMIT=80] -->
+    <string name="mobile_data_always_on">Mobile data always active</string>
     <!-- Setting Checkbox title for disabling Bluetooth absolute volume -->
     <string name="bluetooth_disable_absolute_volume">Disable absolute volume</string>
 
@@ -463,7 +463,7 @@
     <!-- Setting Checkbox summary whether to enable Wifi verbose Logging [CHAR LIMIT=80] -->
     <string name="wifi_verbose_logging_summary">Increase Wi\u2011Fi logging level, show per SSID RSSI in Wi\u2011Fi Picker</string>
     <!-- Setting Checkbox summary whether to enable Wifi aggressive handover [CHAR LIMIT=130] -->
-    <string name="wifi_aggressive_handover_summary">When enabled, Wi\u2011Fi will be more aggressive in handing over the data connection to Cellular, when Wi\u2011Fi signal is low</string>
+    <string name="wifi_aggressive_handover_summary">When enabled, Wi\u2011Fi will be more aggressive in handing over the data connection to mobile, when Wi\u2011Fi signal is low</string>
     <!-- Setting Checkbox summary whether to always allow WiFi Roam Scans [CHAR LIMIT=130] -->
     <string name="wifi_allow_scan_with_traffic_summary">Allow/Disallow Wi\u2011Fi Roam Scans based on the amount of data traffic present at the interface</string>
     <!-- UI debug setting: limit size of Android logger buffers -->
@@ -775,7 +775,7 @@
     <string name="daltonizer_type_overridden">Overridden by <xliff:g id="title" example="Simulate color space">%1$s</xliff:g></string>
 
     <!-- [CHAR_LIMIT=40] Label for estimated remaining duration of battery charging/discharging -->
-    <string name="power_remaining_duration_only">Approx. <xliff:g id="time">%1$s</xliff:g> left</string>
+    <string name="power_remaining_duration_only">about <xliff:g id="time">%1$s</xliff:g> left</string>
 
     <!-- [CHAR_LIMIT=40] Short label for estimated remaining duration of battery charging/discharging -->
     <string name="power_remaining_duration_only_short"><xliff:g id="time">%1$s</xliff:g> left</string>
@@ -793,25 +793,25 @@
             <xliff:g id="state">%2$s</xliff:g></string>
     <!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
     <string name="power_charging_duration"><xliff:g id="level">%1$s</xliff:g> -
-            <xliff:g id="time">%2$s</xliff:g> until full</string>
+            <xliff:g id="time">%2$s</xliff:g> until fully charged</string>
     <!-- [CHAR_LIMIT=40] Short label for battery level chart when charging with duration -->
     <string name="power_charging_duration_short"><xliff:g id="level">%1$s</xliff:g> -
         <xliff:g id="time">%2$s</xliff:g></string>
     <!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
     <string name="power_charging_duration_ac"><xliff:g id="level">%1$s</xliff:g> -
-            <xliff:g id="time">%2$s</xliff:g> until full on AC</string>
+            <xliff:g id="time">%2$s</xliff:g> until fully charged on AC</string>
     <!-- [CHAR_LIMIT=40] Short label for battery level chart when charging with duration -->
     <string name="power_charging_duration_ac_short"><xliff:g id="level">%1$s</xliff:g> -
         <xliff:g id="time">%2$s</xliff:g></string>
     <!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
     <string name="power_charging_duration_usb"><xliff:g id="level">%1$s</xliff:g> -
-            <xliff:g id="time">%2$s</xliff:g> until full over USB</string>
+            <xliff:g id="time">%2$s</xliff:g> until fully charged over USB</string>
     <!-- [CHAR_LIMIT=40] Short label for battery level chart when charging with duration -->
     <string name="power_charging_duration_usb_short"><xliff:g id="level">%1$s</xliff:g> -
         <xliff:g id="time">%2$s</xliff:g></string>
     <!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
     <string name="power_charging_duration_wireless"><xliff:g id="level">%1$s</xliff:g> -
-            <xliff:g id="time">%2$s</xliff:g> until full from wireless</string>
+            <xliff:g id="time">%2$s</xliff:g> until fully charged from wireless</string>
     <!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
     <string name="power_charging_duration_wireless_short"><xliff:g id="level">%1$s</xliff:g> -
         <xliff:g id="time">%2$s</xliff:g></string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java b/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java
index 3fc999f..f6f8168 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java
@@ -48,7 +48,7 @@
     /**
      * List of the category's children
      */
-    public List<Tile> tiles = new ArrayList<Tile>();
+    public List<Tile> tiles = new ArrayList<>();
 
 
     public DashboardCategory() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
index 457ce76..af247bd 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
@@ -30,7 +30,6 @@
 import android.provider.Settings;
 import android.util.ArraySet;
 import android.util.Log;
-import android.util.Pair;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -40,10 +39,8 @@
 import android.widget.Toolbar;
 
 import com.android.settingslib.R;
-import com.android.settingslib.applications.InterestingConfigChanges;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
 
 public class SettingsDrawerActivity extends Activity {
@@ -63,15 +60,6 @@
 
     private FrameLayout mContentHeaderContainer;
 
-    // Remove below after new IA
-    @Deprecated
-    private static List<DashboardCategory> sDashboardCategories;
-    @Deprecated
-    private static HashMap<Pair<String, String>, Tile> sTileCache;
-    @Deprecated
-    private static InterestingConfigChanges sConfigTracker;
-    // Remove above after new IA
-
     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -175,17 +163,6 @@
         getActionBar().setDisplayHomeAsUpEnabled(true);
     }
 
-    public List<DashboardCategory> getDashboardCategories() {
-        if (sDashboardCategories == null) {
-            sTileCache = new HashMap<>();
-            sConfigTracker = new InterestingConfigChanges();
-            // Apply initial current config.
-            sConfigTracker.applyNewConfig(getResources());
-            sDashboardCategories = TileUtils.getCategories(this, sTileCache);
-        }
-        return sDashboardCategories;
-    }
-
     protected void onCategoriesChanged() {
         final int N = mCategoryListeners.size();
         for (int i = 0; i < N; i++) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 48f3e2a..fed48b4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -394,8 +394,9 @@
      *
      * <p>If the given connection is active, the existing value of {@link #mRssi} will be returned.
      * If the given AccessPoint is not active, a value will be calculated from previous scan
-     * results, returning the best RSSI for all matching AccessPoints. If the access point is not
-     * connected and there are no scan results, the rssi will be set to {@link #UNREACHABLE_RSSI}.
+     * results, returning the best RSSI for all matching AccessPoints averaged with the previous
+     * value. If the access point is not connected and there are no scan results, the rssi will be
+     * set to {@link #UNREACHABLE_RSSI}.
      *
      * <p>Old scan results will be evicted from the cache when this method is invoked.
      */
@@ -413,7 +414,11 @@
             }
         }
 
-        mRssi = rssi;
+        if (rssi != UNREACHABLE_RSSI && mRssi != UNREACHABLE_RSSI) {
+            mRssi = (mRssi + rssi) / 2; // half-life previous value
+        } else {
+            mRssi = rssi;
+        }
     }
 
     /**
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
index c9fa017..a9aaa05 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
@@ -43,10 +43,6 @@
     private static final int[] STATE_SECURED = {
             R.attr.state_encrypted
     };
-    private static final int[] STATE_SAVED = {
-            R.attr.state_encrypted,
-            R.attr.state_saved
-    };
 
     private static final int[] wifi_friction_attributes = { R.attr.wifi_friction };
 
@@ -152,10 +148,8 @@
         }
         view.itemView.setContentDescription(mContentDescription);
 
-        if (!mForSavedNetworks) {
-            ImageView frictionImageView = (ImageView) view.findViewById(R.id.friction_icon);
-            bindFrictionImage(frictionImageView);
-        }
+        ImageView frictionImageView = (ImageView) view.findViewById(R.id.friction_icon);
+        bindFrictionImage(frictionImageView);
     }
 
     protected void updateIcon(int level, Context context) {
@@ -184,11 +178,7 @@
             return;
         }
         if (mAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE) {
-            if (mAccessPoint.isSaved()) {
-                mFrictionSld.setState(STATE_SAVED);
-            } else {
-                mFrictionSld.setState(STATE_SECURED);
-            }
+            mFrictionSld.setState(STATE_SECURED);
         }
         Drawable drawable = mFrictionSld.getCurrent();
         frictionImageView.setImageDrawable(drawable);
diff --git a/packages/SettingsLib/tests/integ/Android.mk b/packages/SettingsLib/tests/integ/Android.mk
index 60d1c77..7ace048 100644
--- a/packages/SettingsLib/tests/integ/Android.mk
+++ b/packages/SettingsLib/tests/integ/Android.mk
@@ -25,6 +25,7 @@
 LOCAL_JACK_FLAGS := --multi-dex native
 
 LOCAL_PACKAGE_NAME := SettingsLibTests
+LOCAL_COMPATIBILITY_SUITE := device-tests
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
     android-support-test \
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index e8a58c1..b9b4ef3 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -195,6 +195,26 @@
         assertThat(ap.getRssi()).isEqualTo(newRssi);
     }
 
+    @Test
+    public void testUpdateWithScanResultShouldAverageRssi() {
+        String ssid = "ssid";
+        int originalRssi = -65;
+        int newRssi = -80;
+        int expectedRssi = (originalRssi + newRssi) / 2;
+        AccessPoint ap =
+                new TestAccessPointBuilder(mContext).setSsid(ssid).setRssi(originalRssi).build();
+
+        ScanResult scanResult = new ScanResult();
+        scanResult.SSID = ssid;
+        scanResult.level = newRssi;
+        scanResult.BSSID = "bssid";
+        scanResult.timestamp = SystemClock.elapsedRealtime() * 1000;
+        scanResult.capabilities = "";
+        assertThat(ap.update(scanResult)).isTrue();
+
+        assertThat(ap.getRssi()).isEqualTo(expectedRssi);
+    }
+
     private AccessPoint createAccessPointWithScanResultCache() {
         Bundle bundle = new Bundle();
         ArrayList<ScanResult> scanResults = new ArrayList<>();
@@ -203,6 +223,7 @@
             scanResult.level = i;
             scanResult.BSSID = "bssid-" + i;
             scanResult.timestamp = SystemClock.elapsedRealtime() * 1000;
+            scanResult.capabilities = "";
             scanResults.add(scanResult);
         }
 
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/TestAccessPointBuilder.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/TestAccessPointBuilder.java
index 665c439..81bd723 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/TestAccessPointBuilder.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/TestAccessPointBuilder.java
@@ -73,25 +73,28 @@
         return this;
     }
 
+    public TestAccessPointBuilder setRssi(int rssi) {
+        mRssi = rssi;
+        return this;
+    }
+
     /**
-    * Set the signal level.
-    * Side effect: if this AccessPoint was previously unreachable,
+    * Set the rssi based upon the desired signal level.
+     *
+    * <p>Side effect: if this AccessPoint was previously unreachable,
     * setting the level will also make it reachable.
     */
     public TestAccessPointBuilder setLevel(int level) {
-        int outputRange = AccessPoint.SIGNAL_LEVELS - 1;
-
-        if (level > outputRange) {
-            level = outputRange;
-        } else if (level < 0) {
-            level = 0;
+        // Reversal of WifiManager.calculateSignalLevels
+        if (level == 0) {
+            mRssi = MIN_RSSI;
+        } else if (level >= AccessPoint.SIGNAL_LEVELS) {
+            mRssi = MAX_RSSI;
+        } else {
+            float inputRange = MAX_RSSI - MIN_RSSI;
+            float outputRange = AccessPoint.SIGNAL_LEVELS - 1;
+            mRssi = (int) (level * inputRange / outputRange + MIN_RSSI);
         }
-
-        int inputRange = MAX_RSSI - MIN_RSSI;
-
-        // calculate the rssi required to get the level we want.
-        // this is a rearrangement of the formula from WifiManager.calculateSignalLevel()
-        mRssi = (int)((float)(level * inputRange) / (float)outputRange) + MIN_RSSI;
         return this;
     }
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 91a4e79..1f1c189 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -248,6 +248,9 @@
     @GuardedBy("mLock")
     private HandlerThread mHandlerThread;
 
+    @GuardedBy("mLock")
+    private Handler mHandler;
+
     // We have to call in the user manager with no lock held,
     private volatile UserManager mUserManager;
 
@@ -300,10 +303,13 @@
             mHandlerThread = new HandlerThread(LOG_TAG,
                     Process.THREAD_PRIORITY_BACKGROUND);
             mHandlerThread.start();
+            mHandler = new Handler(mHandlerThread.getLooper());
             mSettingsRegistry = new SettingsRegistry();
         }
-        registerBroadcastReceivers();
-        startWatchingUserRestrictionChanges();
+        mHandler.post(() -> {
+            registerBroadcastReceivers();
+            startWatchingUserRestrictionChanges();
+        });
         ServiceManager.addService("settings", new SettingsService(this));
         return true;
     }
diff --git a/packages/Shell/tests/Android.mk b/packages/Shell/tests/Android.mk
index acd552d..48b757c 100644
--- a/packages/Shell/tests/Android.mk
+++ b/packages/Shell/tests/Android.mk
@@ -16,6 +16,7 @@
     legacy-android-test \
 
 LOCAL_PACKAGE_NAME := ShellTests
+LOCAL_COMPATIBILITY_SUITE := device-tests
 LOCAL_INSTRUMENTATION_FOR := Shell
 
 LOCAL_CERTIFICATE := platform
diff --git a/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml b/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml
index 2b75c36..696e9b1 100644
--- a/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml
+++ b/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml
@@ -17,6 +17,6 @@
   -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false" android:color="@color/qs_tile_disabled_color" />
+    <item android:state_enabled="false" android:color="?android:attr/textColorPrimary" />
     <item android:color="@android:color/transparent" />
-</selector>
\ No newline at end of file
+</selector>
diff --git a/packages/SystemUI/res/drawable/ic_add_circle_qs.xml b/packages/SystemUI/res/drawable/ic_add_circle_qs.xml
index f296076..6415ecb4 100644
--- a/packages/SystemUI/res/drawable/ic_add_circle_qs.xml
+++ b/packages/SystemUI/res/drawable/ic_add_circle_qs.xml
@@ -17,14 +17,15 @@
         android:width="48.0dp"
         android:height="48.0dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
+        android:viewportHeight="24.0"
+        android:tint="?android:attr/colorControlNormal">
     <group
             android:scaleX="1.2"
             android:scaleY="1.2"
             android:pivotX="12.0"
             android:pivotY="12.0">
         <path
-            android:fillColor="@color/qs_user_detail_icon_muted"
+            android:fillColor="#FFFFFFFF"
             android:pathData="M12.000000,2.000000C6.500000,2.000000 2.000000,6.500000 2.000000,12.000000s4.500000,10.000000 10.000000,10.000000c5.500000,0.000000 10.000000,-4.500000 10.000000,-10.000000S17.500000,2.000000 12.000000,2.000000zM17.000000,13.000000l-4.000000,0.000000l0.000000,4.000000l-2.000000,0.000000l0.000000,-4.000000L7.000000,13.000000l0.000000,-2.000000l4.000000,0.000000L11.000000,7.000000l2.000000,0.000000l0.000000,4.000000l4.000000,0.000000L17.000000,13.000000z"/>
     </group>
 </vector>
diff --git a/packages/SystemUI/res/layout/pip_menu_action.xml b/packages/SystemUI/res/layout/pip_menu_action.xml
index 77efc9b..9150a00 100644
--- a/packages/SystemUI/res/layout/pip_menu_action.xml
+++ b/packages/SystemUI/res/layout/pip_menu_action.xml
@@ -18,4 +18,5 @@
     android:layout_width="@dimen/pip_action_size"
     android:layout_height="@dimen/pip_action_size"
     android:padding="@dimen/pip_action_padding"
-    android:background="?android:selectableItemBackgroundBorderless" />
\ No newline at end of file
+    android:background="?android:selectableItemBackgroundBorderless"
+    android:forceHasOverlappingRendering="false" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/pip_menu_activity.xml b/packages/SystemUI/res/layout/pip_menu_activity.xml
index c6837fa..44ced17 100644
--- a/packages/SystemUI/res/layout/pip_menu_activity.xml
+++ b/packages/SystemUI/res/layout/pip_menu_activity.xml
@@ -23,7 +23,8 @@
   <FrameLayout
       android:id="@+id/menu_container"
       android:layout_width="match_parent"
-      android:layout_height="match_parent">
+      android:layout_height="match_parent"
+      android:forceHasOverlappingRendering="false">
 
       <ImageView
           android:id="@+id/dismiss"
diff --git a/packages/SystemUI/res/layout/qs_tile_label.xml b/packages/SystemUI/res/layout/qs_tile_label.xml
index 8d1f9e4..9d1fb8f 100644
--- a/packages/SystemUI/res/layout/qs_tile_label.xml
+++ b/packages/SystemUI/res/layout/qs_tile_label.xml
@@ -14,24 +14,39 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<LinearLayout
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="match_parent"
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="48dp"
+    android:paddingTop="8dp">
+    <LinearLayout
+        android:id="@+id/label_group"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:orientation="horizontal"
-        android:gravity="center_horizontal"
-        android:paddingTop="8dp"
-        android:paddingBottom="8dp">
-     <TextView android:id="@+id/tile_label"
+        android:layout_alignParentTop="true"
+        android:layout_centerHorizontal="true"
+        android:orientation="horizontal">
+
+        <TextView
+            android:id="@+id/tile_label"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:textColor="?android:attr/textColorPrimary"
-            android:gravity="center_horizontal"
-            android:minLines="2"
+            android:clickable="false"
+            android:maxLines="2"
             android:padding="0dp"
             android:textAppearance="@style/TextAppearance.QS.TileLabel"
-            android:clickable="false" />
-     <ImageView android:id="@+id/restricted_padlock"
+            android:textColor="?android:attr/textColorPrimary"/>
+
+        <ImageView
+            android:id="@+id/expand_indicator"
+            android:layout_marginStart="4dp"
+            android:layout_width="12dp"
+            android:layout_height="match_parent"
+            android:src="@drawable/qs_dual_tile_caret"
+            android:tint="?android:attr/textColorPrimary" />
+
+        <ImageView android:id="@+id/restricted_padlock"
             android:layout_width="@dimen/qs_tile_text_size"
             android:layout_height="match_parent"
             android:paddingBottom="@dimen/qs_tile_text_size"
@@ -39,4 +54,32 @@
             android:layout_marginLeft="@dimen/restricted_padlock_pading"
             android:scaleType="centerInside"
             android:visibility="gone" />
-</LinearLayout>
+    </LinearLayout>
+
+    <TextView
+        android:id="@+id/app_label"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignStart="@id/label_group"
+        android:layout_alignEnd="@id/label_group"
+        android:layout_below="@id/label_group"
+        android:clickable="false"
+        android:maxLines="1"
+        android:padding="0dp"
+        android:visibility="gone"
+        android:gravity="center"
+        android:textAppearance="@style/TextAppearance.QS.TileLabel"
+        android:textColor="?android:attr/textColorPrimary"/>
+
+    <View
+        android:id="@+id/underline"
+        android:layout_width="30dp"
+        android:layout_height="1dp"
+        android:layout_marginTop="2dp"
+        android:layout_alignStart="@id/label_group"
+        android:layout_alignEnd="@id/label_group"
+        android:layout_below="@id/label_group"
+        android:alpha="?android:attr/disabledAlpha"
+        android:background="?android:attr/colorForeground"/>
+
+</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/qs_user_detail_item.xml b/packages/SystemUI/res/layout/qs_user_detail_item.xml
index 8c6c7cf..c7bfaef 100644
--- a/packages/SystemUI/res/layout/qs_user_detail_item.xml
+++ b/packages/SystemUI/res/layout/qs_user_detail_item.xml
@@ -53,7 +53,7 @@
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textSize="@dimen/qs_detail_item_secondary_text_size"
-                android:textColor="@color/qs_user_detail_name"
+                android:textColor="?android:attr/textColorSecondary"
                 android:gravity="center_horizontal" />
         <ImageView
                 android:id="@+id/restricted_padlock"
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index cbe822f..a549c73 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1160,7 +1160,8 @@
 
             if (mOccluded != isOccluded) {
                 mOccluded = isOccluded;
-                mStatusBarKeyguardViewManager.setOccluded(isOccluded, animate);
+                mStatusBarKeyguardViewManager.setOccluded(isOccluded, animate
+                        && mDeviceInteractive);
                 adjustStatusBarLocked();
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index 2f9c3fc..9cb518c 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -19,8 +19,8 @@
 import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_ACTIONS;
 import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_CONTROLLER_MESSENGER;
 import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_MOVEMENT_BOUNDS;
-import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_STACK_BOUNDS;
 import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_SHOW_MENU;
+import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_STACK_BOUNDS;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -33,13 +33,11 @@
 import android.app.RemoteAction;
 import android.content.Intent;
 import android.content.pm.ParceledListSlice;
-import android.content.res.Resources;
 import android.graphics.Color;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
@@ -84,6 +82,8 @@
     private static final float MENU_BACKGROUND_ALPHA = 0.3f;
     private static final float DISMISS_BACKGROUND_ALPHA = 0.8f;
 
+    private static final float DISABLED_ACTION_ALPHA = 0.54f;
+
     private boolean mMenuVisible;
     private final List<RemoteAction> mActions = new ArrayList<>();
     private View mViewRoot;
@@ -249,6 +249,7 @@
 
     private void showMenu(Rect stackBounds, Rect movementBounds) {
         if (!mMenuVisible) {
+            setVisible(true);
             updateActionViews(stackBounds);
             if (mMenuContainerAnimator != null) {
                 mMenuContainerAnimator.cancel();
@@ -268,7 +269,10 @@
             mMenuContainerAnimator.addUpdateListener(mMenuBgUpdateListener);
             mMenuContainerAnimator.start();
         } else {
+            // If we are already visible, then just start the delayed dismiss and unregister any
+            // existing input consumers from the previous drag
             repostDelayedFinish(POST_INTERACTION_DISMISS_DELAY);
+            notifyUnregisterInputConsumer();
         }
     }
 
@@ -292,9 +296,7 @@
                     if (animationFinishedRunnable != null) {
                         animationFinishedRunnable.run();
                     }
-                    if (getSystemService(AccessibilityManager.class).isEnabled()) {
-                        finish();
-                    }
+                    setVisible(false);
                 }
             });
             mMenuContainerAnimator.addUpdateListener(mMenuBgUpdateListener);
@@ -369,13 +371,18 @@
                         actionView.setImageDrawable(d);
                     }, mHandler);
                     actionView.setContentDescription(action.getContentDescription());
-                    actionView.setOnClickListener(v -> {
-                        try {
-                            action.getActionIntent().send();
-                        } catch (CanceledException e) {
-                            Log.w(TAG, "Failed to send action", e);
-                        }
-                    });
+                    if (action.isEnabled()) {
+                        actionView.setOnClickListener(v -> {
+                            try {
+                                action.getActionIntent().send();
+                            } catch (CanceledException e) {
+                                Log.w(TAG, "Failed to send action", e);
+                            }
+                        });
+                    } else {
+                        actionView.setAlpha(DISABLED_ACTION_ALPHA);
+                        actionView.setEnabled(false);
+                    }
                     if (isLandscapePip && i > 0) {
                         LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
                                 actionView.getLayoutParams();
@@ -398,6 +405,7 @@
     }
 
     private void updateDismissFraction(float fraction) {
+        setVisible(true);
         int alpha;
         if (mMenuVisible) {
             mMenuContainer.setAlpha(1-fraction);
@@ -416,6 +424,12 @@
         sendMessage(m, "Could not notify controller to register input consumer");
     }
 
+    private void notifyUnregisterInputConsumer() {
+        Message m = Message.obtain();
+        m.what = PipMenuActivityController.MESSAGE_UNREGISTER_INPUT_CONSUMER;
+        sendMessage(m, "Could not notify controller to unregister input consumer");
+    }
+
     private void notifyMenuVisibility(boolean visible) {
         mMenuVisible = visible;
         Message m = Message.obtain();
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
index 7dc455b..724f453 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
@@ -63,6 +63,7 @@
     public static final int MESSAGE_DISMISS_PIP = 103;
     public static final int MESSAGE_UPDATE_ACTIVITY_CALLBACK = 104;
     public static final int MESSAGE_REGISTER_INPUT_CONSUMER = 105;
+    public static final int MESSAGE_UNREGISTER_INPUT_CONSUMER = 106;
 
     /**
      * A listener interface to receive notification on changes in PIP.
@@ -135,6 +136,10 @@
                     mInputConsumerController.registerInputConsumer();
                     break;
                 }
+                case MESSAGE_UNREGISTER_INPUT_CONSUMER: {
+                    mInputConsumerController.unregisterInputConsumer();
+                    break;
+                }
                 case MESSAGE_UPDATE_ACTIVITY_CALLBACK: {
                     mToActivityMessenger = msg.replyTo;
                     mStartActivityRequested = false;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index c52fc3e..f70d5b4 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -504,8 +504,8 @@
                 return false;
             }
 
-            try {
-                if (ENABLE_DISMISS_DRAG_TO_TARGET) {
+            if (ENABLE_DISMISS_DRAG_TO_TARGET) {
+                try {
                     mHandler.removeCallbacks(mShowDismissAffordance);
                     PointF vel = mTouchState.getVelocity();
                     final float velocity = PointF.length(vel.x, vel.y);
@@ -520,9 +520,9 @@
                             return true;
                         }
                     }
+                } finally {
+                    mDismissViewController.destroyDismissTarget();
                 }
-            } finally {
-                mDismissViewController.destroyDismissTarget();
             }
 
             if (touchState.isDragging()) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java
index 0629d66..b080642 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java
@@ -35,19 +35,13 @@
     protected void createLabel() {
         super.createLabel();
         mLabelMinLines = mLabel.getMinLines();
-        View view = LayoutInflater.from(mContext).inflate(R.layout.qs_tile_label, null);
-        mAppLabel = (TextView) view.findViewById(R.id.tile_label);
+        mAppLabel = findViewById(R.id.app_label);
         mAppLabel.setAlpha(.6f);
-        mAppLabel.setSingleLine(true);
-        addView(view);
     }
 
     public void setShowAppLabel(boolean showAppLabel) {
         mAppLabel.setVisibility(showAppLabel ? View.VISIBLE : View.GONE);
         mLabel.setSingleLine(showAppLabel);
-        if (!showAppLabel) {
-            mLabel.setMinLines(mLabelMinLines);
-        }
     }
 
     public void setAppLabel(CharSequence label) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index c0fb4d5..d8e5542 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -41,10 +41,10 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.plugins.qs.QS;
-import com.android.systemui.qs.QSDetailClipper;
 import com.android.systemui.plugins.qs.QSTile;
-import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
+import com.android.systemui.qs.QSDetailClipper;
 import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.statusbar.policy.KeyguardMonitor.Callback;
 
@@ -74,6 +74,7 @@
     private boolean mFinishedFetchingTiles = false;
     private int mX;
     private int mY;
+    private boolean mOpening;
 
     public QSCustomizer(Context context, AttributeSet attrs) {
         super(new ContextThemeWrapper(context, R.style.edit_theme), attrs);
@@ -140,6 +141,7 @@
             mY = y;
             MetricsLogger.visible(getContext(), MetricsProto.MetricsEvent.QS_EDIT);
             isShown = true;
+            mOpening = true;
             setTileSpecs();
             setVisibility(View.VISIBLE);
             mClipper.animateCircularClip(x, y, true, mExpandAnimationListener);
@@ -226,7 +228,8 @@
     }
 
     private final Callback mKeyguardCallback = () -> {
-        if (Dependency.get(KeyguardMonitor.class).isShowing()) {
+        if (!isAttachedToWindow()) return;
+        if (Dependency.get(KeyguardMonitor.class).isShowing() && !mOpening) {
             hide(0, 0);
         }
     };
@@ -237,11 +240,13 @@
             if (isShown) {
                 setCustomizing(true);
             }
+            mOpening = false;
             mNotifQsContainer.setCustomizerAnimating(false);
         }
 
         @Override
         public void onAnimationCancel(Animator animation) {
+            mOpening = false;
             mNotifQsContainer.setCustomizerAnimating(false);
         }
     };
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index 547bef7..2ac592f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -165,6 +165,7 @@
         }
         TileInfo info = new TileInfo();
         info.state = state;
+        info.state.dualTarget = false; // No dual targets in edit.
         info.state.expandedAccessibilityClassName =
                 Button.class.getName();
         info.spec = spec;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 5ac7891..948954c2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -369,7 +369,6 @@
                         Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(
                                 intent, 0);
                     } else {
-                        mAnnounceNextStateChange = true;
                         handleClick();
                     }
                 } else if (msg.what == SECONDARY_CLICK) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
index 2c04e82..d2ae6e9f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
@@ -36,11 +36,12 @@
 /** View that represents a standard quick settings tile. **/
 public class QSTileView extends QSTileBaseView {
 
-    private final View mDivider;
+    private View mDivider;
     protected TextView mLabel;
     private ImageView mPadLock;
     private int mState;
     private ViewGroup mLabelContainer;
+    private View mExpandIndicator;
 
     public QSTileView(Context context, QSIconView icon) {
         this(context, icon, false);
@@ -54,8 +55,6 @@
 
         setClickable(true);
         setId(View.generateViewId());
-        mDivider = LayoutInflater.from(context).inflate(R.layout.divider, this, false);
-        addView(mDivider);
         createLabel();
         setOrientation(VERTICAL);
         setGravity(Gravity.CENTER);
@@ -81,8 +80,10 @@
                 .inflate(R.layout.qs_tile_label, this, false);
         mLabelContainer.setClipChildren(false);
         mLabelContainer.setClipToPadding(false);
-        mLabel = (TextView) mLabelContainer.findViewById(R.id.tile_label);
-        mPadLock = (ImageView) mLabelContainer.findViewById(R.id.restricted_padlock);
+        mLabel = mLabelContainer.findViewById(R.id.tile_label);
+        mPadLock = mLabelContainer.findViewById(R.id.restricted_padlock);
+        mDivider = mLabelContainer.findViewById(R.id.underline);
+        mExpandIndicator = mLabelContainer.findViewById(R.id.expand_indicator);
 
         addView(mLabelContainer);
     }
@@ -101,6 +102,7 @@
             mLabel.setText(state.label);
         }
         mDivider.setVisibility(state.dualTarget ? View.VISIBLE : View.INVISIBLE);
+        mExpandIndicator.setVisibility(state.dualTarget ? View.VISIBLE : View.GONE);
         if (state.dualTarget != mLabelContainer.isClickable()) {
             mLabelContainer.setClickable(state.dualTarget);
             mLabelContainer.setLongClickable(state.dualTarget);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 47468ae..ac24e2e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -67,6 +67,7 @@
 import android.os.UserManager;
 import android.provider.Settings;
 import android.util.ArraySet;
+import android.util.LauncherIcons;
 import android.util.Log;
 import android.util.MutableBoolean;
 import android.view.Display;
@@ -142,6 +143,7 @@
     int mDummyThumbnailHeight;
     Paint mBgProtectionPaint;
     Canvas mBgProtectionCanvas;
+    LauncherIcons mLauncherIcons;
 
     private final Handler mHandler = new H();
 
@@ -299,6 +301,7 @@
             Collections.addAll(sRecentsBlacklist,
                     res.getStringArray(R.array.recents_blacklist_array));
         }
+        mLauncherIcons = new LauncherIcons(context);
     }
 
     /**
@@ -834,7 +837,7 @@
             return new ColorDrawable(0xFF666666);
         }
 
-        Drawable icon = info.loadIcon(mPm);
+        Drawable icon = mLauncherIcons.wrapIconDrawableWithShadow(info.loadIcon(mPm));
         return getBadgedIcon(icon, userId);
     }
 
@@ -850,7 +853,7 @@
             return new ColorDrawable(0xFF666666);
         }
 
-        Drawable icon = appInfo.loadIcon(mPm);
+        Drawable icon = mLauncherIcons.wrapIconDrawableWithShadow(appInfo.loadIcon(mPm));
         return getBadgedIcon(icon, userId);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
index af464c6..5db5498 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -136,12 +136,7 @@
         if (channel.getId().equals(NotificationChannel.DEFAULT_CHANNEL_ID)) {
             channelNameText = mContext.getString(R.string.notification_header_default_channel);
         } else {
-            if (info != null && channel.getNameResId() != 0) {
-                channelNameText = pm.getText(pkg, channel.getNameResId(), info);
-            }
-            if (channel.getName() != null) {
-                channelNameText = channel.getName();
-            }
+            channelNameText = channel.getName();
         }
         ((TextView) findViewById(R.id.pkgname)).setText(appName);
         ((TextView) findViewById(R.id.channel_name)).setText(channelNameText);
@@ -154,12 +149,7 @@
                         iNotificationManager.getNotificationChannelGroupForPackage(
                                 channel.getGroup(), pkg, appUid);
                 if (notificationChannelGroup != null) {
-                    if (info != null && notificationChannelGroup.getNameResId() != 0) {
-                        groupName = pm.getText(pkg, notificationChannelGroup.getNameResId(), info);
-                    }
-                    if (notificationChannelGroup.getName() != null) {
-                        groupName = notificationChannelGroup.getName();
-                    }
+                    groupName = notificationChannelGroup.getName();
                 }
             } catch (RemoteException e) {
                 Log.e(TAG, e.toString());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 8da17fa..b7b4a3b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -23,7 +23,6 @@
 import android.view.View;
 import android.view.ViewGroup;
 
-import com.android.internal.widget.CachingIconView;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.ViewInvertHelper;
@@ -127,12 +126,7 @@
         super.setDark(dark, fade, delay);
         if (mDark == dark) return;
         mDark = dark;
-        if (fade) {
-            mViewInvertHelper.fade(dark, delay);
-        } else {
-            mViewInvertHelper.update(dark);
-        }
-        mShelfIcons.setAmbient(dark);
+        mShelfIcons.setDark(dark, fade, delay);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 1101701..ffc4e8d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -27,6 +27,7 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
@@ -46,6 +47,7 @@
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
+import com.android.systemui.statusbar.notification.NotificationIconDozeHelper;
 import com.android.systemui.statusbar.notification.NotificationUtils;
 
 import java.text.NumberFormat;
@@ -99,7 +101,6 @@
     private int mDensity;
     private float mIconScale = 1.0f;
     private final Paint mDotPaint = new Paint();
-    private boolean mDotVisible;
     private float mDotRadius;
     private int mStaticDotRadius;
     private int mVisibleState = STATE_ICON;
@@ -110,6 +111,8 @@
     private OnVisibilityChangedListener mOnVisibilityChangedListener;
     private int mDrawableColor;
     private int mIconColor;
+    private int mDecorColor;
+    private float mDarkAmount;
     private ValueAnimator mColorAnimator;
     private int mCurrentSetColor = NO_COLOR;
     private int mAnimationStartColor = NO_COLOR;
@@ -119,6 +122,7 @@
                 animation.getAnimatedFraction());
         setColorInternal(newColor);
     };
+    private final NotificationIconDozeHelper mDozer;
 
     public StatusBarIconView(Context context, String slot, Notification notification) {
         this(context, slot, notification, false);
@@ -127,6 +131,7 @@
     public StatusBarIconView(Context context, String slot, Notification notification,
             boolean blocked) {
         super(context);
+        mDozer = new NotificationIconDozeHelper(context);
         mBlocked = blocked;
         mSlot = slot;
         mNumberPain = new Paint();
@@ -190,6 +195,7 @@
 
     public StatusBarIconView(Context context, AttributeSet attrs) {
         super(context, attrs);
+        mDozer = new NotificationIconDozeHelper(context);
         mBlocked = false;
         mAlwaysScaleIcon = true;
         updateIconScale();
@@ -466,7 +472,19 @@
      * to the drawable.
      */
     public void setDecorColor(int iconTint) {
-        mDotPaint.setColor(iconTint);
+        mDecorColor = iconTint;
+        updateDecorColor();
+    }
+
+    private void updateDecorColor() {
+        int color = NotificationUtils.interpolateColors(mDecorColor, Color.WHITE, mDarkAmount);
+        if (mDotPaint.getColor() != color) {
+            mDotPaint.setColor(color);
+
+            if (mDotAppearAmount != 0) {
+                invalidate();
+            }
+        }
     }
 
     /**
@@ -477,6 +495,7 @@
         mDrawableColor = color;
         setColorInternal(color);
         mIconColor = color;
+        mDozer.setColor(color);
     }
 
     private void setColorInternal(int color) {
@@ -649,6 +668,14 @@
         mOnVisibilityChangedListener = listener;
     }
 
+    public void setDark(boolean dark, boolean fade, long delay) {
+        mDozer.setImageDark(this, dark, fade, delay, mIconColor != NO_COLOR);
+        mDozer.setIntensityDark(f -> {
+            mDarkAmount = f;
+            updateDecorColor();
+        }, dark, fade, delay);
+    }
+
     public interface OnVisibilityChangedListener {
         void onVisibilityChanged(int newVisibility);
     }
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 3efa29f..bca4b43 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
@@ -18,7 +18,7 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
+import android.content.Context;
 import android.graphics.ColorMatrixColorFilter;
 import android.graphics.Paint;
 import android.view.View;
@@ -38,8 +38,8 @@
     private boolean mIsLegacy;
     private int mLegacyColor;
 
-    protected NotificationCustomViewWrapper(View view, ExpandableNotificationRow row) {
-        super(view, row);
+    protected NotificationCustomViewWrapper(Context ctx, View view, ExpandableNotificationRow row) {
+        super(ctx, view, row);
         mInvertHelper = new ViewInvertHelper(view, NotificationPanelView.DOZE_ANIMATION_DURATION);
         mLegacyColor = row.getContext().getColor(R.color.notification_legacy_background_color);
     }
@@ -67,13 +67,11 @@
     }
 
     protected void fadeGrayscale(final boolean dark, long delay) {
-        startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                updateGrayscaleMatrix((float) animation.getAnimatedValue());
-                mGreyPaint.setColorFilter(new ColorMatrixColorFilter(mGrayscaleColorMatrix));
-                mView.setLayerPaint(mGreyPaint);
-            }
+        getDozer().startIntensityAnimation(animation -> {
+            getDozer().updateGrayscaleMatrix((float) animation.getAnimatedValue());
+            mGreyPaint.setColorFilter(
+                    new ColorMatrixColorFilter(getDozer().getGrayscaleColorMatrix()));
+            mView.setLayerPaint(mGreyPaint);
         }, dark, delay, new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
@@ -86,9 +84,9 @@
 
     protected void updateGrayscale(boolean dark) {
         if (dark) {
-            updateGrayscaleMatrix(1f);
+            getDozer().updateGrayscaleMatrix(1f);
             mGreyPaint.setColorFilter(
-                    new ColorMatrixColorFilter(mGrayscaleColorMatrix));
+                    new ColorMatrixColorFilter(getDozer().getGrayscaleColorMatrix()));
             mView.setLayerPaint(mGreyPaint);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java
new file mode 100644
index 0000000..d592c5f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java
@@ -0,0 +1,92 @@
+/*
+ * 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.systemui.statusbar.notification;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
+import android.widget.ImageView;
+
+import com.android.systemui.Interpolators;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
+
+import java.util.function.Consumer;
+
+public class NotificationDozeHelper {
+    private final ColorMatrix mGrayscaleColorMatrix = new ColorMatrix();
+
+    public void fadeGrayscale(final ImageView target, final boolean dark, long delay) {
+        startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                updateGrayscaleMatrix((float) animation.getAnimatedValue());
+                target.setColorFilter(new ColorMatrixColorFilter(mGrayscaleColorMatrix));
+            }
+        }, dark, delay, new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                if (!dark) {
+                    target.setColorFilter(null);
+                }
+            }
+        });
+    }
+
+    public void updateGrayscale(ImageView target, boolean dark) {
+        if (dark) {
+            updateGrayscaleMatrix(1f);
+            target.setColorFilter(new ColorMatrixColorFilter(mGrayscaleColorMatrix));
+        } else {
+            target.setColorFilter(null);
+        }
+    }
+
+    public void startIntensityAnimation(ValueAnimator.AnimatorUpdateListener updateListener,
+            boolean dark, long delay, Animator.AnimatorListener listener) {
+        float startIntensity = dark ? 0f : 1f;
+        float endIntensity = dark ? 1f : 0f;
+        ValueAnimator animator = ValueAnimator.ofFloat(startIntensity, endIntensity);
+        animator.addUpdateListener(updateListener);
+        animator.setDuration(NotificationPanelView.DOZE_ANIMATION_DURATION);
+        animator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
+        animator.setStartDelay(delay);
+        if (listener != null) {
+            animator.addListener(listener);
+        }
+        animator.start();
+    }
+
+    public void setIntensityDark(Consumer<Float> listener, boolean dark,
+            boolean animate, long delay) {
+        if (animate) {
+            startIntensityAnimation(a -> listener.accept((Float) a.getAnimatedValue()), dark, delay,
+                    null /* listener */);
+        } else {
+            listener.accept(dark ? 1f : 0f);
+        }
+    }
+
+    public void updateGrayscaleMatrix(float intensity) {
+        mGrayscaleColorMatrix.setSaturation(1 - intensity);
+    }
+
+    public ColorMatrix getGrayscaleColorMatrix() {
+        return mGrayscaleColorMatrix;
+    }
+}
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 38e4ec1..1ffc944 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
@@ -16,17 +16,10 @@
 
 package com.android.systemui.statusbar.notification;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
 import android.app.Notification;
 import android.content.Context;
-import android.graphics.Color;
 import android.graphics.ColorFilter;
-import android.graphics.ColorMatrixColorFilter;
-import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
-import android.graphics.drawable.Drawable;
 import android.util.ArraySet;
 import android.view.NotificationHeaderView;
 import android.view.View;
@@ -37,7 +30,6 @@
 import android.widget.TextView;
 
 import com.android.systemui.Interpolators;
-import com.android.systemui.R;
 import com.android.systemui.ViewInvertHelper;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.TransformableView;
@@ -55,10 +47,6 @@
 
     private static final Interpolator LOW_PRIORITY_HEADER_CLOSE
             = new PathInterpolator(0.4f, 0f, 0.7f, 1f);
-    private final PorterDuffColorFilter mIconColorFilter = new PorterDuffColorFilter(
-            0, PorterDuff.Mode.SRC_ATOP);
-    private final int mIconDarkAlpha;
-    private final int mIconDarkColor = 0xffffffff;
 
     protected final ViewInvertHelper mInvertHelper;
     protected final ViewTransformationHelper mTransformationHelper;
@@ -74,8 +62,7 @@
     private boolean mTransformLowPriorityTitle;
 
     protected NotificationHeaderViewWrapper(Context ctx, View view, ExpandableNotificationRow row) {
-        super(view, row);
-        mIconDarkAlpha = ctx.getResources().getInteger(R.integer.doze_small_icon_alpha);
+        super(ctx, view, row);
         mInvertHelper = new ViewInvertHelper(ctx, NotificationPanelView.DOZE_ANIMATION_DURATION);
         mTransformationHelper = new ViewTransformationHelper();
 
@@ -108,6 +95,16 @@
         updateInvertHelper();
     }
 
+    @Override
+    protected NotificationDozeHelper createDozer(Context ctx) {
+        return new NotificationIconDozeHelper(ctx);
+    }
+
+    @Override
+    protected NotificationIconDozeHelper getDozer() {
+        return (NotificationIconDozeHelper) super.getDozer();
+    }
+
     protected void resolveHeaderViews() {
         mIcon = (ImageView) mView.findViewById(com.android.internal.R.id.icon);
         mHeaderText = (TextView) mView.findViewById(com.android.internal.R.id.header_text);
@@ -116,6 +113,7 @@
         mColor = resolveColor(mExpandButton);
         mNotificationHeader = (NotificationHeaderView) mView.findViewById(
                 com.android.internal.R.id.notification_header);
+        getDozer().setColor(mColor);
     }
 
     private int resolveColor(ImageView icon) {
@@ -223,90 +221,8 @@
             // It also may lead to bugs where the icon isn't correctly greyed out.
             boolean hadColorFilter = mNotificationHeader.getOriginalIconColor()
                     != NotificationHeaderView.NO_COLOR;
-            if (fade) {
-                if (hadColorFilter) {
-                    fadeIconColorFilter(mIcon, dark, delay);
-                    fadeIconAlpha(mIcon, dark, delay);
-                } else {
-                    fadeGrayscale(mIcon, dark, delay);
-                }
-            } else {
-                if (hadColorFilter) {
-                    updateIconColorFilter(mIcon, dark);
-                    updateIconAlpha(mIcon, dark);
-                } else {
-                    updateGrayscale(mIcon, dark);
-                }
-            }
-        }
-    }
 
-    private void fadeIconColorFilter(final ImageView target, boolean dark, long delay) {
-        startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                updateIconColorFilter(target, (Float) animation.getAnimatedValue());
-            }
-        }, dark, delay, null /* listener */);
-    }
-
-    private void fadeIconAlpha(final ImageView target, boolean dark, long delay) {
-        startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                float t = (float) animation.getAnimatedValue();
-                target.setImageAlpha((int) (255 * (1f - t) + mIconDarkAlpha * t));
-            }
-        }, dark, delay, null /* listener */);
-    }
-
-    protected void fadeGrayscale(final ImageView target, final boolean dark, long delay) {
-        startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                updateGrayscaleMatrix((float) animation.getAnimatedValue());
-                target.setColorFilter(new ColorMatrixColorFilter(mGrayscaleColorMatrix));
-            }
-        }, dark, delay, new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                if (!dark) {
-                    target.setColorFilter(null);
-                }
-            }
-        });
-    }
-
-    private void updateIconColorFilter(ImageView target, boolean dark) {
-        updateIconColorFilter(target, dark ? 1f : 0f);
-    }
-
-    private void updateIconColorFilter(ImageView target, float intensity) {
-        int color = interpolateColor(mColor, mIconDarkColor, intensity);
-        mIconColorFilter.setColor(color);
-        Drawable iconDrawable = target.getDrawable();
-
-        // Also, the notification might have been modified during the animation, so background
-        // might be null here.
-        if (iconDrawable != null) {
-            Drawable d = iconDrawable.mutate();
-            // DrawableContainer ignores the color filter if it's already set, so clear it first to
-            // get it set and invalidated properly.
-            d.setColorFilter(null);
-            d.setColorFilter(mIconColorFilter);
-        }
-    }
-
-    private void updateIconAlpha(ImageView target, boolean dark) {
-        target.setImageAlpha(dark ? mIconDarkAlpha : 255);
-    }
-
-    protected void updateGrayscale(ImageView target, boolean dark) {
-        if (dark) {
-            updateGrayscaleMatrix(1f);
-            target.setColorFilter(new ColorMatrixColorFilter(mGrayscaleColorMatrix));
-        } else {
-            target.setColorFilter(null);
+            getDozer().setImageDark(mIcon, dark, fade, delay, !hadColorFilter);
         }
     }
 
@@ -316,22 +232,6 @@
         mNotificationHeader.setOnClickListener(expandable ? onClickListener : null);
     }
 
-    private static int interpolateColor(int source, int target, float t) {
-        int aSource = Color.alpha(source);
-        int rSource = Color.red(source);
-        int gSource = Color.green(source);
-        int bSource = Color.blue(source);
-        int aTarget = Color.alpha(target);
-        int rTarget = Color.red(target);
-        int gTarget = Color.green(target);
-        int bTarget = Color.blue(target);
-        return Color.argb(
-                (int) (aSource * (1f - t) + aTarget * t),
-                (int) (rSource * (1f - t) + rTarget * t),
-                (int) (gSource * (1f - t) + gTarget * t),
-                (int) (bSource * (1f - t) + bTarget * t));
-    }
-
     @Override
     public NotificationHeaderView getNotificationHeader() {
         return mNotificationHeader;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationIconDozeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationIconDozeHelper.java
new file mode 100644
index 0000000..9f79ef2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationIconDozeHelper.java
@@ -0,0 +1,101 @@
+/*
+ * 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.systemui.statusbar.notification;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.drawable.Drawable;
+import android.widget.ImageView;
+
+import com.android.systemui.R;
+
+public class NotificationIconDozeHelper extends NotificationDozeHelper {
+
+    private final int mImageDarkAlpha;
+    private final int mImageDarkColor = 0xffffffff;
+    private final PorterDuffColorFilter mImageColorFilter = new PorterDuffColorFilter(
+            0, PorterDuff.Mode.SRC_ATOP);
+
+    private int mColor = Color.BLACK;
+
+    public NotificationIconDozeHelper(Context ctx) {
+        mImageDarkAlpha = ctx.getResources().getInteger(R.integer.doze_small_icon_alpha);
+    }
+
+    public void setColor(int color) {
+        mColor = color;
+    }
+
+    public void setImageDark(ImageView target, boolean dark, boolean fade, long delay,
+            boolean useGrayscale) {
+        if (fade) {
+            if (!useGrayscale) {
+                fadeImageColorFilter(target, dark, delay);
+                fadeImageAlpha(target, dark, delay);
+            } else {
+                fadeGrayscale(target, dark, delay);
+            }
+        } else {
+            if (!useGrayscale) {
+                updateImageColorFilter(target, dark);
+                updateImageAlpha(target, dark);
+            } else {
+                updateGrayscale(target, dark);
+            }
+        }
+    }
+
+    private void fadeImageColorFilter(final ImageView target, boolean dark, long delay) {
+        startIntensityAnimation(animation -> {
+            updateImageColorFilter(target, (Float) animation.getAnimatedValue());
+        }, dark, delay, null /* listener */);
+    }
+
+    private void fadeImageAlpha(final ImageView target, boolean dark, long delay) {
+        startIntensityAnimation(animation -> {
+            float t = (float) animation.getAnimatedValue();
+            target.setImageAlpha((int) (255 * (1f - t) + mImageDarkAlpha * t));
+        }, dark, delay, null /* listener */);
+    }
+
+    private void updateImageColorFilter(ImageView target, boolean dark) {
+        updateImageColorFilter(target, dark ? 1f : 0f);
+    }
+
+    private void updateImageColorFilter(ImageView target, float intensity) {
+        int color = NotificationUtils.interpolateColors(mColor, mImageDarkColor, intensity);
+        mImageColorFilter.setColor(color);
+        Drawable imageDrawable = target.getDrawable();
+
+        // Also, the notification might have been modified during the animation, so background
+        // might be null here.
+        if (imageDrawable != null) {
+            Drawable d = imageDrawable.mutate();
+            // DrawableContainer ignores the color filter if it's already set, so clear it first to
+            // get it set and invalidated properly.
+            d.setColorFilter(null);
+            d.setColorFilter(mImageColorFilter);
+        }
+    }
+
+    private void updateImageAlpha(ImageView target, boolean dark) {
+        target.setImageAlpha(dark ? mImageDarkAlpha : 255);
+    }
+
+}
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 846d03a..f0b6b2e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar.notification;
 
-import android.animation.ValueAnimator;
 import android.content.Context;
 import android.graphics.Color;
 import android.service.notification.StatusBarNotification;
@@ -46,7 +45,8 @@
     private int mContentHeight;
     private int mMinHeightHint;
 
-    protected NotificationTemplateViewWrapper(Context ctx, View view, ExpandableNotificationRow row) {
+    protected NotificationTemplateViewWrapper(Context ctx, View view,
+            ExpandableNotificationRow row) {
         super(ctx, view, row);
         mTransformationHelper.setCustomTransformation(
                 new ViewTransformationHelper.CustomTransformation() {
@@ -154,16 +154,20 @@
         // This also clears the existing types
         super.updateTransformedTypes();
         if (mTitle != null) {
-            mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TITLE, mTitle);
+            mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TITLE,
+                    mTitle);
         }
         if (mText != null) {
-            mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TEXT, mText);
+            mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TEXT,
+                    mText);
         }
         if (mPicture != null) {
-            mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_IMAGE, mPicture);
+            mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_IMAGE,
+                    mPicture);
         }
         if (mProgressBar != null) {
-            mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_PROGRESS, mProgressBar);
+            mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_PROGRESS,
+                    mProgressBar);
         }
     }
 
@@ -173,7 +177,7 @@
             return;
         }
         super.setDark(dark, fade, delay);
-        setPictureGrayscale(dark, fade, delay);
+        setPictureDark(dark, fade, delay);
         setProgressBarDark(dark, fade, delay);
     }
 
@@ -188,12 +192,9 @@
     }
 
     private void fadeProgressDark(final ProgressBar target, final boolean dark, long delay) {
-        startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                float t = (float) animation.getAnimatedValue();
-                updateProgressDark(target, t);
-            }
+        getDozer().startIntensityAnimation(animation -> {
+            float t = (float) animation.getAnimatedValue();
+            updateProgressDark(target, t);
         }, dark, delay, null /* listener */);
     }
 
@@ -207,13 +208,9 @@
         updateProgressDark(target, dark ? 1f : 0f);
     }
 
-    protected void setPictureGrayscale(boolean grayscale, boolean fade, long delay) {
+    private void setPictureDark(boolean dark, boolean fade, long delay) {
         if (mPicture != null) {
-            if (fade) {
-                fadeGrayscale(mPicture, grayscale, delay);
-            } else {
-                updateGrayscale(mPicture, grayscale);
-            }
+            getDozer().setImageDark(mPicture, dark, fade, delay, true /* useGrayscale */);
         }
     }
 
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 c85e8d8..c86616b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
@@ -16,24 +16,17 @@
 
 package com.android.systemui.statusbar.notification;
 
-import android.animation.Animator;
-import android.animation.ValueAnimator;
 import android.content.Context;
 import android.graphics.Color;
-import android.graphics.ColorMatrix;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
-import android.service.notification.StatusBarNotification;
 import android.support.v4.graphics.ColorUtils;
 import android.view.NotificationHeaderView;
 import android.view.View;
 
-import com.android.systemui.Interpolators;
-import com.android.systemui.R;
 import com.android.systemui.statusbar.CrossFadeHelper;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.TransformableView;
-import com.android.systemui.statusbar.phone.NotificationPanelView;
 
 /**
  * Wraps the actual notification content view; used to implement behaviors which are different for
@@ -41,14 +34,14 @@
  */
 public abstract class NotificationViewWrapper implements TransformableView {
 
-    protected final ColorMatrix mGrayscaleColorMatrix = new ColorMatrix();
     protected final View mView;
     protected final ExpandableNotificationRow mRow;
+    private final NotificationDozeHelper mDozer;
+
     protected boolean mDark;
     private int mBackgroundColor = 0;
     protected boolean mShouldInvertDark;
     protected boolean mDarkInitialized = false;
-    private boolean mForcedInvisible;
 
     public static NotificationViewWrapper wrap(Context ctx, View v, ExpandableNotificationRow row) {
         if (v.getId() == com.android.internal.R.id.status_bar_latest_event_content) {
@@ -65,13 +58,22 @@
         } else if (v instanceof NotificationHeaderView) {
             return new NotificationHeaderViewWrapper(ctx, v, row);
         } else {
-            return new NotificationCustomViewWrapper(v, row);
+            return new NotificationCustomViewWrapper(ctx, v, row);
         }
     }
 
-    protected NotificationViewWrapper(View view, ExpandableNotificationRow row) {
+    protected NotificationViewWrapper(Context ctx, View view, ExpandableNotificationRow row) {
         mView = view;
         mRow = row;
+        mDozer = createDozer(ctx);
+    }
+
+    protected NotificationDozeHelper createDozer(Context ctx) {
+        return new NotificationIconDozeHelper(mView.getContext());
+    }
+
+    protected NotificationDozeHelper getDozer() {
+        return mDozer;
     }
 
     /**
@@ -112,26 +114,6 @@
                 || ColorUtils.calculateLuminance(backgroundColor) > 0.5;
     }
 
-
-    protected void startIntensityAnimation(ValueAnimator.AnimatorUpdateListener updateListener,
-            boolean dark, long delay, Animator.AnimatorListener listener) {
-        float startIntensity = dark ? 0f : 1f;
-        float endIntensity = dark ? 1f : 0f;
-        ValueAnimator animator = ValueAnimator.ofFloat(startIntensity, endIntensity);
-        animator.addUpdateListener(updateListener);
-        animator.setDuration(NotificationPanelView.DOZE_ANIMATION_DURATION);
-        animator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
-        animator.setStartDelay(delay);
-        if (listener != null) {
-            animator.addListener(listener);
-        }
-        animator.start();
-    }
-
-    protected void updateGrayscaleMatrix(float intensity) {
-        mGrayscaleColorMatrix.setSaturation(1 - intensity);
-    }
-
     /**
      * Update the appearance of the expand button.
      *
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
index 820638c..c30bb9a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -74,7 +74,7 @@
         if (mUserListener == null) {
             return false;
         }
-        return mUserListener.getUserCount() > 1;
+        return mUserListener.getUserCount() != 0;
     }
 
     public void setUserSwitcherController(UserSwitcherController userSwitcherController) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 3706dc8..dee15d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -95,7 +95,7 @@
     private int mActualLayoutWidth = NO_VALUE;
     private float mActualPaddingEnd = NO_VALUE;
     private float mActualPaddingStart = NO_VALUE;
-    private boolean mCentered;
+    private boolean mDark;
     private boolean mChangingViewPositions;
     private int mAddAnimationStartIndex = -1;
     private int mCannedAnimationStartIndex = -1;
@@ -183,6 +183,9 @@
                 mAddAnimationStartIndex = Math.min(mAddAnimationStartIndex, childIndex);
             }
         }
+        if (mDark && child instanceof StatusBarIconView) {
+            ((StatusBarIconView) child).setDark(mDark, false, 0);
+        }
     }
 
     @Override
@@ -312,7 +315,8 @@
                 numDots++;
             }
         }
-        if (mCentered && translationX < getLayoutEnd()) {
+        boolean center = mDark;
+        if (center && translationX < getLayoutEnd()) {
             float delta = (getLayoutEnd() - translationX) / 2;
             for (int i = 0; i < childCount; i++) {
                 View view = getChildAt(i);
@@ -390,9 +394,15 @@
         mChangingViewPositions = changingViewPositions;
     }
 
-    public void setAmbient(boolean ambient) {
-        mCentered = ambient;
+    public void setDark(boolean dark, boolean fade, long delay) {
+        mDark = dark;
         mDisallowNextAnimation = true;
+        for (int i = 0; i < getChildCount(); i++) {
+            View view = getChildAt(i);
+            if (view instanceof StatusBarIconView) {
+                ((StatusBarIconView) view).setDark(dark, fade, delay);
+            }
+        }
     }
 
     public IconState getIconState(StatusBarIconView icon) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
index a87b50a..d6c080a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
@@ -129,6 +129,7 @@
 
     public void notifyKeyguardDoneFading() {
         mKeyguardFadingAway = false;
+        mKeyguardGoingAway = false;
         notifyKeyguardChanged();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
index 5df3beb..cd85a76 100644
--- a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
+++ b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
@@ -38,19 +38,19 @@
         nm.createNotificationChannels(Arrays.asList(
                 new NotificationChannel(
                         ALERTS,
-                        R.string.notification_channel_alerts,
+                        context.getString(R.string.notification_channel_alerts),
                         NotificationManager.IMPORTANCE_HIGH),
                 new NotificationChannel(
                         SCREENSHOTS,
-                        R.string.notification_channel_screenshot,
+                        context.getString(R.string.notification_channel_screenshot),
                         NotificationManager.IMPORTANCE_LOW),
                 new NotificationChannel(
                         GENERAL,
-                        R.string.notification_channel_general,
+                        context.getString(R.string.notification_channel_general),
                         NotificationManager.IMPORTANCE_MIN),
                 new NotificationChannel(
                         STORAGE,
-                        R.string.notification_channel_storage,
+                        context.getString(R.string.notification_channel_storage),
                         isTv(context)
                                 ? NotificationManager.IMPORTANCE_DEFAULT
                                 : NotificationManager.IMPORTANCE_LOW)
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 576299f..ddd8d7b 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -26,6 +26,7 @@
 LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors
 
 LOCAL_PACKAGE_NAME := SystemUITests
+LOCAL_COMPATIBILITY_SUITE := device-tests
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src) \
     $(call all-Iaidl-files-under, src) \
@@ -46,7 +47,7 @@
 LOCAL_STATIC_JAVA_LIBRARIES := \
     metrics-helper-lib \
     android-support-test \
-    mockito-updated-target-minus-junit4 \
+    mockito-target-minus-junit4 \
     SystemUI-proto \
     SystemUI-tags \
     legacy-android-test \
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
index 5b9270d..726300f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
@@ -161,27 +161,6 @@
     }
 
     @Test
-    public void testBindNotification_SetsGroupName_resId() throws Exception {
-        when(mMockPackageManager.getText(eq(TEST_PACKAGE_NAME),
-                eq(R.string.legacy_vpn_name), anyObject())).thenReturn(
-                getContext().getString(R.string.legacy_vpn_name));
-        mNotificationChannel.setGroup("test_group_id");
-        final NotificationChannelGroup notificationChannelGroup =
-                new NotificationChannelGroup("test_group_id", R.string.legacy_vpn_name);
-        when(mMockINotificationManager.getNotificationChannelGroupForPackage(
-                eq("test_group_id"), eq(TEST_PACKAGE_NAME), anyInt()))
-                .thenReturn(notificationChannelGroup);
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                mMockStatusBarNotification, mNotificationChannel, null, null, null);
-        final TextView groupNameView = (TextView) mNotificationInfo.findViewById(R.id.group_name);
-        assertEquals(View.VISIBLE, groupNameView.getVisibility());
-        assertEquals(mContext.getString(R.string.legacy_vpn_name), groupNameView.getText());
-        final TextView groupDividerView =
-                (TextView) mNotificationInfo.findViewById(R.id.pkg_group_divider);
-        assertEquals(View.VISIBLE, groupDividerView.getVisibility());
-    }
-
-    @Test
     public void testBindNotification_SetsTextChannelName() throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 mMockStatusBarNotification, mNotificationChannel, null, null, null);
@@ -190,21 +169,6 @@
     }
 
     @Test
-    public void testBindNotification_SetsTextChannelName_resId() throws Exception {
-        when(mMockPackageManager.getText(eq(TEST_PACKAGE_NAME),
-                eq(R.string.notification_menu_accessibility), anyObject())).thenReturn(
-                getContext().getString(R.string.notification_menu_accessibility));
-        NotificationChannel notificationChannelResId = new NotificationChannel(
-                TEST_CHANNEL, R.string.notification_menu_accessibility,
-                NotificationManager.IMPORTANCE_LOW);
-        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
-                mMockStatusBarNotification, notificationChannelResId, null, null, null);
-        final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
-        assertEquals(getContext().getString(R.string.notification_menu_accessibility),
-                textView.getText());
-    }
-
-    @Test
     public void testBindNotification_SetsOnClickListenerForSettings() throws Exception {
         final CountDownLatch latch = new CountDownLatch(1);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 3800f29..8a3b9af 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -56,6 +56,12 @@
     // Type for APP_TRANSITION event: The transition brought an already existing activity to the
     // front.
     TYPE_TRANSITION_HOT_LAUNCH = 9;
+
+    // The action was successful
+    TYPE_SUCCESS = 10;
+
+    // The action failed
+    TYPE_FAILURE = 11;
   }
 
   // Known visual elements: views or controls.
@@ -1180,7 +1186,7 @@
     // OS: 6.0
     BRIGHTNESS_DIALOG = 220;
 
-    // OPEN: Settings > Apps > Configure Apps > Draw over other apps
+    // OPEN: Settings > Apps > Configure Apps > Display over other apps
     // CATEGORY: SETTINGS
     // OS: 6.0
     SYSTEM_ALERT_WINDOW_APPS = 221;
@@ -3227,7 +3233,7 @@
     // ACTION: Allow "Draw over other apps" for an app
     APP_SPECIAL_PERMISSION_APPDRAW_ALLOW = 770;
 
-    // ACTION: Deny "Draw over other apps" for an app
+    // ACTION: Deny "Display over other apps" for an app
     APP_SPECIAL_PERMISSION_APPDRAW_DENY = 771;
 
     // ACTION: Allow "VR helper services" for an app
@@ -3608,6 +3614,169 @@
     // CATEGORY: SETTINGS
     SETTINGS_LOCK_SCREEN_PREFERENCES = 882;
 
+    // ACTION: An app requested the app-op permission ACCESS_NOTIFICATIONS
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_APPOP_REQUEST_ACCESS_NOTIFICATIONS = 883;
+
+    // ACTION: An app was granted the app-op permission ACCESS_NOTIFICATIONS
+    // PACKAGE: The package name of the app that was granted the permission
+    ACTION_APPOP_GRANT_ACCESS_NOTIFICATIONS = 884;
+
+    // ACTION: An app requested the app-op permission ACCESS_NOTIFICATIONS and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_APPOP_DENIED_ACCESS_NOTIFICATIONS = 885;
+
+    // ACTION: The app-op permission ACCESS_NOTIFICATIONS was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    ACTION_APPOP_REVOKE_ACCESS_NOTIFICATIONS = 886;
+
+    // ACTION: An app requested the app-op permission SYSTEM_ALERT_WINDOW
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_APPOP_REQUEST_SYSTEM_ALERT_WINDOW = 887;
+
+    // ACTION: An app was granted the app-op permission SYSTEM_ALERT_WINDOW
+    // PACKAGE: The package name of the app that was granted the permission
+    ACTION_APPOP_GRANT_SYSTEM_ALERT_WINDOW = 888;
+
+    // ACTION: An app requested the app-op permission SYSTEM_ALERT_WINDOW and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_APPOP_DENIED_SYSTEM_ALERT_WINDOW = 889;
+
+    // ACTION: The app-op permission SYSTEM_ALERT_WINDOW was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    ACTION_APPOP_REVOKE_SYSTEM_ALERT_WINDOW = 890;
+
+    // ACTION: An app requested the app-op permission REQUEST_WRITE_SETTINGS
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_APPOP_REQUEST_WRITE_SETTINGS = 891;
+
+    // ACTION: An app was granted the app-op permission REQUEST_WRITE_SETTINGS
+    // PACKAGE: The package name of the app that was granted the permission
+    ACTION_APPOP_GRANT_WRITE_SETTINGS = 892;
+
+    // ACTION: An app requested the app-op permission REQUEST_WRITE_SETTINGS and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_APPOP_DENIED_WRITE_SETTINGS = 893;
+
+    // ACTION: The app-op permission REQUEST_WRITE_SETTINGS was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    ACTION_APPOP_REVOKE_WRITE_SETTINGS = 894;
+
+    // ACTION: An app requested the app-op permission REQUEST_INSTALL_PACKAGES
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_APPOP_REQUEST_REQUEST_INSTALL_PACKAGES = 895;
+
+    // ACTION: An app was granted the app-op permission REQUEST_INSTALL_PACKAGES
+    // PACKAGE: The package name of the app that was granted the permission
+    ACTION_APPOP_GRANT_REQUEST_INSTALL_PACKAGES = 896;
+
+    // ACTION: An app requested the app-op permission REQUEST_INSTALL_PACKAGES and the request was denied
+    // PACKAGE: The package name of the app requesting the permission
+    ACTION_APPOP_DENIED_REQUEST_INSTALL_PACKAGES = 897;
+
+    // ACTION: The app-op permission REQUEST_INSTALL_PACKAGES was revoked for an app
+    // PACKAGE: The package name of the app the permission was revoked for
+    ACTION_APPOP_REVOKE_REQUEST_INSTALL_PACKAGES = 898;
+
+    // ACTION: Phase 1 of instant application resolution occurred
+    // OS: O
+    ACTION_INSTANT_APP_RESOLUTION_PHASE_ONE = 899;
+
+    // ACTION: Phase 2 of instant application resolution occurred
+    // OS: O
+    ACTION_INSTANT_APP_RESOLUTION_PHASE_TWO = 900;
+
+    // FIELD: The amount of time for an ephemeral resolution phase; in milliseconds
+    // OS: O
+    FIELD_INSTANT_APP_RESOLUTION_DELAY_MS = 901;
+
+    // FIELD: The status of an ephemeral resolution phase
+    // Value 0: success
+    // Value 1: no full hash match
+    // OS: O
+    FIELD_INSTANT_APP_RESOLUTION_STATUS = 902;
+
+    // FIELD - A token to identify all events that are part of the same instant application launch
+    // OS: O
+    FIELD_INSTANT_APP_LAUNCH_TOKEN = 903;
+
+    // FIELD - The name of the package responsible for launching the activity
+    // OS: O
+    APP_TRANSITION_CALLING_PACKAGE_NAME = 904;
+
+    // FIELD - Whether or not the launched activity is part of an instant application
+    // OS: O
+    APP_TRANSITION_IS_EPHEMERAL = 905;
+
+    // An autofill session was started
+    // Package: Package of app that is autofilled
+    AUTOFILL_SESSION_STARTED = 906;
+
+    // An autofill request was processed by a service
+    // Type TYPE_SUCCESS: The request succeeded
+    // Type TYPE_FAILURE: The request failed
+    // Package: Package of app that is autofilled
+    // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
+    // Tag FIELD_AUTOFILL_NUM_DATASET: The number of datasets returned (only in success case)
+    AUTOFILL_REQUEST = 907;
+
+    // Tag of a field for a package of an autofill service
+    FIELD_AUTOFILL_SERVICE = 908;
+
+    // Tag of a field for the number of datasets
+    FIELD_AUTOFILL_NUM_DATASETS = 909;
+
+    // An autofill dataset selection UI was shown
+    // Type TYPE_DISMISS: UI was explicityly canceled by the user
+    // Type TYPE_CLOSE: UI was destroyed without influence of the user
+    // Type TYPE_ACTION: dataset was selected
+    // Type TYPE_DETAIL: authentication was selected
+    // Package: Package of app that was autofilled
+    // Tag FIELD_AUTOFILL_FILTERTEXT_LEN: The length of the filter text
+    // Tag FIELD_AUTOFILL_NUM_DATASETS: The number of datasets shown
+    AUTOFILL_FILL_UI = 910;
+
+    // Tag of a field for the length of the filter text
+    FIELD_AUTOFILL_FILTERTEXT_LEN = 911;
+
+    // An autofill authentification succeeded
+    // Package: Package of app that was autofilled
+    AUTOFILL_AUTHENTICATED = 912;
+
+    // An activity was autofilled and all values could be applied
+    // Package: Package of app that is autofilled
+    // Tag FIELD_AUTOFILL_NUM_VALUES: Number of values that were suggested to be autofilled
+    // Tag FIELD_AUTOFILL_NUM_VIEWS_FILLED: Number of views that could be filled
+    AUTOFILL_DATASET_APPLIED = 913;
+
+    // Tag of a field for the number values to be filled in
+    FIELD_AUTOFILL_NUM_VALUES = 914;
+
+    // Tag of a field for the number of views that were filled
+    FIELD_AUTOFILL_NUM_VIEWS_FILLED = 915;
+
+    // An autofill save UI was shown
+    // Type TYPE_DISMISS: UI was explicityly canceled by the user
+    // Type TYPE_CLOSE: UI was destroyed without influence of the user
+    // Type TYPE_ACTION: data was saved
+    // Package: Package of app that was autofilled
+    // Tag FIELD_AUTOFILL_NUM_ID: The number of ids that are saved
+    AUTOFILL_SAVE_UI = 916;
+
+    // Tag of a field for the number of saveable ids
+    FIELD_AUTOFILL_NUM_IDS = 917;
+
+    // ACTION: An autofill service was reqiested to save data
+    // Type TYPE_SUCCESS: The request succeeded
+    // Type TYPE_FAILURE: The request failed
+    // Package: Package of app that was autofilled
+    // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
+    AUTOFILL_DATA_SAVE_REQUEST = 918;
+
+    // An auto-fill session was finished
+    // Package: Package of app that was autofilled
+    AUTOFILL_SESSION_FINISHED = 919;
+
     // ---- 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 a372f95..c7ba1ff 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -28,6 +28,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.database.ContentObserver;
 import android.graphics.Rect;
@@ -53,6 +54,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.os.IResultReceiver;
+import com.android.internal.util.Preconditions;
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
@@ -316,13 +318,27 @@
         @Override
         public void startSession(IBinder activityToken, IBinder windowToken, IBinder appCallback,
                 AutofillId autofillId, Rect bounds, AutofillValue value, int userId,
-                boolean hasCallback) {
+                boolean hasCallback, int flags, String packageName) {
             // TODO(b/33197203): make sure it's called by resumed / focused activity
 
+            activityToken = Preconditions.checkNotNull(activityToken, "activityToken");
+            appCallback = Preconditions.checkNotNull(appCallback, "appCallback");
+            autofillId = Preconditions.checkNotNull(autofillId, "autoFillId");
+            bounds = Preconditions.checkNotNull(bounds, "bounds");
+            packageName = Preconditions.checkNotNull(packageName, "packageName");
+
+            Preconditions.checkArgument(userId == UserHandle.getUserId(getCallingUid()), "userId");
+
+            try {
+                mContext.getPackageManager().getPackageInfoAsUser(packageName, 0, userId);
+            } catch (PackageManager.NameNotFoundException e) {
+                throw new IllegalArgumentException(packageName + " is not a valid package", e);
+            }
+
             synchronized (mLock) {
                 final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
                 service.startSessionLocked(activityToken, windowToken, appCallback,
-                        autofillId, bounds, value, hasCallback);
+                        autofillId, bounds, value, hasCallback, flags, packageName);
             }
         }
 
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 4786cbe..df76009 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -28,6 +28,7 @@
 import static com.android.server.autofill.Helper.VERBOSE;
 import static com.android.server.autofill.Helper.findValue;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.ActivityManager;
@@ -43,6 +44,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
 import android.graphics.Rect;
+import android.metrics.LogMaker;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -67,14 +69,17 @@
 import android.view.autofill.AutofillManager;
 import android.view.autofill.AutofillValue;
 import android.view.autofill.IAutoFillManagerClient;
+import android.view.autofill.AutofillManager.AutofillCallback;
+
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.internal.os.HandlerCaller;
 import com.android.internal.os.IResultReceiver;
 import com.android.server.autofill.ui.AutoFillUI;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Map;
 import java.util.Map.Entry;
 
@@ -93,6 +98,7 @@
     private final Context mContext;
     private final Object mLock;
     private final AutoFillUI mUi;
+    private final MetricsLogger mMetricsLogger = new MetricsLogger();
 
     private RemoteCallbackList<IAutoFillManagerClient> mClients;
     private AutofillServiceInfo mInfo;
@@ -171,7 +177,7 @@
             structure.sanitizeForParceling(true);
 
             // TODO(b/33197203): Need to pipe the bundle
-            session.mRemoteFillService.onFillRequest(structure, null);
+            session.mRemoteFillService.onFillRequest(structure, null, session.mFlags);
         }
     };
 
@@ -229,9 +235,8 @@
                 if (!hasService()) {
                     final int sessionCount = mSessions.size();
                     for (int i = sessionCount - 1; i >= 0; i--) {
-                        Session session = mSessions.valueAt(i);
-                        session.destroyLocked();
-                        mSessions.removeAt(i);
+                        final Session session = mSessions.valueAt(i);
+                        session.removeSelfLocked();
                     }
                 }
                 sendStateToClients();
@@ -285,8 +290,10 @@
         }
     }
 
-    void startSessionLocked(IBinder activityToken, IBinder windowToken, IBinder appCallbackToken,
-            AutofillId autofillId,  Rect bounds, AutofillValue value, boolean hasCallback) {
+    void startSessionLocked(@NonNull IBinder activityToken, @Nullable IBinder windowToken,
+            @NonNull IBinder appCallbackToken, @NonNull AutofillId autofillId, @NonNull Rect bounds,
+            @Nullable AutofillValue value, boolean hasCallback, int flags,
+            @NonNull String packageName) {
         if (!hasService()) {
             return;
         }
@@ -294,7 +301,7 @@
         final String historyItem = "s=" + mInfo.getServiceInfo().packageName
                 + " u=" + mUserId + " a=" + activityToken
 
-                + " i=" + autofillId + " b=" + bounds + " hc=" + hasCallback;
+                + " i=" + autofillId + " b=" + bounds + " hc=" + hasCallback + " f=" + flags;
         mRequestsHistory.log(historyItem);
 
         // TODO(b/33197203): Handle partitioning
@@ -305,7 +312,7 @@
         }
 
         final Session newSession = createSessionByTokenLocked(activityToken,
-                windowToken, appCallbackToken, hasCallback);
+                windowToken, appCallbackToken, hasCallback, flags, packageName);
         newSession.updateLocked(autofillId, bounds, value, FLAG_START_SESSION);
     }
 
@@ -320,7 +327,13 @@
             return;
         }
 
-        session.showSaveLocked();
+        final boolean finished = session.showSaveLocked();
+        if (DEBUG) {
+            Log.d(TAG, "finishSessionLocked(): session finished on save? " + finished);
+        }
+        if (finished) {
+            session.removeSelf();
+        }
     }
 
     void cancelSessionLocked(IBinder activityToken) {
@@ -333,14 +346,14 @@
             Slog.w(TAG, "cancelSessionLocked(): no session for " + activityToken);
             return;
         }
-
-        session.destroyLocked();
+        session.removeSelfLocked();
     }
 
-    private Session createSessionByTokenLocked(IBinder activityToken, IBinder windowToken,
-            IBinder appCallbackToken, boolean hasCallback) {
+    private Session createSessionByTokenLocked(@NonNull IBinder activityToken,
+            @Nullable IBinder windowToken, @NonNull IBinder appCallbackToken, boolean hasCallback,
+            int flags, @NonNull String packageName) {
         final Session newSession = new Session(mContext, activityToken,
-                windowToken, appCallbackToken, hasCallback);
+                windowToken, appCallbackToken, hasCallback, flags, packageName);
         mSessions.put(activityToken, newSession);
 
         /*
@@ -351,7 +364,6 @@
          * - display disclosure if needed
          */
         try {
-            // TODO(b/33197203): add MetricsLogger call
             final Bundle receiverExtras = new Bundle();
             receiverExtras.putBinder(EXTRA_ACTIVITY_TOKEN, activityToken);
             final long identity = Binder.clearCallingIdentity();
@@ -371,7 +383,6 @@
 
     void updateSessionLocked(IBinder activityToken, AutofillId autofillId, Rect bounds,
             AutofillValue value, int flags) {
-        // TODO(b/33197203): add MetricsLogger call
         final Session session = mSessions.get(activityToken);
         if (session == null) {
             if (VERBOSE) {
@@ -595,6 +606,9 @@
         private final IBinder mActivityToken;
         private final IBinder mWindowToken;
 
+        /** Package name of the app that is auto-filled */
+        @NonNull private final String mPackageName;
+
         @GuardedBy("mLock")
         private final Map<AutofillId, ViewState> mViewStates = new ArrayMap<>();
 
@@ -630,13 +644,20 @@
          */
         private boolean mHasCallback;
 
-        private Session(Context context, IBinder activityToken, IBinder windowToken,
-                IBinder client, boolean hasCallback) {
+        /**
+         * Flags used to start the session.
+         */
+        private int mFlags;
+        private Session(@NonNull Context context, @NonNull IBinder activityToken,
+                @Nullable IBinder windowToken, @NonNull IBinder client, boolean hasCallback,
+                int flags, @NonNull String packageName) {
             mRemoteFillService = new RemoteFillService(context,
                     mInfo.getServiceInfo().getComponentName(), mUserId, this);
             mActivityToken = activityToken;
             mWindowToken = windowToken;
             mHasCallback = hasCallback;
+            mFlags = flags;
+            mPackageName = packageName;
 
             mClient = IAutoFillManagerClient.Stub.asInterface(client);
             try {
@@ -650,41 +671,82 @@
             } catch (RemoteException e) {
                 Slog.w(TAG, "linkToDeath() on mClient failed: " + e);
             }
+
+            mMetricsLogger.action(MetricsProto.MetricsEvent.AUTOFILL_SESSION_STARTED, mPackageName);
         }
 
         // FillServiceCallbacks
         @Override
-        public void onFillRequestSuccess(FillResponse response) {
-            // TODO(b/33197203): add MetricsLogger call
+        public void onFillRequestSuccess(@Nullable FillResponse response,
+                @NonNull String servicePackageName) {
             if (response == null) {
+                // Nothing to be done, but need to notify client.
+                notifyUnavailableToClient();
                 removeSelf();
                 return;
             }
+
+            if ((response.getDatasets() == null || response.getDatasets().isEmpty())
+                            && response.getAuthentication() == null) {
+                // Response is "empty" from an UI point of view, need to notify client.
+                notifyUnavailableToClient();
+            }
             synchronized (mLock) {
                 processResponseLocked(response);
             }
+
+            LogMaker log = (new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_REQUEST))
+                    .setType(MetricsProto.MetricsEvent.TYPE_SUCCESS)
+                    .setPackageName(mPackageName)
+                    .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS,
+                            response.getDatasets() == null ? 0 : response.getDatasets().size())
+                    .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_SERVICE,
+                            servicePackageName);
+            mMetricsLogger.write(log);
         }
 
         // FillServiceCallbacks
         @Override
-        public void onFillRequestFailure(CharSequence message) {
-            // TODO(b/33197203): add MetricsLogger call
+        public void onFillRequestFailure(@Nullable CharSequence message,
+                @NonNull String servicePackageName) {
+            LogMaker log = (new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_REQUEST))
+                    .setType(MetricsProto.MetricsEvent.TYPE_FAILURE)
+                    .setPackageName(mPackageName)
+                    .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_SERVICE,
+                            servicePackageName);
+            mMetricsLogger.write(log);
+
             getUiForShowing().showError(message);
             removeSelf();
         }
 
         // FillServiceCallbacks
         @Override
-        public void onSaveRequestSuccess() {
-            // TODO(b/33197203): add MetricsLogger call
+        public void onSaveRequestSuccess(@NonNull String servicePackageName) {
+            LogMaker log = (new LogMaker(
+                    MetricsProto.MetricsEvent.AUTOFILL_DATA_SAVE_REQUEST))
+                    .setType(MetricsProto.MetricsEvent.TYPE_SUCCESS)
+                    .setPackageName(mPackageName)
+                    .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_SERVICE,
+                            servicePackageName);
+            mMetricsLogger.write(log);
+
             // Nothing left to do...
             removeSelf();
         }
 
         // FillServiceCallbacks
         @Override
-        public void onSaveRequestFailure(CharSequence message) {
-            // TODO(b/33197203): add MetricsLogger call
+        public void onSaveRequestFailure(@Nullable CharSequence message,
+                @NonNull String servicePackageName) {
+            LogMaker log = (new LogMaker(
+                    MetricsProto.MetricsEvent.AUTOFILL_DATA_SAVE_REQUEST))
+                    .setType(MetricsProto.MetricsEvent.TYPE_FAILURE)
+                    .setPackageName(mPackageName)
+                    .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_SERVICE,
+                            servicePackageName);
+            mMetricsLogger.write(log);
+
             getUiForShowing().showError(message);
             removeSelf();
         }
@@ -696,9 +758,7 @@
             synchronized (mLock) {
                 fillInIntent = createAuthFillInIntent(mStructure);
             }
-            mHandlerCaller.getHandler().post(() -> {
-                startAuthentication(intent, fillInIntent);
-            });
+            mHandlerCaller.getHandler().post(() -> startAuthentication(intent, fillInIntent));
         }
 
         // FillServiceCallbacks
@@ -718,8 +778,7 @@
                 Binder.restoreCallingIdentity(identity);
             }
             synchronized (mLock) {
-                destroyLocked();
-                mSessions.remove(this);
+                removeSelfLocked();
             }
         }
 
@@ -732,9 +791,7 @@
         // AutoFillUiCallback
         @Override
         public void fill(Dataset dataset) {
-            mHandlerCaller.getHandler().post(() -> {
-                autoFill(dataset);
-            });
+            mHandlerCaller.getHandler().post(() -> autoFill(dataset));
         }
 
         // AutoFillUiCallback
@@ -747,17 +804,13 @@
         // AutoFillUiCallback
         @Override
         public void cancelSave() {
-            mHandlerCaller.getHandler().post(() -> {
-                removeSelf();
-            });
+            mHandlerCaller.getHandler().post(() -> removeSelf());
         }
 
         // AutoFillUiCallback
         @Override
         public void onEvent(AutofillId id, int event) {
-            mHandlerCaller.getHandler().post(() -> {
-                notifyChangeToClient(id, event);
-            });
+            mHandlerCaller.getHandler().post(() -> notifyChangeToClient(id, event));
         }
 
         public void setAuthenticationResultLocked(Bundle data) {
@@ -767,6 +820,9 @@
                 Parcelable result = data.getParcelable(
                         AutofillManager.EXTRA_AUTHENTICATION_RESULT);
                 if (result instanceof FillResponse) {
+                    mMetricsLogger.action(MetricsProto.MetricsEvent.AUTOFILL_AUTHENTICATED,
+                            mPackageName);
+
                     mCurrentResponse = (FillResponse) result;
                     processResponseLocked(mCurrentResponse);
                 } else if (result instanceof Dataset) {
@@ -784,12 +840,14 @@
         }
 
         /**
-         * Show the save UI, when session can be saved.
+         * Shows the save UI, when session can be saved.
+         *
+         * @return {@code true} if session is done, or {@code false} if it's pending user action.
          */
-        public void showSaveLocked() {
+        public boolean showSaveLocked() {
             if (mStructure == null) {
                 Slog.wtf(TAG, "showSaveLocked(): no mStructure");
-                return;
+                return true;
             }
             if (mCurrentResponse == null) {
                 // Happens when the activity / session was finished before the service replied, or
@@ -797,7 +855,7 @@
                 if (DEBUG) {
                     Slog.d(TAG, "showSaveLocked(): no mCurrentResponse");
                 }
-                return;
+                return true;
             }
             final SaveInfo saveInfo = mCurrentResponse.getSaveInfo();
             if (DEBUG) {
@@ -813,13 +871,13 @@
              */
 
             if (saveInfo == null) {
-                return;
+                return true;
             }
 
             final AutofillId[] requiredIds = saveInfo.getRequiredIds();
             if (requiredIds == null || requiredIds.length == 0) {
                 Slog.w(TAG, "showSaveLocked(): no required ids on saveInfo");
-                return;
+                return true;
             }
 
             boolean allRequiredAreNotEmpty = true;
@@ -856,7 +914,8 @@
                 } else {
                     if (state.mAutofillValue == null || state.mAutofillValue.isEmpty()) {
                         if (DEBUG) {
-                            Slog.d(TAG, "finishSessionLocked(): empty value for " + id );
+                            Slog.d(TAG, "finishSessionLocked(): empty value for " + id + ": "
+                                    + state.mAutofillValue);
                         }
                         allRequiredAreNotEmpty = false;
                         break;
@@ -887,8 +946,8 @@
                 if (atLeastOneChanged) {
                     getUiForShowing().showSaveUi(
                             mInfo.getServiceInfo().loadLabel(mContext.getPackageManager()),
-                            saveInfo);
-                    return;
+                            saveInfo, mPackageName);
+                    return false;
                 }
             }
             // Nothing changed...
@@ -897,7 +956,7 @@
                         + "allRequiredAreNotNull=" + allRequiredAreNotEmpty
                         + ", atLeastOneChanged=" + atLeastOneChanged);
             }
-            removeSelf();
+            return true;
         }
 
         /**
@@ -939,7 +998,7 @@
                 mStructure.dump();
             }
 
-            mRemoteFillService.onSaveRequest(mStructure, extras);
+            mRemoteFillService.onSaveRequest(mStructure, extras, () -> removeSelf());
         }
 
         void updateLocked(AutofillId id, Rect bounds, AutofillValue value, int flags) {
@@ -1027,7 +1086,7 @@
                 filterText = value.getTextValue().toString();
             }
 
-            getUiForShowing().showFillUi(filledId, response, bounds, filterText);
+            getUiForShowing().showFillUi(filledId, response, bounds, filterText, mPackageName);
         }
 
         private void notifyChangeToClient(AutofillId id, int event) {
@@ -1039,17 +1098,24 @@
             }
         }
 
+        private void notifyUnavailableToClient() {
+            if (mCurrentViewState == null) {
+                // TODO(b/33197203): temporary sanity check; should never happen
+                Slog.w(TAG, "notifyUnavailable(): mCurrentViewState is null");
+                return;
+            }
+            notifyChangeToClient(mCurrentViewState.mId, AutofillCallback.EVENT_INPUT_UNAVAILABLE);
+        }
+
         private void processResponseLocked(FillResponse response) {
             if (DEBUG) {
                 Slog.d(TAG, "processResponseLocked(auth=" + response.getAuthentication()
                     + "):" + response);
             }
 
-            // TODO(b/33197203): add MetricsLogger calls
-
             if (mCurrentViewState == null) {
                 // TODO(b/33197203): temporary sanity check; should never happen
-                Slog.w(TAG, "processResponseLocked(): mCurrentResponse is null");
+                Slog.w(TAG, "processResponseLocked(): mCurrentViewState is null");
                 return;
             }
 
@@ -1101,6 +1167,7 @@
 
         void dumpLocked(String prefix, PrintWriter pw) {
             pw.print(prefix); pw.print("mActivityToken: "); pw.println(mActivityToken);
+            pw.print(prefix); pw.print("mFlags: "); pw.println(mFlags);
             pw.print(prefix); pw.print("mCurrentResponse: "); pw.println(mCurrentResponse);
             pw.print(prefix); pw.print("mAutoFilledDataset: "); pw.println(mAutoFilledDataset);
             pw.print(prefix); pw.print("mCurrentViewStates: "); pw.println(mCurrentViewState);
@@ -1180,17 +1247,23 @@
         private void destroyLocked() {
             mRemoteFillService.destroy();
             mUi.setCallback(null, null);
+
+            mMetricsLogger.action(MetricsProto.MetricsEvent.AUTOFILL_SESSION_FINISHED,
+                    mPackageName);
         }
 
-        private void removeSelf() {
-            if (VERBOSE) {
-                Slog.v(TAG, "removeSelf()");
-            }
-
+        void removeSelf() {
             synchronized (mLock) {
-                destroyLocked();
-                mSessions.remove(mActivityToken);
+                removeSelfLocked();
             }
         }
+
+        private void removeSelfLocked() {
+            if (VERBOSE) {
+                Slog.v(TAG, "removeSelfLocked()");
+            }
+            destroyLocked();
+            mSessions.remove(mActivityToken);
+        }
     }
 }
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 47251db..d1c8b4f8 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -16,6 +16,8 @@
 
 package com.android.server.autofill;
 
+import static com.android.server.autofill.Helper.DEBUG;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.assist.AssistStructure;
@@ -38,8 +40,10 @@
 import android.service.autofill.ISaveCallback;
 import android.text.format.DateUtils;
 import android.util.Slog;
+
 import com.android.internal.os.HandlerCaller;
 import com.android.server.FgThread;
+import com.android.server.autofill.AutofillManagerServiceImpl.Session;
 
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
@@ -55,8 +59,6 @@
 final class RemoteFillService implements DeathRecipient {
     private static final String LOG_TAG = "RemoteFillService";
 
-    private static final boolean DEBUG = Helper.DEBUG;
-
     // How long after the last interaction with the service we would unbind
     private static final long TIMEOUT_IDLE_BIND_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS;
 
@@ -87,10 +89,10 @@
     private PendingRequest mPendingRequest;
 
     public interface FillServiceCallbacks {
-        void onFillRequestSuccess(FillResponse response);
-        void onFillRequestFailure(CharSequence message);
-        void onSaveRequestSuccess();
-        void onSaveRequestFailure(CharSequence message);
+        void onFillRequestSuccess(@Nullable FillResponse response, @NonNull String servicePackageName);
+        void onFillRequestFailure(@Nullable CharSequence message, @NonNull String servicePackageName);
+        void onSaveRequestSuccess(@NonNull String servicePackageName);
+        void onSaveRequestFailure(@Nullable CharSequence message, @NonNull String servicePackageName);
         void onServiceDied(RemoteFillService service);
         void onDisableSelf();
     }
@@ -132,15 +134,17 @@
         mCallbacks.onServiceDied(this);
     }
 
-    public void onFillRequest(@NonNull AssistStructure structure, @Nullable Bundle extras) {
+    public void onFillRequest(@NonNull AssistStructure structure, @Nullable Bundle extras,
+            int flags) {
         cancelScheduledUnbind();
-        final PendingFillRequest request = new PendingFillRequest(structure, extras, this);
+        final PendingFillRequest request = new PendingFillRequest(structure, extras, this, flags);
         mHandler.obtainMessageO(MyHandler.MSG_ON_PENDING_REQUEST, request).sendToTarget();
     }
 
-    public void onSaveRequest(@NonNull AssistStructure structure, @Nullable Bundle extras) {
+    public void onSaveRequest(@NonNull AssistStructure structure, @Nullable Bundle extras,
+            @Nullable Runnable finalizer) {
         cancelScheduledUnbind();
-        final PendingSaveRequest request = new PendingSaveRequest(structure, extras, this);
+        final PendingSaveRequest request = new PendingSaveRequest(structure, extras, this, finalizer);
         mHandler.obtainMessageO(MyHandler.MSG_ON_PENDING_REQUEST, request).sendToTarget();
     }
 
@@ -261,7 +265,7 @@
             FillResponse response) {
         mHandler.getHandler().post(() -> {
             if (handleResponseCallbackCommon(pendingRequest)) {
-                mCallbacks.onFillRequestSuccess(response);
+                mCallbacks.onFillRequestSuccess(response, mComponentName.getPackageName());
             }
         });
     }
@@ -270,7 +274,7 @@
             CharSequence message) {
         mHandler.getHandler().post(() -> {
             if (handleResponseCallbackCommon(pendingRequest)) {
-                mCallbacks.onFillRequestFailure(message);
+                mCallbacks.onFillRequestFailure(message, mComponentName.getPackageName());
             }
         });
     }
@@ -278,7 +282,7 @@
     private void dispatchOnSaveRequestSuccess(PendingRequest pendingRequest) {
         mHandler.getHandler().post(() -> {
             if (handleResponseCallbackCommon(pendingRequest)) {
-                mCallbacks.onSaveRequestSuccess();
+                mCallbacks.onSaveRequestSuccess(mComponentName.getPackageName());
             }
         });
     }
@@ -287,7 +291,7 @@
             CharSequence message) {
         mHandler.getHandler().post(() -> {
             if (handleResponseCallbackCommon(pendingRequest)) {
-                mCallbacks.onSaveRequestFailure(message);
+                mCallbacks.onSaveRequestFailure(message, mComponentName.getPackageName());
             }
         });
     }
@@ -413,16 +417,18 @@
     private static final class PendingFillRequest extends PendingRequest {
         private final Object mLock = new Object();
         private final WeakReference<RemoteFillService> mWeakService;
-        private AssistStructure mStructure;
-        private Bundle mExtras;
+        private final AssistStructure mStructure;
+        private final Bundle mExtras;
         private final IFillCallback mCallback;
         private ICancellationSignal mCancellation;
         private boolean mCancelled;
+        private int mFlags;
 
         public PendingFillRequest(AssistStructure structure,
-                Bundle extras, RemoteFillService service) {
+                Bundle extras, RemoteFillService service, int flags) {
             mStructure = structure;
             mExtras = extras;
+            mFlags = flags;
             mWeakService = new WeakReference<>(service);
             mCallback = new IFillCallback.Stub() {
                 @Override
@@ -469,11 +475,7 @@
             if (remoteService != null) {
                 try {
                     remoteService.mAutoFillService.onFillRequest(mStructure,
-                            mExtras, mCallback);
-                    synchronized (mLock) {
-                        mStructure = null;
-                        mExtras = null;
-                    }
+                            mExtras, mCallback, mFlags);
                 } catch (RemoteException e) {
                     Slog.e(LOG_TAG, "Error calling on fill request", e);
                     cancel();
@@ -503,17 +505,18 @@
     }
 
     private static final class PendingSaveRequest extends PendingRequest {
-        private final Object mLock = new Object();
         private final WeakReference<RemoteFillService> mWeakService;
-        private AssistStructure mStructure;
-        private Bundle mExtras;
+        private final AssistStructure mStructure;
+        private final Bundle mExtras;
         private final ISaveCallback mCallback;
+        private final Runnable mFinalizer;
 
-        public PendingSaveRequest(@NonNull AssistStructure structure,
-                @Nullable Bundle extras, @NonNull RemoteFillService service) {
+        public PendingSaveRequest(@NonNull AssistStructure structure, @Nullable Bundle extras,
+                @NonNull RemoteFillService service, @Nullable Runnable finalizer) {
             mStructure = structure;
             mExtras = extras;
             mWeakService = new WeakReference<>(service);
+            mFinalizer = finalizer;
             mCallback = new ISaveCallback.Stub() {
                 @Override
                 public void onSuccess() {
@@ -537,19 +540,17 @@
 
         @Override
         public void run() {
-            RemoteFillService service = mWeakService.get();
+            final RemoteFillService service = mWeakService.get();
             if (service != null) {
                 try {
-                    service.mAutoFillService.onSaveRequest(mStructure,
-                            mExtras, mCallback);
-                    synchronized (mLock) {
-                        mStructure = null;
-                        mExtras = null;
-                    }
+                    service.mAutoFillService.onSaveRequest(mStructure, mExtras, mCallback);
                 } catch (RemoteException e) {
                     Slog.e(LOG_TAG, "Error calling on save request", e);
                 }
             }
+            if (mFinalizer != null) {
+              mFinalizer.run();
+            }
         }
 
         @Override
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index c7e59a3..776fa1e 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.content.IntentSender;
 import android.graphics.Rect;
+import android.metrics.LogMaker;
 import android.os.Handler;
 import android.os.IBinder;
 import android.service.autofill.Dataset;
@@ -34,6 +35,8 @@
 import android.view.autofill.AutofillId;
 import android.widget.Toast;
 
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.server.UiThread;
 
 import java.io.PrintWriter;
@@ -60,6 +63,7 @@
     private @Nullable IBinder mWindowToken;
 
     private int mSaveTimeoutMs = (int) (5 * DateUtils.SECOND_IN_MILLIS);
+    private final MetricsLogger mMetricsLogger = new MetricsLogger();
 
     public interface AutoFillUiCallback {
         void authenticate(@NonNull IntentSender intent);
@@ -152,9 +156,17 @@
      * @param response the current fill response
      * @param anchorBounds bounds of the focused view
      * @param filterText text of the view to be filled
+     * @param packageName package name of the activity that is filled
      */
     public void showFillUi(@NonNull AutofillId focusedId, @NonNull FillResponse response,
-            @NonNull Rect anchorBounds, @Nullable String filterText) {
+            @NonNull Rect anchorBounds, @Nullable String filterText, @NonNull String packageName) {
+        LogMaker log = (new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_FILL_UI))
+                .setPackageName(packageName)
+                .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_FILTERTEXT_LEN,
+                        filterText == null ? 0 : filterText.length())
+                .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS,
+                        response.getDatasets() == null ? 0 : response.getDatasets().size());
+
         mHandler.post(() -> {
             if (!hasCallback()) {
                 return;
@@ -164,6 +176,7 @@
                     mWindowToken, anchorBounds, filterText, new FillUi.Callback() {
                 @Override
                 public void onResponsePicked(FillResponse response) {
+                    log.setType(MetricsProto.MetricsEvent.TYPE_DETAIL);
                     hideFillUiUiThread();
                     if (mCallback != null) {
                         mCallback.authenticate(response.getAuthentication());
@@ -172,17 +185,25 @@
 
                 @Override
                 public void onDatasetPicked(Dataset dataset) {
+                    log.setType(MetricsProto.MetricsEvent.TYPE_ACTION);
                     hideFillUiUiThread();
                     if (mCallback != null) {
                         mCallback.fill(dataset);
                     }
-                    // TODO(b/33197203): add MetricsLogger call
                 }
 
                 @Override
                 public void onCanceled() {
+                    log.setType(MetricsProto.MetricsEvent.TYPE_DISMISS);
                     hideFillUiUiThread();
-                    // TODO(b/33197203): add MetricsLogger call
+                }
+
+                @Override
+                public void onDestroy() {
+                    if (log.getType() == MetricsProto.MetricsEvent.TYPE_UNKNOWN) {
+                        log.setType(MetricsProto.MetricsEvent.TYPE_CLOSE);
+                    }
+                    mMetricsLogger.write(log);
                 }
             });
             mCallback.onEvent(focusedId, EVENT_INPUT_SHOWN);
@@ -192,7 +213,16 @@
     /**
      * Shows the UI asking the user to save for autofill.
      */
-    public void showSaveUi(@NonNull CharSequence providerLabel, @NonNull SaveInfo info) {
+    public void showSaveUi(@NonNull CharSequence providerLabel, @NonNull SaveInfo info,
+            @NonNull String packageName) {
+        int numIds = 0;
+        numIds += info.getRequiredIds() == null ? 0 : info.getRequiredIds().length;
+        numIds += info.getOptionalIds() == null ? 0 : info.getOptionalIds().length;
+
+        LogMaker log = (new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_SAVE_UI))
+                .setPackageName(packageName).addTaggedData(
+                        MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_IDS, numIds);
+
         mHandler.post(() -> {
             if (!hasCallback()) {
                 return;
@@ -202,16 +232,16 @@
                     new SaveUi.OnSaveListener() {
                 @Override
                 public void onSave() {
+                    log.setType(MetricsProto.MetricsEvent.TYPE_ACTION);
                     hideSaveUiUiThread();
                     if (mCallback != null) {
                         mCallback.save();
                     }
-                    // TODO(b/33197203): add MetricsLogger call
                 }
 
                 @Override
                 public void onCancel(IntentSender listener) {
-                    // TODO(b/33197203): add MetricsLogger call
+                    log.setType(MetricsProto.MetricsEvent.TYPE_DISMISS);
                     hideSaveUiUiThread();
                     if (listener != null) {
                         try {
@@ -225,6 +255,14 @@
                         mCallback.cancelSave();
                     }
                 }
+
+                @Override
+                public void onDestroy() {
+                    if (log.getType() == MetricsProto.MetricsEvent.TYPE_UNKNOWN) {
+                        log.setType(MetricsProto.MetricsEvent.TYPE_CLOSE);
+                    }
+                    mMetricsLogger.write(log);
+                }
             }, mSaveTimeoutMs);
         });
     }
@@ -247,11 +285,17 @@
     }
 
     public void dump(PrintWriter pw) {
-        pw.println("AufoFill UI");
+        pw.println("Autofill UI");
         final String prefix = "  ";
-        pw.print(prefix); pw.print("showsFillUi: "); pw.println(mFillUi != null);
+        final String prefix2 = "    ";
         pw.print(prefix); pw.print("showsSaveUi: "); pw.println(mSaveUi != null);
         pw.print(prefix); pw.print("save timeout: "); pw.println(mSaveTimeoutMs);
+        if (mFillUi != null) {
+            pw.print(prefix); pw.println("showsFillUi: true");
+            mFillUi.dump(pw, prefix2);
+        } else {
+            pw.print(prefix); pw.println("showsFillUi: false");
+        }
     }
 
     @android.annotation.UiThread
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index a7d9fe9..a8c8752 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -39,6 +39,7 @@
 import com.android.internal.R;
 import libcore.util.Objects;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
 
 final class FillUi {
@@ -50,6 +51,7 @@
         void onResponsePicked(@NonNull FillResponse response);
         void onDatasetPicked(@NonNull Dataset dataset);
         void onCanceled();
+        void onDestroy();
     }
 
     private final Rect mAnchorBounds = new Rect();
@@ -63,6 +65,7 @@
     private final @Nullable ArrayAdapter<ViewItem> mAdapter;
 
     private @Nullable String mFilterText;
+    private final String mAccessibilityTitle;
 
     private int mContentWidth;
     private int mContentHeight;
@@ -76,6 +79,8 @@
         mAnchorBounds.set(anchorBounds);
         mCallback = callback;
 
+        mAccessibilityTitle = context.getString(R.string.autofill_picker_accessibility_title);
+
         if (response.getAuthentication() != null) {
             mListView = null;
             mAdapter = null;
@@ -201,6 +206,7 @@
 
     public void destroy() {
         throwIfDestroyed();
+        mCallback.onDestroy();
         mWindow.hide();
         mDestroyed = true;
     }
@@ -319,6 +325,7 @@
 
         public void show(int desiredWidth, int desiredHeight, Rect anchorBounds) {
             final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
+
             params.setTitle("FillUi");
             params.token = mActivityToken;
             params.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
@@ -327,6 +334,7 @@
                     | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                     | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                     | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+            params.accessibilityTitle = mAccessibilityTitle;
 
             mWm.getDefaultDisplay().getRealSize(mTempPoint);
             final int screenWidth = mTempPoint.x;
@@ -377,4 +385,16 @@
             }
         }
     }
+
+    public void dump(PrintWriter pw, String prefix) {
+        pw.print(prefix); pw.print("mAnchorBounds: "); pw.println(mAnchorBounds);
+        pw.print(prefix); pw.print("mCallback: "); pw.println(mCallback != null);
+        pw.print(prefix); pw.print("mListView: "); pw.println(mListView);
+        pw.print(prefix); pw.print("mAdapter: "); pw.println(mAdapter != null);
+        pw.print(prefix); pw.print("mFilterText: "); pw.println(mFilterText);
+        pw.print(prefix); pw.print("mAccessibilityTitle: "); pw.println(mAccessibilityTitle);
+        pw.print(prefix); pw.print("mContentWidth: "); pw.println(mContentWidth);
+        pw.print(prefix); pw.print("mContentHeight: "); pw.println(mContentHeight);
+        pw.print(prefix); pw.print("mDestroyed: "); pw.println(mDestroyed);
+    }
 }
diff --git a/services/autofill/java/com/android/server/autofill/ui/Helper.java b/services/autofill/java/com/android/server/autofill/ui/Helper.java
new file mode 100644
index 0000000..996e421
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/ui/Helper.java
@@ -0,0 +1,26 @@
+/*
+ * 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.autofill.ui;
+
+final class Helper {
+
+    static final boolean DEBUG = true; // TODO(b/33197203): set to false when stable
+    static final boolean VERBOSE = false;
+    private Helper() {
+        throw new UnsupportedOperationException("contains static members only");
+    }
+}
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index 3f409ad..509351b 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -16,6 +16,8 @@
 
 package com.android.server.autofill.ui;
 
+import static com.android.server.autofill.ui.Helper.DEBUG;
+
 import android.annotation.NonNull;
 import android.app.Dialog;
 import android.content.Context;
@@ -23,6 +25,7 @@
 import android.os.Handler;
 import android.service.autofill.SaveInfo;
 import android.text.format.DateUtils;
+import android.util.Slog;
 import android.view.Gravity;
 import android.view.Window;
 import android.view.WindowManager;
@@ -37,22 +40,66 @@
  * Autofill Save Prompt
  */
 final class SaveUi {
+
+    private static final String TAG = "SaveUi";
+
     public interface OnSaveListener {
         void onSave();
         void onCancel(IntentSender listener);
+        void onDestroy();
+    }
+
+    private class OneTimeListener implements OnSaveListener {
+
+        private final OnSaveListener mRealListener;
+        private boolean mDone;
+
+        OneTimeListener(OnSaveListener realListener) {
+            mRealListener = realListener;
+        }
+
+        @Override
+        public void onSave() {
+            if (DEBUG) Slog.d(TAG, "onSave(): " + mDone);
+            if (mDone) {
+                return;
+            }
+            mDone = true;
+            mRealListener.onSave();
+        }
+
+        @Override
+        public void onCancel(IntentSender listener) {
+            if (DEBUG) Slog.d(TAG, "onCancel(): " + mDone);
+            if (mDone) {
+                return;
+            }
+            mDone = true;
+            mRealListener.onCancel(listener);
+        }
+
+        @Override
+        public void onDestroy() {
+            if (DEBUG) Slog.d(TAG, "onDestroy(): " + mDone);
+            if (mDone) {
+                return;
+            }
+            mDone = true;
+            mRealListener.onDestroy();
+        }
     }
 
     private final Handler mHandler = UiThread.getHandler();
 
     private final @NonNull Dialog mDialog;
 
-    private final @NonNull OnSaveListener mListener;
+    private final @NonNull OneTimeListener mListener;
 
     private boolean mDestroyed;
 
     SaveUi(@NonNull Context context, @NonNull CharSequence providerLabel, @NonNull SaveInfo info,
             @NonNull OnSaveListener listener, int lifeTimeMs) {
-        mListener = listener;
+        mListener = new OneTimeListener(listener);
 
         final LayoutInflater inflater = LayoutInflater.from(context);
         final View view = inflater.inflate(R.layout.autofill_save, null);
@@ -117,11 +164,17 @@
 
         mDialog.show();
 
-        mHandler.postDelayed(() -> mListener.onCancel(null), lifeTimeMs);
+        mHandler.postDelayed(() -> {
+            if (!mListener.mDone) {
+                mListener.onCancel(null);
+                Slog.d(TAG, "Save snackbar timed out after " + lifeTimeMs + "ms");
+            }
+        }, lifeTimeMs);
     }
 
     void destroy() {
         throwIfDestroyed();
+        mListener.onDestroy();
         mHandler.removeCallbacksAndMessages(mListener);
         mDialog.dismiss();
         mDestroyed = true;
diff --git a/services/core/Android.mk b/services/core/Android.mk
index 1864d34..794ece6 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -23,7 +23,9 @@
     android.hardware.power@1.0-java \
     android.hardware.tv.cec@1.0-java
 
-LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update2 \
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    tzdata_shared2 \
+    tzdata_update2 \
     android.hidl.base@1.0-java-static \
     android.hardware.biometrics.fingerprint@2.1-java-static \
 
diff --git a/services/core/java/com/android/server/BackgroundDexOptJobService.java b/services/core/java/com/android/server/BackgroundDexOptJobService.java
deleted file mode 100644
index 69e6ac5..0000000
--- a/services/core/java/com/android/server/BackgroundDexOptJobService.java
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;
-
-import android.app.job.JobInfo;
-import android.app.job.JobParameters;
-import android.app.job.JobScheduler;
-import android.app.job.JobService;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.BatteryManager;
-import android.os.Environment;
-import android.os.ServiceManager;
-import android.os.storage.StorageManager;
-import android.util.ArraySet;
-import android.util.Log;
-import com.android.server.pm.PackageManagerService;
-
-import java.io.File;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.TimeUnit;
-
-public class BackgroundDexOptJobService extends JobService {
-    private static final String TAG = "BackgroundDexOptJobService";
-
-    private static final boolean DEBUG = false;
-
-    private static final int JOB_IDLE_OPTIMIZE = 800;
-    private static final int JOB_POST_BOOT_UPDATE = 801;
-
-    private static final long IDLE_OPTIMIZATION_PERIOD = DEBUG
-            ? TimeUnit.MINUTES.toMillis(1)
-            : TimeUnit.DAYS.toMillis(1);
-
-    private static ComponentName sDexoptServiceName = new ComponentName(
-            "android",
-            BackgroundDexOptJobService.class.getName());
-
-    /**
-     * Set of failed packages remembered across job runs.
-     */
-    static final ArraySet<String> sFailedPackageNames = new ArraySet<String>();
-
-    /**
-     * Atomics set to true if the JobScheduler requests an abort.
-     */
-    final AtomicBoolean mAbortPostBootUpdate = new AtomicBoolean(false);
-    final AtomicBoolean mAbortIdleOptimization = new AtomicBoolean(false);
-
-    /**
-     * Atomic set to true if one job should exit early because another job was started.
-     */
-    final AtomicBoolean mExitPostBootUpdate = new AtomicBoolean(false);
-
-    private final File mDataDir = Environment.getDataDirectory();
-
-    public static void schedule(Context context) {
-        JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
-
-        // Schedule a one-off job which scans installed packages and updates
-        // out-of-date oat files.
-        js.schedule(new JobInfo.Builder(JOB_POST_BOOT_UPDATE, sDexoptServiceName)
-                    .setMinimumLatency(TimeUnit.MINUTES.toMillis(1))
-                    .setOverrideDeadline(TimeUnit.MINUTES.toMillis(1))
-                    .build());
-
-        // Schedule a daily job which scans installed packages and compiles
-        // those with fresh profiling data.
-        js.schedule(new JobInfo.Builder(JOB_IDLE_OPTIMIZE, sDexoptServiceName)
-                    .setRequiresDeviceIdle(true)
-                    .setRequiresCharging(true)
-                    .setPeriodic(IDLE_OPTIMIZATION_PERIOD)
-                    .build());
-
-        if (DEBUG_DEXOPT) {
-            Log.i(TAG, "Jobs scheduled");
-        }
-    }
-
-    public static void notifyPackageChanged(String packageName) {
-        // The idle maintanance job skips packages which previously failed to
-        // compile. The given package has changed and may successfully compile
-        // now. Remove it from the list of known failing packages.
-        synchronized (sFailedPackageNames) {
-            sFailedPackageNames.remove(packageName);
-        }
-    }
-
-    // Returns the current battery level as a 0-100 integer.
-    private int getBatteryLevel() {
-        IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
-        Intent intent = registerReceiver(null, filter);
-        int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
-        int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
-
-        if (level < 0 || scale <= 0) {
-            // Battery data unavailable. This should never happen, so assume the worst.
-            return 0;
-        }
-
-        return (100 * level / scale);
-    }
-
-    private long getLowStorageThreshold() {
-        @SuppressWarnings("deprecation")
-        final long lowThreshold = StorageManager.from(this).getStorageLowBytes(mDataDir);
-        if (lowThreshold == 0) {
-            Log.e(TAG, "Invalid low storage threshold");
-        }
-
-        return lowThreshold;
-    }
-
-    private boolean runPostBootUpdate(final JobParameters jobParams,
-            final PackageManagerService pm, final ArraySet<String> pkgs) {
-        if (mExitPostBootUpdate.get()) {
-            // This job has already been superseded. Do not start it.
-            return false;
-        }
-        new Thread("BackgroundDexOptService_PostBootUpdate") {
-            @Override
-            public void run() {
-                postBootUpdate(jobParams, pm, pkgs);
-            }
-
-        }.start();
-        return true;
-    }
-
-    private void postBootUpdate(JobParameters jobParams, PackageManagerService pm,
-            ArraySet<String> pkgs) {
-        // Load low battery threshold from the system config. This is a 0-100 integer.
-        final int lowBatteryThreshold = getResources().getInteger(
-                com.android.internal.R.integer.config_lowBatteryWarningLevel);
-        final long lowThreshold = getLowStorageThreshold();
-
-        mAbortPostBootUpdate.set(false);
-
-        for (String pkg : pkgs) {
-            if (mAbortPostBootUpdate.get()) {
-                // JobScheduler requested an early abort.
-                return;
-            }
-            if (mExitPostBootUpdate.get()) {
-                // Different job, which supersedes this one, is running.
-                break;
-            }
-            if (getBatteryLevel() < lowBatteryThreshold) {
-                // Rather bail than completely drain the battery.
-                break;
-            }
-            long usableSpace = mDataDir.getUsableSpace();
-            if (usableSpace < lowThreshold) {
-                // Rather bail than completely fill up the disk.
-                Log.w(TAG, "Aborting background dex opt job due to low storage: " +
-                        usableSpace);
-                break;
-            }
-
-            if (DEBUG_DEXOPT) {
-                Log.i(TAG, "Updating package " + pkg);
-            }
-
-            // Update package if needed. Note that there can be no race between concurrent
-            // jobs because PackageDexOptimizer.performDexOpt is synchronized.
-
-            // checkProfiles is false to avoid merging profiles during boot which
-            // might interfere with background compilation (b/28612421).
-            // Unfortunately this will also means that "pm.dexopt.boot=speed-profile" will
-            // behave differently than "pm.dexopt.bg-dexopt=speed-profile" but that's a
-            // trade-off worth doing to save boot time work.
-            pm.performDexOpt(pkg,
-                    /* checkProfiles */ false,
-                    PackageManagerService.REASON_BOOT,
-                    /* force */ false);
-        }
-        // Ran to completion, so we abandon our timeslice and do not reschedule.
-        jobFinished(jobParams, /* reschedule */ false);
-    }
-
-    private boolean runIdleOptimization(final JobParameters jobParams,
-            final PackageManagerService pm, final ArraySet<String> pkgs) {
-        new Thread("BackgroundDexOptService_IdleOptimization") {
-            @Override
-            public void run() {
-                idleOptimization(jobParams, pm, pkgs);
-            }
-        }.start();
-        return true;
-    }
-
-    private void idleOptimization(JobParameters jobParams, PackageManagerService pm,
-            ArraySet<String> pkgs) {
-        Log.i(TAG, "Performing idle optimizations");
-        // If post-boot update is still running, request that it exits early.
-        mExitPostBootUpdate.set(true);
-
-        mAbortIdleOptimization.set(false);
-
-        final long lowThreshold = getLowStorageThreshold();
-        for (String pkg : pkgs) {
-            if (mAbortIdleOptimization.get()) {
-                // JobScheduler requested an early abort.
-                return;
-            }
-
-            synchronized (sFailedPackageNames) {
-                if (sFailedPackageNames.contains(pkg)) {
-                    // Skip previously failing package
-                    continue;
-                }
-            }
-
-            long usableSpace = mDataDir.getUsableSpace();
-            if (usableSpace < lowThreshold) {
-                // Rather bail than completely fill up the disk.
-                Log.w(TAG, "Aborting background dex opt job due to low storage: " +
-                        usableSpace);
-                break;
-            }
-
-            // Conservatively add package to the list of failing ones in case performDexOpt
-            // never returns.
-            synchronized (sFailedPackageNames) {
-                sFailedPackageNames.add(pkg);
-            }
-            // Optimize package if needed. Note that there can be no race between
-            // concurrent jobs because PackageDexOptimizer.performDexOpt is synchronized.
-            if (pm.performDexOpt(pkg,
-                    /* checkProfiles */ true,
-                    PackageManagerService.REASON_BACKGROUND_DEXOPT,
-                    /* force */ false)) {
-                // Dexopt succeeded, remove package from the list of failing ones.
-                synchronized (sFailedPackageNames) {
-                    sFailedPackageNames.remove(pkg);
-                }
-            }
-        }
-        // Ran to completion, so we abandon our timeslice and do not reschedule.
-        jobFinished(jobParams, /* reschedule */ false);
-    }
-
-    @Override
-    public boolean onStartJob(JobParameters params) {
-        if (DEBUG_DEXOPT) {
-            Log.i(TAG, "onStartJob");
-        }
-
-        // NOTE: PackageManagerService.isStorageLow uses a different set of criteria from
-        // the checks above. This check is not "live" - the value is determined by a background
-        // restart with a period of ~1 minute.
-        PackageManagerService pm = (PackageManagerService)ServiceManager.getService("package");
-        if (pm.isStorageLow()) {
-            if (DEBUG_DEXOPT) {
-                Log.i(TAG, "Low storage, skipping this run");
-            }
-            return false;
-        }
-
-        final ArraySet<String> pkgs = pm.getOptimizablePackages();
-        if (pkgs == null || pkgs.isEmpty()) {
-            if (DEBUG_DEXOPT) {
-                Log.i(TAG, "No packages to optimize");
-            }
-            return false;
-        }
-
-        if (params.getJobId() == JOB_POST_BOOT_UPDATE) {
-            return runPostBootUpdate(params, pm, pkgs);
-        } else {
-            return runIdleOptimization(params, pm, pkgs);
-        }
-    }
-
-    @Override
-    public boolean onStopJob(JobParameters params) {
-        if (DEBUG_DEXOPT) {
-            Log.i(TAG, "onStopJob");
-        }
-
-        if (params.getJobId() == JOB_POST_BOOT_UPDATE) {
-            mAbortPostBootUpdate.set(true);
-        } else {
-            mAbortIdleOptimization.set(true);
-        }
-        return false;
-    }
-}
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index bcee2c1b..c946d09 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -146,6 +146,7 @@
     private final LockPatternUtils mLockPatternUtils;
     private final NotificationManager mNotificationManager;
     private final UserManager mUserManager;
+    private final DevicePolicyManager mDevicePolicyManager;
     private final IActivityManager mActivityManager;
 
     private final KeyStore mKeyStore;
@@ -333,6 +334,10 @@
             return (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         }
 
+        public DevicePolicyManager getDevicePolicyManager() {
+            return (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+        }
+
         public KeyStore getKeyStore() {
             return KeyStore.getInstance();
         }
@@ -380,6 +385,7 @@
         mStorage = injector.getStorage();
         mNotificationManager = injector.getNotificationManager();
         mUserManager = injector.getUserManager();
+        mDevicePolicyManager = injector.getDevicePolicyManager();
         mStrongAuthTracker = injector.getStrongAuthTracker();
         mStrongAuthTracker.register(mStrongAuth);
 
@@ -1482,7 +1488,7 @@
             return VerifyCredentialResponse.OK;
         }
 
-        if (TextUtils.isEmpty(credential)) {
+        if (storedHash == null || TextUtils.isEmpty(credential)) {
             return VerifyCredentialResponse.ERROR;
         }
 
@@ -2015,14 +2021,17 @@
             }
         }
         long handle = getSyntheticPasswordHandleLocked(userId);
-        AuthenticationToken auth = mSpManager.unwrapPasswordBasedSyntheticPassword(
-                getGateKeeperService(), handle, savedCredential, userId).authToken;
+        AuthenticationResult authResult = mSpManager.unwrapPasswordBasedSyntheticPassword(
+                getGateKeeperService(), handle, savedCredential, userId);
+        VerifyCredentialResponse response = authResult.gkResponse;
+        AuthenticationToken auth = authResult.authToken;
         if (auth != null) {
             // We are performing a trusted credential change i.e. a correct existing credential
             // is provided
             setLockCredentialWithAuthTokenLocked(credential, credentialType, auth, userId);
             mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId);
-        } else {
+        } else if (response != null
+                && response.getResponseCode() == VerifyCredentialResponse.RESPONSE_ERROR){
             // We are performing an untrusted credential change i.e. by DevicePolicyManager.
             // So provision a new SP and SID. This would invalidate existing escrow tokens.
             // Still support this for now but this flow will be removed in the next release.
@@ -2031,6 +2040,10 @@
             initializeSyntheticPasswordLocked(null, credential, credentialType, userId);
             synchronizeUnifiedWorkChallengeForProfiles(userId, null);
             mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId);
+        } else /* response == null || responseCode == VerifyCredentialResponse.RESPONSE_RETRY */ {
+            Slog.w(TAG, "spBasedSetLockCredentialInternalLocked: " +
+                    (response != null ? "rate limit exceeded" : "failed"));
+            return;
         }
         notifyActivePasswordMetricsAvailable(credential, userId);
 
@@ -2042,7 +2055,7 @@
         if (DEBUG) Slog.d(TAG, "addEscrowToken: user=" + userId);
         synchronized (mSpManager) {
             enableSyntheticPasswordLocked();
-            // Migrate to synthetic password based credentials if ther user has no password,
+            // Migrate to synthetic password based credentials if the user has no password,
             // the token can then be activated immediately.
             AuthenticationToken auth = null;
             if (!isUserSecure(userId)) {
@@ -2201,22 +2214,20 @@
                 Slog.i(TAG, "Managed profile can have escrow token");
                 return;
             }
-            DevicePolicyManager dpm = (DevicePolicyManager)
-                    mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
             // Devices with Device Owner should have escrow enabled on all users.
-            if (dpm.getDeviceOwnerComponentOnAnyUser() != null) {
+            if (mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser() != null) {
                 Slog.i(TAG, "Corp-owned device can have escrow token");
                 return;
             }
             // We could also have a profile owner on the given (non-managed) user for unicorn cases
-            if (dpm.getProfileOwnerAsUser(userId) != null) {
+            if (mDevicePolicyManager.getProfileOwnerAsUser(userId) != null) {
                 Slog.i(TAG, "User with profile owner can have escrow token");
                 return;
             }
             // If the device is yet to be provisioned (still in SUW), there is still
             // a chance that Device Owner will be set on the device later, so postpone
             // disabling escrow token for now.
-            if (!dpm.isDeviceProvisioned()) {
+            if (!mDevicePolicyManager.isDeviceProvisioned()) {
                 Slog.i(TAG, "Postpone disabling escrow tokens until device is provisioned");
                 return;
             }
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 3667ecd..8e6310f 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -2721,7 +2721,7 @@
      */
     @Override
     public int getPasswordType() {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
+        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
             "no permission to access the crypt keeper");
 
         waitForReady();
@@ -2747,7 +2747,7 @@
      */
     @Override
     public void setField(String field, String contents) throws RemoteException {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
+        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
             "no permission to access the crypt keeper");
 
         waitForReady();
@@ -2767,7 +2767,7 @@
      */
     @Override
     public String getField(String field) throws RemoteException {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
+        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
             "no permission to access the crypt keeper");
 
         waitForReady();
@@ -2793,7 +2793,7 @@
      */
     @Override
     public boolean isConvertibleToFBE() throws RemoteException {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
+        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
             "no permission to access the crypt keeper");
 
         waitForReady();
@@ -2809,7 +2809,7 @@
 
     @Override
     public String getPassword() throws RemoteException {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
+        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
                 "only keyguard can retrieve password");
 
         if (!isReady()) {
@@ -2834,7 +2834,7 @@
 
     @Override
     public void clearPassword() throws RemoteException {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
+        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
                 "only keyguard can clear password");
 
         if (!isReady()) {
diff --git a/services/core/java/com/android/server/SyntheticPasswordManager.java b/services/core/java/com/android/server/SyntheticPasswordManager.java
index 6267880..2517613 100644
--- a/services/core/java/com/android/server/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/SyntheticPasswordManager.java
@@ -526,7 +526,7 @@
      * RESPONSE_OK, since user authentication failures are detected earlier when trying to
      * decrypt SP.
      */
-    public VerifyCredentialResponse verifyChallenge(IGateKeeperService gatekeeper,
+    public @Nullable VerifyCredentialResponse verifyChallenge(IGateKeeperService gatekeeper,
             @NonNull AuthenticationToken auth, long challenge, int userId) throws RemoteException {
         byte[] spHandle = loadSyntheticPasswordHandle(userId);
         if (spHandle == null) {
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index accae0d..f954f75 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -35,7 +35,6 @@
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityThread;
-import android.app.AppGlobals;
 import android.app.AppOpsManager;
 import android.app.INotificationManager;
 import android.app.Notification;
@@ -64,7 +63,6 @@
 import android.content.pm.UserInfo;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteStatement;
-import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Environment;
@@ -80,7 +78,6 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.os.storage.StorageManager;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
@@ -113,7 +110,6 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -158,6 +154,11 @@
         public void onUnlockUser(int userHandle) {
             mService.onUnlockUser(userHandle);
         }
+
+        @Override
+        public void onCleanupUser(int userHandle) {
+            mService.onCleanupUser(userHandle);
+        }
     }
 
     final Context mContext;
@@ -303,18 +304,6 @@
             }
         }, intentFilter);
 
-        IntentFilter userFilter = new IntentFilter();
-        userFilter.addAction(Intent.ACTION_USER_REMOVED);
-        mContext.registerReceiverAsUser(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                String action = intent.getAction();
-                if (Intent.ACTION_USER_REMOVED.equals(action)) {
-                    onUserRemoved(intent);
-                }
-            }
-        }, UserHandle.ALL, userFilter, null, null);
-
         injector.addLocalService(new AccountManagerInternalImpl());
 
         // Need to cancel account request notifications if the update/install can access the account
@@ -1133,16 +1122,12 @@
         }
     }
 
-    private void onUserRemoved(Intent intent) {
-        int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
-        if (userId < 1) return;
-
+    private void onCleanupUser(int userId) {
+        Log.i(TAG, "onCleanupUser " + userId);
         UserAccounts accounts;
-        boolean userUnlocked;
         synchronized (mUsers) {
             accounts = mUsers.get(userId);
             mUsers.remove(userId);
-            userUnlocked = mLocalUnlockedUsers.get(userId);
             mLocalUnlockedUsers.delete(userId);
         }
         if (accounts != null) {
@@ -1150,18 +1135,6 @@
                 accounts.accountsDb.close();
             }
         }
-        Log.i(TAG, "Removing database files for user " + userId);
-        File dbFile = new File(mInjector.getDeDatabaseName(userId));
-
-        AccountsDb.deleteDbFileWarnIfFailed(dbFile);
-        // Remove CE file if user is unlocked, or FBE is not enabled
-        boolean fbeEnabled = StorageManager.isFileEncryptedNativeOrEmulated();
-        if (!fbeEnabled || userUnlocked) {
-            File ceDb = new File(mInjector.getCeDatabaseName(userId));
-            if (ceDb.exists()) {
-                AccountsDb.deleteDbFileWarnIfFailed(ceDb);
-            }
-        }
     }
 
     @VisibleForTesting
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 100d821..df250b1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -105,16 +105,16 @@
     }
 
     private void updateConstants() {
+        final String setting = Settings.Global.getString(mResolver,
+                Settings.Global.ACTIVITY_MANAGER_CONSTANTS);
         synchronized (mService) {
             try {
-                mParser.setString(Settings.Global.getString(mResolver,
-                        Settings.Global.ACTIVITY_MANAGER_CONSTANTS));
+                mParser.setString(setting);
             } 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);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 55d661c..b40e709 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5384,9 +5384,10 @@
             ProcessCpuTracker processCpuTracker, SparseArray<Boolean> lastPids, String[] nativeProcs) {
         // Use a FileObserver to detect when traces finish writing.
         // The order of traces is considered important to maintain for legibility.
+        final boolean[] closed = new boolean[1];
         FileObserver observer = new FileObserver(tracesPath, FileObserver.CLOSE_WRITE) {
             @Override
-            public synchronized void onEvent(int event, String path) { notify(); }
+            public synchronized void onEvent(int event, String path) { closed[0] = true; notify(); }
         };
 
         try {
@@ -5403,6 +5404,7 @@
                             final long sime = SystemClock.elapsedRealtime();
                             Process.sendSignal(firstPids.get(i), Process.SIGNAL_QUIT);
                             observer.wait(1000);  // Wait for write-close, give up after 1 sec
+                            if (!closed[0]) Slog.w(TAG, "Didn't see close of " + tracesPath);
                             if (DEBUG_ANR) Slog.d(TAG, "Done with pid " + firstPids.get(i)
                                     + " in " + (SystemClock.elapsedRealtime()-sime) + "ms");
                         }
@@ -21493,6 +21495,15 @@
         return success;
     }
 
+    private boolean isEphemeralLocked(int uid) {
+        String packages[] = mContext.getPackageManager().getPackagesForUid(uid);
+        if (packages == null || packages.length != 1) { // Ephemeral apps cannot share uid
+            return false;
+        }
+        return getPackageManagerInternalLocked().isPackageEphemeral(UserHandle.getUserId(uid),
+                packages[0]);
+    }
+
     private final void enqueueUidChangeLocked(UidRecord uidRec, int uid, int change) {
         final UidRecord.ChangeItem pendingChange;
         if (uidRec == null || uidRec.pendingChange == null) {
@@ -21533,7 +21544,7 @@
         pendingChange.change = change;
         pendingChange.processState = uidRec != null
                 ? uidRec.setProcState : ActivityManager.PROCESS_STATE_NONEXISTENT;
-        pendingChange.ephemeral = uidRec.ephemeral;
+        pendingChange.ephemeral = uidRec != null ? uidRec.ephemeral : isEphemeralLocked(uid);
         pendingChange.procStateSeq = uidRec != null ? uidRec.curProcStateSeq : 0;
 
         // Directly update the power manager, since we sit on top of it and it is critical
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index ebbce02..918747b 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -251,7 +251,8 @@
      *                       ActivityManagerInternal.APP_TRANSITION_* reasons.
      */
     void notifyTransitionStarting(SparseIntArray stackIdReasons) {
-        if (!isAnyTransitionActive() || mLoggedTransitionStarting) {
+        // TODO (b/36339388): Figure out why stackIdReasons can be null
+        if (stackIdReasons == null || !isAnyTransitionActive() || mLoggedTransitionStarting) {
             return;
         }
         mCurrentTransitionDelayMs = calculateCurrentDelay();
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 2e26bed..2b2471b 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -1953,11 +1953,6 @@
     }
 
     void setRequestedOrientation(int requestedOrientation) {
-        if (task != null && (!task.mFullscreen || !task.getStack().mFullscreen)) {
-            // Fixed screen orientation isn't supported when activities aren't in full screen mode.
-            return;
-        }
-
         final int displayId = getDisplayId();
         final Configuration displayConfig =
                 mStackSupervisor.getDisplayOverrideConfiguration(displayId);
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 42efe0b..217515b 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -16,6 +16,7 @@
 
 package com.android.server.am;
 
+import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
 import static android.Manifest.permission.START_ANY_ACTIVITY;
 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
 import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
@@ -1612,8 +1613,8 @@
             return true;
         }
 
-        // Check if the caller can launch anything.
-        final int startAnyPerm = mService.checkPermission(START_ANY_ACTIVITY, callingPid,
+        // Check if the caller can manage activity stacks.
+        final int startAnyPerm = mService.checkPermission(MANAGE_ACTIVITY_STACKS, callingPid,
                 callingUid);
         if (startAnyPerm == PERMISSION_GRANTED) {
             if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 36a913f..f927cce 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -857,17 +857,26 @@
 
         ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);
 
-        String[] nativeProcs = NATIVE_STACKS_OF_INTEREST;
-        // don't dump native PIDs for background ANRs
-        File tracesFile = null;
+        // don't dump native PIDs for background ANRs unless it is the process of interest
+        String[] nativeProcs = null;
         if (isSilentANR) {
-            tracesFile = mService.dumpStackTraces(true, firstPids, null, lastPids,
-                null);
+            for (int i = 0; i < NATIVE_STACKS_OF_INTEREST.length; i++) {
+                if (NATIVE_STACKS_OF_INTEREST[i].equals(app.processName)) {
+                    nativeProcs = new String[] { app.processName };
+                    break;
+                }
+            }
         } else {
-            tracesFile = mService.dumpStackTraces(true, firstPids, processCpuTracker, lastPids,
-                nativeProcs);
+            nativeProcs = NATIVE_STACKS_OF_INTEREST;
         }
 
+        // For background ANRs, don't pass the ProcessCpuTracker to
+        // avoid spending 1/2 second collecting stats to rank lastPids.
+        File tracesFile = mService.dumpStackTraces(true, firstPids,
+                                                   (isSilentANR) ? null : processCpuTracker,
+                                                   (isSilentANR) ? null : lastPids,
+                                                   nativeProcs);
+
         String cpuInfo = null;
         if (ActivityManagerService.MONITOR_CPU_USAGE) {
             mService.updateCpuStatsNow();
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 2787895..dd3d4e0 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -1152,17 +1152,14 @@
                     skip = true;
                 }
             }
-            final boolean visibleToInstantApps =
-                    (r.intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0;
             if (!skip && info.activityInfo.applicationInfo.isInstantApp()
-                    && !visibleToInstantApps
                     && r.callingUid != info.activityInfo.applicationInfo.uid) {
                 Slog.w(TAG, "Instant App Denial: receiving "
                         + r.intent
                         + " to " + component.flattenToShortString()
                         + " due to sender " + r.callerPackage
                         + " (uid " + r.callingUid + ")"
-                        + " not specifying FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS");
+                        + " Instant Apps do not support manifest receivers");
                 skip = true;
             }
             if (!skip && r.callerInstantApp
diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
index dec2f77..8c6430c 100644
--- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
+++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
@@ -16,6 +16,8 @@
 
 package com.android.server.connectivity.tethering;
 
+import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
+
 import android.net.INetd;
 import android.net.IpPrefix;
 import android.net.LinkAddress;
@@ -48,7 +50,6 @@
 public class IPv6TetheringInterfaceServices {
     private static final String TAG = IPv6TetheringInterfaceServices.class.getSimpleName();
     private static final IpPrefix LINK_LOCAL_PREFIX = new IpPrefix("fe80::/64");
-    private static final int RFC7421_IP_PREFIX_LENGTH = 64;
 
     private final String mIfName;
     private final INetworkManagementService mNMService;
@@ -124,7 +125,7 @@
             params.hasDefaultRoute = v6only.hasIPv6DefaultRoute();
 
             for (LinkAddress linkAddr : v6only.getLinkAddresses()) {
-                if (linkAddr.getPrefixLength() != RFC7421_IP_PREFIX_LENGTH) continue;
+                if (linkAddr.getPrefixLength() != RFC7421_PREFIX_LENGTH) continue;
 
                 final IpPrefix prefix = new IpPrefix(
                         linkAddr.getAddress(), linkAddr.getPrefixLength());
@@ -206,7 +207,7 @@
             for (Inet6Address dns : deprecatedDnses) {
                 final String dnsString = dns.getHostAddress();
                 try {
-                    netd.interfaceDelAddress(mIfName, dnsString, RFC7421_IP_PREFIX_LENGTH);
+                    netd.interfaceDelAddress(mIfName, dnsString, RFC7421_PREFIX_LENGTH);
                 } catch (ServiceSpecificException | RemoteException e) {
                     Log.e(TAG, "Failed to remove local dns IP: " + dnsString, e);
                 }
@@ -223,7 +224,7 @@
             for (Inet6Address dns : addedDnses) {
                 final String dnsString = dns.getHostAddress();
                 try {
-                    netd.interfaceAddAddress(mIfName, dnsString, RFC7421_IP_PREFIX_LENGTH);
+                    netd.interfaceAddAddress(mIfName, dnsString, RFC7421_PREFIX_LENGTH);
                 } catch (ServiceSpecificException | RemoteException e) {
                     Log.e(TAG, "Failed to add local dns IP: " + dnsString, e);
                     newDnses.remove(dns);
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 3262151..bdba64f 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -97,7 +97,6 @@
     static final String TAG = "FingerprintService";
     static final boolean DEBUG = true;
     private static final String FP_DATA_DIR = "fpdata";
-    private static final String FINGERPRINT_HIDL = "fingerprint_hal";
     private static final int MSG_USER_SWITCHING = 10;
     private static final String ACTION_LOCKOUT_RESET =
             "com.android.server.fingerprint.ACTION_LOCKOUT_RESET";
@@ -219,7 +218,7 @@
     public synchronized IBiometricsFingerprint getFingerprintDaemon() {
         if (mDaemon == null) {
             try {
-                mDaemon = IBiometricsFingerprint.getService(FINGERPRINT_HIDL);
+                mDaemon = IBiometricsFingerprint.getService();
             } catch (java.util.NoSuchElementException e) {
                 // Service doesn't exist or cannot be opened. Logged below.
             } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index be8aaf0..3dcc5d9 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -22,10 +22,10 @@
 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
 import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
-import static android.service.notification.NotificationListenerService.REASON_DELEGATE_CANCEL;
-import static android.service.notification.NotificationListenerService.REASON_DELEGATE_CANCEL_ALL;
-import static android.service.notification.NotificationListenerService.REASON_DELEGATE_CLICK;
-import static android.service.notification.NotificationListenerService.REASON_DELEGATE_ERROR;
+import static android.service.notification.NotificationListenerService.REASON_CANCEL;
+import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
+import static android.service.notification.NotificationListenerService.REASON_CLICK;
+import static android.service.notification.NotificationListenerService.REASON_ERROR;
 import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL;
 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL;
@@ -88,7 +88,6 @@
 import android.media.AudioManager;
 import android.media.AudioManagerInternal;
 import android.media.IRingtonePlayer;
-import android.metrics.LogMaker;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
@@ -179,7 +178,6 @@
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -543,7 +541,7 @@
         @Override
         public void onClearAll(int callingUid, int callingPid, int userId) {
             synchronized (mNotificationLock) {
-                cancelAllLocked(callingUid, callingPid, userId, REASON_DELEGATE_CANCEL_ALL, null,
+                cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null,
                         /*includeCurrentProfiles*/ true);
             }
         }
@@ -567,7 +565,7 @@
                 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
                         sbn.getId(), Notification.FLAG_AUTO_CANCEL,
                         Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
-                        REASON_DELEGATE_CLICK, null);
+                        REASON_CLICK, null);
             }
         }
 
@@ -596,7 +594,7 @@
                 String pkg, String tag, int id, int userId) {
             cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
                     Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
-                    true, userId, REASON_DELEGATE_CANCEL, null);
+                    true, userId, REASON_CANCEL, null);
         }
 
         @Override
@@ -631,7 +629,7 @@
             Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
                     + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
             cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
-                    REASON_DELEGATE_ERROR, null);
+                    REASON_ERROR, null);
             long ident = Binder.clearCallingIdentity();
             try {
                 ActivityManager.getService().crashApplication(uid, initialPid, pkg, -1,
@@ -1658,8 +1656,7 @@
         public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
                 String channelId, boolean includeDeleted) {
             checkCallerIsSystem();
-            return mRankingHelper.getNotificationChannel
-                    (pkg, uid, channelId, includeDeleted);
+            return mRankingHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted);
         }
 
         @Override
@@ -1675,6 +1672,27 @@
         }
 
         @Override
+        public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
+                String pkg) {
+            checkCallerIsSystemOrSameApp(pkg);
+            return new ParceledListSlice<>(new ArrayList(
+                    mRankingHelper.getNotificationChannelGroups(pkg, Binder.getCallingUid())));
+        }
+
+        @Override
+        public void deleteNotificationChannelGroup(String pkg, String channelGroupId) {
+            checkCallerIsSystemOrSameApp(pkg);
+
+            List<String> deletedChannelIds = mRankingHelper.deleteNotificationChannelGroup(
+                    pkg, Binder.getCallingUid(), channelGroupId);
+            for (int i = 0; i < deletedChannelIds.size(); i++) {
+                cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannelIds.get(i), 0, 0, true,
+                        UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
+            }
+            savePolicyFile();
+        }
+
+        @Override
         public void updateNotificationChannelForPackage(String pkg, int uid,
                 NotificationChannel channel) {
             enforceSystemOrSystemUI("Caller not system or systemui");
@@ -1698,6 +1716,12 @@
         }
 
         @Override
+        public int getDeletedChannelCount(String pkg, int uid) {
+            enforceSystemOrSystemUI("getDeletedChannelCount");
+            return mRankingHelper.getDeletedChannelCount(pkg, uid);
+        }
+
+        @Override
         public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
                 String pkg, int uid, boolean includeDeleted) {
             checkCallerIsSystem();
@@ -3349,7 +3373,7 @@
                         Slog.e(TAG, "Not posting notification without small icon: " + notification);
                         if (old != null && !old.isCanceled) {
                             mListeners.notifyRemovedLocked(n,
-                                    NotificationListenerService.REASON_DELEGATE_ERROR);
+                                    NotificationListenerService.REASON_ERROR);
                             mHandler.post(new Runnable() {
                                 @Override
                                 public void run() {
@@ -3996,8 +4020,8 @@
         // Record usage stats
         // TODO: add unbundling stats?
         switch (reason) {
-            case REASON_DELEGATE_CANCEL:
-            case REASON_DELEGATE_CANCEL_ALL:
+            case REASON_CANCEL:
+            case REASON_CANCEL_ALL:
             case REASON_LISTENER_CANCEL:
             case REASON_LISTENER_CANCEL_ALL:
                 mUsageStats.registerDismissedByUser(r);
@@ -4057,7 +4081,7 @@
 
                         // Ideally we'd do this in the caller of this method. However, that would
                         // require the caller to also find the notification.
-                        if (reason == REASON_DELEGATE_CLICK) {
+                        if (reason == REASON_CLICK) {
                             mUsageStats.registerClickedByUser(r);
                         }
 
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 4b1804c..02f92fe 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -15,8 +15,6 @@
  */
 package com.android.server.notification;
 
-import static android.app.NotificationManager.IMPORTANCE_NONE;
-
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
@@ -69,7 +67,6 @@
 
     private static final String ATT_VERSION = "version";
     private static final String ATT_NAME = "name";
-    private static final String ATT_NAME_RES_ID = "name_res_id";
     private static final String ATT_UID = "uid";
     private static final String ATT_ID = "id";
     private static final String ATT_PRIORITY = "priority";
@@ -195,14 +192,9 @@
                             if (TAG_GROUP.equals(tagName)) {
                                 String id = parser.getAttributeValue(null, ATT_ID);
                                 CharSequence groupName = parser.getAttributeValue(null, ATT_NAME);
-                                int groupNameRes = safeInt(parser, ATT_NAME_RES_ID, 0);
                                 if (!TextUtils.isEmpty(id)) {
-                                    NotificationChannelGroup group = null;
-                                    if (groupName != null) {
-                                        group = new NotificationChannelGroup(id, groupName);
-                                    } else {
-                                        group = new NotificationChannelGroup(id, groupNameRes);
-                                    }
+                                    NotificationChannelGroup group
+                                            = new NotificationChannelGroup(id, groupName);
                                     r.groups.put(id, group);
                                 }
                             }
@@ -210,19 +202,12 @@
                             if (TAG_CHANNEL.equals(tagName)) {
                                 String id = parser.getAttributeValue(null, ATT_ID);
                                 CharSequence channelName = parser.getAttributeValue(null, ATT_NAME);
-                                int channelNameRes = safeInt(parser, ATT_NAME_RES_ID, 0);
                                 int channelImportance =
                                         safeInt(parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
 
-                                if (!TextUtils.isEmpty(id)) {
-                                    NotificationChannel channel;
-                                    if (channelName != null) {
-                                        channel = new NotificationChannel(id, channelName,
-                                                channelImportance);
-                                    } else {
-                                        channel = new NotificationChannel(id, channelNameRes,
-                                                channelImportance);
-                                    }
+                                if (!TextUtils.isEmpty(id) && !TextUtils.isEmpty(channelName)) {
+                                    NotificationChannel channel = new NotificationChannel(id,
+                                            channelName, channelImportance);
                                     channel.populateFromXml(parser);
                                     r.channels.put(id, channel);
                                 }
@@ -302,7 +287,7 @@
             NotificationChannel channel;
             channel = new NotificationChannel(
                     NotificationChannel.DEFAULT_CHANNEL_ID,
-                    R.string.default_notification_channel_label,
+                    mContext.getString(R.string.default_notification_channel_label),
                     r.importance);
             channel.setBypassDnd(r.priority == Notification.PRIORITY_MAX);
             channel.setLockscreenVisibility(r.visibility);
@@ -482,8 +467,7 @@
         Preconditions.checkNotNull(pkg);
         Preconditions.checkNotNull(group);
         Preconditions.checkNotNull(group.getId());
-        Preconditions.checkNotNull(!TextUtils.isEmpty(group.getName())
-                || group.getNameResId() != 0);
+        Preconditions.checkNotNull(!TextUtils.isEmpty(group.getName()));
         Record r = getOrCreateRecord(pkg, uid);
         if (r == null) {
             throw new IllegalArgumentException("Invalid package");
@@ -504,8 +488,7 @@
         Preconditions.checkNotNull(pkg);
         Preconditions.checkNotNull(channel);
         Preconditions.checkNotNull(channel.getId());
-        Preconditions.checkArgument(!TextUtils.isEmpty(channel.getName())
-                || channel.getNameResId() != 0);
+        Preconditions.checkArgument(!TextUtils.isEmpty(channel.getName()));
         Record r = getOrCreateRecord(pkg, uid);
         if (r == null) {
             throw new IllegalArgumentException("Invalid package");
@@ -524,7 +507,7 @@
                 existing.setDeleted(false);
             }
 
-            existing.setNameResId(channel.getNameResId());
+            existing.setName(channel.getName());
 
             MetricsLogger.action(getChannelLog(channel, pkg));
             updateConfig();
@@ -669,8 +652,6 @@
 
     @Override
     public void deleteNotificationChannel(String pkg, int uid, String channelId) {
-        Preconditions.checkNotNull(pkg);
-        Preconditions.checkNotNull(channelId);
         Record r = getRecord(pkg, uid);
         if (r == null) {
             return;
@@ -682,6 +663,7 @@
         LogMaker lm = getChannelLog(channel, pkg);
         lm.setType(MetricsProto.MetricsEvent.TYPE_CLOSE);
         MetricsLogger.action(lm);
+        updateConfig();
     }
 
     @Override
@@ -694,6 +676,7 @@
             return;
         }
         r.channels.remove(channelId);
+        updateConfig();
     }
 
     @Override
@@ -710,6 +693,7 @@
                 r.channels.remove(key);
             }
         }
+        updateConfig();
     }
 
     public NotificationChannelGroup getNotificationChannelGroup(String groupId, String pkg,
@@ -734,12 +718,15 @@
             final NotificationChannel nc = r.channels.valueAt(i);
             if (includeDeleted || !nc.isDeleted()) {
                 if (nc.getGroup() != null) {
-                    NotificationChannelGroup ncg = groups.get(nc.getGroup());
-                    if (ncg == null ) {
-                        ncg = r.groups.get(nc.getGroup()).clone();
-                        groups.put(nc.getGroup(), ncg);
+                    if (r.groups.get(nc.getGroup()) != null) {
+                        NotificationChannelGroup ncg = groups.get(nc.getGroup());
+                        if (ncg == null) {
+                            ncg = r.groups.get(nc.getGroup()).clone();
+                            groups.put(nc.getGroup(), ncg);
+
+                        }
+                        ncg.addChannel(nc);
                     }
-                    ncg.addChannel(nc);
                 } else {
                     nonGrouped.addChannel(nc);
                 }
@@ -751,8 +738,29 @@
         return new ParceledListSlice<>(new ArrayList<>(groups.values()));
     }
 
+    public List<String> deleteNotificationChannelGroup(String pkg, int uid,
+            String groupId) {
+        List<String> deletedChannelIds = new ArrayList<>();
+        Record r = getRecord(pkg, uid);
+        if (r == null || TextUtils.isEmpty(groupId)) {
+            return deletedChannelIds;
+        }
+
+        r.groups.remove(groupId);
+
+        int N = r.channels.size();
+        for (int i = 0; i < N; i++) {
+            final NotificationChannel nc = r.channels.valueAt(i);
+            if (groupId.equals(nc.getGroup())) {
+                nc.setDeleted(true);
+                deletedChannelIds.add(nc.getId());
+            }
+        }
+        updateConfig();
+        return deletedChannelIds;
+    }
+
     @Override
-    @VisibleForTesting
     public Collection<NotificationChannelGroup> getNotificationChannelGroups(String pkg,
             int uid) {
         Record r = getRecord(pkg, uid);
@@ -781,6 +789,23 @@
         return new ParceledListSlice<>(channels);
     }
 
+    public int getDeletedChannelCount(String pkg, int uid) {
+        Preconditions.checkNotNull(pkg);
+        int deletedCount = 0;
+        Record r = getRecord(pkg, uid);
+        if (r == null) {
+            return deletedCount;
+        }
+        int N = r.channels.size();
+        for (int i = 0; i < N; i++) {
+            final NotificationChannel nc = r.channels.valueAt(i);
+            if (nc.isDeleted()) {
+                deletedCount++;
+            }
+        }
+        return deletedCount;
+    }
+
     /**
      * Sets importance.
      */
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index 6af1c3b..db133f8 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -130,7 +130,7 @@
         // installed and should be removed
         final int storedOverlayInfosSize = storedOverlayInfos.size();
         for (int i = 0; i < storedOverlayInfosSize; i++) {
-            final OverlayInfo oi = storedOverlayInfos.get(i);
+            final OverlayInfo oi = storedOverlayInfos.valueAt(i);
             mSettings.remove(oi.packageName, oi.userId);
             removeIdmapIfPossible(oi);
             packagesToUpdateAssets.add(oi.targetPackageName);
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 7aa96cf..d364d17 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -49,8 +49,6 @@
 
     private static final boolean DEBUG = false;
 
-    private static final long RETRY_LATENCY = 4 * AlarmManager.INTERVAL_HOUR;
-
     private static final int JOB_IDLE_OPTIMIZE = 800;
     private static final int JOB_POST_BOOT_UPDATE = 801;
 
@@ -292,8 +290,8 @@
                             PackageManagerService.REASON_BACKGROUND_DEXOPT,
                             /* force */ false)
                     : pm.performDexOptSecondary(pkg,
-                            PackageManagerServiceCompilerMapping.getFullCompilerFilter(),
-                            /* force */ true);
+                            PackageManagerService.REASON_BACKGROUND_DEXOPT,
+                            /* force */ false);
             if (success) {
                 // Dexopt succeeded, remove package from the list of failing ones.
                 synchronized (failedPackageNames) {
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index aac04da..126f8c4 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -214,6 +214,7 @@
         if (getAvailableSpace() > 0) {
             dexoptCommandCountExecuted++;
 
+            Log.d(TAG, "Next command: " + next);
             return next;
         } else {
             if (DEBUG_DEXOPT) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 0ec85aa..2e4a3a3 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -915,7 +915,7 @@
 
         // This is kind of hacky; we're creating a half-parsed package that is
         // straddled between the inherited and staged APKs.
-        final PackageLite pkg = new PackageLite(null, baseApk, null, null,
+        final PackageLite pkg = new PackageLite(null, baseApk, null, null, null, null,
                 splitPaths.toArray(new String[splitPaths.size()]), null);
         final boolean isForwardLocked =
                 (params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 4ac1cce..2882d20 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -260,7 +260,6 @@
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
 import com.android.server.AttributeCache;
-import com.android.server.BackgroundDexOptJobService;
 import com.android.server.DeviceIdleController;
 import com.android.server.EventLogTags;
 import com.android.server.FgThread;
@@ -272,6 +271,7 @@
 import com.android.server.SystemServerInitThreadPool;
 import com.android.server.Watchdog;
 import com.android.server.net.NetworkPolicyManagerInternal;
+import com.android.server.pm.BackgroundDexOptService;
 import com.android.server.pm.Installer.InstallerException;
 import com.android.server.pm.PermissionsState.PermissionState;
 import com.android.server.pm.Settings.DatabaseVersion;
@@ -2038,12 +2038,15 @@
         final boolean supportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion
                 >= Build.VERSION_CODES.M;
 
+        final boolean instantApp = isInstantApp(pkg.packageName, userId);
+
         for (String permission : pkg.requestedPermissions) {
             final BasePermission bp;
             synchronized (mPackages) {
                 bp = mSettings.mPermissions.get(permission);
             }
             if (bp != null && (bp.isRuntime() || bp.isDevelopment())
+                    && (!instantApp || bp.isInstant())
                     && (grantedPermissions == null
                            || ArrayUtils.contains(grantedPermissions, permission))) {
                 final int flags = permissionsState.getPermissionFlags(permission, userId);
@@ -3348,7 +3351,7 @@
         //   * The system/shell/root can see metadata for any app
         //   * An installed app can see metadata for 1) other installed apps
         //     and 2) ephemeral apps that have explicitly interacted with it
-        //   * Ephemeral apps can only see their own metadata
+        //   * Ephemeral apps can only see their own data and exposed installed apps
         //   * Holding a signature permission allows seeing instant apps
         final int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
         if (callingAppId != Process.SYSTEM_UID
@@ -3358,8 +3361,10 @@
                         Binder.getCallingUid()) != PackageManager.PERMISSION_GRANTED) {
             final String instantAppPackageName = getInstantAppPackageName(Binder.getCallingUid());
             if (instantAppPackageName != null) {
-                // ephemeral apps can only get information on themselves
-                if (!instantAppPackageName.equals(p.packageName)) {
+                // ephemeral apps can only get information on themselves or
+                // installed apps that are exposed.
+                if (!instantAppPackageName.equals(p.packageName)
+                        && (ps.getInstantApp(userId) || !p.visibleToInstantApps)) {
                     return null;
                 }
             } else {
@@ -8453,6 +8458,11 @@
         return mDexManager.dexoptSecondaryDex(packageName, compilerFilter, force);
     }
 
+    public boolean performDexOptSecondary(String packageName, int compileReason,
+            boolean force) {
+        return mDexManager.dexoptSecondaryDex(packageName, compileReason, force);
+    }
+
     /**
      * Reconcile the information we have about the secondary dex files belonging to
      * {@code packagName} and the actual dex files. For all dex files that were
@@ -16850,11 +16860,11 @@
                     mDexManager.isUsedByOtherApps(pkg.packageName));
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
 
-            // Notify BackgroundDexOptJobService that the package has been changed.
+            // Notify BackgroundDexOptService that the package has been changed.
             // If this is an update of a package which used to fail to compile,
             // BDOS will remove it from its blacklist.
             // TODO: Layering violation
-            BackgroundDexOptJobService.notifyPackageChanged(pkg.packageName);
+            BackgroundDexOptService.notifyPackageChanged(pkg.packageName);
         }
 
         if (!args.doRename(res.returnCode, pkg, oldCodePath)) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index a7349fc..25a596a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -147,6 +147,8 @@
                     return runSetHomeActivity();
                 case "get-privapp-permissions":
                     return runGetPrivappPermissions();
+                case "has-feature":
+                    return runHasFeature();
                 default:
                     return handleDefaultCommands(cmd);
             }
@@ -169,7 +171,8 @@
             if (file.isFile()) {
                 try {
                     ApkLite baseApk = PackageParser.parseApkLite(file, 0);
-                    PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null);
+                    PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null,
+                            null, null);
                     params.sessionParams.setSize(PackageHelper.calculateInstalledSize(
                             pkgLite, false, params.sessionParams.abiOverride));
                 } catch (PackageParserException | IOException e) {
@@ -1268,6 +1271,28 @@
         return 0;
     }
 
+    private int runHasFeature() {
+        final PrintWriter err = getErrPrintWriter();
+        final String featureName = getNextArg();
+        if (featureName == null) {
+            err.println("Error: expected FEATURE name");
+            return 1;
+        }
+        final String versionString = getNextArg();
+        try {
+            final int version = (versionString == null) ? 0 : Integer.parseInt(versionString);
+            final boolean hasFeature = mInterface.hasSystemFeature(featureName, version);
+            getOutPrintWriter().println(hasFeature);
+            return hasFeature ? 0 : 1;
+        } catch (NumberFormatException e) {
+            err.println("Error: illegal version number " + versionString);
+            return 1;
+        } catch (RemoteException e) {
+            err.println(e.toString());
+            return 1;
+        }
+    }
+
     private static String checkAbiArgument(String abi) {
         if (TextUtils.isEmpty(abi)) {
             throw new IllegalArgumentException("Missing ABI argument");
@@ -1649,6 +1674,9 @@
         pw.println("    Unsuspends the specified package (as user).");
         pw.println("  set-home-activity [--user USER_ID] TARGET-COMPONENT");
         pw.println("    set the default home activity (aka launcher).");
+        pw.println("  has-feature FEATURE_NAME [version]");
+        pw.println("   prints true and returns exit status 0 when system has a FEATURE_NAME,");
+        pw.println("   otherwise prints false and returns exit status 1");
         pw.println();
         Intent.printIntentArgsHelp(pw , "");
     }
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index b9fcf4e..a31258c3 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1493,6 +1493,10 @@
                     listeners[i].onUserRestrictionsChanged(userId,
                             newRestrictionsFinal, prevRestrictionsFinal);
                 }
+
+                final Intent broadcast = new Intent(UserManager.ACTION_USER_RESTRICTIONS_CHANGED)
+                        .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+                mContext.sendBroadcastAsUser(broadcast, UserHandle.of(userId));
             }
         });
     }
@@ -1810,8 +1814,8 @@
                             if (type == XmlPullParser.START_TAG) {
                                 if (parser.getName().equals(TAG_RESTRICTIONS)) {
                                     synchronized (mGuestRestrictions) {
-                                        mGuestRestrictions.putAll(
-                                                UserRestrictionsUtils.readRestrictions(parser));
+                                        UserRestrictionsUtils
+                                                .readRestrictions(parser, mGuestRestrictions);
                                     }
                                 }
                                 break;
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 36eba8e..cb2ed6e 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -207,6 +207,7 @@
     }
 
     public static void readRestrictions(XmlPullParser parser, Bundle restrictions) {
+        restrictions.clear();
         for (String key : USER_RESTRICTIONS) {
             final String value = parser.getAttributeValue(null, key);
             if (value != null) {
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index 83dd392..a904d17 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -279,6 +279,17 @@
      * @return true if all secondary dex files were processed successfully (compiled or skipped
      *         because they don't need to be compiled)..
      */
+    public boolean dexoptSecondaryDex(String packageName, int compilerReason, boolean force) {
+        return dexoptSecondaryDex(packageName,
+                PackageManagerServiceCompilerMapping.getCompilerFilterForReason(compilerReason),
+                force);
+    }
+
+    /**
+     * Perform dexopt on the package {@code packageName} secondary dex files.
+     * @return true if all secondary dex files were processed successfully (compiled or skipped
+     *         because they don't need to be compiled)..
+     */
     public boolean dexoptSecondaryDex(String packageName, String compilerFilter, boolean force) {
         // Select the dex optimizer based on the force parameter.
         // Forced compilation is done through ForcedUpdatePackageDexOptimizer which will adjust
diff --git a/services/core/java/com/android/server/vr/CompatibilityDisplay.java b/services/core/java/com/android/server/vr/CompatibilityDisplay.java
index 5e17daa..8f95cc7 100644
--- a/services/core/java/com/android/server/vr/CompatibilityDisplay.java
+++ b/services/core/java/com/android/server/vr/CompatibilityDisplay.java
@@ -1,6 +1,8 @@
 
 package com.android.server.vr;
 
+import static android.view.Display.INVALID_DISPLAY;
+
 import android.app.Service;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -86,10 +88,8 @@
                 startVirtualDisplay();
             }
         } else {
-            // TODO: Remove conditional when launching apps 2D doesn't force VrMode to stop.
-            if (!DEBUG) {
-                stopVirtualDisplay();
-            }
+            // Stop virtual display to test exit condition
+            stopVirtualDisplay();
         }
     }
 
@@ -138,6 +138,19 @@
         }
     }
 
+    public int getVirtualDisplayId() {
+        synchronized(vdLock) {
+            if (mVirtualDisplay != null) {
+                int virtualDisplayId = mVirtualDisplay.getDisplay().getDisplayId();
+                if (DEBUG) {
+                    Log.e(TAG, "VD id: " + virtualDisplayId);
+                }
+                return virtualDisplayId;
+            }
+        }
+        return INVALID_DISPLAY;
+    }
+
     private void startVirtualDisplay() {
         if (DEBUG) {
             Log.d(TAG, "Request to start VD, DM:" + mDisplayManager);
diff --git a/services/core/java/com/android/server/vr/VrManagerInternal.java b/services/core/java/com/android/server/vr/VrManagerInternal.java
index 58e4bdc..210aa44 100644
--- a/services/core/java/com/android/server/vr/VrManagerInternal.java
+++ b/services/core/java/com/android/server/vr/VrManagerInternal.java
@@ -90,6 +90,15 @@
     public abstract void setPersistentVrModeEnabled(boolean enabled);
 
     /**
+     * Return {@link android.view.Display.INVALID_DISPLAY} if there exists no virtual display
+     * currently or the display id of the current virtual display.
+     *
+     * @return {@link android.view.Display.INVALID_DISPLAY} if there is no virtual display
+     * currently, else return the display id of the virtual display
+     */
+    public abstract int getCompatibilityDisplayId();
+
+    /**
      * Adds listener that reports state changes to persistent VR mode.
      */
     public abstract void addPersistentVrModeStateListener(PersistentVrStateListener listener);
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 8a23173..a00115c 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -15,6 +15,8 @@
  */
 package com.android.server.vr;
 
+import static android.view.Display.INVALID_DISPLAY;
+
 import android.Manifest;
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
@@ -392,6 +394,11 @@
         }
 
         @Override
+        public int getCompatibilityDisplayId() {
+            return VrManagerService.this.getCompatibilityDisplayId();
+        }
+
+        @Override
         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
                     != PackageManager.PERMISSION_GRANTED) {
@@ -495,6 +502,11 @@
         }
 
         @Override
+        public int getCompatibilityDisplayId() {
+            return VrManagerService.this.getCompatibilityDisplayId();
+        }
+
+        @Override
         public void addPersistentVrModeStateListener(PersistentVrStateListener listener) {
             VrManagerService.this.addPersistentVrModeStateListener(listener);
         }
@@ -1054,6 +1066,14 @@
         }
     }
 
+    private int getCompatibilityDisplayId() {
+        if (mCompatibilityDisplay != null) {
+            return mCompatibilityDisplay.getVirtualDisplayId();
+        }
+        Slog.w(TAG, "CompatibilityDisplay is null!");
+        return INVALID_DISPLAY;
+    }
+
     private void setPersistentModeAndNotifyListenersLocked(boolean enabled) {
         if (mPersistentVrModeEnabled == enabled) {
             return;
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 2f221df..c20ee97 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -163,9 +163,6 @@
     private boolean mLastContainsShowWhenLockedWindow;
     private boolean mLastContainsDismissKeyguardWindow;
 
-    private ArrayList<WindowSurfaceController.SurfaceControlWithBackground> mSurfaceViewBackgrounds =
-        new ArrayList<>();
-
     ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
     ArrayDeque<Configuration> mFrozenMergedConfig = new ArrayDeque<>();
 
@@ -970,36 +967,6 @@
         mService.mWindowPlacerLocked.performSurfacePlacement();
     }
 
-    void addSurfaceViewBackground(WindowSurfaceController.SurfaceControlWithBackground background) {
-        mSurfaceViewBackgrounds.add(background);
-    }
-
-    void removeSurfaceViewBackground(WindowSurfaceController.SurfaceControlWithBackground background) {
-        mSurfaceViewBackgrounds.remove(background);
-        updateSurfaceViewBackgroundVisibilities();
-    }
-
-    // We use DimLayers behind SurfaceViews to prevent holes while resizing and creating.
-    // However, we need to ensure one SurfaceView doesn't cover another when they are both placed
-    // below the main app window (as traditionally a SurfaceView which is never drawn
-    // to is totally translucent). So we look at all our SurfaceView backgrounds and only enable
-    // the background for the SurfaceView with lowest Z order
-    void updateSurfaceViewBackgroundVisibilities() {
-        WindowSurfaceController.SurfaceControlWithBackground bottom = null;
-        int bottomLayer = Integer.MAX_VALUE;
-        for (int i = 0; i < mSurfaceViewBackgrounds.size(); i++) {
-            WindowSurfaceController.SurfaceControlWithBackground sc = mSurfaceViewBackgrounds.get(i);
-            if (sc.mVisible && sc.mLayer < bottomLayer) {
-                bottomLayer = sc.mLayer;
-                bottom = sc;
-            }
-        }
-        for (int i = 0; i < mSurfaceViewBackgrounds.size(); i++) {
-            WindowSurfaceController.SurfaceControlWithBackground sc = mSurfaceViewBackgrounds.get(i);
-            sc.updateBackgroundVisibility(sc != bottom);
-        }
-    }
-
     void resetJustMovedInStack() {
         for (int i = mChildren.size() - 1; i >= 0; i--) {
             (mChildren.get(i)).resetJustMovedInStack();
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index b7a9e66..30e0ded 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -28,7 +28,6 @@
 
 import android.content.ClipData;
 import android.content.Context;
-import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.os.Binder;
@@ -39,6 +38,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
+import android.util.MergedConfiguration;
 import android.util.Slog;
 import android.view.Display;
 import android.view.IWindow;
@@ -208,13 +208,6 @@
     }
 
     @Override
-    public void repositionChild(IWindow window, int left, int top, int right, int bottom,
-            long deferTransactionUntilFrame, Rect outFrame) {
-        mService.repositionChild(this, window, left, top, right, bottom,
-                deferTransactionUntilFrame, outFrame);
-    }
-
-    @Override
     public void prepareToReplaceWindows(IBinder appToken, boolean childrenOnly) {
         mService.setWillReplaceWindows(appToken, childrenOnly);
     }
@@ -223,22 +216,18 @@
             int requestedWidth, int requestedHeight, int viewFlags,
             int flags, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
             Rect outVisibleInsets, Rect outStableInsets, Rect outsets, Rect outBackdropFrame,
-            Configuration outConfig, Surface outSurface) {
+            MergedConfiguration mergedConfiguration, Surface outSurface) {
         if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
                 + Binder.getCallingPid());
         int res = mService.relayoutWindow(this, window, seq, attrs,
                 requestedWidth, requestedHeight, viewFlags, flags,
                 outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,
-                outStableInsets, outsets, outBackdropFrame, outConfig, outSurface);
+                outStableInsets, outsets, outBackdropFrame, mergedConfiguration, outSurface);
         if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
                 + Binder.getCallingPid());
         return res;
     }
 
-    public void performDeferredDestroy(IWindow window) {
-        mService.performDeferredDestroyWindow(this, window);
-    }
-
     public boolean outOfMemory(IWindow window) {
         return mService.outOfMemoryWindow(this, window);
     }
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index c0598ca..04403e2 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -27,7 +27,6 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import android.app.ActivityManager.TaskDescription;
-import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -38,6 +37,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
+import android.util.MergedConfiguration;
 import android.util.Slog;
 import android.view.IWindowSession;
 import android.view.Surface;
@@ -78,7 +78,7 @@
         final Surface surface = new Surface();
         final Rect tmpRect = new Rect();
         final Rect tmpFrame = new Rect();
-        final Configuration tmpConfiguration = new Configuration();
+        final MergedConfiguration tmpMergedConfiguration = new MergedConfiguration();
         int fillBackgroundColor = Color.WHITE;
         synchronized (service.mWindowMap) {
             layoutParams.type = TYPE_APPLICATION_STARTING;
@@ -122,7 +122,7 @@
         window.setOuter(snapshotSurface);
         try {
             session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, tmpFrame,
-                    tmpRect, tmpRect, tmpRect, tmpRect, tmpRect, tmpRect, tmpConfiguration,
+                    tmpRect, tmpRect, tmpRect, tmpRect, tmpRect, tmpRect, tmpMergedConfiguration,
                     surface);
         } catch (RemoteException e) {
             // Local call.
@@ -221,9 +221,9 @@
 
         @Override
         public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
-                Rect stableInsets, Rect outsets, boolean reportDraw, Configuration newConfig,
-                Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeNavBar,
-                int displayId) {
+                Rect stableInsets, Rect outsets, boolean reportDraw,
+                MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
+                boolean alwaysConsumeNavBar, int displayId) {
             if (reportDraw) {
                 sHandler.obtainMessage(MSG_REPORT_DRAW, mOuter).sendToTarget();
             }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 014a89d..7539cd4 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -150,6 +150,7 @@
 import android.os.WorkSource;
 import android.provider.Settings;
 import android.util.ArraySet;
+import android.util.MergedConfiguration;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
@@ -1808,70 +1809,12 @@
         }
     }
 
-    void repositionChild(Session session, IWindow client,
-            int left, int top, int right, int bottom,
-            long frameNumber, Rect outFrame) {
-        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "repositionChild");
-        long origId = Binder.clearCallingIdentity();
-
-        try {
-            synchronized(mWindowMap) {
-                WindowState win = windowForClientLocked(session, client, false);
-                if (win == null) {
-                    return;
-                }
-                if (!win.isChildWindow()) {
-                    throw new IllegalArgumentException(
-                            "repositionChild called but window is not"
-                            + "attached to a parent win=" + win);
-                }
-
-                win.mAttrs.x = left;
-                win.mAttrs.y = top;
-                win.mAttrs.width = right - left;
-                win.mAttrs.height = bottom - top;
-                win.setWindowScale(win.mRequestedWidth, win.mRequestedHeight);
-
-                if (win.mHasSurface) {
-                    if (SHOW_TRANSACTIONS) {
-                        Slog.i(TAG_WM, ">>> OPEN TRANSACTION repositionChild");
-                    }
-
-                    openSurfaceTransaction();
-
-                    try {
-
-                        win.applyGravityAndUpdateFrame(win.mContainingFrame, win.mDisplayFrame);
-                        win.mWinAnimator.computeShownFrameLocked();
-
-                        win.mWinAnimator.setSurfaceBoundariesLocked(false);
-
-                        if (frameNumber > 0) {
-                            win.mWinAnimator.deferTransactionUntilParentFrame(frameNumber);
-                        }
-
-                    } finally {
-                        closeSurfaceTransaction();
-                        if (SHOW_TRANSACTIONS) {
-                            Slog.i(TAG_WM, "<<< CLOSE TRANSACTION repositionChild");
-                        }
-                    }
-                }
-
-                outFrame = win.mCompatFrame;
-            }
-        } finally {
-            Binder.restoreCallingIdentity(origId);
-            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
-        }
-    }
-
     public int relayoutWindow(Session session, IWindow client, int seq,
             WindowManager.LayoutParams attrs, int requestedWidth,
             int requestedHeight, int viewVisibility, int flags,
             Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
             Rect outVisibleInsets, Rect outStableInsets, Rect outOutsets, Rect outBackdropFrame,
-            Configuration outConfig, Surface outSurface) {
+            MergedConfiguration mergedConfiguration, Surface outSurface) {
         int result = 0;
         boolean configChanged;
         boolean hasStatusBarPermission =
@@ -1983,7 +1926,7 @@
             if (viewVisibility == View.VISIBLE &&
                     (win.mAppToken == null || win.mAttrs.type == TYPE_APPLICATION_STARTING
                             || !win.mAppToken.clientHidden)) {
-                result = win.relayoutVisibleWindow(outConfig, result, attrChanges,
+                result = win.relayoutVisibleWindow(mergedConfiguration, result, attrChanges,
                         oldVisibility);
                 try {
                     result = createSurfaceControl(outSurface, result, win, winAnimator);
@@ -2210,23 +2153,6 @@
         return result;
     }
 
-    public void performDeferredDestroyWindow(Session session, IWindow client) {
-        long origId = Binder.clearCallingIdentity();
-
-        try {
-            synchronized (mWindowMap) {
-                WindowState win = windowForClientLocked(session, client, false);
-                if (win == null || win.mWillReplaceWindow) {
-                    return;
-                }
-
-                win.mWinAnimator.destroyDeferredSurfaceLocked();
-            }
-        } finally {
-            Binder.restoreCallingIdentity(origId);
-        }
-    }
-
     public boolean outOfMemoryWindow(Session session, IWindow client) {
         final long origId = Binder.clearCallingIdentity();
 
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 4e593d8..ca5d551 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -114,6 +114,7 @@
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.WorkSource;
+import android.util.MergedConfiguration;
 import android.util.DisplayMetrics;
 import android.util.Slog;
 import android.util.TimeUtils;
@@ -2265,7 +2266,7 @@
         }
     }
 
-    void prepareWindowToDisplayDuringRelayout(Configuration outConfig) {
+    void prepareWindowToDisplayDuringRelayout(MergedConfiguration mergedConfiguration) {
         if ((mAttrs.softInputMode & SOFT_INPUT_MASK_ADJUST)
                 == SOFT_INPUT_ADJUST_RESIZE) {
             mLayoutNeeded = true;
@@ -2278,10 +2279,13 @@
             mTurnOnScreen = true;
         }
         if (isConfigChanged()) {
-            outConfig.setTo(getConfiguration());
-            if (DEBUG_CONFIGURATION) Slog.i(TAG, "Window " + this + " visible with new config: "
-                    + outConfig);
-            mLastReportedConfiguration.setTo(outConfig);
+            final Configuration globalConfig = mService.mRoot.getConfiguration();
+            final Configuration overrideConfig = getMergedOverrideConfiguration();
+            mergedConfiguration.setConfiguration(globalConfig, overrideConfig);
+            if (DEBUG_CONFIGURATION) Slog.i(TAG, "Window " + this
+                    + " visible with new global config: " + globalConfig
+                    + " merged override config: " + overrideConfig);
+            mLastReportedConfiguration.setTo(getConfiguration());
         }
     }
 
@@ -3027,12 +3031,13 @@
         try {
             if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, "Reporting new frame to " + this
                     + ": " + mCompatFrame);
-            final Configuration newConfig;
+            final MergedConfiguration mergedConfiguration;
             if (isConfigChanged()) {
-                newConfig = new Configuration(getConfiguration());
-                mLastReportedConfiguration.setTo(newConfig);
+                mergedConfiguration = new MergedConfiguration(mService.mRoot.getConfiguration(),
+                        getMergedOverrideConfiguration());
+                mLastReportedConfiguration.setTo(mergedConfiguration.getMergedConfiguration());
             } else {
-                newConfig = null;
+                mergedConfiguration = null;
             }
             if (DEBUG_ORIENTATION && mWinAnimator.mDrawState == DRAW_PENDING)
                 Slog.i(TAG, "Resizing " + this + " WITH DRAW PENDING");
@@ -3054,7 +3059,7 @@
                     public void run() {
                         try {
                             dispatchResized(frame, overscanInsets, contentInsets, visibleInsets,
-                                    stableInsets, outsets, reportDraw, newConfig,
+                                    stableInsets, outsets, reportDraw, mergedConfiguration,
                                     reportOrientation, displayId);
                         } catch (RemoteException e) {
                             // Not a remote call, RemoteException won't be raised.
@@ -3063,7 +3068,7 @@
                 });
             } else {
                 dispatchResized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets,
-                        outsets, reportDraw, newConfig, reportOrientation, displayId);
+                        outsets, reportDraw, mergedConfiguration, reportOrientation, displayId);
             }
 
             //TODO (multidisplay): Accessibility supported only for the default display.
@@ -3120,14 +3125,14 @@
 
     private void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
             Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
-            Configuration newConfig, boolean reportOrientation, int displayId)
+            MergedConfiguration mergedConfiguration, boolean reportOrientation, int displayId)
             throws RemoteException {
         final boolean forceRelayout = isDragResizeChanged() || mResizedWhileNotDragResizing
                 || reportOrientation;
 
         mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets, outsets,
-                reportDraw, newConfig, getBackdropFrame(frame),
-                forceRelayout, mPolicy.isNavBarForcedShownLw(this), displayId);
+                reportDraw, mergedConfiguration, getBackdropFrame(frame), forceRelayout,
+                mPolicy.isNavBarForcedShownLw(this), displayId);
         mDragResizingChangeReported = true;
     }
 
@@ -4341,8 +4346,8 @@
         return !mLastSurfaceInsets.equals(mAttrs.surfaceInsets);
     }
 
-    int relayoutVisibleWindow(Configuration outConfig, int result,
-            int attrChanges, int oldVisibility) {
+    int relayoutVisibleWindow(MergedConfiguration mergedConfiguration, int result, int attrChanges,
+            int oldVisibility) {
         result |= !isVisibleLw() ? RELAYOUT_RES_FIRST_TIME : 0;
         if (mAnimatingExit) {
             Slog.d(TAG, "relayoutVisibleWindow: " + this + " mAnimatingExit=true, mRemoveOnExit="
@@ -4363,7 +4368,7 @@
 
         mWinAnimator.mEnteringAnimation = true;
         if ((result & RELAYOUT_RES_FIRST_TIME) != 0) {
-            prepareWindowToDisplayDuringRelayout(outConfig);
+            prepareWindowToDisplayDuringRelayout(mergedConfiguration);
         }
         if ((attrChanges & FORMAT_CHANGED) != 0) {
             // If the format can't be changed in place, preserve the old surface until the app draws
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index c9863c5..b08bb70 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -97,13 +97,7 @@
         mWindowType = windowType;
         mWindowSession = win.mSession;
 
-        // For opaque child windows placed under parent windows, we use a special SurfaceControl
-        // which mirrors commands to a black-out layer placed one Z-layer below the surface.
-        // This prevents holes to whatever app/wallpaper is underneath.
-        if (win.isChildWindow() && win.mSubLayer < 0 && win.mAppToken != null) {
-            mSurfaceControl = new SurfaceControlWithBackground(
-                    s, name, w, h, format, flags, win.mAppToken, windowType, ownerUid);
-        } else if (DEBUG_SURFACE_TRACE) {
+        if (DEBUG_SURFACE_TRACE) {
             mSurfaceControl = new SurfaceTrace(
                     s, name, w, h, format, flags, windowType, ownerUid);
         } else {
@@ -834,141 +828,4 @@
                     + " (" + mDsdx + "," + mDtdx + "," + mDsdy + "," + mDtdy + ")";
         }
     }
-
-    class SurfaceControlWithBackground extends SurfaceControl {
-        private SurfaceControl mBackgroundControl;
-        private boolean mOpaque = true;
-        private boolean mAppForcedInvisible = false;
-        private AppWindowToken mAppToken;
-        public boolean mVisible = false;
-        public int mLayer = -1;
-
-        public SurfaceControlWithBackground(SurfaceSession s, String name, int w, int h, int format,
-                    int flags, AppWindowToken token, int windowType, int ownerUid)
-                throws OutOfResourcesException {
-            super(s, name, w, h, format, flags, windowType, ownerUid);
-            mBackgroundControl = new SurfaceControl(s, name, w, h,
-                    PixelFormat.OPAQUE, flags | SurfaceControl.FX_SURFACE_DIM);
-            mOpaque = (flags & SurfaceControl.OPAQUE) != 0;
-            mAppToken = token;
-
-            mAppToken.addSurfaceViewBackground(this);
-        }
-
-        @Override
-        public void setAlpha(float alpha) {
-            super.setAlpha(alpha);
-            mBackgroundControl.setAlpha(alpha);
-        }
-
-        @Override
-        public void setLayer(int zorder) {
-            super.setLayer(zorder);
-            mBackgroundControl.setLayer(zorder - 1);
-            if (mLayer != zorder) {
-                mLayer = zorder;
-                mAppToken.updateSurfaceViewBackgroundVisibilities();
-            }
-        }
-
-        @Override
-        public void setPosition(float x, float y) {
-            super.setPosition(x, y);
-            mBackgroundControl.setPosition(x, y);
-        }
-
-        @Override
-        public void setSize(int w, int h) {
-            super.setSize(w, h);
-            mBackgroundControl.setSize(w, h);
-        }
-
-        @Override
-        public void setWindowCrop(Rect crop) {
-            super.setWindowCrop(crop);
-            mBackgroundControl.setWindowCrop(crop);
-        }
-
-        @Override
-        public void setFinalCrop(Rect crop) {
-            super.setFinalCrop(crop);
-            mBackgroundControl.setFinalCrop(crop);
-        }
-
-        @Override
-        public void setLayerStack(int layerStack) {
-            super.setLayerStack(layerStack);
-            mBackgroundControl.setLayerStack(layerStack);
-        }
-
-        @Override
-        public void setOpaque(boolean isOpaque) {
-            super.setOpaque(isOpaque);
-            mOpaque = isOpaque;
-            updateBackgroundVisibility(mAppForcedInvisible);
-        }
-
-        @Override
-        public void setSecure(boolean isSecure) {
-            super.setSecure(isSecure);
-        }
-
-        @Override
-        public void setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
-            super.setMatrix(dsdx, dtdx, dsdy, dtdy);
-            mBackgroundControl.setMatrix(dsdx, dtdx, dsdy, dtdy);
-        }
-
-        @Override
-        public void hide() {
-            super.hide();
-            if (mVisible) {
-                mVisible = false;
-                mAppToken.updateSurfaceViewBackgroundVisibilities();
-            }
-        }
-
-        @Override
-        public void show() {
-            super.show();
-            if (!mVisible) {
-                mVisible = true;
-                mAppToken.updateSurfaceViewBackgroundVisibilities();
-            }
-        }
-
-        @Override
-        public void destroy() {
-            super.destroy();
-            mBackgroundControl.destroy();
-            mAppToken.removeSurfaceViewBackground(this);
-         }
-
-        @Override
-        public void release() {
-            super.release();
-            mBackgroundControl.release();
-        }
-
-        @Override
-        public void setTransparentRegionHint(Region region) {
-            super.setTransparentRegionHint(region);
-            mBackgroundControl.setTransparentRegionHint(region);
-        }
-
-        @Override
-        public void deferTransactionUntil(IBinder handle, long frame) {
-            super.deferTransactionUntil(handle, frame);
-            mBackgroundControl.deferTransactionUntil(handle, frame);
-        }
-
-        void updateBackgroundVisibility(boolean forcedInvisible) {
-            mAppForcedInvisible = forcedInvisible;
-            if (mOpaque && mVisible && !mAppForcedInvisible) {
-                mBackgroundControl.show();
-            } else {
-                mBackgroundControl.hide();
-            }
-        }
-    }
 }
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index ac95db5..b5ed266 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -65,6 +65,7 @@
     libinputflinger \
     libinputservice \
     libsensorservice \
+    libsensorservicehidl \
     libskia \
     libgui \
     libusbhost \
@@ -88,5 +89,6 @@
     android.hardware.tv.input@1.0 \
     android.hardware.vibrator@1.0 \
     android.hardware.vr@1.0 \
+    android.frameworks.sensorservice@1.0 \
 
-LOCAL_STATIC_LIBRARIES += libscrypt_static
\ No newline at end of file
+LOCAL_STATIC_LIBRARIES += libscrypt_static
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index 3120af56..8ad88ed 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -17,7 +17,10 @@
 #include <jni.h>
 #include <JNIHelp.h>
 
+#include <hidl/HidlTransportSupport.h>
+
 #include <sensorservice/SensorService.h>
+#include <sensorservicehidl/SensorManager.h>
 
 #include <cutils/properties.h>
 #include <utils/Log.h>
@@ -32,6 +35,21 @@
     if (strcmp(propBuf, "1") == 0) {
         SensorService::instantiate();
     }
+
+}
+
+static void android_server_SystemServer_startHidlServices(JNIEnv* /* env */, jobject /* clazz */) {
+    using ::android::frameworks::sensorservice::V1_0::ISensorManager;
+    using ::android::frameworks::sensorservice::V1_0::implementation::SensorManager;
+    using ::android::hardware::configureRpcThreadpool;
+
+    configureRpcThreadpool(1, false /* callerWillJoin */);
+    sp<ISensorManager> sensorService = new SensorManager();
+    status_t err = sensorService->registerAsService();
+    if (err != OK) {
+        ALOGE("Cannot register ::android::frameworks::sensorservice::V1_0::"
+              "implementation::SensorManager: %d", err);
+    }
 }
 
 /*
@@ -40,6 +58,7 @@
 static const JNINativeMethod gMethods[] = {
     /* name, signature, funcPtr */
     { "startSensorService", "()V", (void*) android_server_SystemServer_startSensorService },
+    { "startHidlServices", "()V", (void*) android_server_SystemServer_startHidlServices },
 };
 
 int register_android_server_SystemServer(JNIEnv* env)
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index a8423e2..e6e0242 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -86,6 +86,7 @@
 import com.android.server.om.OverlayManagerService;
 import com.android.server.os.DeviceIdentifiersPolicyService;
 import com.android.server.os.SchedulingPolicyService;
+import com.android.server.pm.BackgroundDexOptService;
 import com.android.server.pm.Installer;
 import com.android.server.pm.LauncherAppsService;
 import com.android.server.pm.OtaDexoptService;
@@ -235,16 +236,24 @@
     private final boolean mRuntimeRestart;
 
     private static final String START_SENSOR_SERVICE = "StartSensorService";
+    private static final String START_HIDL_SERVICES = "StartHidlServices";
+
+
     private Future<?> mSensorServiceStart;
     private Future<?> mZygotePreload;
 
-
     /**
      * Start the sensor service. This is a blocking call and can take time.
      */
     private static native void startSensorService();
 
     /**
+     * Start all HIDL services that are run inside the system server. This
+     * may take some time.
+     */
+    private static native void startHidlServices();
+
+    /**
      * The main entry point from zygote.
      */
     public static void main(String[] args) {
@@ -610,6 +619,7 @@
             startSensorService();
             traceLog.traceEnd();
         }, START_SENSOR_SERVICE);
+
     }
 
     /**
@@ -637,6 +647,14 @@
         traceBeginAndSlog("StartWebViewUpdateService");
         mWebViewUpdateService = mSystemServiceManager.startService(WebViewUpdateService.class);
         traceEnd();
+
+        // Start receiving calls from HIDL services. Start in in a separate thread
+        // because it need to connect to SensorManager.
+        SystemServerInitThreadPool.get().submit(() -> {
+            traceBeginAndSlog(START_HIDL_SERVICES);
+            startHidlServices();
+            traceEnd();
+        }, START_HIDL_SERVICES);
     }
 
     /**
@@ -1428,11 +1446,11 @@
                     traceEnd();
                 }
 
-                traceBeginAndSlog("StartBackgroundDexOptJobService");
+                traceBeginAndSlog("StartBackgroundDexOptService");
                 try {
-                    BackgroundDexOptJobService.schedule(context);
+                    BackgroundDexOptService.schedule(context);
                 } catch (Throwable e) {
-                    reportWtf("starting StartBackgroundDexOptJobService", e);
+                    reportWtf("starting StartBackgroundDexOptService", e);
                 }
                 traceEnd();
 
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index a3b0429..c670782 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -16,6 +16,8 @@
 
 package android.net.ip;
 
+import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
+
 import com.android.internal.util.MessageUtils;
 import com.android.internal.util.WakeupMessage;
 
@@ -23,6 +25,7 @@
 import android.net.apf.ApfCapabilities;
 import android.net.apf.ApfFilter;
 import android.net.DhcpResults;
+import android.net.INetd;
 import android.net.InterfaceConfiguration;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
@@ -34,11 +37,14 @@
 import android.net.metrics.IpConnectivityLog;
 import android.net.metrics.IpManagerEvent;
 import android.net.util.MultinetworkPolicyTracker;
+import android.net.util.NetdService;
 import android.os.INetworkManagementService;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
 import android.os.SystemClock;
+import android.system.OsConstants;
 import android.text.TextUtils;
 import android.util.LocalLog;
 import android.util.Log;
@@ -1025,16 +1031,39 @@
         return true;
     }
 
-    private boolean startIPv6() {
-        // Set privacy extensions.
+    private void enableInterfaceIPv6PrivacyExtensions() {
+        final String PREFER_TEMPADDRS = "2";
+        NetdService.run((INetd netd) -> {
+                netd.setProcSysNet(
+                        INetd.IPV6, INetd.CONF, mInterfaceName, "use_tempaddr", PREFER_TEMPADDRS);
+            });
+    }
+
+    private void setInterfaceIPv6RaRtInfoMaxPlen(int plen) {
+        // Setting RIO max plen is best effort. Catch and ignore most exceptions.
         try {
-            mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
+            NetdService.run((INetd netd) -> {
+                    netd.setProcSysNet(
+                            INetd.IPV6, INetd.CONF, mInterfaceName, "accept_ra_rt_info_max_plen",
+                            Integer.toString(plen));
+                });
+        } catch (ServiceSpecificException e) {
+            // Old kernel versions without support for RIOs do not export accept_ra_rt_info_max_plen
+            // in the /proc filesystem. If the kernel supports RIOs we should never see any other
+            // type of error.
+            if (e.errorCode != OsConstants.ENOENT) {
+                logError("unexpected error setting accept_ra_rt_info_max_plen %s", e);
+            }
+        }
+    }
+
+    private boolean startIPv6() {
+        try {
+            enableInterfaceIPv6PrivacyExtensions();
+            setInterfaceIPv6RaRtInfoMaxPlen(RFC7421_PREFIX_LENGTH);
             mNwService.enableIpv6(mInterfaceName);
-        } catch (RemoteException re) {
-            logError("Unable to change interface settings: %s", re);
-            return false;
-        } catch (IllegalStateException ie) {
-            logError("Unable to change interface settings: %s", ie);
+        } catch (IllegalStateException|RemoteException|ServiceSpecificException e) {
+            logError("Unable to change interface settings: %s", e);
             return false;
         }
 
diff --git a/services/net/java/android/net/util/NetdService.java b/services/net/java/android/net/util/NetdService.java
index 153cb50..6e69ff5 100644
--- a/services/net/java/android/net/util/NetdService.java
+++ b/services/net/java/android/net/util/NetdService.java
@@ -17,7 +17,10 @@
 package android.net.util;
 
 import android.net.INetd;
+import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
+import android.os.SystemClock;
 import android.util.Log;
 
 
@@ -27,15 +30,24 @@
 public class NetdService {
     private static final String TAG = NetdService.class.getSimpleName();
     private static final String NETD_SERVICE_NAME = "netd";
+    private static final long BASE_TIMEOUT_MS = 100;
+    private static final long MAX_TIMEOUT_MS = 1000;
+
 
     /**
+     * Return an INetd instance, or null if not available.
+     *
      * It is the caller's responsibility to check for a null return value
      * and to handle RemoteException errors from invocations on the returned
      * interface if, for example, netd dies and is restarted.
      *
+     * Returned instances of INetd should not be cached.
+     *
      * @return an INetd instance or null.
      */
     public static INetd getInstance() {
+        // NOTE: ServiceManager does no caching for the netd service,
+        // because netd is not one of the defined common services.
         final INetd netdInstance = INetd.Stub.asInterface(
                 ServiceManager.getService(NETD_SERVICE_NAME));
         if (netdInstance == null) {
@@ -43,4 +55,82 @@
         }
         return netdInstance;
     }
+
+    /**
+     * Blocks for a specified time until an INetd instance is available.
+     *
+     * It is the caller's responsibility to handle RemoteException errors
+     * from invocations on the returned interface if, for example, netd
+     * dies after this interface was returned.
+     *
+     * Returned instances of INetd should not be cached.
+     *
+     * Special values of maxTimeoutMs include: 0, meaning try to obtain an
+     * INetd instance only once, and -1 (or any value less than 0), meaning
+     * try to obtain an INetd instance indefinitely.
+     *
+     * @param maxTimeoutMs the maximum time to spend getting an INetd instance
+     * @return an INetd instance or null if no instance is available
+     * within |maxTimeoutMs| milliseconds.
+     */
+    public static INetd get(long maxTimeoutMs) {
+        if (maxTimeoutMs == 0) return getInstance();
+
+        final long stop = (maxTimeoutMs > 0)
+                ? SystemClock.elapsedRealtime() + maxTimeoutMs
+                : Long.MAX_VALUE;
+
+        long timeoutMs = 0;
+        while (true) {
+            final INetd netdInstance = getInstance();
+            if (netdInstance != null) {
+                return netdInstance;
+            }
+
+            final long remaining = stop - SystemClock.elapsedRealtime();
+            if (remaining <= 0) break;
+
+            // No netdInstance was received; sleep and retry.
+            timeoutMs = Math.min(timeoutMs + BASE_TIMEOUT_MS, MAX_TIMEOUT_MS);
+            timeoutMs = Math.min(timeoutMs, remaining);
+            try {
+                Thread.sleep(timeoutMs);
+            } catch (InterruptedException e) {}
+        }
+        return null;
+    }
+
+    /**
+     * Blocks until an INetd instance is available.
+     *
+     * It is the caller's responsibility to handle RemoteException errors
+     * from invocations on the returned interface if, for example, netd
+     * dies after this interface was returned.
+     *
+     * Returned instances of INetd should not be cached.
+     *
+     * @return an INetd instance.
+     */
+    public static INetd get() {
+        return get(-1);
+    }
+
+    public static interface NetdCommand {
+        void run(INetd netd) throws RemoteException;
+    }
+
+    /**
+     * Blocks until an INetd instance is availabe, and retries until either
+     * the command succeeds or a runtime exception is thrown.
+     */
+    public static void run(NetdCommand cmd) {
+        while (true) {
+            try {
+                cmd.run(get());
+                return;
+            } catch (RemoteException re) {
+                Log.e(TAG, "error communicating with netd: " + re);
+            }
+        }
+    }
 }
diff --git a/services/net/java/android/net/util/NetworkConstants.java b/services/net/java/android/net/util/NetworkConstants.java
index 362f757..26f3050 100644
--- a/services/net/java/android/net/util/NetworkConstants.java
+++ b/services/net/java/android/net/util/NetworkConstants.java
@@ -97,6 +97,7 @@
     public static final int IPV6_SRC_ADDR_OFFSET = 8;
     public static final int IPV6_DST_ADDR_OFFSET = 24;
     public static final int IPV6_ADDR_LEN = 16;
+    public static final int RFC7421_PREFIX_LENGTH = 64;
 
     /**
      * ICMPv6 constants.
diff --git a/services/tests/notification/Android.mk b/services/tests/notification/Android.mk
index de9553a..a5d5570 100644
--- a/services/tests/notification/Android.mk
+++ b/services/tests/notification/Android.mk
@@ -30,6 +30,7 @@
 LOCAL_JACK_FLAGS := --multi-dex native
 
 LOCAL_PACKAGE_NAME := FrameworksNotificationTests
+LOCAL_COMPATIBILITY_SUITE := device-tests
 
 LOCAL_CERTIFICATE := platform
 
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index 5f215f9..27b9a88 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -203,7 +203,6 @@
     private void compareChannels(NotificationChannel expected, NotificationChannel actual) {
         assertEquals(expected.getId(), actual.getId());
         assertEquals(expected.getName(), actual.getName());
-        assertEquals(expected.getNameResId(), actual.getNameResId());
         assertEquals(expected.shouldVibrate(), actual.shouldVibrate());
         assertEquals(expected.shouldShowLights(), actual.shouldShowLights());
         assertEquals(expected.getImportance(), actual.getImportance());
@@ -219,7 +218,6 @@
     private void compareGroups(NotificationChannelGroup expected, NotificationChannelGroup actual) {
         assertEquals(expected.getId(), actual.getId());
         assertEquals(expected.getName(), actual.getName());
-        assertEquals(expected.getNameResId(), actual.getNameResId());
     }
 
     @Test
@@ -274,15 +272,12 @@
 
     @Test
     public void testChannelXml() throws Exception {
-        int nameResId = 924896;
-        int groupNameResId = 426272;
-
-        NotificationChannelGroup ncg = new NotificationChannelGroup("1", groupNameResId);
+        NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye");
         NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello");
         NotificationChannel channel1 =
                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
         NotificationChannel channel2 =
-                new NotificationChannel("id2", nameResId, IMPORTANCE_LOW);
+                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
         channel2.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
         channel2.enableLights(true);
         channel2.setBypassDnd(true);
@@ -728,6 +723,25 @@
     }
 
     @Test
+    public void testGetDeletedChannelCount() throws Exception {
+        NotificationChannel channel =
+                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
+        NotificationChannel channel2 =
+                new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH);
+        NotificationChannel channel3 =
+                new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH);
+        mHelper.createNotificationChannel(pkg, uid, channel, true);
+        mHelper.createNotificationChannel(pkg, uid, channel2, true);
+        mHelper.createNotificationChannel(pkg, uid, channel3, true);
+
+        mHelper.deleteNotificationChannel(pkg, uid, channel.getId());
+        mHelper.deleteNotificationChannel(pkg, uid, channel3.getId());
+
+        assertEquals(2, mHelper.getDeletedChannelCount(pkg, uid));
+        assertEquals(0, mHelper.getDeletedChannelCount(pkg2, uid2));
+    }
+
+    @Test
     public void testUpdateDeletedChannels() throws Exception {
         NotificationChannel channel =
                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
@@ -840,6 +854,43 @@
     }
 
     @Test
+    public void testDeleteGroup() throws Exception {
+        NotificationChannelGroup notDeleted = new NotificationChannelGroup("not", "deleted");
+        NotificationChannelGroup deleted = new NotificationChannelGroup("totally", "deleted");
+        NotificationChannel nonGroupedNonDeletedChannel =
+                new NotificationChannel("no group", "so not deleted", IMPORTANCE_HIGH);
+        NotificationChannel groupedButNotDeleted =
+                new NotificationChannel("not deleted", "belongs to notDeleted", IMPORTANCE_DEFAULT);
+        groupedButNotDeleted.setGroup("not");
+        NotificationChannel groupedAndDeleted =
+                new NotificationChannel("deleted", "belongs to deleted", IMPORTANCE_DEFAULT);
+        groupedAndDeleted.setGroup("totally");
+
+        mHelper.createNotificationChannelGroup(pkg, uid, notDeleted, true);
+        mHelper.createNotificationChannelGroup(pkg, uid, deleted, true);
+        mHelper.createNotificationChannel(pkg, uid, nonGroupedNonDeletedChannel, true);
+        mHelper.createNotificationChannel(pkg, uid, groupedAndDeleted, true);
+        mHelper.createNotificationChannel(pkg, uid, groupedButNotDeleted, true);
+
+        mHelper.deleteNotificationChannelGroup(pkg, uid, deleted.getId());
+
+        assertNull(mHelper.getNotificationChannelGroup(deleted.getId(), pkg, uid));
+        assertNotNull(mHelper.getNotificationChannelGroup(notDeleted.getId(), pkg, uid));
+
+        assertNull(mHelper.getNotificationChannel(pkg, uid, groupedAndDeleted.getId(), false));
+        compareChannels(groupedAndDeleted,
+                mHelper.getNotificationChannel(pkg, uid, groupedAndDeleted.getId(), true));
+
+        compareChannels(groupedButNotDeleted,
+                mHelper.getNotificationChannel(pkg, uid, groupedButNotDeleted.getId(), false));
+        compareChannels(nonGroupedNonDeletedChannel, mHelper.getNotificationChannel(
+                pkg, uid, nonGroupedNonDeletedChannel.getId(), false));
+
+        // notDeleted
+        assertEquals(1, mHelper.getNotificationChannelGroups(pkg, uid).size());
+    }
+
+    @Test
     public void testOnPackageChanged_packageRemoval() throws Exception {
         // Deleted
         NotificationChannel channel1 =
@@ -875,7 +926,7 @@
 
         mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{pkg}, new int[]{uid});
 
-        assertEquals(0, mHelper.getNotificationChannelGroups(pkg, uid, true).getList().size());
+        assertEquals(0, mHelper.getNotificationChannelGroups(pkg, uid).size());
     }
 
     @Test
@@ -994,14 +1045,18 @@
     }
 
     @Test
-    public void testCreateChannel_updateNameResId() throws Exception {
-        NotificationChannel nc = new NotificationChannel("id", 1, IMPORTANCE_DEFAULT);
+    public void testCreateChannel_updateName() throws Exception {
+        NotificationChannel nc = new NotificationChannel("id", "hello", IMPORTANCE_DEFAULT);
+        mHelper.createNotificationChannel(pkg, uid, nc, true);
+        NotificationChannel actual = mHelper.getNotificationChannel(pkg, uid, "id", false);
+        assertEquals("hello", actual.getName());
+
+        nc = new NotificationChannel("id", "goodbye", IMPORTANCE_HIGH);
         mHelper.createNotificationChannel(pkg, uid, nc, true);
 
-        nc = new NotificationChannel("id", 2, IMPORTANCE_DEFAULT);
-        mHelper.createNotificationChannel(pkg, uid, nc, true);
-
-        assertEquals(2, mHelper.getNotificationChannel(pkg, uid, "id", false).getNameResId());
+        actual = mHelper.getNotificationChannel(pkg, uid, "id", false);
+        assertEquals("goodbye", actual.getName());
+        assertEquals(IMPORTANCE_DEFAULT, actual.getImportance());
     }
 
     @Test
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index 15c61f6..2a8f4a3 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -30,6 +30,7 @@
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
 LOCAL_PACKAGE_NAME := FrameworksServicesTests
+LOCAL_COMPATIBILITY_SUITE := device-tests
 
 LOCAL_CERTIFICATE := platform
 
diff --git a/services/tests/servicestests/src/com/android/server/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/BaseLockSettingsServiceTests.java
index c6265bc..a2a4019 100644
--- a/services/tests/servicestests/src/com/android/server/BaseLockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/BaseLockSettingsServiceTests.java
@@ -25,6 +25,8 @@
 
 import android.app.IActivityManager;
 import android.app.NotificationManager;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.UserInfo;
 import android.database.sqlite.SQLiteDatabase;
@@ -76,7 +78,7 @@
     UserManager mUserManager;
     MockStorageManager mStorageManager;
     IActivityManager mActivityManager;
-
+    DevicePolicyManager mDevicePolicyManager;
     KeyStore mKeyStore;
 
     @Override
@@ -89,7 +91,9 @@
         mUserManager = mock(UserManager.class);
         mStorageManager = new MockStorageManager();
         mActivityManager = mock(IActivityManager.class);
-        mContext = new MockLockSettingsContext(getContext(), mUserManager, mNotificationManager);
+        mDevicePolicyManager = mock(DevicePolicyManager.class);
+        mContext = new MockLockSettingsContext(getContext(), mUserManager, mNotificationManager,
+                mDevicePolicyManager);
         mStorage = new LockSettingsStorageTestable(mContext,
                 new File(getContext().getFilesDir(), "locksettings"));
         File storageDir = mStorage.mStorageDir;
@@ -122,6 +126,10 @@
         });
 
         when(mLockPatternUtils.getLockSettings()).thenReturn(mService);
+
+        // Adding a fake Device Owner app which will enable escrow token support in LSS.
+        when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser()).thenReturn(
+                new ComponentName("com.dummy.package", ".FakeDeviceOwner"));
     }
 
     @Override
diff --git a/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java b/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java
index c68fbdc..4677904 100644
--- a/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java
+++ b/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java
@@ -21,6 +21,7 @@
 import static org.mockito.Mockito.when;
 
 import android.app.NotificationManager;
+import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.pm.UserInfo;
@@ -68,7 +69,7 @@
         when(mockUserManager.getProfileParent(eq(3))).thenReturn(new UserInfo(0, "name", 0));
 
         MockLockSettingsContext context = new MockLockSettingsContext(getContext(), mockUserManager,
-                mock(NotificationManager.class));
+                mock(NotificationManager.class), mock(DevicePolicyManager.class));
         mStorage = new LockSettingsStorageTestable(context,
                 new File(getContext().getFilesDir(), "locksettings"));
         mStorage.setDatabaseOnCreateCallback(new LockSettingsStorage.Callback() {
diff --git a/services/tests/servicestests/src/com/android/server/MockLockSettingsContext.java b/services/tests/servicestests/src/com/android/server/MockLockSettingsContext.java
index b63936f..8bceed4 100644
--- a/services/tests/servicestests/src/com/android/server/MockLockSettingsContext.java
+++ b/services/tests/servicestests/src/com/android/server/MockLockSettingsContext.java
@@ -17,6 +17,7 @@
 package com.android.server;
 
 import android.app.NotificationManager;
+import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.os.UserManager;
@@ -25,12 +26,14 @@
 
     private UserManager mUserManager;
     private NotificationManager mNotificationManager;
+    private DevicePolicyManager mDevicePolicyManager;
 
     public MockLockSettingsContext(Context base, UserManager userManager,
-            NotificationManager notificationManager) {
+            NotificationManager notificationManager, DevicePolicyManager devicePolicyManager) {
         super(base);
         mUserManager = userManager;
         mNotificationManager = notificationManager;
+        mDevicePolicyManager = devicePolicyManager;
     }
 
     @Override
@@ -39,6 +42,8 @@
             return mUserManager;
         } else if (NOTIFICATION_SERVICE.equals(name)) {
             return mNotificationManager;
+        } else if (DEVICE_POLICY_SERVICE.equals(name)) {
+            return mDevicePolicyManager;
         } else {
             throw new RuntimeException("System service not mocked: " + name);
         }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 8987ac1..721d337 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -157,7 +157,6 @@
         super.setUp();
 
         mContext = getContext();
-
         when(mContext.packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN)))
                 .thenReturn(true);
 
@@ -174,6 +173,12 @@
         setUpUserManager();
     }
 
+    @Override
+    protected void tearDown() throws Exception {
+        flushTasks();
+        super.tearDown();
+    }
+
     private void initializeDpms() {
         // Need clearCallingIdentity() to pass permission checks.
         final long ident = mContext.binder.clearCallingIdentity();
@@ -1246,7 +1251,7 @@
         mContext.applicationInfo = new ApplicationInfo();
         mContext.callerPermissions.add(permission.MANAGE_USERS);
         mContext.packageName = "com.android.frameworks.servicestests";
-        mContext.userContexts.put(user, mContext);
+        mContext.addPackageContext(user, mContext);
         when(mContext.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE);
 
         StringParceledListSlice oneCert = asSlice(new String[] {"1"});
@@ -3966,121 +3971,168 @@
     }
 
     public void testGetOwnerInstalledCaCertsForDeviceOwner() throws Exception {
+        mContext.packageName = mRealTestContext.getPackageName();
         setDeviceOwner();
 
-        mContext.packageName = admin1.getPackageName();
-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
-        verifyCanGetOwnerInstalledCaCerts(admin1);
+        final DpmMockContext caller = new DpmMockContext(mRealTestContext, "test-caller");
+        caller.packageName = admin1.getPackageName();
+        caller.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+        verifyCanGetOwnerInstalledCaCerts(admin1, caller);
     }
 
     public void testGetOwnerInstalledCaCertsForProfileOwner() throws Exception {
+        mContext.packageName = mRealTestContext.getPackageName();
         setAsProfileOwner(admin1);
 
-        mContext.packageName = admin1.getPackageName();
-        verifyCanGetOwnerInstalledCaCerts(admin1);
-        verifyCantGetOwnerInstalledCaCertsProfileOwnerRemoval(admin1);
+        final DpmMockContext caller = new DpmMockContext(mRealTestContext, "test-caller");
+        caller.packageName = admin1.getPackageName();
+        caller.binder.callingUid = DpmMockContext.CALLER_UID;
+
+        verifyCanGetOwnerInstalledCaCerts(admin1, caller);
+        verifyCantGetOwnerInstalledCaCertsProfileOwnerRemoval(admin1, caller);
     }
 
     public void testGetOwnerInstalledCaCertsForDelegate() throws Exception {
+        mContext.packageName = mRealTestContext.getPackageName();
         setAsProfileOwner(admin1);
 
         final String delegate = "com.example.delegate";
         final int delegateUid = setupPackageInPackageManager(delegate, 20988);
         dpm.setCertInstallerPackage(admin1, delegate);
 
-        mContext.packageName = delegate;
-        mContext.binder.callingUid = delegateUid;
-        verifyCanGetOwnerInstalledCaCerts(null);
-        verifyCantGetOwnerInstalledCaCertsProfileOwnerRemoval(null);
+        final DpmMockContext caller = new DpmMockContext(mRealTestContext, "test-caller");
+        caller.packageName = delegate;
+        caller.binder.callingUid = delegateUid;
+
+        verifyCanGetOwnerInstalledCaCerts(null, caller);
+        verifyCantGetOwnerInstalledCaCertsProfileOwnerRemoval(null, caller);
     }
 
-    private void verifyCanGetOwnerInstalledCaCerts(ComponentName caller) throws Exception {
-        final UserHandle user = UserHandle.getUserHandleForUid(mContext.binder.callingUid);
-        final int ownerUid = user.equals(UserHandle.SYSTEM) ?
-                DpmMockContext.CALLER_SYSTEM_USER_UID : DpmMockContext.CALLER_UID;
-
-        mContext.applicationInfo = new ApplicationInfo();
-        mContext.userContexts.put(user, mContext);
-        when(mContext.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE);
-
-        // Install a CA cert.
+    private void verifyCanGetOwnerInstalledCaCerts(
+            final ComponentName caller, final DpmMockContext callerContext) throws Exception {
         final String alias = "cert";
         final byte[] caCert = TEST_CA.getBytes();
-        when(mContext.keyChainConnection.getService().installCaCertificate(caCert))
-                .thenReturn(alias);
-        assertTrue(dpm.installCaCert(caller, caCert));
-        when(mContext.keyChainConnection.getService().getUserCaAliases())
-                .thenReturn(asSlice(new String[] {alias}));
-        mContext.injectBroadcast(new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED));
+
+        // device admin (used for posting the tls notification)
+        final DpmMockContext admin1Context;
+        if (admin1.getPackageName().equals(callerContext.getPackageName())) {
+            admin1Context = callerContext;
+        } else {
+            admin1Context = new DpmMockContext(mRealTestContext, "test-admin");
+            admin1Context.packageName = admin1.getPackageName();
+            admin1Context.applicationInfo = new ApplicationInfo();
+        }
+        when(admin1Context.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE);
+
+        // caller: device admin or delegated certificate installer
+        callerContext.applicationInfo = new ApplicationInfo();
+        final UserHandle callerUser = callerContext.binder.getCallingUserHandle();
+
+        // system_server
+        final DpmMockContext serviceContext = mContext;
+        serviceContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
+        serviceContext.addPackageContext(callerUser, admin1Context);
+        serviceContext.addPackageContext(callerUser, callerContext);
+
+        // Install a CA cert.
+        runAsCaller(callerContext, dpms, (dpm) -> {
+            when(mContext.keyChainConnection.getService().installCaCertificate(caCert))
+                        .thenReturn(alias);
+            assertTrue(dpm.installCaCert(caller, caCert));
+            when(mContext.keyChainConnection.getService().getUserCaAliases())
+                    .thenReturn(asSlice(new String[] {alias}));
+
+        });
+
+        serviceContext.injectBroadcast(new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED)
+                .putExtra(Intent.EXTRA_USER_HANDLE, callerUser.getIdentifier()));
         flushTasks();
 
+        final List<String> ownerInstalledCaCerts = new ArrayList<>();
+
         // Device Owner / Profile Owner can find out which CA certs were installed by itself.
-        final String packageName = mContext.packageName;
-        mContext.packageName = admin1.getPackageName();
-        final long callerIdentity = mContext.binder.clearCallingIdentity();
-        mContext.binder.callingUid = ownerUid;
-        List<String> ownerInstalledCaCerts = dpm.getOwnerInstalledCaCerts(user);
-        assertNotNull(ownerInstalledCaCerts);
-        assertEquals(1, ownerInstalledCaCerts.size());
-        assertTrue(ownerInstalledCaCerts.contains(alias));
+        runAsCaller(admin1Context, dpms, (dpm) -> {
+            final List<String> installedCaCerts = dpm.getOwnerInstalledCaCerts(callerUser);
+            assertEquals(Arrays.asList(alias), installedCaCerts);
+            ownerInstalledCaCerts.addAll(installedCaCerts);
+        });
 
         // Restarting the DPMS should not lose information.
         initializeDpms();
-        assertEquals(ownerInstalledCaCerts, dpm.getOwnerInstalledCaCerts(user));
+        runAsCaller(admin1Context, dpms, (dpm) -> {
+            assertEquals(ownerInstalledCaCerts, dpm.getOwnerInstalledCaCerts(callerUser));
+        });
 
         // System can find out which CA certs were installed by the Device Owner / Profile Owner.
-        mContext.packageName = "com.android.frameworks.servicestests";
-        mContext.binder.clearCallingIdentity();
-        assertEquals(ownerInstalledCaCerts, dpm.getOwnerInstalledCaCerts(user));
+        runAsCaller(serviceContext, dpms, (dpm) -> {
+            assertEquals(ownerInstalledCaCerts, dpm.getOwnerInstalledCaCerts(callerUser));
 
-        // Remove the CA cert.
-        mContext.packageName = packageName;
-        mContext.binder.restoreCallingIdentity(callerIdentity);
-        reset(mContext.keyChainConnection.getService());
-        mContext.injectBroadcast(new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED));
+            // Remove the CA cert.
+            reset(mContext.keyChainConnection.getService());
+        });
+
+        serviceContext.injectBroadcast(new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED)
+                .putExtra(Intent.EXTRA_USER_HANDLE, callerUser.getIdentifier()));
         flushTasks();
 
         // Verify that the CA cert is no longer reported as installed by the Device Owner / Profile
         // Owner.
-        mContext.packageName = admin1.getPackageName();
-        mContext.binder.callingUid = ownerUid;
-        ownerInstalledCaCerts = dpm.getOwnerInstalledCaCerts(user);
-        assertNotNull(ownerInstalledCaCerts);
-        assertTrue(ownerInstalledCaCerts.isEmpty());
-
-        mContext.packageName = packageName;
-        mContext.binder.restoreCallingIdentity(callerIdentity);
+        runAsCaller(admin1Context, dpms, (dpm) -> {
+            MoreAsserts.assertEmpty(dpm.getOwnerInstalledCaCerts(callerUser));
+        });
     }
 
-    private void verifyCantGetOwnerInstalledCaCertsProfileOwnerRemoval(ComponentName caller)
-            throws Exception {
-        final UserHandle user = UserHandle.of(DpmMockContext.CALLER_USER_HANDLE);
-
-        mContext.applicationInfo = new ApplicationInfo();
-        mContext.userContexts.put(user, mContext);
-        when(mContext.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE);
-
-        // Install a CA cert.
+    private void verifyCantGetOwnerInstalledCaCertsProfileOwnerRemoval(
+            final ComponentName callerName, final DpmMockContext callerContext) throws Exception {
         final String alias = "cert";
         final byte[] caCert = TEST_CA.getBytes();
-        when(mContext.keyChainConnection.getService().installCaCertificate(caCert))
-                .thenReturn(alias);
-        assertTrue(dpm.installCaCert(caller, caCert));
-        when(mContext.keyChainConnection.getService().getUserCaAliases())
+
+        // device admin (used for posting the tls notification)
+        final DpmMockContext admin1Context;
+        if (admin1.getPackageName().equals(callerContext.getPackageName())) {
+            admin1Context = callerContext;
+        } else {
+            admin1Context = new DpmMockContext(mRealTestContext, "test-admin");
+            admin1Context.packageName = admin1.getPackageName();
+            admin1Context.applicationInfo = new ApplicationInfo();
+        }
+        when(admin1Context.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE);
+
+        // caller: device admin or delegated certificate installer
+        callerContext.applicationInfo = new ApplicationInfo();
+        final UserHandle callerUser = callerContext.binder.getCallingUserHandle();
+
+        // system_server
+        final DpmMockContext serviceContext = mContext;
+        serviceContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
+        serviceContext.addPackageContext(callerUser, admin1Context);
+        serviceContext.addPackageContext(callerUser, callerContext);
+
+        // Install a CA cert as caller
+        runAsCaller(callerContext, dpms, (dpm) -> {
+            when(mContext.keyChainConnection.getService().installCaCertificate(caCert))
+                    .thenReturn(alias);
+            assertTrue(dpm.installCaCert(callerName, caCert));
+        });
+
+        // Fake the CA cert as having been installed
+        when(serviceContext.keyChainConnection.getService().getUserCaAliases())
                 .thenReturn(asSlice(new String[] {alias}));
-        mContext.injectBroadcast(new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED));
+        serviceContext.injectBroadcast(new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED)
+                .putExtra(Intent.EXTRA_USER_HANDLE, callerUser.getIdentifier()));
         flushTasks();
 
-        // Removing the Profile Owner should clear the information which CA certs were installed
-        // by it.
-        mContext.packageName = admin1.getPackageName();
-        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
-        dpm.clearProfileOwner(admin1);
-        mContext.packageName = "com.android.frameworks.servicestests";
-        mContext.binder.clearCallingIdentity();
-        final List<String> ownerInstalledCaCerts = dpm.getOwnerInstalledCaCerts(user);
-        assertNotNull(ownerInstalledCaCerts);
-        assertTrue(ownerInstalledCaCerts.isEmpty());
+        // Removing the Profile Owner should clear the information on which CA certs were installed
+        runAsCaller(admin1Context, dpms, (dpm) -> {
+            dpm.clearProfileOwner(admin1);
+        });
+
+        runAsCaller(serviceContext, dpms, (dpm) -> {
+            final List<String> ownerInstalledCaCerts = dpm.getOwnerInstalledCaCerts(callerUser);
+            assertNotNull(ownerInstalledCaCerts);
+            assertTrue(ownerInstalledCaCerts.isEmpty());
+        });
     }
 
     private void setUserSetupCompleteForUser(boolean isUserSetupComplete, int userhandle) {
@@ -4147,29 +4199,11 @@
     }
 
     private void flushTasks() throws Exception {
-        Boolean tasksFlushed[] = new Boolean[] {false};
-        final Runnable tasksFlushedNotifier = () -> {
-            synchronized (tasksFlushed) {
-                tasksFlushed[0] = true;
-                tasksFlushed.notify();
-            }
-        };
+        dpms.mHandler.runWithScissors(() -> {}, 0 /*now*/);
+        dpms.mBackgroundHandler.runWithScissors(() -> {}, 0 /*now*/);
 
-        // Flush main thread handler.
-        dpms.mHandler.post(tasksFlushedNotifier);
-        synchronized (tasksFlushed) {
-            if (!tasksFlushed[0]) {
-                tasksFlushed.wait();
-            }
-        }
-
-        // Flush background thread handler.
-        tasksFlushed[0] = false;
-        dpms.mBackgroundHandler.post(tasksFlushedNotifier);
-        synchronized (tasksFlushed) {
-            if (!tasksFlushed[0]) {
-                tasksFlushed.wait();
-            }
-        }
+        // We can't let exceptions happen on the background thread. Throw them here if they happen
+        // so they still cause the test to fail despite being suppressed.
+        mContext.rethrowBackgroundBroadcastExceptions();
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 7d017c5..1ea12d8 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -48,6 +48,7 @@
 import android.test.mock.MockContentResolver;
 import android.test.mock.MockContext;
 import android.util.ArrayMap;
+import android.util.Pair;
 import android.view.IWindowManager;
 
 import com.android.internal.widget.LockPatternUtils;
@@ -61,6 +62,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
 
 import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.anyInt;
@@ -111,6 +113,7 @@
     public static class MockBinder {
         public int callingUid = CALLER_UID;
         public int callingPid = CALLER_PID;
+        public final Map<Integer, List<String>> callingPermissions = new ArrayMap<>();
 
         public long clearCallingIdentity() {
             final long token = (((long) callingUid) << 32) | (callingPid);
@@ -303,14 +306,19 @@
     /** Note this is a partial mock, not a real mock. */
     public final PackageManager packageManager;
 
+    /** TODO: Migrate everything to use {@link #permissions} to avoid confusion. */
+    @Deprecated
     public final List<String> callerPermissions = new ArrayList<>();
 
+    /** Less confusing alias for {@link #callerPermissions}. */
+    public final List<String> permissions = callerPermissions;
+
     private final ArrayList<UserInfo> mUserInfos = new ArrayList<>();
 
     public final BuildMock buildMock = new BuildMock();
 
     /** Optional mapping of other user contexts for {@link #createPackageContextAsUser} to return */
-    public final Map<UserHandle, Context> userContexts = new ArrayMap<>();
+    public final Map<Pair<UserHandle, String>, Context> userPackageContexts = new ArrayMap<>();
 
     public String packageName = null;
 
@@ -324,6 +332,9 @@
         public final IntentFilter filter;
         public final Handler scheduler;
 
+        // Exceptions thrown in a background thread kill the whole test. Save them instead.
+        public final AtomicReference<Exception> backgroundException = new AtomicReference<>();
+
         public BroadcastReceiverRegistration(BroadcastReceiver receiver, IntentFilter filter,
                 Handler scheduler) {
             this.receiver = receiver;
@@ -337,20 +348,30 @@
                     0 /* type */, false /* ordered */, false /* sticky */, null /* token */, userId,
                     0 /* flags */);
             if (filter.match(null, intent, false, "DpmMockContext") > 0) {
-                if (scheduler != null) {
-                    scheduler.post(() -> {
-                        receiver.setPendingResult(result);
-                        receiver.onReceive(DpmMockContext.this, intent);
-                    });
-                } else {
+                final Runnable send = () -> {
                     receiver.setPendingResult(result);
                     receiver.onReceive(DpmMockContext.this, intent);
+                };
+                if (scheduler != null) {
+                    scheduler.post(() -> {
+                        try {
+                            send.run();
+                        } catch (Exception e) {
+                            backgroundException.compareAndSet(null, e);
+                        }
+                    });
+                } else {
+                    send.run();
                 }
             }
         }
     }
     private List<BroadcastReceiverRegistration> mBroadcastReceivers = new ArrayList<>();
 
+    public DpmMockContext(Context realTestContext, String name) {
+        this(realTestContext, new File(realTestContext.getCacheDir(), name));
+    }
+
     public DpmMockContext(Context context, File dataDir) {
         realTestContext = context;
 
@@ -511,13 +532,29 @@
                 .thenReturn(isRunning);
     }
 
-    public void injectBroadcast(Intent intent) {
+    public void injectBroadcast(final Intent intent) {
         final int userId = UserHandle.getUserId(binder.getCallingUid());
         for (final BroadcastReceiverRegistration receiver : mBroadcastReceivers) {
             receiver.sendBroadcastIfApplicable(userId, intent);
         }
     }
 
+    public void rethrowBackgroundBroadcastExceptions() throws Exception {
+        for (final BroadcastReceiverRegistration receiver : mBroadcastReceivers) {
+            final Exception e = receiver.backgroundException.getAndSet(null);
+            if (e != null) {
+                throw e;
+            }
+        }
+    }
+
+    public void addPackageContext(UserHandle user, Context context) {
+        if (context.getPackageName() == null) {
+            throw new NullPointerException("getPackageName() == null");
+        }
+        userPackageContexts.put(new Pair<>(user, context.getPackageName()), context);
+    }
+
     @Override
     public Resources getResources() {
         return resources;
@@ -576,7 +613,16 @@
         if (binder.getCallingUid() == SYSTEM_UID) {
             return; // Assume system has all permissions.
         }
-        if (!callerPermissions.contains(permission)) {
+
+        List<String> permissions = binder.callingPermissions.get(binder.getCallingUid());
+        if (permissions == null) {
+            // TODO: delete the following line. to do this without breaking any tests, first it's
+            //       necessary to remove all tests that set it directly.
+            permissions = callerPermissions;
+//            throw new UnsupportedOperationException(
+//                    "Caller UID " + binder.getCallingUid() + " doesn't exist");
+        }
+        if (!permissions.contains(permission)) {
             throw new SecurityException("Caller doesn't have " + permission + " : " + message);
         }
     }
@@ -751,14 +797,11 @@
     @Override
     public Context createPackageContextAsUser(String packageName, int flags, UserHandle user)
             throws PackageManager.NameNotFoundException {
-        if (!userContexts.containsKey(user)) {
-            return super.createPackageContextAsUser(packageName, flags, user);
+        final Pair<UserHandle, String> key = new Pair<>(user, packageName);
+        if (userPackageContexts.containsKey(key)) {
+            return userPackageContexts.get(key);
         }
-        if (!getPackageName().equals(packageName)) {
-            throw new UnsupportedOperationException(
-                    "Creating a context as another package is not implemented");
-        }
-        return userContexts.get(user);
+        throw new UnsupportedOperationException("No package " + packageName + " for user " + user);
     }
 
     @Override
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
index 43e2610..5d68edd 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
@@ -16,6 +16,7 @@
 
 package com.android.server.devicepolicy;
 
+import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -70,6 +71,34 @@
         return mMockContext;
     }
 
+    protected interface DpmRunnable {
+        public void run(DevicePolicyManager dpm) throws Exception;
+    }
+
+    /**
+     * Simulate an RPC from {@param caller} to the service context ({@link #mContext}).
+     *
+     * The caller sees its own context. The server also sees its own separate context, with the
+     * appropriate calling UID and calling permissions fields already set up.
+     */
+    protected void runAsCaller(DpmMockContext caller, DevicePolicyManagerServiceTestable dpms,
+            DpmRunnable action) {
+        final DpmMockContext serviceContext = mMockContext;
+
+        final long origId = serviceContext.binder.clearCallingIdentity();
+        try {
+            serviceContext.binder.callingUid = caller.binder.callingUid;
+            serviceContext.binder.callingPid = caller.binder.callingPid;
+            serviceContext.binder.callingPermissions.put(caller.binder.callingUid,
+                    caller.permissions);
+            action.run(new DevicePolicyManagerTestable(caller, dpms));
+        } catch (Exception e) {
+            throw new AssertionError(e);
+        } finally {
+            serviceContext.binder.restoreCallingIdentity(origId);
+        }
+    }
+
     protected void markPackageAsInstalled(String packageName, ApplicationInfo ai, int userId)
             throws Exception {
         final PackageInfo pi = DpmTestUtils.cloneParcelable(
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
index 9f50a2c..921e0e3 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -126,8 +126,6 @@
     }
 
     @Test
-    @Ignore
-    // TODO(b/35034729): Need to fix before re-enabling
     public void testLandscapeSeascapeRotationByPolicy() throws Exception {
         // Some plumbing to get the service ready for rotation updates.
         sWm.mDisplayReady = true;
@@ -145,15 +143,20 @@
         appWindowToken.addWindow(appWindow);
 
         // Set initial orientation and update.
-        ((TestWindowManagerPolicy) sWm.mPolicy).rotationToReport = Surface.ROTATION_90;
-        sWm.updateRotation(false, false);
+        performRotation(Surface.ROTATION_90);
         appWindow.resizeReported = false;
 
         // Update the rotation to perform 180 degree rotation and check that resize was reported.
-        ((TestWindowManagerPolicy) sWm.mPolicy).rotationToReport = Surface.ROTATION_270;
-        sWm.updateRotation(false, false);
-        sWm.mRoot.performSurfacePlacement(false /* recoveringMemory */);
+        performRotation(Surface.ROTATION_270);
         assertTrue(appWindow.resizeReported);
         appWindow.removeImmediately();
     }
+
+    private void performRotation(int rotationToReport) {
+        ((TestWindowManagerPolicy) sWm.mPolicy).rotationToReport = rotationToReport;
+        sWm.updateRotation(false, false);
+        // Simulate animator finishing orientation change
+        sWm.mRoot.mOrientationChangeComplete = true;
+        sWm.mRoot.performSurfacePlacement(false /* recoveringMemory */);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java b/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java
index b6dc9a5..0a644b60 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java
@@ -18,11 +18,11 @@
 
 import com.android.internal.os.IResultReceiver;
 
-import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
+import android.util.MergedConfiguration;
 import android.view.DragEvent;
 import android.view.IWindow;
 
@@ -36,7 +36,7 @@
 
     @Override
     public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
-            Rect stableInsets, Rect outsets, boolean reportDraw, Configuration newConfig,
+            Rect stableInsets, Rect outsets, boolean reportDraw, MergedConfiguration mergedConfig,
             Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeNavBar, int displayId)
             throws RemoteException {
 
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 911050a..65efd9c 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -71,7 +71,10 @@
     static TestWindowManagerPolicy sPolicy = null;
     private final static IWindow sIWindow = new TestIWindow();
     private final static Session sMockSession = mock(Session.class);
-    private static int sNextDisplayId = Display.DEFAULT_DISPLAY + 1;
+    // The default display is removed in {@link #setUp} and then we iterate over all displays to
+    // make sure we don't collide with any existing display. If we run into no other display, the
+    // added display should be treated as default.
+    private static int sNextDisplayId = Display.DEFAULT_DISPLAY;
     static int sNextStackId = FIRST_DYNAMIC_STACK_ID;
     private static int sNextTaskId = 0;
 
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 40bdaa5..03d8241 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -25,8 +25,8 @@
 import android.media.AudioSystem;
 import android.media.IAudioService;
 import android.media.midi.MidiDeviceInfo;
-import android.os.FileObserver;
 import android.os.Bundle;
+import android.os.FileObserver;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
@@ -41,10 +41,7 @@
 import libcore.io.IoUtils;
 
 import java.io.File;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
 import java.util.HashMap;
-import java.util.ArrayList;
 
 /**
  * UsbAlsaManager manages USB audio and MIDI devices.
@@ -219,23 +216,23 @@
         AlsaDevice testDevice = new AlsaDevice(type, card, device);
 
         // This value was empirically determined.
-        final int kWaitTime = 2500; // ms
+        final int kWaitTimeMs = 2500;
 
         synchronized(mAlsaDevices) {
-            long timeout = SystemClock.elapsedRealtime() + kWaitTime;
+            long timeoutMs = SystemClock.elapsedRealtime() + kWaitTimeMs;
             do {
                 if (mAlsaDevices.values().contains(testDevice)) {
                     return testDevice;
                 }
-                long waitTime = timeout - SystemClock.elapsedRealtime();
-                if (waitTime > 0) {
+                long waitTimeMs = timeoutMs - SystemClock.elapsedRealtime();
+                if (waitTimeMs > 0) {
                     try {
-                        mAlsaDevices.wait(waitTime);
+                        mAlsaDevices.wait(waitTimeMs);
                     } catch (InterruptedException e) {
                         Slog.d(TAG, "usb: InterruptedException while waiting for ALSA file.");
                     }
                 }
-            } while (timeout > SystemClock.elapsedRealtime());
+            } while (timeoutMs > SystemClock.elapsedRealtime());
         }
 
         Slog.e(TAG, "waitForAlsaDevice failed for " + testDevice);
@@ -498,6 +495,7 @@
     // Devices List
     //
 /*
+    //import java.util.ArrayList;
     public ArrayList<UsbAudioDevice> getConnectedDevices() {
         ArrayList<UsbAudioDevice> devices = new ArrayList<UsbAudioDevice>(mAudioDevices.size());
         for (HashMap.Entry<UsbDevice,UsbAudioDevice> entry : mAudioDevices.entrySet()) {
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 4178f4d..4da2853 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -169,6 +169,7 @@
         public AdbSettingsObserver() {
             super(null);
         }
+
         @Override
         public void onChange(boolean selfChange) {
             boolean enable = (Settings.Global.getInt(mContentResolver,
@@ -208,9 +209,9 @@
     private final BroadcastReceiver mChargingReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-             int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
-             boolean usbCharging = chargePlug == BatteryManager.BATTERY_PLUGGED_USB;
-             mHandler.sendMessage(MSG_UPDATE_CHARGING_STATE, usbCharging);
+            int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
+            boolean usbCharging = chargePlug == BatteryManager.BATTERY_PLUGGED_USB;
+            mHandler.sendMessage(MSG_UPDATE_CHARGING_STATE, usbCharging);
         }
     };
 
@@ -261,9 +262,10 @@
             // TV-specific notification channel
             mNotificationManager.createNotificationChannel(
                     new NotificationChannel(ADB_NOTIFICATION_CHANNEL_ID_TV,
-                        mContext.getString(
-                            com.android.internal.R.string.adb_debugging_notification_channel_tv),
-                        NotificationManager.IMPORTANCE_HIGH));
+                            mContext.getString(
+                                    com.android.internal.R.string
+                                            .adb_debugging_notification_channel_tv),
+                            NotificationManager.IMPORTANCE_HIGH));
         }
 
         // We do not show the USB notification if the primary volume supports mass storage.
@@ -309,8 +311,8 @@
         boolean enableAudio = (nativeGetAudioMode() == AUDIO_MODE_SOURCE);
         // don't start accessory mode if our mandatory strings have not been set
         boolean enableAccessory = (mAccessoryStrings != null &&
-                        mAccessoryStrings[UsbAccessory.MANUFACTURER_STRING] != null &&
-                        mAccessoryStrings[UsbAccessory.MODEL_STRING] != null);
+                mAccessoryStrings[UsbAccessory.MANUFACTURER_STRING] != null &&
+                mAccessoryStrings[UsbAccessory.MODEL_STRING] != null);
         String functions = null;
 
         if (enableAccessory && enableAudio) {
@@ -341,14 +343,14 @@
         int serialLength = serial.length();
         // XOR the USB serial across the remaining 5 bytes
         for (int i = 0; i < serialLength; i++) {
-            address[i % (ETH_ALEN - 1) + 1] ^= (int)serial.charAt(i);
+            address[i % (ETH_ALEN - 1) + 1] ^= (int) serial.charAt(i);
         }
         String addrString = String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X",
-            address[0], address[1], address[2], address[3], address[4], address[5]);
+                address[0], address[1], address[2], address[3], address[4], address[5]);
         try {
             FileUtils.stringToFile(RNDIS_ETH_ADDR_PATH, addrString);
         } catch (IOException e) {
-           Slog.e(TAG, "failed to write to " + RNDIS_ETH_ADDR_PATH);
+            Slog.e(TAG, "failed to write to " + RNDIS_ETH_ADDR_PATH);
         }
     }
 
@@ -400,7 +402,7 @@
                 // register observer to listen for settings changes
                 mContentResolver.registerContentObserver(
                         Settings.Global.getUriFor(Settings.Global.ADB_ENABLED),
-                                false, new AdbSettingsObserver());
+                        false, new AdbSettingsObserver());
 
                 // Watch for USB configuration changes
                 mUEventObserver.startObserving(USB_STATE_MATCH);
@@ -466,9 +468,9 @@
             }
 
             SomeArgs args = SomeArgs.obtain();
-            args.argi1 = hostConnected ? 1 :0;
-            args.argi2 = sourcePower ? 1 :0;
-            args.argi3 = sinkPower ? 1 :0;
+            args.argi1 = hostConnected ? 1 : 0;
+            args.argi2 = sourcePower ? 1 : 0;
+            args.argi3 = sinkPower ? 1 : 0;
 
             removeMessages(MSG_UPDATE_HOST_STATE);
             Message msg = obtainMessage(MSG_UPDATE_HOST_STATE, args);
@@ -506,7 +508,7 @@
 
                 // Persist the adb setting
                 String newFunction = applyAdbFunction(SystemProperties.get(
-                            USB_PERSISTENT_CONFIG_PROPERTY, UsbManager.USB_FUNCTION_NONE));
+                        USB_PERSISTENT_CONFIG_PROPERTY, UsbManager.USB_FUNCTION_NONE));
                 SystemProperties.set(USB_PERSISTENT_CONFIG_PROPERTY, newFunction);
 
                 // Remove mtp from the config if file transfer is not enabled
@@ -529,8 +531,10 @@
          */
         private void setEnabledFunctions(String functions, boolean forceRestart,
                 boolean usbDataUnlocked) {
-            if (DEBUG) Slog.d(TAG, "setEnabledFunctions functions=" + functions + ", "
-                    + "forceRestart=" + forceRestart);
+            if (DEBUG) {
+                Slog.d(TAG, "setEnabledFunctions functions=" + functions + ", "
+                        + "forceRestart=" + forceRestart);
+            }
 
             if (usbDataUnlocked != mUsbDataUnlocked) {
                 mUsbDataUnlocked = usbDataUnlocked;
@@ -680,7 +684,7 @@
                 }
                 for (String key : keySet) {
                     if (intent.getBooleanExtra(key, false) !=
-                        mBroadcastedIntent.getBooleanExtra(key, false)) {
+                            mBroadcastedIntent.getBooleanExtra(key, false)) {
                         return true;
                     }
                 }
@@ -697,7 +701,8 @@
             intent.putExtra(UsbManager.USB_CONNECTED, mConnected);
             intent.putExtra(UsbManager.USB_HOST_CONNECTED, mHostConnected);
             intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured);
-            intent.putExtra(UsbManager.USB_DATA_UNLOCKED, isUsbTransferAllowed() && mUsbDataUnlocked);
+            intent.putExtra(UsbManager.USB_DATA_UNLOCKED,
+                    isUsbTransferAllowed() && mUsbDataUnlocked);
             intent.putExtra(UsbManager.USB_CONFIG_CHANGED, configChanged);
 
             if (mCurrentFunctions != null) {
@@ -825,7 +830,7 @@
                     setAdbEnabled(msg.arg1 == 1);
                     break;
                 case MSG_SET_CURRENT_FUNCTIONS:
-                    String functions = (String)msg.obj;
+                    String functions = (String) msg.obj;
                     setEnabledFunctions(functions, false, msg.arg1 == 1);
                     break;
                 case MSG_UPDATE_USER_RESTRICTIONS:
@@ -854,9 +859,9 @@
                     if (mCurrentUser != msg.arg1) {
                         // Restart the USB stack and re-apply user restrictions for MTP or PTP.
                         final boolean active = UsbManager.containsFunction(mCurrentFunctions,
-                                        UsbManager.USB_FUNCTION_MTP)
+                                UsbManager.USB_FUNCTION_MTP)
                                 || UsbManager.containsFunction(mCurrentFunctions,
-                                        UsbManager.USB_FUNCTION_PTP);
+                                UsbManager.USB_FUNCTION_PTP);
                         if (mUsbDataUnlocked && active && mCurrentUser != UserHandle.USER_NULL) {
                             Slog.v(TAG, "Current user switched to " + mCurrentUser
                                     + "; resetting USB host stack for MTP or PTP");
@@ -885,7 +890,9 @@
 
         private void updateUsbNotification() {
             if (mNotificationManager == null || !mUseUsbNotification
-                    || ("0".equals(SystemProperties.get("persist.charging.notify")))) return;
+                    || ("0".equals(SystemProperties.get("persist.charging.notify")))) {
+                return;
+            }
             int id = 0;
             Resources r = mContext.getResources();
             if (mConnected) {
@@ -937,18 +944,19 @@
 
                     Notification notification =
                             new Notification.Builder(mContext, SystemNotificationChannels.USB)
-                            .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
-                            .setWhen(0)
-                            .setOngoing(true)
-                            .setTicker(title)
-                            .setDefaults(0)  // please be quiet
-                            .setColor(mContext.getColor(
-                                    com.android.internal.R.color.system_notification_accent_color))
-                            .setContentTitle(title)
-                            .setContentText(message)
-                            .setContentIntent(pi)
-                            .setVisibility(Notification.VISIBILITY_PUBLIC)
-                            .build();
+                                    .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
+                                    .setWhen(0)
+                                    .setOngoing(true)
+                                    .setTicker(title)
+                                    .setDefaults(0)  // please be quiet
+                                    .setColor(mContext.getColor(
+                                            com.android.internal.R.color
+                                                    .system_notification_accent_color))
+                                    .setContentTitle(title)
+                                    .setContentText(message)
+                                    .setContentIntent(pi)
+                                    .setVisibility(Notification.VISIBILITY_PUBLIC)
+                                    .build();
                     mNotificationManager.notifyAsUser(null, id, notification,
                             UserHandle.ALL);
                     mUsbNotificationId = id;
@@ -976,20 +984,21 @@
 
                     Notification notification =
                             new Notification.Builder(mContext, SystemNotificationChannels.DEVELOPER)
-                            .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
-                            .setWhen(0)
-                            .setOngoing(true)
-                            .setTicker(title)
-                            .setDefaults(0)  // please be quiet
-                            .setColor(mContext.getColor(
-                                    com.android.internal.R.color.system_notification_accent_color))
-                            .setContentTitle(title)
-                            .setContentText(message)
-                            .setContentIntent(pi)
-                            .setVisibility(Notification.VISIBILITY_PUBLIC)
-                            .extend(new Notification.TvExtender()
-                                    .setChannel(ADB_NOTIFICATION_CHANNEL_ID_TV))
-                            .build();
+                                    .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
+                                    .setWhen(0)
+                                    .setOngoing(true)
+                                    .setTicker(title)
+                                    .setDefaults(0)  // please be quiet
+                                    .setColor(mContext.getColor(
+                                            com.android.internal.R.color
+                                                    .system_notification_accent_color))
+                                    .setContentTitle(title)
+                                    .setContentText(message)
+                                    .setContentIntent(pi)
+                                    .setVisibility(Notification.VISIBILITY_PUBLIC)
+                                    .extend(new Notification.TvExtender()
+                                            .setChannel(ADB_NOTIFICATION_CHANNEL_ID_TV))
+                                    .build();
                     mAdbNotificationShown = true;
                     mNotificationManager.notifyAsUser(null, id, notification,
                             UserHandle.ALL);
@@ -1038,7 +1047,8 @@
     }
 
     /* opens the currently attached USB accessory */
-    public ParcelFileDescriptor openAccessory(UsbAccessory accessory, UsbUserSettingsManager settings) {
+    public ParcelFileDescriptor openAccessory(UsbAccessory accessory,
+            UsbUserSettingsManager settings) {
         UsbAccessory currentAccessory = mHandler.getCurrentAccessory();
         if (currentAccessory == null) {
             throw new IllegalArgumentException("no accessory attached");
@@ -1058,17 +1068,19 @@
     }
 
     public void setCurrentFunctions(String functions, boolean usbDataUnlocked) {
-        if (DEBUG) Slog.d(TAG, "setCurrentFunctions(" + functions + ", " +
-				usbDataUnlocked + ")");
+        if (DEBUG) {
+            Slog.d(TAG, "setCurrentFunctions(" + functions + ", " +
+                    usbDataUnlocked + ")");
+        }
         mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions, usbDataUnlocked);
     }
 
     private void readOemUsbOverrideConfig() {
         String[] configList = mContext.getResources().getStringArray(
-            com.android.internal.R.array.config_oemUsbModeOverride);
+                com.android.internal.R.array.config_oemUsbModeOverride);
 
         if (configList != null) {
-            for (String config: configList) {
+            for (String config : configList) {
                 String[] items = config.split(":");
                 if (items.length == 3) {
                     if (mOemModeMap == null) {
@@ -1092,7 +1104,7 @@
 
         List<Pair<String, String>> overrides = mOemModeMap.get(bootMode);
         if (overrides != null) {
-            for (Pair<String, String> pair: overrides) {
+            for (Pair<String, String> pair : overrides) {
                 if (pair.first.equals(usbFunctions)) {
                     Slog.d(TAG, "OEM USB override: " + pair.first + " ==> " + pair.second);
                     return pair.second;
@@ -1120,7 +1132,7 @@
             mDebuggingManager.clearUsbDebuggingKeys();
         } else {
             throw new RuntimeException("Cannot clear Usb Debugging keys, "
-                        + "UsbDebuggingManager not enabled");
+                    + "UsbDebuggingManager not enabled");
         }
     }
 
@@ -1134,7 +1146,10 @@
     }
 
     private native String[] nativeGetAccessoryStrings();
+
     private native ParcelFileDescriptor nativeOpenAccessory();
+
     private native boolean nativeIsStartRequested();
+
     private native int nativeGetAudioMode();
 }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 748e32a..7a226a0 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1374,6 +1374,22 @@
     public static final String KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG =
             "data_limit_threshold_bytes_long";
 
+    /**
+     * Offset to be reduced from rsrp threshold while calculating signal strength level.
+     * @hide
+     */
+    public static final String KEY_LTE_EARFCNS_RSRP_BOOST_INT = "lte_earfcns_rsrp_boost_int";
+
+    /**
+     * List of EARFCN (E-UTRA Absolute Radio Frequency Channel Number,
+     * Reference: 3GPP TS 36.104 5.4.3) inclusive ranges on which lte_rsrp_boost_int
+     * will be applied. Format of the String array is expected to be {"erafcn1_start-earfcn1_end",
+     * "earfcn2_start-earfcn2_end" ... }
+     * @hide
+     */
+    public static final String KEY_BOOSTED_LTE_EARFCNS_STRING_ARRAY =
+            "boosted_lte_earfcns_string_array";
+
     /** The default value for every variable. */
     private final static PersistableBundle sDefaults;
 
@@ -1607,6 +1623,8 @@
         sDefaults.putBoolean(KEY_EDITABLE_TETHER_APN_BOOL, false);
         sDefaults.putStringArray(KEY_CALL_FORWARDING_BLOCKS_WHILE_ROAMING_STRING_ARRAY,
                 null);
+        sDefaults.putInt(KEY_LTE_EARFCNS_RSRP_BOOST_INT, 0);
+        sDefaults.putStringArray(KEY_BOOSTED_LTE_EARFCNS_STRING_ARRAY, null);
     }
 
     /**
diff --git a/telephony/java/android/telephony/PreciseDisconnectCause.java b/telephony/java/android/telephony/PreciseDisconnectCause.java
index 54ab19d..2516d51 100644
--- a/telephony/java/android/telephony/PreciseDisconnectCause.java
+++ b/telephony/java/android/telephony/PreciseDisconnectCause.java
@@ -25,75 +25,480 @@
 public class PreciseDisconnectCause {
 
     /** The disconnect cause is not valid (Not received a disconnect cause)*/
-    public static final int NOT_VALID                      = -1;
+    public static final int NOT_VALID                                        = -1;
     /** No disconnect cause provided. Generally a local disconnect or an incoming missed call */
-    public static final int NO_DISCONNECT_CAUSE_AVAILABLE  = 0;
+    public static final int NO_DISCONNECT_CAUSE_AVAILABLE                    = 0;
     /**
      * The destination cannot be reached because the number, although valid,
      * is not currently assigned
      */
-    public static final int UNOBTAINABLE_NUMBER            = 1;
+    public static final int UNOBTAINABLE_NUMBER                              = 1;
+    /** The user cannot be reached because the network through which the call has been
+     *  routed does not serve the destination desired
+     */
+    public static final int NO_ROUTE_TO_DESTINATION                          = 3;
+    /** The channel most recently identified is not acceptable to the sending entity for
+     *  use in this call
+     */
+    public static final int CHANNEL_UNACCEPTABLE                             = 6;
+    /** The MS has tried to access a service that the MS's network operator or service
+     *  provider is not prepared to allow
+     */
+    public static final int OPERATOR_DETERMINED_BARRING                      = 8;
     /** One of the users involved in the call has requested that the call is cleared */
-    public static final int NORMAL                         = 16;
+    public static final int NORMAL                                           = 16;
     /** The called user is unable to accept another call */
-    public static final int BUSY                           = 17;
+    public static final int BUSY                                             = 17;
+    /** The user does not respond to a call establishment message with either an alerting
+     *  or connect indication within the prescribed period of time allocated
+     */
+    public static final int NO_USER_RESPONDING                               = 18;
+    /** The user has provided an alerting indication but has not provided a connect
+     *  indication within a prescribed period of time
+     */
+    public static final int NO_ANSWER_FROM_USER                              = 19;
+    /** The equipment sending this cause does not wish to accept this call */
+    public static final int CALL_REJECTED                                    = 21;
     /** The called number is no longer assigned */
-    public static final int NUMBER_CHANGED                 = 22;
+    public static final int NUMBER_CHANGED                                   = 22;
+    /** This cause is returned to the network when a mobile station clears an active
+     *  call which is being pre-empted by another call with higher precedence
+     */
+    public static final int PREEMPTION                                       = 25;
+    /** The destination indicated by the mobile station cannot be reached because
+     *  the interface to the destination is not functioning correctly
+     */
+    public static final int DESTINATION_OUT_OF_ORDER                         = 27;
+    /** The called party number is not a valid format or is not complete */
+    public static final int INVALID_NUMBER_FORMAT                            = 28;
+    /** The facility requested by user can not be provided by the network */
+    public static final int FACILITY_REJECTED                                = 29;
     /** Provided in response to a STATUS ENQUIRY message */
-    public static final int STATUS_ENQUIRY                 = 30;
+    public static final int STATUS_ENQUIRY                                   = 30;
     /** Reports a normal disconnect only when no other normal cause applies */
-    public static final int NORMAL_UNSPECIFIED             = 31;
+    public static final int NORMAL_UNSPECIFIED                               = 31;
     /** There is no channel presently available to handle the call */
-    public static final int NO_CIRCUIT_AVAIL               = 34;
+    public static final int NO_CIRCUIT_AVAIL                                 = 34;
+    /** The network is not functioning correctly and that the condition is likely
+     *  to last a relatively long period of time
+     */
+    public static final int NETWORK_OUT_OF_ORDER                             = 38;
     /**
      * The network is not functioning correctly and the condition is not likely to last
      * a long period of time
      */
-    public static final int TEMPORARY_FAILURE              = 41;
+    public static final int TEMPORARY_FAILURE                                = 41;
     /** The switching equipment is experiencing a period of high traffic */
-    public static final int SWITCHING_CONGESTION           = 42;
+    public static final int SWITCHING_CONGESTION                             = 42;
+    /** The network could not deliver access information to the remote user as requested */
+    public static final int ACCESS_INFORMATION_DISCARDED                     = 43;
     /** The channel cannot be provided */
-    public static final int CHANNEL_NOT_AVAIL              = 44;
+    public static final int CHANNEL_NOT_AVAIL                                = 44;
+    /** This cause is used to report a resource unavailable event only when no other
+     *  cause in the resource unavailable class applies
+     */
+    public static final int RESOURCES_UNAVAILABLE_OR_UNSPECIFIED             = 44;
     /** The requested quality of service (ITU-T X.213) cannot be provided */
-    public static final int QOS_NOT_AVAIL                  = 49;
+    public static final int QOS_NOT_AVAIL                                    = 49;
+    /** The facility could not be provided by the network because the user has no
+     *  complete subscription
+     */
+    public static final int REQUESTED_FACILITY_NOT_SUBSCRIBED                = 50;
+    /** Incoming calls are not allowed within this CUG */
+    public static final int INCOMING_CALLS_BARRED_WITHIN_CUG                 = 55;
+    /** The mobile station is not authorized to use bearer capability requested */
+    public static final int BEARER_CAPABILITY_NOT_AUTHORIZED                 = 57;
     /** The requested bearer capability is not available at this time */
-    public static final int BEARER_NOT_AVAIL               = 58;
+    public static final int BEARER_NOT_AVAIL                                 = 58;
+    /** The service option is not availble at this time */
+    public static final int SERVICE_OPTION_NOT_AVAILABLE                     = 63;
+    /** The equipment sending this cause does not support the bearer capability requested */
+    public static final int BEARER_SERVICE_NOT_IMPLEMENTED                   = 65;
     /** The call clearing is due to ACM being greater than or equal to ACMmax */
-    public static final int ACM_LIMIT_EXCEEDED             = 68;
+    public static final int ACM_LIMIT_EXCEEDED                               = 68;
+    /** The equipment sending this cause does not support the requested facility */
+    public static final int REQUESTED_FACILITY_NOT_IMPLEMENTED               = 69;
+    /** The equipment sending this cause only supports the restricted version of
+     *  the requested bearer capability
+     */
+    public static final int ONLY_DIGITAL_INFORMATION_BEARER_AVAILABLE        = 70;
+    /** The service requested is not implemented at network */
+    public static final int SERVICE_OR_OPTION_NOT_IMPLEMENTED                = 79;
+    /** The equipment sending this cause has received a message with a transaction identifier
+     *  which is not currently in use on the MS-network interface
+     */
+    public static final int INVALID_TRANSACTION_IDENTIFIER                   = 81;
+    /** The called user for the incoming CUG call is not a member of the specified CUG */
+    public static final int USER_NOT_MEMBER_OF_CUG                           = 87;
+    /** The equipment sending this cause has received a request which can't be accomodated */
+    public static final int INCOMPATIBLE_DESTINATION                         = 88;
+    /** This cause is used to report receipt of a message with semantically incorrect contents */
+    public static final int SEMANTICALLY_INCORRECT_MESSAGE                   = 95;
+    /** The equipment sending this cause has received a message with a non-semantical
+     *  mandatory IE error
+     */
+    public static final int INVALID_MANDATORY_INFORMATION                    = 96;
+    /** This is sent in response to a message which is not defined, or defined but not
+     *  implemented by the equipment sending this cause
+     */
+    public static final int MESSAGE_TYPE_NON_IMPLEMENTED                     = 97;
+    /** The equipment sending this cause has received a message not compatible with the
+     *  protocol state
+     */
+    public static final int MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE  = 98;
+    /** The equipment sending this cause has received a message which includes information
+     *  elements not recognized because its identifier is not defined or it is defined but not
+     *  implemented by the equipment sending the cause
+     */
+    public static final int INFORMATION_ELEMENT_NON_EXISTENT                 = 99;
+    /** The equipment sending this cause has received a message with conditional IE errors */
+    public static final int CONDITIONAL_IE_ERROR                             = 100;
+    /** The message has been received which is incompatible with the protocol state */
+    public static final int MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE       = 101;
+    /** The  procedure has been initiated by the expiry of a timer in association with
+     *  3GPP TS 24.008 error handling procedures
+     */
+    public static final int RECOVERY_ON_TIMER_EXPIRED                        = 102;
+    /** This protocol error event is reported only when no other cause in the protocol
+     *  error class applies
+     */
+    public static final int PROTOCOL_ERROR_UNSPECIFIED                       = 111;
+    /** interworking with a network which does not provide causes for actions it takes
+     *  thus, the precise cause for a message which is being sent cannot be ascertained
+     */
+    public static final int INTERWORKING_UNSPECIFIED                         = 127;
     /** The call is restricted */
-    public static final int CALL_BARRED                    = 240;
+    public static final int CALL_BARRED                                      = 240;
     /** The call is blocked by the Fixed Dialing Number list */
-    public static final int FDN_BLOCKED                    = 241;
+    public static final int FDN_BLOCKED                                      = 241;
     /** The given IMSI is not known at the VLR */
     /** TS 24.008 cause 4 */
-    public static final int IMSI_UNKNOWN_IN_VLR            = 242;
+    public static final int IMSI_UNKNOWN_IN_VLR                              = 242;
     /**
      * The network does not accept emergency call establishment using an IMEI or not accept attach
      * procedure for emergency services using an IMEI
      */
-    public static final int IMEI_NOT_ACCEPTED              = 243;
+    public static final int IMEI_NOT_ACCEPTED                                = 243;
+    /** The call cannot be established because RADIO is OFF */
+    public static final int RADIO_OFF                                        = 247;
+    /** The call cannot be established because of no cell coverage */
+    public static final int OUT_OF_SRV                                       = 248;
+    /** The call cannot be established because of no valid SIM */
+    public static final int NO_VALID_SIM                                     = 249;
+    /** The call is dropped or failed internally by modem */
+    public static final int RADIO_INTERNAL_ERROR                             = 250;
+    /** Call failed because of UE timer expired while waiting for a response from network */
+    public static final int NETWORK_RESP_TIMEOUT                             = 251;
+    /** Call failed because of a network reject */
+    public static final int NETWORK_REJECT                                   = 252;
+    /** Call failed because of radio access failure. ex. RACH failure */
+    public static final int RADIO_ACCESS_FAILURE                             = 253;
+    /** Call failed/dropped because of a RLF */
+    public static final int RADIO_LINK_FAILURE                               = 254;
+    /** Call failed/dropped because of radio link lost */
+    public static final int RADIO_LINK_LOST                                  = 255;
+    /** Call failed because of a radio uplink issue */
+    public static final int RADIO_UPLINK_FAILURE                             = 256;
+    /** Call failed because of a RRC connection setup failure */
+    public static final int RADIO_SETUP_FAILURE                              = 257;
+    /** Call failed/dropped because of RRC connection release from NW */
+    public static final int RADIO_RELEASE_NORMAL                             = 258;
+    /** Call failed/dropped because of RRC abnormally released by modem/network */
+    public static final int RADIO_RELEASE_ABNORMAL                           = 259;
+    /** Call setup failed because of access class barring */
+    public static final int ACCESS_CLASS_BLOCKED                             = 260;
+    /** Call failed/dropped because of a network detach */
+    public static final int NETWORK_DETACH                                   = 261;
+
     /** MS is locked until next power cycle */
-    public static final int CDMA_LOCKED_UNTIL_POWER_CYCLE  = 1000;
+    public static final int CDMA_LOCKED_UNTIL_POWER_CYCLE                    = 1000;
     /** Drop call*/
-    public static final int CDMA_DROP                      = 1001;
+    public static final int CDMA_DROP                                        = 1001;
     /** INTERCEPT order received, MS state idle entered */
-    public static final int CDMA_INTERCEPT                 = 1002;
+    public static final int CDMA_INTERCEPT                                   = 1002;
     /** MS has been redirected, call is cancelled */
-    public static final int CDMA_REORDER                   = 1003;
+    public static final int CDMA_REORDER                                     = 1003;
     /** Service option rejection */
-    public static final int CDMA_SO_REJECT                 = 1004;
+    public static final int CDMA_SO_REJECT                                   = 1004;
     /** Requested service is rejected, retry delay is set */
-    public static final int CDMA_RETRY_ORDER               = 1005;
+    public static final int CDMA_RETRY_ORDER                                 = 1005;
     /** Unable to obtain access to the CDMA system */
-    public static final int CDMA_ACCESS_FAILURE            = 1006;
+    public static final int CDMA_ACCESS_FAILURE                              = 1006;
     /** Not a preempted call */
-    public static final int CDMA_PREEMPTED                 = 1007;
+    public static final int CDMA_PREEMPTED                                   = 1007;
     /** Not an emergency call */
-    public static final int CDMA_NOT_EMERGENCY             = 1008;
+    public static final int CDMA_NOT_EMERGENCY                               = 1008;
     /** Access Blocked by CDMA network */
-    public static final int CDMA_ACCESS_BLOCKED            = 1009;
+    public static final int CDMA_ACCESS_BLOCKED                              = 1009;
+
+    /** Mapped from ImsReasonInfo */
+    /* The passed argument is an invalid */
+    public static final int LOCAL_ILLEGAL_ARGUMENT                           = 1200;
+    // The operation is invoked in invalid call state
+    public static final int LOCAL_ILLEGAL_STATE                              = 1201;
+    // IMS service internal error
+    public static final int LOCAL_INTERNAL_ERROR                             = 1202;
+    // IMS service goes down (service connection is lost)
+    public static final int LOCAL_IMS_SERVICE_DOWN                           = 1203;
+    // No pending incoming call exists
+    public static final int LOCAL_NO_PENDING_CALL                            = 1204;
+    // Service unavailable; by power off
+    public static final int LOCAL_POWER_OFF                                  = 1205;
+    // Service unavailable; by low battery
+    public static final int LOCAL_LOW_BATTERY                                = 1206;
+    // Service unavailable; by out of service (data service state)
+    public static final int LOCAL_NETWORK_NO_SERVICE                         = 1207;
+    /* Service unavailable; by no LTE coverage
+     * (VoLTE is not supported even though IMS is registered)
+     */
+    public static final int LOCAL_NETWORK_NO_LTE_COVERAGE                    = 1208;
+    /** Service unavailable; by located in roaming area */
+    public static final int LOCAL_NETWORK_ROAMING                            = 1209;
+    /** Service unavailable; by IP changed */
+    public static final int LOCAL_NETWORK_IP_CHANGED                         = 1210;
+    /** Service unavailable; other */
+    public static final int LOCAL_SERVICE_UNAVAILABLE                        = 1211;
+    /* Service unavailable; IMS connection is lost (IMS is not registered) */
+    public static final int LOCAL_NOT_REGISTERED                             = 1212;
+    /** Max call exceeded */
+    public static final int LOCAL_MAX_CALL_EXCEEDED                          = 1213;
+    /** Call decline */
+    public static final int LOCAL_CALL_DECLINE                               = 1214;
+    /** SRVCC is in progress */
+    public static final int LOCAL_CALL_VCC_ON_PROGRESSING                    = 1215;
+    /** Resource reservation is failed (QoS precondition) */
+    public static final int LOCAL_CALL_RESOURCE_RESERVATION_FAILED           = 1216;
+    /** Retry CS call; VoLTE service can't be provided by the network or remote end
+     *  Resolve the extra code(EXTRA_CODE_CALL_RETRY_*) if the below code is set
+     */
+    public static final int LOCAL_CALL_CS_RETRY_REQUIRED                     = 1217;
+    /** Retry VoLTE call; VoLTE service can't be provided by the network temporarily */
+    public static final int LOCAL_CALL_VOLTE_RETRY_REQUIRED                  = 1218;
+    /** IMS call is already terminated (in TERMINATED state) */
+    public static final int LOCAL_CALL_TERMINATED                            = 1219;
+    /** Handover not feasible */
+    public static final int LOCAL_HO_NOT_FEASIBLE                            = 1220;
+
+    /** 1xx waiting timer is expired after sending INVITE request (MO only) */
+    public static final int TIMEOUT_1XX_WAITING                              = 1221;
+    /** User no answer during call setup operation (MO/MT)
+     *  MO : 200 OK to INVITE request is not received,
+     *  MT : No action from user after alerting the call
+     */
+    public static final int TIMEOUT_NO_ANSWER                                = 1222;
+    /** User no answer during call update operation (MO/MT)
+     *  MO : 200 OK to re-INVITE request is not received,
+     *  MT : No action from user after alerting the call
+     */
+    public static final int TIMEOUT_NO_ANSWER_CALL_UPDATE                    = 1223;
+
+    /**
+     * STATUSCODE (SIP response code) (IMS -> Telephony)
+     */
+    /** SIP request is redirected */
+    public static final int SIP_REDIRECTED                                   = 1300;
+    /** 4xx responses */
+    /** 400 : Bad Request */
+    public static final int SIP_BAD_REQUEST                                  = 1310;
+    /** 403 : Forbidden */
+    public static final int SIP_FORBIDDEN                                    = 1311;
+    /** 404 : Not Found */
+    public static final int SIP_NOT_FOUND                                    = 1312;
+    /** 415 : Unsupported Media Type
+     *  416 : Unsupported URI Scheme
+     *  420 : Bad Extension
+     */
+    public static final int SIP_NOT_SUPPORTED                                = 1313;
+    /** 408 : Request Timeout */
+    public static final int SIP_REQUEST_TIMEOUT                              = 1314;
+    /** 480 : Temporarily Unavailable */
+    public static final int SIP_TEMPRARILY_UNAVAILABLE                       = 1315;
+    /** 484 : Address Incomplete */
+    public static final int SIP_BAD_ADDRESS                                  = 1316;
+    /** 486 : Busy Here
+     *  600 : Busy Everywhere
+     */
+    public static final int SIP_BUSY                                         = 1317;
+    /** 487 : Request Terminated */
+    public static final int SIP_REQUEST_CANCELLED                            = 1318;
+    /** 406 : Not Acceptable
+     *  488 : Not Acceptable Here
+     *  606 : Not Acceptable
+     */
+    public static final int SIP_NOT_ACCEPTABLE                               = 1319;
+    /** 410 : Gone
+     *  604 : Does Not Exist Anywhere
+     */
+    public static final int SIP_NOT_REACHABLE                                = 1320;
+    /** Others */
+    public static final int SIP_CLIENT_ERROR                                 = 1321;
+    /** 5xx responses
+     *  501 : Server Internal Error
+     */
+    public static final int SIP_SERVER_INTERNAL_ERROR                        = 1330;
+    /** 503 : Service Unavailable */
+    public static final int SIP_SERVICE_UNAVAILABLE                          = 1331;
+    /** 504 : Server Time-out */
+    public static final int SIP_SERVER_TIMEOUT                               = 1332;
+    /** Others */
+    public static final int SIP_SERVER_ERROR                                 = 1333;
+    /** 6xx responses
+     *  603 : Decline
+     */
+    public static final int SIP_USER_REJECTED                                = 1340;
+    /** Others */
+    public static final int SIP_GLOBAL_ERROR                                 = 1341;
+    /** Emergency failure */
+    public static final int EMERGENCY_TEMP_FAILURE                           = 1342;
+    public static final int EMERGENCY_PERM_FAILURE                           = 1343;
+    /** Media resource initialization failed */
+    public static final int MEDIA_INIT_FAILED                                = 1400;
+    /** RTP timeout (no audio / video traffic in the session) */
+    public static final int MEDIA_NO_DATA                                    = 1401;
+    /** Media is not supported; so dropped the call */
+    public static final int MEDIA_NOT_ACCEPTABLE                             = 1402;
+    /** Unknown media related errors */
+    public static final int MEDIA_UNSPECIFIED                                = 1403;
+    /** User triggers the call end */
+    public static final int USER_TERMINATED                                  = 1500;
+    /** No action while an incoming call is ringing */
+    public static final int USER_NOANSWER                                    = 1501;
+    /** User ignores an incoming call */
+    public static final int USER_IGNORE                                      = 1502;
+    /** User declines an incoming call */
+    public static final int USER_DECLINE                                     = 1503;
+    /** Device declines/ends a call due to low battery */
+    public static final int LOW_BATTERY                                      = 1504;
+    /** Device declines call due to blacklisted call ID */
+    public static final int BLACKLISTED_CALL_ID                              = 1505;
+    /** The call is terminated by the network or remote user */
+    public static final int USER_TERMINATED_BY_REMOTE                        = 1510;
+
+    /**
+     * UT
+     */
+    public static final int UT_NOT_SUPPORTED                                 = 1800;
+    public static final int UT_SERVICE_UNAVAILABLE                           = 1801;
+    public static final int UT_OPERATION_NOT_ALLOWED                         = 1802;
+    public static final int UT_NETWORK_ERROR                                 = 1803;
+    public static final int UT_CB_PASSWORD_MISMATCH                          = 1804;
+
+    /**
+     * ECBM
+     */
+    public static final int ECBM_NOT_SUPPORTED                               = 1900;
+
+    /**
+     * Fail code used to indicate that Multi-endpoint is not supported by the Ims framework.
+     */
+    public static final int MULTIENDPOINT_NOT_SUPPORTED                      = 1901;
+
+    /**
+     * CALL DROP error codes (Call could drop because of many reasons like Network not available,
+     *  handover, failed, etc)
+     */
+
+    /**
+     * CALL DROP error code for the case when a device is ePDG capable and when the user is on an
+     * active wifi call and at the edge of coverage and there is no qualified LTE network available
+     * to handover the call to. We get a handover NOT_TRIGERRED message from the modem. This error
+     * code is received as part of the handover message.
+     */
+    public static final int CALL_DROP_IWLAN_TO_LTE_UNAVAILABLE               = 2000;
+
+    /**
+     * MT call has ended due to a release from the network
+     * because the call was answered elsewhere
+     */
+    public static final int ANSWERED_ELSEWHERE                               = 2100;
+
+    /**
+     * For MultiEndpoint - Call Pull request has failed
+     */
+    public static final int CALL_PULL_OUT_OF_SYNC                            = 2101;
+
+    /**
+     * For MultiEndpoint - Call has been pulled from primary to secondary
+     */
+    public static final int CALL_PULLED                                      = 2102;
+
+    /**
+     * Supplementary services (HOLD/RESUME) failure error codes.
+     * Values for Supplemetary services failure - Failed, Cancelled and Re-Invite collision.
+     */
+    public static final int SUPP_SVC_FAILED                                  = 2300;
+    public static final int SUPP_SVC_CANCELLED                               = 2301;
+    public static final int SUPP_SVC_REINVITE_COLLISION                      = 2302;
+
+    /**
+     * DPD Procedure received no response or send failed
+     */
+    public static final int IWLAN_DPD_FAILURE                                = 2400;
+
+    /**
+     * Establishment of the ePDG Tunnel Failed
+     */
+    public static final int EPDG_TUNNEL_ESTABLISH_FAILURE                    = 2500;
+
+    /**
+     * Re-keying of the ePDG Tunnel Failed; may not always result in teardown
+     */
+    public static final int EPDG_TUNNEL_REKEY_FAILURE                        = 2501;
+
+    /**
+     * Connection to the packet gateway is lost
+     */
+    public static final int EPDG_TUNNEL_LOST_CONNECTION                      = 2502;
+
+    /**
+     * The maximum number of calls allowed has been reached.  Used in a multi-endpoint scenario
+     * where the number of calls across all connected devices has reached the maximum.
+     */
+    public static final int MAXIMUM_NUMBER_OF_CALLS_REACHED                  = 2503;
+
+    /**
+     * Similar to {@link #CODE_LOCAL_CALL_DECLINE}, except indicates that a remote device has
+     * declined the call.  Used in a multi-endpoint scenario where a remote device declined an
+     * incoming call.
+     */
+    public static final int REMOTE_CALL_DECLINE                              = 2504;
+
+    /**
+     * Indicates the call was disconnected due to the user reaching their data limit.
+     */
+    public static final int DATA_LIMIT_REACHED                               = 2505;
+
+    /**
+     * Indicates the call was disconnected due to the user disabling cellular data.
+     */
+    public static final int DATA_DISABLED                                    = 2506;
+
+    /**
+     * Indicates a call was disconnected due to loss of wifi signal.
+     */
+    public static final int WIFI_LOST                                        = 2507;
+
+
+    /* OEM specific error codes. To be used by OEMs when they don't want to
+       reveal error code which would be replaced by ERROR_UNSPECIFIED */
+    public static final int OEM_CAUSE_1                                      = 0xf001;
+    public static final int OEM_CAUSE_2                                      = 0xf002;
+    public static final int OEM_CAUSE_3                                      = 0xf003;
+    public static final int OEM_CAUSE_4                                      = 0xf004;
+    public static final int OEM_CAUSE_5                                      = 0xf005;
+    public static final int OEM_CAUSE_6                                      = 0xf006;
+    public static final int OEM_CAUSE_7                                      = 0xf007;
+    public static final int OEM_CAUSE_8                                      = 0xf008;
+    public static final int OEM_CAUSE_9                                      = 0xf009;
+    public static final int OEM_CAUSE_10                                     = 0xf00a;
+    public static final int OEM_CAUSE_11                                     = 0xf00b;
+    public static final int OEM_CAUSE_12                                     = 0xf00c;
+    public static final int OEM_CAUSE_13                                     = 0xf00d;
+    public static final int OEM_CAUSE_14                                     = 0xf00e;
+    public static final int OEM_CAUSE_15                                     = 0xf00f;
+
     /** Disconnected due to unspecified reasons */
-    public static final int ERROR_UNSPECIFIED              = 0xffff;
+    public static final int ERROR_UNSPECIFIED                                = 0xffff;
 
     /** Private constructor to avoid class instantiation. */
     private PreciseDisconnectCause() {
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 7a83979..5fb83ab 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -243,6 +243,10 @@
 
     private boolean mIsUsingCarrierAggregation;
 
+    /* EARFCN stands for E-UTRA Absolute Radio Frequency Channel Number,
+     * Reference: 3GPP TS 36.104 5.4.3 */
+    private int mLteEarfcnRsrpBoost = 0;
+
     /**
      * get String description of roaming type
      * @hide
@@ -322,6 +326,7 @@
         mIsEmergencyOnly = s.mIsEmergencyOnly;
         mIsDataRoamingFromRegistration = s.mIsDataRoamingFromRegistration;
         mIsUsingCarrierAggregation = s.mIsUsingCarrierAggregation;
+        mLteEarfcnRsrpBoost = s.mLteEarfcnRsrpBoost;
     }
 
     /**
@@ -351,6 +356,7 @@
         mIsEmergencyOnly = in.readInt() != 0;
         mIsDataRoamingFromRegistration = in.readInt() != 0;
         mIsUsingCarrierAggregation = in.readInt() != 0;
+        mLteEarfcnRsrpBoost = in.readInt();
     }
 
     public void writeToParcel(Parcel out, int flags) {
@@ -377,6 +383,7 @@
         out.writeInt(mIsEmergencyOnly ? 1 : 0);
         out.writeInt(mIsDataRoamingFromRegistration ? 1 : 0);
         out.writeInt(mIsUsingCarrierAggregation ? 1 : 0);
+        out.writeInt(mLteEarfcnRsrpBoost);
     }
 
     public int describeContents() {
@@ -814,7 +821,8 @@
                 + " DefRoamInd=" + mCdmaDefaultRoamingIndicator
                 + " EmergOnly=" + mIsEmergencyOnly
                 + " IsDataRoamingFromRegistration=" + mIsDataRoamingFromRegistration
-                + " IsUsingCarrierAggregation=" + mIsUsingCarrierAggregation);
+                + " IsUsingCarrierAggregation=" + mIsUsingCarrierAggregation
+                + " mLteEarfcnRsrpBoost=" + mLteEarfcnRsrpBoost);
     }
 
     private void setNullState(int state) {
@@ -842,6 +850,7 @@
         mIsEmergencyOnly = false;
         mIsDataRoamingFromRegistration = false;
         mIsUsingCarrierAggregation = false;
+        mLteEarfcnRsrpBoost = 0;
     }
 
     public void setStateOutOfService() {
@@ -1016,6 +1025,7 @@
         mIsEmergencyOnly = m.getBoolean("emergencyOnly");
         mIsDataRoamingFromRegistration = m.getBoolean("isDataRoamingFromRegistration");
         mIsUsingCarrierAggregation = m.getBoolean("isUsingCarrierAggregation");
+        mLteEarfcnRsrpBoost = m.getInt("LteEarfcnRsrpBoost");
     }
 
     /**
@@ -1046,6 +1056,7 @@
         m.putBoolean("emergencyOnly", mIsEmergencyOnly);
         m.putBoolean("isDataRoamingFromRegistration", mIsDataRoamingFromRegistration);
         m.putBoolean("isUsingCarrierAggregation", mIsUsingCarrierAggregation);
+        m.putInt("LteEarfcnRsrpBoost", mLteEarfcnRsrpBoost);
     }
 
     /** @hide */
@@ -1081,6 +1092,16 @@
     }
 
     /** @hide */
+    public int getLteEarfcnRsrpBoost() {
+        return mLteEarfcnRsrpBoost;
+    }
+
+    /** @hide */
+    public void setLteEarfcnRsrpBoost(int LteEarfcnRsrpBoost) {
+        mLteEarfcnRsrpBoost = LteEarfcnRsrpBoost;
+    }
+
+    /** @hide */
     public void setCssIndicator(int css) {
         this.mCssIndicator = (css != 0);
     }
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index c484fd3..9e02399 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -64,6 +64,8 @@
     private int mLteRsrq;
     private int mLteRssnr;
     private int mLteCqi;
+    private int mLteRsrpBoost; // offset to be reduced from the rsrp threshold while calculating
+                                // signal strength level
     private int mTdScdmaRscp;
 
     private boolean isGsm; // This value is set by the ServiceStateTracker onSignalStrengthResult
@@ -104,6 +106,7 @@
         mLteRsrq = INVALID;
         mLteRssnr = INVALID;
         mLteCqi = INVALID;
+        mLteRsrpBoost = 0;
         mTdScdmaRscp = INVALID;
         isGsm = true;
     }
@@ -129,6 +132,7 @@
         mLteRsrq = INVALID;
         mLteRssnr = INVALID;
         mLteCqi = INVALID;
+        mLteRsrpBoost = 0;
         mTdScdmaRscp = INVALID;
         isGsm = gsmFlag;
     }
@@ -142,10 +146,26 @@
             int cdmaDbm, int cdmaEcio,
             int evdoDbm, int evdoEcio, int evdoSnr,
             int lteSignalStrength, int lteRsrp, int lteRsrq, int lteRssnr, int lteCqi,
+            int lteRsrpBoost, int tdScdmaRscp, boolean gsmFlag) {
+        initialize(gsmSignalStrength, gsmBitErrorRate, cdmaDbm, cdmaEcio,
+                evdoDbm, evdoEcio, evdoSnr, lteSignalStrength, lteRsrp,
+                lteRsrq, lteRssnr, lteCqi, lteRsrpBoost, gsmFlag);
+        mTdScdmaRscp = tdScdmaRscp;
+    }
+
+    /**
+     * Constructor
+     *
+     * @hide
+     */
+    public SignalStrength(int gsmSignalStrength, int gsmBitErrorRate,
+            int cdmaDbm, int cdmaEcio,
+            int evdoDbm, int evdoEcio, int evdoSnr,
+            int lteSignalStrength, int lteRsrp, int lteRsrq, int lteRssnr, int lteCqi,
             int tdScdmaRscp, boolean gsmFlag) {
         initialize(gsmSignalStrength, gsmBitErrorRate, cdmaDbm, cdmaEcio,
                 evdoDbm, evdoEcio, evdoSnr, lteSignalStrength, lteRsrp,
-                lteRsrq, lteRssnr, lteCqi, gsmFlag);
+                lteRsrq, lteRssnr, lteCqi, 0, gsmFlag);
         mTdScdmaRscp = tdScdmaRscp;
     }
 
@@ -161,7 +181,7 @@
             boolean gsmFlag) {
         initialize(gsmSignalStrength, gsmBitErrorRate, cdmaDbm, cdmaEcio,
                 evdoDbm, evdoEcio, evdoSnr, lteSignalStrength, lteRsrp,
-                lteRsrq, lteRssnr, lteCqi, gsmFlag);
+                lteRsrq, lteRssnr, lteCqi, 0, gsmFlag);
     }
 
     /**
@@ -175,7 +195,7 @@
             boolean gsmFlag) {
         initialize(gsmSignalStrength, gsmBitErrorRate, cdmaDbm, cdmaEcio,
                 evdoDbm, evdoEcio, evdoSnr, 99, INVALID,
-                INVALID, INVALID, INVALID, gsmFlag);
+                INVALID, INVALID, INVALID, 0, gsmFlag);
     }
 
     /**
@@ -209,7 +229,7 @@
             boolean gsm) {
         initialize(gsmSignalStrength, gsmBitErrorRate, cdmaDbm, cdmaEcio,
                 evdoDbm, evdoEcio, evdoSnr, 99, INVALID,
-                INVALID, INVALID, INVALID, gsm);
+                INVALID, INVALID, INVALID, 0, gsm);
     }
 
     /**
@@ -227,6 +247,7 @@
      * @param lteRsrq
      * @param lteRssnr
      * @param lteCqi
+     * @param lteRsrpBoost
      * @param gsm
      *
      * @hide
@@ -235,7 +256,7 @@
             int cdmaDbm, int cdmaEcio,
             int evdoDbm, int evdoEcio, int evdoSnr,
             int lteSignalStrength, int lteRsrp, int lteRsrq, int lteRssnr, int lteCqi,
-            boolean gsm) {
+            int lteRsrpBoost, boolean gsm) {
         mGsmSignalStrength = gsmSignalStrength;
         mGsmBitErrorRate = gsmBitErrorRate;
         mCdmaDbm = cdmaDbm;
@@ -248,6 +269,7 @@
         mLteRsrq = lteRsrq;
         mLteRssnr = lteRssnr;
         mLteCqi = lteCqi;
+        mLteRsrpBoost = lteRsrpBoost;
         mTdScdmaRscp = INVALID;
         isGsm = gsm;
         if (DBG) log("initialize: " + toString());
@@ -269,6 +291,7 @@
         mLteRsrq = s.mLteRsrq;
         mLteRssnr = s.mLteRssnr;
         mLteCqi = s.mLteCqi;
+        mLteRsrpBoost = s.mLteRsrpBoost;
         mTdScdmaRscp = s.mTdScdmaRscp;
         isGsm = s.isGsm;
     }
@@ -293,6 +316,7 @@
         mLteRsrq = in.readInt();
         mLteRssnr = in.readInt();
         mLteCqi = in.readInt();
+        mLteRsrpBoost = in.readInt();
         mTdScdmaRscp = in.readInt();
         isGsm = (in.readInt() != 0);
     }
@@ -340,6 +364,7 @@
         out.writeInt(mLteRsrq);
         out.writeInt(mLteRssnr);
         out.writeInt(mLteCqi);
+        out.writeInt(mLteRsrpBoost);
         out.writeInt(mTdScdmaRscp);
         out.writeInt(isGsm ? 1 : 0);
     }
@@ -416,6 +441,18 @@
     }
 
     /**
+     * @param lteRsrpBoost - signal strength offset
+     *
+     * Used by phone to set the lte signal strength offset which will be
+     * reduced from rsrp threshold while calculating signal strength level
+     *
+     * @hide
+     */
+    public void setLteRsrpBoost(int lteRsrpBoost) {
+        mLteRsrpBoost = lteRsrpBoost;
+    }
+
+    /**
      * Get the GSM Signal Strength, valid values are (0-31, 99) as defined in TS
      * 27.007 8.5
      */
@@ -490,6 +527,11 @@
         return mLteCqi;
     }
 
+    /** @hide */
+    public int getLteRsrpBoost() {
+        return mLteRsrpBoost;
+    }
+
     /**
      * Retrieve an abstract level value for the overall signal strength.
      *
@@ -793,12 +835,19 @@
             Log.wtf(LOG_TAG, "getLteLevel - config_lteDbmThresholds has invalid num of elements."
                     + " Cannot evaluate RSRP signal.");
         } else {
-            if (mLteRsrp > threshRsrp[5]) rsrpIconLevel = -1;
-            else if (mLteRsrp >= threshRsrp[4]) rsrpIconLevel = SIGNAL_STRENGTH_GREAT;
-            else if (mLteRsrp >= threshRsrp[3]) rsrpIconLevel = SIGNAL_STRENGTH_GOOD;
-            else if (mLteRsrp >= threshRsrp[2]) rsrpIconLevel = SIGNAL_STRENGTH_MODERATE;
-            else if (mLteRsrp >= threshRsrp[1]) rsrpIconLevel = SIGNAL_STRENGTH_POOR;
-            else if (mLteRsrp >= threshRsrp[0]) rsrpIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+            if (mLteRsrp > threshRsrp[5]) {
+                rsrpIconLevel = -1;
+            } else if (mLteRsrp >= (threshRsrp[4] - mLteRsrpBoost)) {
+                rsrpIconLevel = SIGNAL_STRENGTH_GREAT;
+            } else if (mLteRsrp >= (threshRsrp[3] - mLteRsrpBoost)) {
+                rsrpIconLevel = SIGNAL_STRENGTH_GOOD;
+            } else if (mLteRsrp >= (threshRsrp[2] - mLteRsrpBoost)) {
+                rsrpIconLevel = SIGNAL_STRENGTH_MODERATE;
+            } else if (mLteRsrp >= (threshRsrp[1] - mLteRsrpBoost)) {
+                rsrpIconLevel = SIGNAL_STRENGTH_POOR;
+            } else if (mLteRsrp >= threshRsrp[0]) {
+                rsrpIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+            }
         }
 
         /*
@@ -816,7 +865,8 @@
             snrIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
 
         if (DBG) log("getLTELevel - rsrp:" + mLteRsrp + " snr:" + mLteRssnr + " rsrpIconLevel:"
-                + rsrpIconLevel + " snrIconLevel:" + snrIconLevel);
+                + rsrpIconLevel + " snrIconLevel:" + snrIconLevel
+                + " lteRsrpBoost:" + mLteRsrpBoost);
 
         /* Choose a measurement type to use for notification */
         if (snrIconLevel != -1 && rsrpIconLevel != -1) {
@@ -939,7 +989,7 @@
                 + (mEvdoDbm * primeNum) + (mEvdoEcio * primeNum) + (mEvdoSnr * primeNum)
                 + (mLteSignalStrength * primeNum) + (mLteRsrp * primeNum)
                 + (mLteRsrq * primeNum) + (mLteRssnr * primeNum) + (mLteCqi * primeNum)
-                + (mTdScdmaRscp * primeNum) + (isGsm ? 1 : 0));
+                + (mLteRsrpBoost * primeNum) + (mTdScdmaRscp * primeNum) + (isGsm ? 1 : 0));
     }
 
     /**
@@ -971,6 +1021,7 @@
                 && mLteRsrq == s.mLteRsrq
                 && mLteRssnr == s.mLteRssnr
                 && mLteCqi == s.mLteCqi
+                && mLteRsrpBoost == s.mLteRsrpBoost
                 && mTdScdmaRscp == s.mTdScdmaRscp
                 && isGsm == s.isGsm);
     }
@@ -993,6 +1044,7 @@
                 + " " + mLteRsrq
                 + " " + mLteRssnr
                 + " " + mLteCqi
+                + " " + mLteRsrpBoost
                 + " " + mTdScdmaRscp
                 + " " + (isGsm ? "gsm|lte" : "cdma"));
     }
@@ -1016,6 +1068,7 @@
         mLteRsrq = m.getInt("LteRsrq");
         mLteRssnr = m.getInt("LteRssnr");
         mLteCqi = m.getInt("LteCqi");
+        mLteRsrpBoost = m.getInt("lteRsrpBoost");
         mTdScdmaRscp = m.getInt("TdScdma");
         isGsm = m.getBoolean("isGsm");
     }
@@ -1039,6 +1092,7 @@
         m.putInt("LteRsrq", mLteRsrq);
         m.putInt("LteRssnr", mLteRssnr);
         m.putInt("LteCqi", mLteCqi);
+        m.putInt("lteRsrpBoost", mLteRsrpBoost);
         m.putInt("TdScdma", mTdScdmaRscp);
         m.putBoolean("isGsm", isGsm);
     }
diff --git a/telephony/java/com/android/ims/ImsReasonInfo.java b/telephony/java/com/android/ims/ImsReasonInfo.java
index e4f380f..bd8492b3 100644
--- a/telephony/java/com/android/ims/ImsReasonInfo.java
+++ b/telephony/java/com/android/ims/ImsReasonInfo.java
@@ -318,6 +318,66 @@
      */
     public static final int CODE_IKEV2_AUTH_FAILURE = 1408;
 
+    /** The call cannot be established because RADIO is OFF */
+    public static final int CODE_RADIO_OFF = 1500;
+
+    /** The call cannot be established because of no valid SIM */
+    public static final int CODE_NO_VALID_SIM = 1501;
+
+    /** The failure is due internal error at modem */
+    public static final int CODE_RADIO_INTERNAL_ERROR = 1502;
+
+    /** The failure is due to UE timer expired while waiting for a response from network */
+    public static final int CODE_NETWORK_RESP_TIMEOUT = 1503;
+
+    /** The failure is due to explicit reject from network */
+    public static final int CODE_NETWORK_REJECT = 1504;
+
+    /** The failure is due to radio access failure. ex. RACH failure */
+    public static final int CODE_RADIO_ACCESS_FAILURE = 1505;
+
+    /** Call/IMS registration failed/dropped because of a RLF */
+    public static final int CODE_RADIO_LINK_FAILURE = 1506;
+
+    /** Call/IMS registration failed/dropped because of radio link lost */
+    public static final int CODE_RADIO_LINK_LOST = 1507;
+
+    /** The call Call/IMS registration failed because of a radio uplink issue */
+    public static final int CODE_RADIO_UPLINK_FAILURE = 1508;
+
+    /** Call failed because of a RRC connection setup failure */
+    public static final int CODE_RADIO_SETUP_FAILURE = 1509;
+
+    /** Call failed/dropped because of RRC connection release from NW */
+    public static final int CODE_RADIO_RELEASE_NORMAL = 1510;
+
+    /** Call failed/dropped because of RRC abnormally released by modem/network */
+    public static final int CODE_RADIO_RELEASE_ABNORMAL = 1511;
+
+    /** Call failed because of access class barring */
+    public static final int CODE_ACCESS_CLASS_BLOCKED = 1512;
+
+    /** Call/IMS registration is failed/dropped because of a network detach */
+    public static final int CODE_NETWORK_DETACH = 1513;
+
+    /* OEM specific error codes. To be used by OEMs when they don't want to
+   reveal error code which would be replaced by ERROR_UNSPECIFIED */
+    public static final int CODE_OEM_CAUSE_1 = 0xf001;
+    public static final int CODE_OEM_CAUSE_2 = 0xf002;
+    public static final int CODE_OEM_CAUSE_3 = 0xf003;
+    public static final int CODE_OEM_CAUSE_4 = 0xf004;
+    public static final int CODE_OEM_CAUSE_5 = 0xf005;
+    public static final int CODE_OEM_CAUSE_6 = 0xf006;
+    public static final int CODE_OEM_CAUSE_7 = 0xf007;
+    public static final int CODE_OEM_CAUSE_8 = 0xf008;
+    public static final int CODE_OEM_CAUSE_9 = 0xf009;
+    public static final int CODE_OEM_CAUSE_10 = 0xf00a;
+    public static final int CODE_OEM_CAUSE_11 = 0xf00b;
+    public static final int CODE_OEM_CAUSE_12 = 0xf00c;
+    public static final int CODE_OEM_CAUSE_13 = 0xf00d;
+    public static final int CODE_OEM_CAUSE_14 = 0xf00e;
+    public static final int CODE_OEM_CAUSE_15 = 0xf00f;
+
     /**
      * Network string error messages.
      * mExtraMessage may have these values.
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
index 808b5d3..a7bdabd 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
@@ -138,7 +138,7 @@
             mSaturation = saturation;
             final ColorMatrixColorFilter filter =
                     (ColorMatrixColorFilter) mColorMatrixPaint.getColorFilter();
-            final ColorMatrix m = filter.getColorMatrix();
+            final ColorMatrix m = new ColorMatrix();
             m.setSaturation(saturation);
             filter.setColorMatrix(m);
             invalidate();
diff --git a/tests/net/Android.mk b/tests/net/Android.mk
index 79f6e4d..504d54e 100644
--- a/tests/net/Android.mk
+++ b/tests/net/Android.mk
@@ -24,6 +24,7 @@
     android.test.runner
 
 LOCAL_PACKAGE_NAME := FrameworksNetTests
+LOCAL_COMPATIBILITY_SUITE := device-tests
 
 LOCAL_CERTIFICATE := platform
 
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
index 3691cac..785e1ce 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
@@ -85,7 +85,7 @@
             new Thread() {
                 public void run() {
                     for (int j = 0; j < nEvents; j++) {
-                        assertTrue(logger.log(i * 100 + j, FAKE_EV));
+                        assertTrue(logger.log(1 + i * 100 + j, FAKE_EV));
                     }
                 }
             }.start();
@@ -96,7 +96,7 @@
         Iterator<ConnectivityMetricsEvent> iter = got.iterator();
         for (int i = 0; i < nCallers; i++) {
             for (int j = 0; j < nEvents; j++) {
-                int expectedTimestamp = i * 100 + j;
+                int expectedTimestamp = 1 + i * 100 + j;
                 assertEventsEqual(expectedEvent(expectedTimestamp), iter.next());
             }
         }
diff --git a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
index 9e0f3213..0ab4406 100644
--- a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
@@ -23,6 +23,7 @@
 import android.net.metrics.DnsEvent;
 import android.net.metrics.INetdEventListener;
 import android.net.metrics.IpConnectivityLog;
+import android.os.Parcelable;
 import android.os.RemoteException;
 import android.system.OsConstants;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -165,8 +166,8 @@
         // call onLost() asynchronously to logDnsAsync's onDnsEvent() calls.
         mCallbackCaptor.getValue().onLost(new Network(105));
 
-        // do not verify unpredictable batch
-        verify(mLog, timeout(500).times(1)).log(any());
+        // do not verify batch with unpredictable length
+        verify(mLog, timeout(500).times(1)).log(any(Parcelable.class));
     }
 
     @SmallTest
@@ -279,11 +280,7 @@
     }
 
     void logDnsAsync(int netId, int[] latencies) {
-        new Thread() {
-            public void run() {
-                log(netId, latencies);
-            }
-        }.start();
+        new Thread(() -> log(netId, latencies)).start();
     }
 
     void verifyLoggedDnsEvents(DnsEvent... expected) {
diff --git a/tests/testables/Android.mk b/tests/testables/Android.mk
index 58399fd..759bc35 100644
--- a/tests/testables/Android.mk
+++ b/tests/testables/Android.mk
@@ -25,7 +25,7 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
     android-support-test \
-    mockito-updated-target-minus-junit4 \
+    mockito-target-minus-junit4 \
     legacy-android-test
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
diff --git a/tests/testables/tests/Android.mk b/tests/testables/tests/Android.mk
index 752d536..a123d80 100644
--- a/tests/testables/tests/Android.mk
+++ b/tests/testables/tests/Android.mk
@@ -27,7 +27,7 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
     android-support-test \
-    mockito-updated-target-minus-junit4 \
+    mockito-target-minus-junit4 \
     legacy-android-test \
 	testables
 
diff --git a/tools/aapt2/AppInfo.h b/tools/aapt2/AppInfo.h
index 1e488f7..9db21aa 100644
--- a/tools/aapt2/AppInfo.h
+++ b/tools/aapt2/AppInfo.h
@@ -23,30 +23,22 @@
 
 namespace aapt {
 
-/**
- * Holds basic information about the app being built. Most of this information
- * will come from the app's AndroidManifest.
- */
+// Information relevant to building an app, parsed from the app's AndroidManifest.xml.
 struct AppInfo {
-  /**
-   * App's package name.
-   */
+  // The app's package name.
   std::string package;
 
-  /**
-   * The App's minimum SDK version.
-   */
+  // The app's minimum SDK version, if it is defined.
   Maybe<std::string> min_sdk_version;
 
-  /**
-   * The Version code of the app.
-   */
+  // The app's version code, if it is defined.
   Maybe<uint32_t> version_code;
 
-  /**
-   * The revision code of the app.
-   */
+  // The app's revision code, if it is defined.
   Maybe<uint32_t> revision_code;
+
+  // The app's split name, if it is a split.
+  Maybe<std::string> split_name;
 };
 
 }  // namespace aapt
diff --git a/tools/aapt2/link/Link.cpp b/tools/aapt2/link/Link.cpp
index 1042111..1b4d5bb 100644
--- a/tools/aapt2/link/Link.cpp
+++ b/tools/aapt2/link/Link.cpp
@@ -751,70 +751,67 @@
     return true;
   }
 
-  Maybe<AppInfo> ExtractAppInfoFromManifest(xml::XmlResource* xml_res,
-                                            IDiagnostics* diag) {
+  Maybe<AppInfo> ExtractAppInfoFromManifest(xml::XmlResource* xml_res, IDiagnostics* diag) {
     // Make sure the first element is <manifest> with package attribute.
-    if (xml::Element* manifest_el = xml::FindRootElement(xml_res->root.get())) {
-      AppInfo app_info;
-
-      if (!manifest_el->namespace_uri.empty() ||
-          manifest_el->name != "manifest") {
-        diag->Error(DiagMessage(xml_res->file.source)
-                    << "root tag must be <manifest>");
-        return {};
-      }
-
-      xml::Attribute* package_attr = manifest_el->FindAttribute({}, "package");
-      if (!package_attr) {
-        diag->Error(DiagMessage(xml_res->file.source)
-                    << "<manifest> must have a 'package' attribute");
-        return {};
-      }
-
-      app_info.package = package_attr->value;
-
-      if (xml::Attribute* version_code_attr =
-              manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode")) {
-        Maybe<uint32_t> maybe_code =
-            ResourceUtils::ParseInt(version_code_attr->value);
-        if (!maybe_code) {
-          diag->Error(DiagMessage(xml_res->file.source.WithLine(
-                          manifest_el->line_number))
-                      << "invalid android:versionCode '"
-                      << version_code_attr->value << "'");
-          return {};
-        }
-        app_info.version_code = maybe_code.value();
-      }
-
-      if (xml::Attribute* revision_code_attr =
-              manifest_el->FindAttribute(xml::kSchemaAndroid, "revisionCode")) {
-        Maybe<uint32_t> maybe_code =
-            ResourceUtils::ParseInt(revision_code_attr->value);
-        if (!maybe_code) {
-          diag->Error(DiagMessage(xml_res->file.source.WithLine(
-                          manifest_el->line_number))
-                      << "invalid android:revisionCode '"
-                      << revision_code_attr->value << "'");
-          return {};
-        }
-        app_info.revision_code = maybe_code.value();
-      }
-
-      if (xml::Element* uses_sdk_el = manifest_el->FindChild({}, "uses-sdk")) {
-        if (xml::Attribute* min_sdk = uses_sdk_el->FindAttribute(
-                xml::kSchemaAndroid, "minSdkVersion")) {
-          app_info.min_sdk_version = min_sdk->value;
-        }
-      }
-      return app_info;
+    xml::Element* manifest_el = xml::FindRootElement(xml_res->root.get());
+    if (manifest_el == nullptr) {
+      return {};
     }
-    return {};
+
+    AppInfo app_info;
+
+    if (!manifest_el->namespace_uri.empty() || manifest_el->name != "manifest") {
+      diag->Error(DiagMessage(xml_res->file.source) << "root tag must be <manifest>");
+      return {};
+    }
+
+    xml::Attribute* package_attr = manifest_el->FindAttribute({}, "package");
+    if (!package_attr) {
+      diag->Error(DiagMessage(xml_res->file.source)
+                  << "<manifest> must have a 'package' attribute");
+      return {};
+    }
+    app_info.package = package_attr->value;
+
+    if (xml::Attribute* version_code_attr =
+            manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode")) {
+      Maybe<uint32_t> maybe_code = ResourceUtils::ParseInt(version_code_attr->value);
+      if (!maybe_code) {
+        diag->Error(DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number))
+                    << "invalid android:versionCode '" << version_code_attr->value << "'");
+        return {};
+      }
+      app_info.version_code = maybe_code.value();
+    }
+
+    if (xml::Attribute* revision_code_attr =
+            manifest_el->FindAttribute(xml::kSchemaAndroid, "revisionCode")) {
+      Maybe<uint32_t> maybe_code = ResourceUtils::ParseInt(revision_code_attr->value);
+      if (!maybe_code) {
+        diag->Error(DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number))
+                    << "invalid android:revisionCode '" << revision_code_attr->value << "'");
+        return {};
+      }
+      app_info.revision_code = maybe_code.value();
+    }
+
+    if (xml::Attribute* split_name_attr = manifest_el->FindAttribute({}, "split")) {
+      if (!split_name_attr->value.empty()) {
+        app_info.split_name = split_name_attr->value;
+      }
+    }
+
+    if (xml::Element* uses_sdk_el = manifest_el->FindChild({}, "uses-sdk")) {
+      if (xml::Attribute* min_sdk =
+              uses_sdk_el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion")) {
+        app_info.min_sdk_version = min_sdk->value;
+      }
+    }
+    return app_info;
   }
 
   /**
-   * Precondition: ResourceTable doesn't have any IDs assigned yet, nor is it
-   * linked.
+   * Precondition: ResourceTable doesn't have any IDs assigned yet, nor is it linked.
    * Postcondition: ResourceTable has only one package left. All others are
    * stripped, or there is an error and false is returned.
    */
@@ -1367,45 +1364,44 @@
     return true;
   }
 
-  std::unique_ptr<xml::XmlResource> GenerateSplitManifest(
-      const AppInfo& app_info, const SplitConstraints& constraints) {
-    std::unique_ptr<xml::XmlResource> doc =
-        util::make_unique<xml::XmlResource>();
+  std::unique_ptr<xml::XmlResource> GenerateSplitManifest(const AppInfo& app_info,
+                                                          const SplitConstraints& constraints) {
+    std::unique_ptr<xml::XmlResource> doc = util::make_unique<xml::XmlResource>();
 
-    std::unique_ptr<xml::Namespace> namespace_android =
-        util::make_unique<xml::Namespace>();
+    std::unique_ptr<xml::Namespace> namespace_android = util::make_unique<xml::Namespace>();
     namespace_android->namespace_uri = xml::kSchemaAndroid;
     namespace_android->namespace_prefix = "android";
 
-    std::unique_ptr<xml::Element> manifest_el =
-        util::make_unique<xml::Element>();
+    std::unique_ptr<xml::Element> manifest_el = util::make_unique<xml::Element>();
     manifest_el->name = "manifest";
-    manifest_el->attributes.push_back(
-        xml::Attribute{"", "package", app_info.package});
+    manifest_el->attributes.push_back(xml::Attribute{"", "package", app_info.package});
 
     if (app_info.version_code) {
-      manifest_el->attributes.push_back(
-          xml::Attribute{xml::kSchemaAndroid, "versionCode",
-                         std::to_string(app_info.version_code.value())});
+      manifest_el->attributes.push_back(xml::Attribute{
+          xml::kSchemaAndroid, "versionCode", std::to_string(app_info.version_code.value())});
     }
 
     if (app_info.revision_code) {
-      manifest_el->attributes.push_back(
-          xml::Attribute{xml::kSchemaAndroid, "revisionCode",
-                         std::to_string(app_info.revision_code.value())});
+      manifest_el->attributes.push_back(xml::Attribute{
+          xml::kSchemaAndroid, "revisionCode", std::to_string(app_info.revision_code.value())});
     }
 
     std::stringstream split_name;
+    if (app_info.split_name) {
+      split_name << app_info.split_name.value() << ".";
+    }
     split_name << "config." << util::Joiner(constraints.configs, "_");
 
-    manifest_el->attributes.push_back(
-        xml::Attribute{"", "split", split_name.str()});
+    manifest_el->attributes.push_back(xml::Attribute{"", "split", split_name.str()});
 
-    std::unique_ptr<xml::Element> application_el =
-        util::make_unique<xml::Element>();
+    if (app_info.split_name) {
+      manifest_el->attributes.push_back(
+          xml::Attribute{"", "configForSplit", app_info.split_name.value()});
+    }
+
+    std::unique_ptr<xml::Element> application_el = util::make_unique<xml::Element>();
     application_el->name = "application";
-    application_el->attributes.push_back(
-        xml::Attribute{xml::kSchemaAndroid, "hasCode", "false"});
+    application_el->attributes.push_back(xml::Attribute{xml::kSchemaAndroid, "hasCode", "false"});
 
     manifest_el->AppendChild(std::move(application_el));
     namespace_android->AppendChild(std::move(manifest_el));
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 313fe45..0c19c7a 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -29,10 +29,7 @@
 
 namespace aapt {
 
-/**
- * This is how PackageManager builds class names from AndroidManifest.xml
- * entries.
- */
+// This is how PackageManager builds class names from AndroidManifest.xml entries.
 static bool NameIsJavaClassName(xml::Element* el, xml::Attribute* attr,
                                 SourcePathDiagnostics* diag) {
   // We allow unqualified class names (ie: .HelloActivity)
@@ -90,6 +87,36 @@
   };
 }
 
+static bool AutoGenerateIsFeatureSplit(xml::Element* el, SourcePathDiagnostics* diag) {
+  constexpr const char* kFeatureSplit = "featureSplit";
+  constexpr const char* kIsFeatureSplit = "isFeatureSplit";
+
+  xml::Attribute* attr = el->FindAttribute({}, kFeatureSplit);
+  if (attr != nullptr) {
+    // Rewrite the featureSplit attribute to be "split". This is what the
+    // platform recognizes.
+    attr->name = "split";
+
+    // Now inject the android:isFeatureSplit="true" attribute.
+    xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, kIsFeatureSplit);
+    if (attr != nullptr) {
+      if (!ResourceUtils::ParseBool(attr->value).value_or_default(false)) {
+        // The isFeatureSplit attribute is false, which conflicts with the use
+        // of "featureSplit".
+        diag->Error(DiagMessage(el->line_number)
+                    << "attribute 'featureSplit' used in <manifest> but 'android:isFeatureSplit' "
+                       "is not 'true'");
+        return false;
+      }
+
+      // The attribute is already there and set to true, nothing to do.
+    } else {
+      el->attributes.push_back(xml::Attribute{xml::kSchemaAndroid, kIsFeatureSplit, "true"});
+    }
+  }
+  return true;
+}
+
 static bool VerifyManifest(xml::Element* el, SourcePathDiagnostics* diag) {
   xml::Attribute* attr = el->FindAttribute({}, "package");
   if (!attr) {
@@ -97,31 +124,34 @@
                 << "<manifest> tag is missing 'package' attribute");
     return false;
   } else if (ResourceUtils::IsReference(attr->value)) {
-    diag->Error(
-        DiagMessage(el->line_number)
-        << "attribute 'package' in <manifest> tag must not be a reference");
+    diag->Error(DiagMessage(el->line_number)
+                << "attribute 'package' in <manifest> tag must not be a reference");
     return false;
   } else if (!util::IsJavaPackageName(attr->value)) {
     diag->Error(DiagMessage(el->line_number)
-                << "attribute 'package' in <manifest> tag is not a valid Java "
-                   "package name: '"
+                << "attribute 'package' in <manifest> tag is not a valid Java package name: '"
                 << attr->value << "'");
     return false;
   }
+
+  attr = el->FindAttribute({}, "split");
+  if (attr) {
+    if (!util::IsJavaPackageName(attr->value)) {
+      diag->Error(DiagMessage(el->line_number) << "attribute 'split' in <manifest> tag is not a "
+                                                  "valid split name");
+      return false;
+    }
+  }
   return true;
 }
 
-/**
- * The coreApp attribute in <manifest> is not a regular AAPT attribute, so type
- * checking on it is manual.
- */
+// The coreApp attribute in <manifest> is not a regular AAPT attribute, so type
+// checking on it is manual.
 static bool FixCoreAppAttribute(xml::Element* el, SourcePathDiagnostics* diag) {
   if (xml::Attribute* attr = el->FindAttribute("", "coreApp")) {
-    std::unique_ptr<BinaryPrimitive> result =
-        ResourceUtils::TryParseBool(attr->value);
+    std::unique_ptr<BinaryPrimitive> result = ResourceUtils::TryParseBool(attr->value);
     if (!result) {
-      diag->Error(DiagMessage(el->line_number)
-                  << "attribute coreApp must be a boolean");
+      diag->Error(DiagMessage(el->line_number) << "attribute coreApp must be a boolean");
       return false;
     }
     attr->compiled_value = std::move(result);
@@ -172,8 +202,7 @@
   }
 
   if (options_.rename_instrumentation_target_package) {
-    if (!util::IsJavaPackageName(
-            options_.rename_instrumentation_target_package.value())) {
+    if (!util::IsJavaPackageName(options_.rename_instrumentation_target_package.value())) {
       diag->Error(DiagMessage()
                   << "invalid instrumentation target package override '"
                   << options_.rename_instrumentation_target_package.value()
@@ -203,6 +232,7 @@
 
   // Manifest actions.
   xml::XmlNodeAction& manifest_action = (*executor)["manifest"];
+  manifest_action.Action(AutoGenerateIsFeatureSplit);
   manifest_action.Action(VerifyManifest);
   manifest_action.Action(FixCoreAppAttribute);
   manifest_action.Action([&](xml::Element* el) -> bool {
@@ -276,6 +306,7 @@
   manifest_action["compatible-screens"]["screen"];
   manifest_action["supports-gl-texture"];
   manifest_action["meta-data"] = meta_data_action;
+  manifest_action["uses-split"].Action(RequiredNameIsJavaPackage);
 
   // Application actions.
   xml::XmlNodeAction& application_action = manifest_action["application"];
@@ -311,15 +342,13 @@
  public:
   using xml::Visitor::Visit;
 
-  explicit FullyQualifiedClassNameVisitor(const StringPiece& package)
-      : package_(package) {}
+  explicit FullyQualifiedClassNameVisitor(const StringPiece& package) : package_(package) {}
 
   void Visit(xml::Element* el) override {
     for (xml::Attribute& attr : el->attributes) {
       if (attr.namespace_uri == xml::kSchemaAndroid &&
           class_attributes_.find(attr.name) != class_attributes_.end()) {
-        if (Maybe<std::string> new_value =
-                util::GetFullyQualifiedClassName(package_, attr.value)) {
+        if (Maybe<std::string> new_value = util::GetFullyQualifiedClassName(package_, attr.value)) {
           attr.value = std::move(new_value.value());
         }
       }
@@ -334,8 +363,7 @@
   std::unordered_set<StringPiece> class_attributes_ = {"name"};
 };
 
-static bool RenameManifestPackage(const StringPiece& package_override,
-                                  xml::Element* manifest_el) {
+static bool RenameManifestPackage(const StringPiece& package_override, xml::Element* manifest_el) {
   xml::Attribute* attr = manifest_el->FindAttribute({}, "package");
 
   // We've already verified that the manifest element is present, with a package
@@ -358,8 +386,7 @@
     return false;
   }
 
-  if ((options_.min_sdk_version_default ||
-       options_.target_sdk_version_default) &&
+  if ((options_.min_sdk_version_default || options_.target_sdk_version_default) &&
       root->FindChild({}, "uses-sdk") == nullptr) {
     // Auto insert a <uses-sdk> element. This must be inserted before the
     // <application> tag. The device runtime PackageParser will make SDK version
@@ -374,8 +401,7 @@
     return false;
   }
 
-  if (!executor.Execute(xml::XmlActionExecutorPolicy::kWhitelist,
-                        context->GetDiagnostics(), doc)) {
+  if (!executor.Execute(xml::XmlActionExecutorPolicy::kWhitelist, context->GetDiagnostics(), doc)) {
     return false;
   }
 
@@ -383,8 +409,7 @@
     // Rename manifest package outside of the XmlActionExecutor.
     // We need to extract the old package name and FullyQualify all class
     // names.
-    if (!RenameManifestPackage(options_.rename_manifest_package.value(),
-                               root)) {
+    if (!RenameManifestPackage(options_.rename_manifest_package.value(), root)) {
       return false;
     }
   }
diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py
index eb8a1cc..008344c 100755
--- a/tools/fonts/fontchain_lint.py
+++ b/tools/fonts/fontchain_lint.py
@@ -521,36 +521,21 @@
     # add zwj sequences not in the current emoji-zwj-sequences.txt
     adjusted_emoji_zwj_sequences = dict(_emoji_zwj_sequences)
     adjusted_emoji_zwj_sequences.update(_emoji_zwj_sequences)
-    # single parent families
+    # Wrestlers with modifiers
     additional_emoji_zwj = (
-        (0x1F468, 0x200D, 0x1F466),
-        (0x1F468, 0x200D, 0x1F467),
-        (0x1F468, 0x200D, 0x1F466, 0x200D, 0x1F466),
-        (0x1F468, 0x200D, 0x1F467, 0x200D, 0x1F466),
-        (0x1F468, 0x200D, 0x1F467, 0x200D, 0x1F467),
-        (0x1F469, 0x200D, 0x1F466),
-        (0x1F469, 0x200D, 0x1F467),
-        (0x1F469, 0x200D, 0x1F466, 0x200D, 0x1F466),
-        (0x1F469, 0x200D, 0x1F467, 0x200D, 0x1F466),
-        (0x1F469, 0x200D, 0x1F467, 0x200D, 0x1F467),
-    )
-    # sequences formed from man and woman and optional fitzpatrick modifier
-    modified_extensions = (
-        0x2696,
-        0x2708,
-        0x1F3A8,
-        0x1F680,
-        0x1F692,
+        (0x1F93C, 0x1F3FB, 0x200D, 0x2640),
+        (0x1F93C, 0x1F3FB, 0x200D, 0x2642),
+        (0x1F93C, 0x1F3FC, 0x200D, 0x2640),
+        (0x1F93C, 0x1F3FC, 0x200D, 0x2642),
+        (0x1F93C, 0x1F3FD, 0x200D, 0x2640),
+        (0x1F93C, 0x1F3FD, 0x200D, 0x2642),
+        (0x1F93C, 0x1F3FE, 0x200D, 0x2640),
+        (0x1F93C, 0x1F3FE, 0x200D, 0x2642),
+        (0x1F93C, 0x1F3FF, 0x200D, 0x2640),
+        (0x1F93C, 0x1F3FF, 0x200D, 0x2642),
     )
     for seq in additional_emoji_zwj:
         adjusted_emoji_zwj_sequences[seq] = 'Emoji_ZWJ_Sequence'
-    for ext in modified_extensions:
-        for base in (0x1F468, 0x1F469):
-            seq = (base, 0x200D, ext)
-            adjusted_emoji_zwj_sequences[seq] = 'Emoji_ZWJ_Sequence'
-            for modifier in range(0x1F3FB, 0x1F400):
-                seq = (base, modifier, 0x200D, ext)
-                adjusted_emoji_zwj_sequences[seq] = 'Emoji_ZWJ_Sequence'
 
     for sequence in _emoji_sequences.keys():
         sequence = tuple(ch for ch in sequence if ch != EMOJI_VS)
diff --git a/tools/layoutlib/bridge/src/android/graphics/BaseCanvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BaseCanvas_Delegate.java
index b1e71b2..cc71053 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BaseCanvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BaseCanvas_Delegate.java
@@ -24,6 +24,7 @@
 import com.android.ninepatch.NinePatchChunk;
 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
 
+import android.annotation.Nullable;
 import android.text.TextUtils;
 
 import java.awt.*;
@@ -31,6 +32,8 @@
 import java.awt.geom.Arc2D;
 import java.awt.geom.Rectangle2D;
 import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBuffer;
 
 public class BaseCanvas_Delegate {
     // ---- delegate manager ----
@@ -646,9 +649,15 @@
         forceSrcMode[0] = false;
 
         // if the bitmap config is alpha_8, then we erase all color value from it
-        // before drawing it.
+        // before drawing it or apply the texture from the shader if present.
         if (bitmap.getConfig() == Bitmap.Config.ALPHA_8) {
-            fixAlpha8Bitmap(image);
+            Shader_Delegate shader = paint.getShader();
+            java.awt.Paint javaPaint = null;
+            if (shader instanceof BitmapShader_Delegate) {
+                javaPaint = shader.getJavaPaint();
+            }
+
+            fixAlpha8Bitmap(image, javaPaint);
         } else if (!bitmap.hasAlpha()) {
             // hasAlpha is merely a rendering hint. There can in fact be alpha values
             // in the bitmap but it should be ignored at drawing time.
@@ -672,16 +681,37 @@
         return image;
     }
 
-    private static void fixAlpha8Bitmap(final BufferedImage image) {
+    /**
+     * This method will apply the correct color to the passed "only alpha" image. Colors on the
+     * passed image will be destroyed.
+     * If the passed javaPaint is null, the color will be set to 0. If a paint is passed, it will
+     * be used to obtain the color that will be applied.
+     * <p/>
+     * This will destroy the passed image color channel.
+     */
+    private static void fixAlpha8Bitmap(final BufferedImage image,
+            @Nullable java.awt.Paint javaPaint) {
         int w = image.getWidth();
         int h = image.getHeight();
+
+        DataBuffer texture = null;
+        if (javaPaint != null) {
+            PaintContext context = javaPaint.createContext(ColorModel.getRGBdefault(), null, null,
+                    new AffineTransform(), null);
+            texture = context.getRaster(0, 0, w, h).getDataBuffer();
+        }
+
         int[] argb = new int[w * h];
         image.getRGB(0, 0, image.getWidth(), image.getHeight(), argb, 0, image.getWidth());
 
         final int length = argb.length;
-        for (int i = 0 ; i < length; i++) {
+        for (int i = 0; i < length; i++) {
             argb[i] &= 0xFF000000;
+            if (texture != null) {
+                argb[i] |= texture.getElem(i) & 0x00FFFFFF;
+            }
         }
+
         image.setRGB(0, 0, w, h, argb, 0, w);
     }
 
diff --git a/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java
index bd934d0..cb013b6 100644
--- a/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java
@@ -66,7 +66,7 @@
     // ---- native methods ----
 
     @LayoutlibDelegate
-    /*package*/ static void destroyFilter(long native_instance) {
+    /*package*/ static void nSafeUnref(long native_instance) {
         sManager.removeJavaReferenceFor(native_instance);
     }
 
diff --git a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
index ff5a5e9..aaff5d5 100644
--- a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
@@ -16,7 +16,6 @@
 
 package android.graphics;
 
-import android.text.FontConfig;
 import com.android.ide.common.rendering.api.AssetRepository;
 import com.android.ide.common.rendering.api.LayoutLog;
 import com.android.layoutlib.bridge.Bridge;
@@ -293,12 +292,16 @@
 
     @LayoutlibDelegate
     /*package*/ static boolean nAddFontWeightStyle(long builderPtr, ByteBuffer font,
-            int ttcIndex, List<FontConfig.Axis> listOfAxis,
-            int weight, boolean isItalic) {
+            int ttcIndex, int weight, boolean isItalic) {
         assert false : "The only client of this method has been overriden.";
         return false;
     }
 
+    @LayoutlibDelegate
+    /*package*/ static void nAddAxisValue(long builderPtr, int tag, float value) {
+        assert false : "The only client of this method has been overriden.";
+    }
+
     static boolean addFont(long builderPtr, final String path, final int weight,
             final boolean isItalic) {
         final FontFamily_Delegate delegate = getDelegate(builderPtr);
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index aa1f00d..1bb56e3 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -964,8 +964,9 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static int nGetTextRunCursor(Paint paint, long native_object, char[] text,
-            int contextStart, int contextLength, int flags, int offset, int cursorOpt) {
+    /*package*/ static int nGetTextRunCursor(Paint paint, long native_object, long typefacePtr,
+            char[] text, int contextStart, int contextLength, int flags, int offset,
+            int cursorOpt) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
                 "Paint.getTextRunCursor is not supported.", null, null /*data*/);
@@ -973,8 +974,8 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static int nGetTextRunCursor(Paint paint, long native_object, String text,
-            int contextStart, int contextEnd, int flags, int offset, int cursorOpt) {
+    /*package*/ static int nGetTextRunCursor(Paint paint, long native_object, long typefacePtr,
+            String text, int contextStart, int contextEnd, int flags, int offset, int cursorOpt) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
                 "Paint.getTextRunCursor is not supported.", null, null /*data*/);
diff --git a/tools/layoutlib/bridge/src/android/graphics/drawable/AdaptiveIconDrawable_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/drawable/AdaptiveIconDrawable_Delegate.java
deleted file mode 100644
index 7e9432d..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/drawable/AdaptiveIconDrawable_Delegate.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.graphics.drawable;
-
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.PorterDuff.Mode;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.Rect;
-import android.graphics.drawable.AdaptiveIconDrawable.LayerState;
-
-/**
- * Delegate used to provide new implementation of a select few methods of {@link
- * AdaptiveIconDrawable}
- * <p>
- * Through the layoutlib_create tool, the original  methods of AdaptiveIconDrawable have been
- * replaced by calls to methods of the same name in this delegate class.
- */
-@SuppressWarnings("unused")
-public class AdaptiveIconDrawable_Delegate {
-    @LayoutlibDelegate
-    /*package*/ static void draw(AdaptiveIconDrawable thisDrawable, Canvas canvas) {
-        // This is a workaround for the broken BitmapShader in layoutlib. This new draw methods
-        // avoids the use of the shader.
-
-        for (int i = 0; i < LayerState.N_CHILDREN; i++) {
-            if (thisDrawable.mLayerState.mChildren[i] == null) {
-                continue;
-            }
-            final Drawable dr = thisDrawable.mLayerState.mChildren[i].mDrawable;
-            if (dr != null) {
-                dr.draw(canvas);
-            }
-        }
-
-        if (thisDrawable.mMaskBitmap != null) {
-            Rect bounds = thisDrawable.getBounds();
-            Paint paint = new Paint();
-            paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
-            canvas.drawBitmap(thisDrawable.mMaskBitmap, bounds.left, bounds.top, paint);
-        }
-    }
-}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
index 4689491..ffbe7c4 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
@@ -18,12 +18,12 @@
 
 import com.android.internal.os.IResultReceiver;
 
-import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
+import android.util.MergedConfiguration;
 import android.view.DragEvent;
 import android.view.IWindow;
 
@@ -50,7 +50,7 @@
 
     @Override
     public void resized(Rect rect, Rect rect2, Rect rect3, Rect rect4, Rect rect5, Rect rect6,
-            boolean b, Configuration configuration, Rect rect7, boolean b2, boolean b3, int i0)
+            boolean b, MergedConfiguration mergedConfig, Rect rect7, boolean b2, boolean b3, int i0)
             throws RemoteException {
         // pass for now.
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index 7582fda..2c88394 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -17,12 +17,12 @@
 package com.android.layoutlib.bridge.android;
 
 import android.content.ClipData;
-import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.util.MergedConfiguration;
 import android.view.IWindow;
 import android.view.IWindowId;
 import android.view.IWindowSession;
@@ -89,25 +89,13 @@
     @Override
     public int relayout(IWindow iWindow, int i, LayoutParams layoutParams, int i2,
             int i3, int i4, int i5, Rect rect, Rect rect2, Rect rect3, Rect rect4, Rect rect5,
-            Rect rect6, Rect rect7, Configuration configuration, Surface surface)
+            Rect rect6, Rect rect7, MergedConfiguration mergedConfig, Surface surface)
             throws RemoteException {
         // pass for now.
         return 0;
     }
 
     @Override
-    public void repositionChild(IWindow window, int left, int top, int right, int bottom,
-            long deferTransactionUntilFrame, Rect outFrame) {
-        // pass for now.
-        return;
-    }
-
-    @Override
-    public void performDeferredDestroy(IWindow window) {
-        // pass for now.
-    }
-
-    @Override
     public boolean outOfMemory(IWindow window) throws RemoteException {
         return false;
     }
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 4f226cb..b0aa3c2 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -163,7 +163,6 @@
         "android.content.res.TypedArray#obtain",
         "android.graphics.BitmapFactory#finishDecode",
         "android.graphics.BitmapFactory#setDensityFromOptions",
-        "android.graphics.drawable.AdaptiveIconDrawable#draw",
         "android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorRT#useLastSeenTarget",
         "android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorRT#onDraw",
         "android.graphics.drawable.GradientDrawable#buildRing",
@@ -333,8 +332,6 @@
      * needed when access from the delegate classes is needed.
      */
     private final static String[] PROMOTED_FIELDS = new String[] {
-        "android.graphics.drawable.AdaptiveIconDrawable#mMaskBitmap",
-        "android.graphics.drawable.AdaptiveIconDrawable#mPaint",
         "android.graphics.drawable.VectorDrawable#mVectorState",
         "android.view.Choreographer#mLastFrameTimeNanos",
         "android.graphics.FontFamily#mBuilderPtr"
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index a1099f8..04f9059 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -281,7 +281,9 @@
     public int apChannel = 0;
 
     /**
-     * Pre-shared key for use with WPA-PSK.
+     * Pre-shared key for use with WPA-PSK. Either an ASCII string enclosed in
+     * double quotation marks (e.g., {@code "abcdefghij"} for PSK passphrase or
+     * a string of 64 hex digits for raw PSK.
      * <p/>
      * When the value of this key is read, the actual key is
      * not returned, just a "*" if the key has a value, or the null
@@ -305,7 +307,7 @@
     /**
      * Priority determines the preference given to a network by {@code wpa_supplicant}
      * when choosing an access point with which to associate.
-     * @deprecated Priority is no longer used.
+     * @deprecated This field does not exist anymore.
      */
     @Deprecated
     public int priority;
@@ -434,6 +436,13 @@
     public int dtimInterval = 0;
 
     /**
+     * Flag indicating if this configuration represents a legacy Passpoint configuration
+     * (Release N or older).  This is used for migrating Passpoint configuration from N to O.
+     * This will no longer be needed after O.
+     * @hide
+     */
+    public boolean isLegacyPasspointConfig = false;
+    /**
      * @hide
      * Uid of app creating the configuration
      */
@@ -1961,6 +1970,7 @@
             mCachedConfigKey = null; //force null configKey
             selfAdded = source.selfAdded;
             validatedInternetAccess = source.validatedInternetAccess;
+            isLegacyPasspointConfig = source.isLegacyPasspointConfig;
             ephemeral = source.ephemeral;
             meteredHint = source.meteredHint;
             meteredOverride = source.meteredOverride;
@@ -2037,6 +2047,7 @@
         dest.writeInt(selfAdded ? 1 : 0);
         dest.writeInt(didSelfAdd ? 1 : 0);
         dest.writeInt(validatedInternetAccess ? 1 : 0);
+        dest.writeInt(isLegacyPasspointConfig ? 1 : 0);
         dest.writeInt(ephemeral ? 1 : 0);
         dest.writeInt(meteredHint ? 1 : 0);
         dest.writeInt(meteredOverride ? 1 : 0);
@@ -2103,6 +2114,7 @@
                 config.selfAdded = in.readInt() != 0;
                 config.didSelfAdd = in.readInt() != 0;
                 config.validatedInternetAccess = in.readInt() != 0;
+                config.isLegacyPasspointConfig = in.readInt() != 0;
                 config.ephemeral = in.readInt() != 0;
                 config.meteredHint = in.readInt() != 0;
                 config.meteredOverride = in.readInt() != 0;
diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
index 7de55aa..333a4f7d 100644
--- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
+++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
@@ -28,6 +28,7 @@
 import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
@@ -329,6 +330,50 @@
                 mUsageLimitStartTimeInMs, mUsageLimitDataLimit, mUsageLimitTimeLimitInMinutes);
     }
 
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("UpdateIdentifier: ").append(mUpdateIdentifier).append("\n");
+        builder.append("CredentialPriority: ").append(mCredentialPriority).append("\n");
+        builder.append("SubscriptionCreationTime: ").append(
+                mSubscriptionCreationTimeInMs != Long.MIN_VALUE
+                ? new Date(mSubscriptionCreationTimeInMs) : "Not specified").append("\n");
+        builder.append("SubscriptionExpirationTime: ").append(
+                mSubscriptionExpirationTimeInMs != Long.MIN_VALUE
+                ? new Date(mSubscriptionExpirationTimeInMs) : "Not specified").append("\n");
+        builder.append("UsageLimitStartTime: ").append(mUsageLimitStartTimeInMs != Long.MIN_VALUE
+                ? new Date(mUsageLimitStartTimeInMs) : "Not specified").append("\n");
+        builder.append("UsageTimePeriod: ").append(mUsageLimitUsageTimePeriodInMinutes)
+                .append("\n");
+        builder.append("UsageLimitDataLimit: ").append(mUsageLimitDataLimit).append("\n");
+        builder.append("UsageLimitTimeLimit: ").append(mUsageLimitTimeLimitInMinutes).append("\n");
+        if (mHomeSp != null) {
+            builder.append("HomeSP Begin ---\n");
+            builder.append(mHomeSp);
+            builder.append("HomeSP End ---\n");
+        }
+        if (mCredential != null) {
+            builder.append("Credential Begin ---\n");
+            builder.append(mCredential);
+            builder.append("Credential End ---\n");
+        }
+        if (mPolicy != null) {
+            builder.append("Policy Begin ---\n");
+            builder.append(mPolicy);
+            builder.append("Policy End ---\n");
+        }
+        if (mSubscriptionUpdate != null) {
+            builder.append("SubscriptionUpdate Begin ---\n");
+            builder.append(mSubscriptionUpdate);
+            builder.append("SubscriptionUpdate End ---\n");
+        }
+        if (mTrustRootCertList != null) {
+            builder.append("TrustRootCertServers: ").append(mTrustRootCertList.keySet())
+                    .append("\n");
+        }
+        return builder.toString();
+    }
+
     /**
      * Validate the configuration data.
      *
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
index d8da84f..67fa1bb 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
@@ -30,6 +30,7 @@
 import java.security.cert.CertificateEncodingException;
 import java.security.cert.X509Certificate;
 import java.util.Arrays;
+import java.util.Date;
 import java.util.HashSet;
 import java.util.Objects;
 import java.util.Set;
@@ -282,6 +283,18 @@
                     mAbleToShare, mEapType, mNonEapInnerMethod);
         }
 
+        @Override
+        public String toString() {
+            StringBuilder builder = new StringBuilder();
+            builder.append("Username: ").append(mUsername).append("\n");
+            builder.append("MachineManaged: ").append(mMachineManaged).append("\n");
+            builder.append("SoftTokenApp: ").append(mSoftTokenApp).append("\n");
+            builder.append("AbleToShare: ").append(mAbleToShare).append("\n");
+            builder.append("EAPType: ").append(mEapType).append("\n");
+            builder.append("AuthMethod: ").append(mNonEapInnerMethod).append("\n");
+            return builder.toString();
+        }
+
         /**
          * Validate the configuration data.
          *
@@ -440,6 +453,11 @@
             return Objects.hash(mCertType, mCertSha256Fingerprint);
         }
 
+        @Override
+        public String toString() {
+            return "CertificateType: " + mCertType + "\n";
+        }
+
         /**
          * Validate the configuration data.
          *
@@ -562,6 +580,14 @@
         }
 
         @Override
+        public String toString() {
+            StringBuilder builder = new StringBuilder();
+            builder.append("IMSI: ").append(mImsi).append("\n");
+            builder.append("EAPType: ").append(mEapType).append("\n");
+            return builder.toString();
+        }
+
+        @Override
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeString(mImsi);
             dest.writeInt(mEapType);
@@ -767,6 +793,33 @@
                 mCaCertificate, mClientCertificateChain, mClientPrivateKey);
     }
 
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("Realm: ").append(mRealm).append("\n");
+        builder.append("CreationTime: ").append(mCreationTimeInMs != Long.MIN_VALUE
+                ? new Date(mCreationTimeInMs) : "Not specified").append("\n");
+        builder.append("ExpirationTime: ").append(mExpirationTimeInMs != Long.MIN_VALUE
+                ? new Date(mExpirationTimeInMs) : "Not specified").append("\n");
+        builder.append("CheckAAAServerStatus: ").append(mCheckAaaServerCertStatus).append("\n");
+        if (mUserCredential != null) {
+            builder.append("UserCredential Begin ---\n");
+            builder.append(mUserCredential);
+            builder.append("UserCredential End ---\n");
+        }
+        if (mCertCredential != null) {
+            builder.append("CertificateCredential Begin ---\n");
+            builder.append(mCertCredential);
+            builder.append("CertificateCredential End ---\n");
+        }
+        if (mSimCredential != null) {
+            builder.append("SIMCredential Begin ---\n");
+            builder.append(mSimCredential);
+            builder.append("SIMCredential End ---\n");
+        }
+        return builder.toString();
+    }
+
     /**
      * Validate the configuration data.
      *
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java
index 68bdf37..9192ab0 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java
@@ -241,6 +241,20 @@
                 mMatchAnyOis, mOtherHomePartners, mRoamingConsortiumOis);
     }
 
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("FQDN: ").append(mFqdn).append("\n");
+        builder.append("FriendlyName: ").append(mFriendlyName).append("\n");
+        builder.append("IconURL: ").append(mIconUrl).append("\n");
+        builder.append("HomeNetworkIDs: ").append(mHomeNetworkIds).append("\n");
+        builder.append("MatchAllOIs: ").append(mMatchAllOis).append("\n");
+        builder.append("MatchAnyOIs: ").append(mMatchAnyOis).append("\n");
+        builder.append("OtherHomePartners: ").append(mOtherHomePartners).append("\n");
+        builder.append("RoamingConsortiumOIs: ").append(mRoamingConsortiumOis).append("\n");
+        return builder.toString();
+    }
+
     /**
      * Validate HomeSp data.
      *
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Policy.java b/wifi/java/android/net/wifi/hotspot2/pps/Policy.java
index da36a11..1df70f8 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/Policy.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/Policy.java
@@ -249,6 +249,16 @@
             return Objects.hash(mFqdn, mFqdnExactMatch, mPriority, mCountries);
         }
 
+        @Override
+        public String toString() {
+            StringBuilder builder = new StringBuilder();
+            builder.append("FQDN: ").append(mFqdn).append("\n");
+            builder.append("ExactMatch: ").append("mFqdnExactMatch").append("\n");
+            builder.append("Priority: ").append(mPriority).append("\n");
+            builder.append("Countries: ").append(mCountries).append("\n");
+            return builder.toString();
+        }
+
         /**
          * Validate RoamingParnter data.
          *
@@ -390,6 +400,29 @@
                 mPolicyUpdate);
     }
 
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("MinHomeDownlinkBandwidth: ").append(mMinHomeDownlinkBandwidth)
+                .append("\n");
+        builder.append("MinHomeUplinkBandwidth: ").append(mMinHomeUplinkBandwidth).append("\n");
+        builder.append("MinRoamingDownlinkBandwidth: ").append(mMinRoamingDownlinkBandwidth)
+                .append("\n");
+        builder.append("MinRoamingUplinkBandwidth: ").append(mMinRoamingUplinkBandwidth)
+                .append("\n");
+        builder.append("ExcludedSSIDList: ").append(mExcludedSsidList).append("\n");
+        builder.append("RequiredProtoPortMap: ").append(mRequiredProtoPortMap).append("\n");
+        builder.append("MaximumBSSLoadValue: ").append(mMaximumBssLoadValue).append("\n");
+        builder.append("PreferredRoamingPartnerList: ").append(mPreferredRoamingPartnerList)
+                .append("\n");
+        if (mPolicyUpdate != null) {
+            builder.append("PolicyUpdate Begin ---\n");
+            builder.append(mPolicyUpdate);
+            builder.append("PolicyUpdate End ---\n");
+        }
+        return builder.toString();
+    }
+
     /**
      * Validate Policy data.
      *
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.java b/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.java
index ae051b0..a7adfeb 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.java
@@ -247,6 +247,18 @@
                 mTrustRootCertSha256Fingerprint);
     }
 
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("UpdateInterval: ").append(mUpdateIntervalInMinutes).append("\n");
+        builder.append("UpdateMethod: ").append(mUpdateMethod).append("\n");
+        builder.append("Restriction: ").append(mRestriction).append("\n");
+        builder.append("ServerURI: ").append(mServerUri).append("\n");
+        builder.append("Username: ").append(mUsername).append("\n");
+        builder.append("TrustRootCertURL: ").append(mTrustRootCertUrl).append("\n");
+        return builder.toString();
+    }
+
     /**
      * Validate UpdateParameter data.
      *
diff --git a/wifi/tests/Android.mk b/wifi/tests/Android.mk
index eac49d2..8dc244f 100644
--- a/wifi/tests/Android.mk
+++ b/wifi/tests/Android.mk
@@ -58,5 +58,6 @@
 	android.test.runner \
 
 LOCAL_PACKAGE_NAME := FrameworksWifiApiTests
+LOCAL_COMPATIBILITY_SUITE := device-tests
 
 include $(BUILD_PACKAGE)