Merge "Bowing my head in shame, going back to gamma interpolated gradients"
diff --git a/api/current.txt b/api/current.txt
index 77cb9e4..9557ee5 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1790,6 +1790,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
@@ -5493,7 +5494,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 +5507,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 +5514,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 +5527,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 +5548,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();
@@ -10672,6 +10672,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";
@@ -21827,7 +21828,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 +22380,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 +22635,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 +22738,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 +22906,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;
@@ -24653,7 +24717,7 @@
 
   public final class TvInputInfo implements android.os.Parcelable {
     method public boolean canRecord();
-    method public android.content.Intent createSettingsIntent();
+    method public deprecated android.content.Intent createSettingsIntent();
     method public android.content.Intent createSetupIntent();
     method public int describeContents();
     method public android.os.Bundle getExtras();
@@ -33878,6 +33942,7 @@
     field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_CHAT_ID = "android.provider.extra.RECIPIENT_CONTACT_CHAT_ID";
     field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_NAME = "android.provider.extra.RECIPIENT_CONTACT_NAME";
     field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_URI = "android.provider.extra.RECIPIENT_CONTACT_URI";
+    field public static final java.lang.String EXTRA_SENDER_ACCOUNT_HASH = "android.provider.extra.SENDER_ACCOUNT_HASH";
     field public static final java.lang.String INVITE_CONTACT = "com.android.contacts.action.INVITE_CONTACT";
     field public static final java.lang.String METADATA_ACCOUNT_TYPE = "android.provider.account_type";
     field public static final java.lang.String METADATA_MIMETYPE = "android.provider.mimetype";
@@ -36742,7 +36807,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";
@@ -39812,7 +39877,6 @@
     method public android.os.PersistableBundle getCarrierConfig();
     method public android.telephony.CellLocation getCellLocation();
     method public int getDataActivity();
-    method public boolean getDataEnabled();
     method public int getDataNetworkType();
     method public int getDataState();
     method public java.lang.String getDeviceId();
@@ -39853,6 +39917,7 @@
     method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, java.lang.String);
     method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
     method public boolean isConcurrentVoiceAndDataAllowed();
+    method public boolean isDataEnabled();
     method public boolean isHearingAidCompatibilitySupported();
     method public boolean isNetworkRoaming();
     method public boolean isSmsCapable();
@@ -45423,7 +45488,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);
@@ -47506,6 +47571,7 @@
   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 notifyViewEntered(android.view.View);
     method public void notifyViewExited(android.view.View);
@@ -47513,9 +47579,12 @@
     method public void notifyVirtualViewEntered(android.view.View, int, android.graphics.Rect);
     method public void notifyVirtualViewExited(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 {
diff --git a/api/system-current.txt b/api/system-current.txt
index 827b46c..6d01c6b 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1907,6 +1907,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
@@ -5680,7 +5681,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 +5694,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 +5729,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 +5751,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();
@@ -11334,6 +11330,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";
@@ -23623,7 +23620,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 +24172,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 +24427,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 +24530,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 +24698,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;
@@ -26653,7 +26713,7 @@
 
   public final class TvInputInfo implements android.os.Parcelable {
     method public boolean canRecord();
-    method public android.content.Intent createSettingsIntent();
+    method public deprecated android.content.Intent createSettingsIntent();
     method public android.content.Intent createSetupIntent();
     method public static deprecated android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.hardware.hdmi.HdmiDeviceInfo, java.lang.String, java.lang.String, android.net.Uri) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public static deprecated android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.hardware.hdmi.HdmiDeviceInfo, java.lang.String, int, android.graphics.drawable.Icon) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
@@ -36758,6 +36818,7 @@
     field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_CHAT_ID = "android.provider.extra.RECIPIENT_CONTACT_CHAT_ID";
     field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_NAME = "android.provider.extra.RECIPIENT_CONTACT_NAME";
     field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_URI = "android.provider.extra.RECIPIENT_CONTACT_URI";
+    field public static final java.lang.String EXTRA_SENDER_ACCOUNT_HASH = "android.provider.extra.SENDER_ACCOUNT_HASH";
     field public static final java.lang.String INVITE_CONTACT = "com.android.contacts.action.INVITE_CONTACT";
     field public static final java.lang.String METADATA_ACCOUNT_TYPE = "android.provider.account_type";
     field public static final java.lang.String METADATA_MIMETYPE = "android.provider.mimetype";
@@ -39780,7 +39841,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";
@@ -43216,8 +43277,8 @@
     method public int getCurrentPhoneType();
     method public int getCurrentPhoneType(int);
     method public int getDataActivity();
-    method public boolean getDataEnabled();
-    method public boolean getDataEnabled(int);
+    method public deprecated boolean getDataEnabled();
+    method public deprecated boolean getDataEnabled(int);
     method public int getDataNetworkType();
     method public int getDataState();
     method public java.lang.String getDeviceId();
@@ -43264,6 +43325,7 @@
     method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
     method public boolean isConcurrentVoiceAndDataAllowed();
     method public boolean isDataConnectivityPossible();
+    method public boolean isDataEnabled();
     method public boolean isHearingAidCompatibilitySupported();
     method public boolean isIdle();
     method public boolean isNetworkRoaming();
@@ -48889,7 +48951,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);
@@ -50975,6 +51037,7 @@
   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 notifyViewEntered(android.view.View);
     method public void notifyViewExited(android.view.View);
@@ -50982,9 +51045,12 @@
     method public void notifyVirtualViewEntered(android.view.View, int, android.graphics.Rect);
     method public void notifyVirtualViewExited(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 {
diff --git a/api/test-current.txt b/api/test-current.txt
index 04f4f21..1d0a289 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1790,6 +1790,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
@@ -5503,7 +5504,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 +5517,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 +5524,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 +5537,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 +5558,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 +5566,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();
@@ -10708,6 +10708,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";
@@ -21928,7 +21929,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 +22481,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 +22736,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 +22839,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 +23007,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;
@@ -24754,7 +24818,7 @@
 
   public final class TvInputInfo implements android.os.Parcelable {
     method public boolean canRecord();
-    method public android.content.Intent createSettingsIntent();
+    method public deprecated android.content.Intent createSettingsIntent();
     method public android.content.Intent createSetupIntent();
     method public int describeContents();
     method public android.os.Bundle getExtras();
@@ -34005,6 +34069,7 @@
     field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_CHAT_ID = "android.provider.extra.RECIPIENT_CONTACT_CHAT_ID";
     field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_NAME = "android.provider.extra.RECIPIENT_CONTACT_NAME";
     field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_URI = "android.provider.extra.RECIPIENT_CONTACT_URI";
+    field public static final java.lang.String EXTRA_SENDER_ACCOUNT_HASH = "android.provider.extra.SENDER_ACCOUNT_HASH";
     field public static final java.lang.String INVITE_CONTACT = "com.android.contacts.action.INVITE_CONTACT";
     field public static final java.lang.String METADATA_ACCOUNT_TYPE = "android.provider.account_type";
     field public static final java.lang.String METADATA_MIMETYPE = "android.provider.mimetype";
@@ -36886,7 +36951,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";
@@ -40001,7 +40066,6 @@
     method public android.os.PersistableBundle getCarrierConfig();
     method public android.telephony.CellLocation getCellLocation();
     method public int getDataActivity();
-    method public boolean getDataEnabled();
     method public int getDataNetworkType();
     method public int getDataState();
     method public java.lang.String getDeviceId();
@@ -40042,6 +40106,7 @@
     method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, java.lang.String);
     method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
     method public boolean isConcurrentVoiceAndDataAllowed();
+    method public boolean isDataEnabled();
     method public boolean isHearingAidCompatibilitySupported();
     method public boolean isNetworkRoaming();
     method public boolean isSmsCapable();
@@ -45786,7 +45851,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);
@@ -47875,6 +47940,7 @@
   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 notifyViewEntered(android.view.View);
     method public void notifyViewExited(android.view.View);
@@ -47882,9 +47948,12 @@
     method public void notifyVirtualViewEntered(android.view.View, int, android.graphics.Rect);
     method public void notifyVirtualViewExited(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 {
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/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 44cc5b4..9b64f0c 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;
@@ -5570,6 +5572,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.INSTANCE);
+        }
+
         // 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 +5677,7 @@
         }
 
         // Preload fonts resources
+        Typeface.setApplicationContext(appContext);
         try {
             final ApplicationInfo info =
                     getPackageManager().getApplicationInfo(
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/DexLoadReporter.java b/core/java/android/app/DexLoadReporter.java
new file mode 100644
index 0000000..009c448
--- /dev/null
+++ b/core/java/android/app/DexLoadReporter.java
@@ -0,0 +1,57 @@
+/*
+ * 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.RemoteException;
+import android.util.Slog;
+
+import dalvik.system.BaseDexClassLoader;
+import dalvik.system.VMRuntime;
+
+import java.util.List;
+
+/**
+ * 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";
+
+    /*package*/ 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);
+        }
+    }
+}
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 be38f42..8299c50 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -55,7 +55,6 @@
 
 import com.android.internal.util.ArrayUtils;
 
-import dalvik.system.BaseDexClassLoader;
 import dalvik.system.VMRuntime;
 
 import java.io.File;
@@ -597,8 +596,7 @@
         // Avoid the binder call when the package is the current application package.
         // The activity manager will perform ensure that dexopt is performed before
         // spinning up the process.
-        if (!Objects.equals(mPackageName, ActivityThread.currentPackageName())) {
-            VMRuntime.getRuntime().vmInstructionSet();
+        if (!Objects.equals(mPackageName, ActivityThread.currentPackageName()) && mIncludeCode) {
             try {
                 ActivityThread.getPackageManager().notifyPackageUse(mPackageName,
                         PackageManager.NOTIFY_PACKAGE_USE_CROSS_PACKAGE);
@@ -752,40 +750,6 @@
 
         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);
-            }
-        }
     }
 
     /**
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/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/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/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java
index d428a3a..2f87633 100644
--- a/core/java/android/content/ContentProviderNative.java
+++ b/core/java/android/content/ContentProviderNative.java
@@ -24,6 +24,7 @@
 import android.database.CursorToBulkCursorAdaptor;
 import android.database.DatabaseUtils;
 import android.database.IContentObserver;
+import android.database.PageViewCursor;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
@@ -103,6 +104,7 @@
                     if (cursor != null) {
                         CursorToBulkCursorAdaptor adaptor = null;
 
+                        cursor = PageViewCursor.wrap(cursor, queryArgs);
                         try {
                             adaptor = new CursorToBulkCursorAdaptor(cursor, observer,
                                     getProviderName());
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 1f01e28e..4dc6fd2 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;
@@ -1992,6 +1993,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/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..5a28e87 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -211,6 +211,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;
@@ -4247,6 +4255,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*/,
diff --git a/core/java/android/database/PageViewCursor.java b/core/java/android/database/PageViewCursor.java
new file mode 100644
index 0000000..fbd039d
--- /dev/null
+++ b/core/java/android/database/PageViewCursor.java
@@ -0,0 +1,245 @@
+/*
+ * 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.database;
+
+import static com.android.internal.util.Preconditions.checkArgument;
+
+import android.annotation.Nullable;
+import android.content.ContentResolver;
+import android.os.Bundle;
+import android.util.Log;
+import android.util.MathUtils;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
+
+/**
+ * Cursor wrapper that provides visibility into a subset of a wrapped cursor.
+ *
+ * The window is specified by offset and limit.
+ *
+ * @hide
+ */
+public final class PageViewCursor extends CrossProcessCursorWrapper {
+
+    /**
+     * An extra added to results that are auto-paged using the wrapper.
+     */
+    public static final String EXTRA_AUTO_PAGED = "android.content.extra.AUTO_PAGED";
+
+    private static final String TAG = "PageViewCursor";
+    private static final boolean DEBUG = false;
+    private static final boolean VERBOSE = false;
+
+    private final int mOffset;  // aka first index
+    private final int mCount;
+    private final Bundle mExtras;
+
+    private int mPos = -1;
+
+    /**
+     * @see PageViewCursor#wrap(Cursor, Bundle)
+     */
+    @VisibleForTesting
+    public PageViewCursor(Cursor cursor, int offset, int limit) {
+        super(cursor);
+
+        checkArgument(offset > -1);
+        checkArgument(limit > -1);
+
+        mOffset = offset;
+
+        mExtras = new Bundle();
+        Bundle extras = cursor.getExtras();
+        if (extras != null) {
+            mExtras.putAll(extras);
+        }
+        mExtras.putBoolean(EXTRA_AUTO_PAGED, true);
+
+        // We need a mutable bundle so we can add QUERY_RESULT_SIZE.
+        // Direct equality check is correct here. Bundle.EMPTY is a specific instance
+        // of Bundle that is immutable by way of implementation.
+        // mExtras = (extras == Bundle.EMPTY) ? new Bundle() : extras;
+
+        // When we're wrapping another cursor, it should not already be "paged".
+        checkArgument(!mExtras.containsKey(ContentResolver.EXTRA_TOTAL_SIZE));
+
+        int count = mCursor.getCount();
+        mExtras.putInt(ContentResolver.EXTRA_TOTAL_SIZE, count);
+
+        mCount = MathUtils.constrain(count - offset, 0, limit);
+
+        if (DEBUG) Log.d(TAG, "Wrapped cursor"
+            + " offset: " + mOffset
+            + ", limit: " + limit
+            + ", delegate_size: " + count
+            + ", paged_count: " + mCount);
+    }
+
+    @Override
+    public Bundle getExtras() {
+        return mExtras;
+    }
+
+    @Override
+    public int getPosition() {
+        return mPos;
+    }
+
+    @Override
+    public boolean isBeforeFirst() {
+        if (mCount == 0) {
+            return true;
+        }
+        return mPos == -1;
+    }
+
+    @Override
+    public boolean isAfterLast() {
+        if (mCount == 0) {
+            return true;
+        }
+        return mPos == mCount;
+    }
+
+    @Override
+    public boolean isFirst() {
+        return mPos == 0;
+    }
+
+    @Override
+    public boolean isLast() {
+        return mPos == mCount - 1;
+    }
+
+    @Override
+    public boolean moveToFirst() {
+        return moveToPosition(0);
+    }
+
+    @Override
+    public boolean moveToLast() {
+        return moveToPosition(mCount - 1);
+    }
+
+    @Override
+    public boolean moveToNext() {
+        return move(1);
+    }
+
+    @Override
+    public boolean moveToPrevious() {
+        return move(-1);
+    }
+
+    @Override
+    public boolean move(int offset) {
+        return moveToPosition(mPos + offset);
+    }
+
+    @Override
+    public boolean moveToPosition(int position) {
+        if (position >= mCount) {
+            if (VERBOSE) Log.v(TAG, "Invalid Positon: " + position + " >= count: " + mCount
+                    + ". Moving to last record.");
+            mPos = mCount;
+            super.moveToPosition(mOffset + mPos);  // move into "after last" state.
+            return false;
+        }
+
+        // Make sure position isn't before the beginning of the cursor
+        if (position < 0) {
+            if (VERBOSE) Log.v(TAG, "Ignoring invalid move to position: " + position);
+            mPos = -1;
+            super.moveToPosition(mPos);
+            return false;
+        }
+
+        if (position == mPos) {
+            if (VERBOSE) Log.v(TAG, "Ignoring no-op move to position: " + position);
+            return true;
+        }
+
+        int delegatePosition = position + mOffset;
+        if (VERBOSE) Log.v(TAG, "Moving delegate cursor to position: " + delegatePosition);
+        if (super.moveToPosition(delegatePosition)) {
+            mPos = position;
+            return true;
+        } else {
+            mPos = -1;
+            super.moveToPosition(-1);
+            return false;
+        }
+    }
+
+    @Override
+    public boolean onMove(int oldPosition, int newPosition) {
+        throw new UnsupportedOperationException("Not supported.");
+    }
+
+    @Override
+    public int getCount() {
+        return mCount;
+    }
+
+    /**
+     * Wraps the cursor such that it will honor paging args (if present), AND if the cursor
+     * does not report paging size.
+     *
+     * <p>No-op if cursor already contains paging or is less than specified page size.
+     */
+    public static Cursor wrap(Cursor cursor, @Nullable Bundle queryArgs) {
+
+        boolean hasPagingArgs =
+                queryArgs != null
+                && (queryArgs.containsKey(ContentResolver.QUERY_ARG_OFFSET)
+                || queryArgs.containsKey(ContentResolver.QUERY_ARG_LIMIT));
+
+        if (!hasPagingArgs) {
+            if (VERBOSE) Log.d(TAG, "No-wrap: No paging args in request.");
+            return cursor;
+        }
+
+        if (hasPagedResponseDetails(cursor.getExtras())) {
+            if (VERBOSE) Log.d(TAG, "No-wrap. Cursor has paging details.");
+            return cursor;
+        }
+
+        return new PageViewCursor(
+                cursor,
+                queryArgs.getInt(ContentResolver.QUERY_ARG_OFFSET, 0),
+                queryArgs.getInt(ContentResolver.QUERY_ARG_LIMIT, Integer.MAX_VALUE));
+    }
+
+    /**
+     * @return true if the extras contains information indicating the associated
+     * cursor is paged.
+     */
+    private static boolean hasPagedResponseDetails(@Nullable Bundle extras) {
+        if (extras != null && extras.containsKey(ContentResolver.EXTRA_TOTAL_SIZE)) {
+            return true;
+        }
+
+        String[] honoredArgs = extras.getStringArray(ContentResolver.EXTRA_HONORED_ARGS);
+        if (honoredArgs != null && (
+                ArrayUtils.contains(honoredArgs, ContentResolver.QUERY_ARG_OFFSET)
+                || ArrayUtils.contains(honoredArgs, ContentResolver.QUERY_ARG_LIMIT))) {
+            return true;
+        }
+
+        return false;
+    }
+}
diff --git a/core/java/android/net/ConnectivityMetricsEvent.java b/core/java/android/net/ConnectivityMetricsEvent.java
index 6fdc739..4faff62 100644
--- a/core/java/android/net/ConnectivityMetricsEvent.java
+++ b/core/java/android/net/ConnectivityMetricsEvent.java
@@ -19,39 +19,40 @@
 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(). */
-    final public long timestamp;
-
-    /** The subsystem that generated the event. One of the COMPONENT_TAG_xxx constants. */
-    final public int componentTag;
-
-    /** The subsystem-specific event ID. */
-    final public int eventTag;
-
+    /** 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. */
-    final public Parcelable data;
+    public Parcelable data;
 
-    public ConnectivityMetricsEvent(long timestamp, int componentTag,
-                                    int eventTag, Parcelable data) {
-        this.timestamp = timestamp;
-        this.componentTag = componentTag;
-        this.eventTag = eventTag;
-        this.data = data;
+    public ConnectivityMetricsEvent() {
+    }
+
+    private ConnectivityMetricsEvent(Parcel in) {
+        timestamp = in.readLong();
+        transports = in.readLong();
+        netId = in.readInt();
+        ifname = in.readString();
+        data = in.readParcelable(null);
     }
 
     /** Implement the Parcelable interface */
     public static final Parcelable.Creator<ConnectivityMetricsEvent> CREATOR
             = new Parcelable.Creator<ConnectivityMetricsEvent> (){
         public ConnectivityMetricsEvent createFromParcel(Parcel source) {
-            final long timestamp = source.readLong();
-            final int componentTag = source.readInt();
-            final int eventTag = source.readInt();
-            final Parcelable data = source.readParcelable(null);
-            return new ConnectivityMetricsEvent(timestamp, componentTag,
-                    eventTag, data);
+            return new ConnectivityMetricsEvent(source);
         }
 
         public ConnectivityMetricsEvent[] newArray(int size) {
@@ -59,7 +60,6 @@
         }
     };
 
-    /** Implement the Parcelable interface */
     @Override
     public int describeContents() {
         return 0;
@@ -68,13 +68,15 @@
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeLong(timestamp);
-        dest.writeInt(componentTag);
-        dest.writeInt(eventTag);
+        dest.writeLong(transports);
+        dest.writeInt(netId);
+        dest.writeString(ifname);
         dest.writeParcelable(data, 0);
     }
 
+    @Override
     public String toString() {
-        return String.format("ConnectivityMetricsEvent(%tT.%tL, %d, %d): %s",
-                timestamp, timestamp, componentTag, eventTag, data);
+        // 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 173e5fd..79094c0 100644
--- a/core/java/android/net/metrics/IpConnectivityLog.java
+++ b/core/java/android/net/metrics/IpConnectivityLog.java
@@ -60,21 +60,23 @@
     }
 
     /**
-     * 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 {
-            int left = mService.logEvent(new ConnectivityMetricsEvent(timestamp, 0, 0, data));
+            int left = mService.logEvent(ev);
             return left >= 0;
         } catch (RemoteException e) {
             Log.e(TAG, "Error logging event", e);
@@ -82,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/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/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/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index a0d16bc..dac8354 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -44,7 +44,6 @@
 import android.util.DisplayMetrics;
 import android.util.Pair;
 import android.view.View;
-
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -8913,11 +8912,15 @@
          * ambiguous then the activity should prompt the user for the recipient to send the message
          * to.
          * <p>
+         * Voice Assistant may provide additional information to messaging app about which account
+         * to use for sending a message by populating {@link #EXTRA_SENDER_ACCOUNT_HASH}.
+         * <p>
          * Output: nothing
          *
          * @see #EXTRA_RECIPIENT_CONTACT_URI
          * @see #EXTRA_RECIPIENT_CONTACT_CHAT_ID
          * @see #EXTRA_RECIPIENT_CONTACT_NAME
+         * @see #EXTRA_SENDER_ACCOUNT_HASH
          * @see #METADATA_ACCOUNT_TYPE
          * @see #METADATA_MIMETYPE
          */
@@ -8975,6 +8978,16 @@
                 "android.provider.extra.RECIPIENT_CONTACT_NAME";
 
         /**
+         * This optional extra specifies the hash of the account that should be used by messaging
+         * app for sending voice message with {@link #ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS}. The
+         * value of this extra is a {@code String} and should be the value of {@link
+         * android.accounts.Account#hashCode()} for some account returned by {@link
+         * android.accounts.AccountManager#getAccounts()}.
+         */
+        public static final String EXTRA_SENDER_ACCOUNT_HASH =
+                "android.provider.extra.SENDER_ACCOUNT_HASH";
+
+        /**
          * A string associated with an {@link #ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS} activity
          * describing {@link RawContacts#ACCOUNT_TYPE} for the corresponding Contacts Provider
          * implementation.
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 8a2a14c..391ee83 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5605,10 +5605,10 @@
             "accessibility_web_content_key_bindings";
 
         /**
-         * Setting that specifies whether the display magnification is enabled.
-         * Display magnifications allows the user to zoom in the display content
-         * and is targeted to low vision users. The current magnification scale
-         * is controlled by {@link #ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE}.
+         * Setting that specifies whether the display magnification is enabled via a system-wide
+         * triple tap gesture. Display magnifications allows the user to zoom in the display content
+         * and is targeted to low vision users. The current magnification scale is controlled by
+         * {@link #ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE}.
          *
          * @hide
          */
@@ -5616,11 +5616,23 @@
                 "accessibility_display_magnification_enabled";
 
         /**
+         * Setting that specifies whether the display magnification is enabled via a shortcut
+         * affordance within the system's navigation area. Display magnifications allows the user to
+         * zoom in the display content and is targeted to low vision users. The current
+         * magnification scale is controlled by {@link #ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE}.
+         *
+         * @hide
+         */
+        public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED =
+                "accessibility_display_magnification_navbar_enabled";
+
+        /**
          * Setting that specifies what the display magnification scale is.
          * Display magnifications allows the user to zoom in the display
          * content and is targeted to low vision users. Whether a display
          * magnification is performed is controlled by
-         * {@link #ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED}
+         * {@link #ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED} and
+         * {@link #ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED}
          *
          * @hide
          */
@@ -6950,6 +6962,7 @@
             ACCESSIBILITY_DISPLAY_DALTONIZER,
             ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
             ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
+            ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED,
             ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
             ACCESSIBILITY_SCRIPT_INJECTION,
             ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS,
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/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 1facc10..7e6af11 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -98,31 +98,6 @@
             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);
-
     /*
      * Notify the window manager that an application is relaunching and
      * windows should be prepared for replacement.
@@ -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/ViewStructure.java b/core/java/android/view/ViewStructure.java
index a71b899..38c7738 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -350,7 +350,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 +360,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/WindowManagerInternal.java b/core/java/android/view/WindowManagerInternal.java
index a541a4c..6dbc09c 100644
--- a/core/java/android/view/WindowManagerInternal.java
+++ b/core/java/android/view/WindowManagerInternal.java
@@ -168,6 +168,14 @@
     public abstract void setMagnificationSpec(MagnificationSpec spec);
 
     /**
+     * Set by the accessibility framework to indicate whether the magnifiable regions of the display
+     * should be shown.
+     *
+     * @param show {@code true} to show magnifiable region bounds, {@code false} to hide
+     */
+    public abstract void setForceShowMagnifiableBounds(boolean show);
+
+    /**
      * Obtains the magnification regions.
      *
      * @param magnificationRegion the current magnification region
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index c4f90dc..f036b9c 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -71,10 +71,17 @@
     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 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;
 
     private final Rect mTempRect = new Rect();
 
@@ -121,6 +128,66 @@
     }
 
     /**
+     * Checkes whether autofill is enabled for the current user.
+     *
+     * <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 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) {
+            return;
+        }
+
+        final Rect bounds = mTempRect;
+        view.getBoundsOnScreen(bounds);
+        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.
@@ -139,7 +206,7 @@
 
         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);
@@ -181,7 +248,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);
@@ -224,16 +291,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 notifyVirtualValueChanged(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);
     }
 
@@ -305,15 +372,16 @@
     }
 
     private void startSession(AutofillId id, IBinder windowToken, Rect bounds,
-            AutofillValue value) {
+            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);
+                    mCallback != null, flags);
             final AutofillClient client = getClient();
             if (client != null) {
                 client.resetableStateAvailable();
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index 86a4965..85b05e5 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);
     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/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/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..c5c317d 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -10012,6 +10012,21 @@
 
     // 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) {
         if (value.isText()) {
@@ -10481,6 +10496,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 +10561,11 @@
             case ID_SHARE:
                 shareSelectedText();
                 return true;
+
+            case ID_AUTOFILL:
+                requestAutofill();
+                stopTextActionMode();
+                return true;
         }
         return false;
     }
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/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_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/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.xml b/core/res/res/values/attrs.xml
index b44ebec..4432e3c 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -8380,7 +8380,9 @@
         <!-- Component name of an activity that allows the user to set up this service. -->
         <attr name="setupActivity" format="string" />
         <!-- Component name of an activity that allows the user to modify the settings for this
-             service. -->
+             service.
+             {@deprecated This value is deprecated and not used by the framework starting from API
+                         level 26. Use setupActivity instead.} -->
         <attr name="settingsActivity" />
         <!-- Attribute whether the TV input service can record programs. This value can be changed
              at runtime by calling
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..2897c62 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2815,6 +2815,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..1ed069b 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>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 26d71c3..07cecbc 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2841,11 +2841,13 @@
   <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_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/core/tests/coretests/src/android/database/PageViewCursorTest.java b/core/tests/coretests/src/android/database/PageViewCursorTest.java
new file mode 100644
index 0000000..0be89d5
--- /dev/null
+++ b/core/tests/coretests/src/android/database/PageViewCursorTest.java
@@ -0,0 +1,318 @@
+/*
+ * 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.database;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.annotation.Nullable;
+import android.content.ContentResolver;
+import android.os.Bundle;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+import android.util.MathUtils;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Random;
+
+@RunWith(AndroidJUnit4.class)
+public class PageViewCursorTest {
+
+    private static final int ITEM_COUNT = 20;
+
+    private static final String NAME_COLUMN = "name";
+    private static final String NUM_COLUMN = "num";
+
+    private static final String[] COLUMNS = new String[]{
+      NAME_COLUMN,
+      NUM_COLUMN
+    };
+
+    private static final String[] NAMES = new String[] {
+            "000",
+            "111",
+            "222",
+            "333",
+            "444",
+            "555",
+            "666",
+            "777",
+            "888",
+            "999",
+            "aaa",
+            "bbb",
+            "ccc",
+            "ddd",
+            "eee",
+            "fff",
+            "ggg",
+            "hhh",
+            "iii",
+            "jjj"
+    };
+
+    private MatrixCursor mDelegate;
+    private PageViewCursor mCursor;
+
+    @Before
+    public void setUp() {
+        Random rand = new Random();
+
+        mDelegate = new MatrixCursor(COLUMNS);
+        for (int i = 0; i < ITEM_COUNT; i++) {
+            MatrixCursor.RowBuilder row = mDelegate.newRow();
+            row.add(NAME_COLUMN, NAMES[i]);
+            row.add(NUM_COLUMN, rand.nextInt());
+        }
+
+        mCursor = new PageViewCursor(mDelegate, 10, 5);
+    }
+
+    @Test
+    public void testPage_Size() {
+        assertEquals(5, mCursor.getCount());
+    }
+
+    @Test
+    public void testPage_TotalSize() {
+        assertEquals(ITEM_COUNT, mCursor.getExtras().getInt(ContentResolver.EXTRA_TOTAL_SIZE));
+    }
+
+    @Test
+    public void testPage_OffsetExceedsCursorCount_EffectivelyEmptyCursor() {
+        mCursor = new PageViewCursor(mDelegate, ITEM_COUNT * 2, 5);
+        assertEquals(0, mCursor.getCount());
+    }
+
+    @Test
+    public void testMoveToPosition() {
+        assertTrue(mCursor.moveToPosition(0));
+        assertEquals(NAMES[10], mCursor.getString(0));
+        assertTrue(mCursor.moveToPosition(1));
+        assertEquals(NAMES[11], mCursor.getString(0));
+        assertTrue(mCursor.moveToPosition(4));
+        assertEquals(NAMES[14], mCursor.getString(0));
+
+        // and then back down again for good measure.
+        assertTrue(mCursor.moveToPosition(1));
+        assertEquals(NAMES[11], mCursor.getString(0));
+        assertTrue(mCursor.moveToPosition(0));
+        assertEquals(NAMES[10], mCursor.getString(0));
+    }
+
+    @Test
+    public void testMoveToPosition_MoveToSamePosition_NoOp() {
+        assertTrue(mCursor.moveToPosition(1));
+        assertEquals(NAMES[11], mCursor.getString(0));
+        assertTrue(mCursor.moveToPosition(1));
+        assertEquals(NAMES[11], mCursor.getString(0));
+    }
+
+    @Test
+    public void testMoveToPosition_PositionOutOfBounds_MovesToBeforeFirst() {
+        assertTrue(mCursor.moveToPosition(0));
+        assertEquals(NAMES[10], mCursor.getString(0));
+
+        // move before
+        assertFalse(mCursor.moveToPosition(-12));
+        assertTrue(mCursor.isBeforeFirst());
+    }
+
+    @Test
+    public void testMoveToPosition_PositionOutOfBounds_MovesToAfterLast() {
+        assertTrue(mCursor.moveToPosition(0));
+        assertEquals(NAMES[10], mCursor.getString(0));
+
+        assertFalse(mCursor.moveToPosition(222));
+        assertTrue(mCursor.isAfterLast());
+    }
+
+    @Test
+    public void testPosition() {
+        assertEquals(-1, mCursor.getPosition());
+    }
+
+    @Test
+    public void testIsBeforeFirst() {
+        assertTrue(mCursor.isBeforeFirst());
+        mCursor.moveToFirst();
+        assertFalse(mCursor.isBeforeFirst());
+    }
+
+    @Test
+    public void testCount_ZeroForEmptyCursor() {
+        mCursor = new PageViewCursor(mDelegate, 0, 0);
+        assertEquals(0, mCursor.getCount());
+    }
+
+    @Test
+    public void testIsBeforeFirst_TrueForEmptyCursor() {
+        mCursor = new PageViewCursor(mDelegate, 0, 0);
+        assertTrue(mCursor.isBeforeFirst());
+    }
+
+    @Test
+    public void testIsAfterLast() {
+        assertFalse(mCursor.isAfterLast());
+        mCursor.moveToLast();
+        mCursor.moveToNext();
+        assertTrue(mCursor.isAfterLast());
+    }
+
+    @Test
+    public void testIsAfterLast_TrueForEmptyCursor() {
+        mCursor = new PageViewCursor(mDelegate, 0, 0);
+        assertTrue(mCursor.isAfterLast());
+    }
+
+    @Test
+    public void testIsFirst() {
+        assertFalse(mCursor.isFirst());
+        mCursor.moveToFirst();
+        assertTrue(mCursor.isFirst());
+    }
+
+    @Test
+    public void testIsLast() {
+        assertFalse(mCursor.isLast());
+        mCursor.moveToLast();
+        assertTrue(mCursor.isLast());
+    }
+
+    @Test
+    public void testMove() {
+        // note that initial position is -1, so moving
+        // 2 will only put as at 1.
+        mCursor.move(2);
+        assertEquals(NAMES[11], mCursor.getString(0));
+        mCursor.move(-1);
+        assertEquals(NAMES[10], mCursor.getString(0));
+    }
+
+    @Test
+    public void testMoveToFist() {
+        mCursor.moveToPosition(3);
+        mCursor.moveToFirst();
+        assertEquals(NAMES[10], mCursor.getString(0));
+    }
+
+    @Test
+    public void testMoveToLast() {
+        mCursor.moveToLast();
+        assertEquals(NAMES[14], mCursor.getString(0));
+    }
+
+    @Test
+    public void testMoveToNext() {
+        // default position is -1, so next is 0.
+        mCursor.moveToNext();
+        assertEquals(NAMES[10], mCursor.getString(0));
+    }
+
+    @Test
+    public void testMoveToNext_AfterLastReturnsFalse() {
+        mCursor.moveToLast();
+        assertFalse(mCursor.moveToNext());
+    }
+
+    @Test
+    public void testMoveToPrevious() {
+        mCursor.moveToPosition(3);
+        mCursor.moveToPrevious();
+        assertEquals(NAMES[12], mCursor.getString(0));
+    }
+
+    @Test
+    public void testMoveToPrevious_BeforeFirstReturnsFalse() {
+        assertFalse(mCursor.moveToPrevious());
+    }
+
+    @Test
+    public void testWindow_ReadPastEnd() {
+        assertFalse(mCursor.moveToPosition(10));
+    }
+
+    @Test
+    public void testOffset_LimitOutOfBounds() {
+        mCursor = new PageViewCursor(mDelegate, 5, 100);
+        assertEquals(15, mCursor.getCount());
+    }
+
+    @Test
+    public void testPagingMarker() {
+        mCursor = new PageViewCursor(mDelegate, 5, 100);
+        assertTrue(mCursor.getExtras().getBoolean(PageViewCursor.EXTRA_AUTO_PAGED));
+    }
+
+    @Test
+    public void testWrap() {
+        Bundle queryArgs = new Bundle();
+        queryArgs.putInt(ContentResolver.QUERY_ARG_OFFSET, 5);
+        queryArgs.putInt(ContentResolver.QUERY_ARG_LIMIT, 5);
+        Cursor wrapped = PageViewCursor.wrap(mDelegate, queryArgs);
+        assertTrue(wrapped instanceof PageViewCursor);
+        assertEquals(5, wrapped.getCount());
+    }
+
+    @Test
+    public void testWrap_NoOpWithoutPagingArgs() {
+        Cursor wrapped = PageViewCursor.wrap(mDelegate, Bundle.EMPTY);
+        assertTrue(mDelegate == wrapped);
+    }
+
+    @Test
+    public void testWrap_NoOpCursorsWithExistingPaging_ByTotalSize() {
+        Bundle extras = new Bundle();
+        extras.putInt(ContentResolver.EXTRA_TOTAL_SIZE, 5);
+        mDelegate.setExtras(extras);
+
+        Bundle queryArgs = new Bundle();
+        queryArgs.putInt(ContentResolver.QUERY_ARG_OFFSET, 5);
+        queryArgs.putInt(ContentResolver.QUERY_ARG_LIMIT, 5);
+        Cursor wrapped = PageViewCursor.wrap(mDelegate, queryArgs);
+        assertTrue(mDelegate == wrapped);
+    }
+
+    @Test
+    public void testWrap_NoOpCursorsWithExistingPaging_ByHonoredArgs() {
+        Bundle extras = new Bundle();
+        extras.putStringArray(
+                ContentResolver.EXTRA_HONORED_ARGS,
+                new String[] {
+                    ContentResolver.QUERY_ARG_OFFSET,
+                    ContentResolver.QUERY_ARG_LIMIT
+                });
+        mDelegate.setExtras(extras);
+
+        Bundle queryArgs = new Bundle();
+        queryArgs.putInt(ContentResolver.QUERY_ARG_OFFSET, 5);
+        queryArgs.putInt(ContentResolver.QUERY_ARG_LIMIT, 5);
+        Cursor wrapped = PageViewCursor.wrap(mDelegate, queryArgs);
+        assertTrue(mDelegate == wrapped);
+    }
+
+    private void assertStringAt(int row, int column, String expected) {
+        mCursor.moveToPosition(row);
+        assertEquals(expected, mCursor.getString(column));
+    }
+}
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/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/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/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 39184f1..0906ba5 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -677,7 +677,7 @@
              ((audioSource > MediaRecorder.getAudioSourceMax()) &&
               (audioSource != MediaRecorder.AudioSource.RADIO_TUNER) &&
               (audioSource != MediaRecorder.AudioSource.HOTWORD)) )  {
-            throw new IllegalArgumentException("Invalid audio source.");
+            throw new IllegalArgumentException("Invalid audio source " + audioSource);
         }
         mRecordSource = audioSource;
 
@@ -703,8 +703,8 @@
             mAudioFormat = audioFormat;
             break;
         default:
-            throw new IllegalArgumentException("Unsupported sample encoding."
-                    + " Should be ENCODING_PCM_8BIT, ENCODING_PCM_16BIT, or ENCODING_PCM_FLOAT.");
+            throw new IllegalArgumentException("Unsupported sample encoding " + audioFormat
+                    + ". Should be ENCODING_PCM_8BIT, ENCODING_PCM_16BIT, or ENCODING_PCM_FLOAT.");
         }
     }
 
@@ -722,7 +722,8 @@
         int frameSizeInBytes = mChannelCount
             * (AudioFormat.getBytesPerSample(mAudioFormat));
         if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) {
-            throw new IllegalArgumentException("Invalid audio buffer size.");
+            throw new IllegalArgumentException("Invalid audio buffer size " + audioBufferSize
+                    + " (frame size " + frameSizeInBytes + ")");
         }
 
         mNativeBufferSizeInBytes = audioBufferSize;
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/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index 35988d4..a292b8e 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -138,7 +138,6 @@
 
     // Attributes from XML meta data.
     private final String mSetupActivity;
-    private final String mSettingsActivity;
     private final boolean mCanRecord;
     private final int mTunerCount;
 
@@ -259,9 +258,8 @@
 
     private TvInputInfo(ResolveInfo service, String id, int type, boolean isHardwareInput,
             CharSequence label, int labelResId, Icon icon, Icon iconStandby, Icon iconDisconnected,
-            String setupActivity, String settingsActivity, boolean canRecord, int tunerCount,
-            HdmiDeviceInfo hdmiDeviceInfo, boolean isConnectedToHdmiSwitch, String parentId,
-            Bundle extras) {
+            String setupActivity, boolean canRecord, int tunerCount, HdmiDeviceInfo hdmiDeviceInfo,
+            boolean isConnectedToHdmiSwitch, String parentId, Bundle extras) {
         mService = service;
         mId = id;
         mType = type;
@@ -272,7 +270,6 @@
         mIconStandby = iconStandby;
         mIconDisconnected = iconDisconnected;
         mSetupActivity = setupActivity;
-        mSettingsActivity = settingsActivity;
         mCanRecord = canRecord;
         mTunerCount = tunerCount;
         mHdmiDeviceInfo = hdmiDeviceInfo;
@@ -340,14 +337,12 @@
 
     /**
      * Returns an intent to start the settings activity for this TV input.
+     *
+     * @deprecated Use {@link #createSetupIntent()} instead. Settings activity is deprecated.
+     *             Use setup activity instead to provide settings.
      */
+    @Deprecated
     public Intent createSettingsIntent() {
-        if (!TextUtils.isEmpty(mSettingsActivity)) {
-            Intent intent = new Intent(Intent.ACTION_MAIN);
-            intent.setClassName(mService.serviceInfo.packageName, mSettingsActivity);
-            intent.putExtra(EXTRA_INPUT_ID, getId());
-            return intent;
-        }
         return null;
     }
 
@@ -554,7 +549,6 @@
                 && Objects.equals(mIconStandby, obj.mIconStandby)
                 && Objects.equals(mIconDisconnected, obj.mIconDisconnected)
                 && TextUtils.equals(mSetupActivity, obj.mSetupActivity)
-                && TextUtils.equals(mSettingsActivity, obj.mSettingsActivity)
                 && mCanRecord == obj.mCanRecord
                 && mTunerCount == obj.mTunerCount
                 && Objects.equals(mHdmiDeviceInfo, obj.mHdmiDeviceInfo)
@@ -589,7 +583,6 @@
         dest.writeParcelable(mIconStandby, flags);
         dest.writeParcelable(mIconDisconnected, flags);
         dest.writeString(mSetupActivity);
-        dest.writeString(mSettingsActivity);
         dest.writeByte(mCanRecord ? (byte) 1 : 0);
         dest.writeInt(mTunerCount);
         dest.writeParcelable(mHdmiDeviceInfo, flags);
@@ -631,7 +624,6 @@
         mIconStandby = in.readParcelable(null);
         mIconDisconnected = in.readParcelable(null);
         mSetupActivity = in.readString();
-        mSettingsActivity = in.readString();
         mCanRecord = in.readByte() == 1;
         mTunerCount = in.readInt();
         mHdmiDeviceInfo = in.readParcelable(null);
@@ -678,7 +670,6 @@
         private Icon mIconStandby;
         private Icon mIconDisconnected;
         private String mSetupActivity;
-        private String mSettingsActivity;
         private Boolean mCanRecord;
         private Integer mTunerCount;
         private TvInputHardwareInfo mTvInputHardwareInfo;
@@ -906,7 +897,7 @@
             }
             parseServiceMetadata(type);
             return new TvInputInfo(mResolveInfo, id, type, isHardwareInput, mLabel, mLabelResId,
-                    mIcon, mIconStandby, mIconDisconnected, mSetupActivity, mSettingsActivity,
+                    mIcon, mIconStandby, mIconDisconnected, mSetupActivity,
                     mCanRecord == null ? false : mCanRecord, mTunerCount == null ? 0 : mTunerCount,
                     mHdmiDeviceInfo, isConnectedToHdmiSwitch, mParentId, mExtras);
         }
@@ -961,8 +952,6 @@
                 if (inputType == TYPE_TUNER && TextUtils.isEmpty(mSetupActivity)) {
                     throw new IllegalStateException("Setup activity not found for " + si.name);
                 }
-                mSettingsActivity = sa.getString(
-                        com.android.internal.R.styleable.TvInputService_settingsActivity);
                 if (mCanRecord == null) {
                     mCanRecord = sa.getBoolean(
                             com.android.internal.R.styleable.TvInputService_canRecord, false);
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/CarrierDefaultApp/AndroidManifest.xml b/packages/CarrierDefaultApp/AndroidManifest.xml
index 2e642ec..8df194c 100644
--- a/packages/CarrierDefaultApp/AndroidManifest.xml
+++ b/packages/CarrierDefaultApp/AndroidManifest.xml
@@ -25,7 +25,6 @@
     <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
     <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
     <uses-permission android:name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS" />
-    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
     <uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
 
     <application android:label="@string/app_name" >
@@ -34,10 +33,16 @@
                 <action android:name="com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED" />
             </intent-filter>
         </receiver>
-        <activity android:name="com.android.carrierdefaultapp.CaptivePortalLaunchActivity"
-            android:theme="@android:style/Theme.Translucent.NoTitleBar"
-            android:excludeFromRecents="true"/>
         <service android:name="com.android.carrierdefaultapp.ProvisionObserver"
                  android:permission="android.permission.BIND_JOB_SERVICE"/>
+        <activity
+            android:name="com.android.carrierdefaultapp.CaptivePortalLoginActivity"
+            android:label="@string/action_bar_label"
+            android:theme="@style/AppTheme"
+            android:configChanges="keyboardHidden|orientation|screenSize" >
+            <intent-filter>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
diff --git a/packages/CarrierDefaultApp/assets/quantum_ic_warning_amber_96.png b/packages/CarrierDefaultApp/assets/quantum_ic_warning_amber_96.png
new file mode 100644
index 0000000..08294ce
--- /dev/null
+++ b/packages/CarrierDefaultApp/assets/quantum_ic_warning_amber_96.png
Binary files differ
diff --git a/packages/CarrierDefaultApp/res/drawable/ic_sim_card.xml b/packages/CarrierDefaultApp/res/drawable/ic_sim_card.xml
index dc54fe2..75aa405 100644
--- a/packages/CarrierDefaultApp/res/drawable/ic_sim_card.xml
+++ b/packages/CarrierDefaultApp/res/drawable/ic_sim_card.xml
@@ -22,4 +22,4 @@
 <path
     android:fillColor="#757575"
     android:pathData="M18,2h-8L4.02,8 4,20c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,4c0,-1.1 -0.9,-2 -2,-2zM13,17h-2v-2h2v2zM13,13h-2L11,8h2v5z"/>
-</vector>
\ No newline at end of file
+</vector>
diff --git a/packages/CarrierDefaultApp/res/layout/activity_captive_portal_login.xml b/packages/CarrierDefaultApp/res/layout/activity_captive_portal_login.xml
new file mode 100644
index 0000000..528576b
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/layout/activity_captive_portal_login.xml
@@ -0,0 +1,34 @@
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context="com.android.carrierdefaultapp.CaptivePortalLoginActivity"
+    tools:ignore="MergeRootFrame">
+    <LinearLayout
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical" >
+
+    <TextView
+        android:id="@+id/url_bar"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:textSize="20sp"
+        android:singleLine="true" />
+
+    <ProgressBar
+        android:id="@+id/progress_bar"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        style="?android:attr/progressBarStyleHorizontal" />
+
+    <WebView
+        android:id="@+id/webview"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_alignParentBottom="false"
+        android:layout_alignParentRight="false" />
+
+</LinearLayout>
+</FrameLayout>
diff --git a/packages/CarrierDefaultApp/res/values/dimens.xml b/packages/CarrierDefaultApp/res/values/dimens.xml
index a3c5049..1ea8c35 100644
--- a/packages/CarrierDefaultApp/res/values/dimens.xml
+++ b/packages/CarrierDefaultApp/res/values/dimens.xml
@@ -1,3 +1,6 @@
 <resources>
     <dimen name="glif_icon_size">32dp</dimen>
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values/strings.xml b/packages/CarrierDefaultApp/res/values/strings.xml
index f904600..f9342b7 100644
--- a/packages/CarrierDefaultApp/res/values/strings.xml
+++ b/packages/CarrierDefaultApp/res/values/strings.xml
@@ -6,9 +6,8 @@
     <string name="no_data_notification_id">Your mobile data has been deactivated</string>
     <string name="portal_notification_detail">Tap to visit the %s website</string>
     <string name="no_data_notification_detail">Please contact your service provider %s</string>
-    <string name="progress_dialogue_network_connection">Connecting to captive portal...</string>
-    <string name="alert_dialogue_network_timeout">Network timeout, would you like to retry?</string>
-    <string name="alert_dialogue_network_timeout_title">Network unavailable</string>
-    <string name="quit">Quit</string>
-    <string name="wait">Wait</string>
+    <string name="action_bar_label">Sign in to mobile network</string>
+    <string name="ssl_error_warning">The network you&#8217;re trying to join has security issues.</string>
+    <string name="ssl_error_example">For example, the login page may not belong to the organization shown.</string>
+    <string name="ssl_error_continue">Continue anyway via browser</string>
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values/styles.xml b/packages/CarrierDefaultApp/res/values/styles.xml
index 3d26915..939c1aa 100644
--- a/packages/CarrierDefaultApp/res/values/styles.xml
+++ b/packages/CarrierDefaultApp/res/values/styles.xml
@@ -1,3 +1,16 @@
 <resources>
-    <style name="AlertDialog" parent="android:Theme.Material.Light.Dialog.Alert"/>
+    <style name="AppBaseTheme" parent="@android:style/Theme.Material.Settings">
+        <!--
+            Theme customizations available in newer API levels can go in
+            res/values-vXX/styles.xml, while customizations related to
+            backward-compatibility can go here.
+        -->
+    </style>
+
+    <!-- Application theme. -->
+    <style name="AppTheme" parent="AppBaseTheme">
+        <!-- All customizations that are NOT specific to a particular API-level can go here. -->
+        <!-- Setting's theme's accent color makes ProgressBar useless, reset back. -->
+        <item name="android:colorAccent">@*android:color/material_deep_teal_500</item>
+    </style>
 </resources>
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLaunchActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLaunchActivity.java
deleted file mode 100644
index 28251cb..0000000
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLaunchActivity.java
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.carrierdefaultapp;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.ProgressDialog;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.net.CaptivePortal;
-import android.net.ConnectivityManager;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.net.NetworkRequest;
-import android.os.Bundle;
-import android.telephony.CarrierConfigManager;
-import android.telephony.Rlog;
-import android.telephony.SubscriptionManager;
-import android.text.TextUtils;
-import android.net.ICaptivePortal;
-import android.view.ContextThemeWrapper;
-import android.view.WindowManager;
-import com.android.carrierdefaultapp.R;
-import com.android.internal.telephony.PhoneConstants;
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.util.ArrayUtils;
-
-import static android.net.CaptivePortal.APP_RETURN_DISMISSED;
-
-/**
- * Activity that launches in response to the captive portal notification
- * @see com.android.carrierdefaultapp.CarrierActionUtils#CARRIER_ACTION_SHOW_PORTAL_NOTIFICATION
- * This activity requests network connection if there is no available one, launches the
- * {@link com.android.captiveportallogin portalApp} and keeps track of the portal activation result.
- */
-public class CaptivePortalLaunchActivity extends Activity {
-    private static final String TAG = CaptivePortalLaunchActivity.class.getSimpleName();
-    private static final boolean DBG = true;
-    public static final int NETWORK_REQUEST_TIMEOUT_IN_MS = 5 * 1000;
-
-    private ConnectivityManager mCm = null;
-    private ConnectivityManager.NetworkCallback mCb = null;
-    /* Progress dialogue when request network connection for captive portal */
-    private AlertDialog mProgressDialog = null;
-    /* Alert dialogue when network request is timeout */
-    private AlertDialog mAlertDialog = null;
-
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        mCm = ConnectivityManager.from(this);
-        // Check network connection before loading portal
-        Network network = getNetworkForCaptivePortal();
-        NetworkInfo nwInfo = mCm.getNetworkInfo(network);
-        if (nwInfo == null || !nwInfo.isConnected()) {
-            if (DBG) logd("Network unavailable, request restricted connection");
-            requestNetwork(getIntent());
-        } else {
-            launchCaptivePortal(getIntent(), network);
-        }
-    }
-
-    // show progress dialog during network connecting
-    private void showConnectingProgressDialog() {
-        mProgressDialog = new ProgressDialog(getApplicationContext());
-        mProgressDialog.setMessage(getString(R.string.progress_dialogue_network_connection));
-        mProgressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
-        mProgressDialog.show();
-    }
-
-    // if network request is timeout, show alert dialog with two option: cancel & wait
-    private void showConnectionTimeoutAlertDialog() {
-        mAlertDialog = new AlertDialog.Builder(new ContextThemeWrapper(this, R.style.AlertDialog))
-                .setMessage(getString(R.string.alert_dialogue_network_timeout))
-                .setTitle(getString(R.string.alert_dialogue_network_timeout_title))
-                .setNegativeButton(getString(R.string.quit),
-                        new DialogInterface.OnClickListener() {
-                            @Override
-                            public void onClick(DialogInterface dialog, int which) {
-                                // cancel
-                                dismissDialog(mAlertDialog);
-                                finish();
-                            }
-                        })
-                .setPositiveButton(getString(R.string.wait),
-                        new DialogInterface.OnClickListener() {
-                            @Override
-                            public void onClick(DialogInterface dialog, int which) {
-                                // wait, request network again
-                                dismissDialog(mAlertDialog);
-                                requestNetwork(getIntent());
-                            }
-                        })
-                .create();
-        mAlertDialog.show();
-    }
-
-    private void requestNetwork(final Intent intent) {
-        NetworkRequest request = new NetworkRequest.Builder()
-                .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
-                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-                .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
-                .build();
-
-        mCb = new ConnectivityManager.NetworkCallback() {
-            @Override
-            public void onAvailable(Network network) {
-                if (DBG) logd("Network available: " + network);
-                dismissDialog(mProgressDialog);
-                mCm.bindProcessToNetwork(network);
-                launchCaptivePortal(intent, network);
-            }
-
-            @Override
-            public void onUnavailable() {
-                if (DBG) logd("Network unavailable");
-                dismissDialog(mProgressDialog);
-                showConnectionTimeoutAlertDialog();
-            }
-        };
-        showConnectingProgressDialog();
-        mCm.requestNetwork(request, mCb, NETWORK_REQUEST_TIMEOUT_IN_MS);
-    }
-
-    private void releaseNetworkRequest() {
-        logd("release Network Request");
-        if (mCb != null) {
-            mCm.unregisterNetworkCallback(mCb);
-            mCb = null;
-        }
-    }
-
-    private void dismissDialog(AlertDialog dialog) {
-        if (dialog != null) {
-            dialog.dismiss();
-        }
-    }
-
-    private Network getNetworkForCaptivePortal() {
-        Network[] info = mCm.getAllNetworks();
-        if (!ArrayUtils.isEmpty(info)) {
-            for (Network nw : info) {
-                final NetworkCapabilities nc = mCm.getNetworkCapabilities(nw);
-                if (nc.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
-                        && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
-                    return nw;
-                }
-            }
-        }
-        return null;
-    }
-
-    private void launchCaptivePortal(final Intent intent, Network network) {
-        String redirectUrl = intent.getStringExtra(TelephonyIntents.EXTRA_REDIRECTION_URL_KEY);
-        int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
-                SubscriptionManager.getDefaultVoiceSubscriptionId());
-        if (TextUtils.isEmpty(redirectUrl) || !matchUrl(redirectUrl, subId)) {
-            loge("Launch portal fails due to incorrect redirection URL: " +
-                    Rlog.pii(TAG, redirectUrl));
-            return;
-        }
-        final Intent portalIntent = new Intent(ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN);
-        portalIntent.putExtra(ConnectivityManager.EXTRA_NETWORK, network);
-        portalIntent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL,
-                new CaptivePortal(new ICaptivePortal.Stub() {
-                    @Override
-                    public void appResponse(int response) {
-                        logd("portal response code: " + response);
-                        releaseNetworkRequest();
-                        if (response == APP_RETURN_DISMISSED) {
-                            // Upon success http response code, trigger re-evaluation
-                            CarrierActionUtils.applyCarrierAction(
-                                    CarrierActionUtils.CARRIER_ACTION_ENABLE_RADIO, intent,
-                                    getApplicationContext());
-                            CarrierActionUtils.applyCarrierAction(
-                                    CarrierActionUtils.CARRIER_ACTION_ENABLE_METERED_APNS, intent,
-                                    getApplicationContext());
-                            CarrierActionUtils.applyCarrierAction(
-                                    CarrierActionUtils.CARRIER_ACTION_CANCEL_ALL_NOTIFICATIONS,
-                                    intent, getApplicationContext());
-                        }
-                    }
-                }));
-        portalIntent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL, redirectUrl);
-        portalIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK
-                        | Intent.FLAG_ACTIVITY_CLEAR_TASK);
-        if (DBG) logd("launching portal");
-        startActivity(portalIntent);
-        finish();
-    }
-
-    // match configured redirection url
-    private boolean matchUrl(String url, int subId) {
-        CarrierConfigManager configManager = getApplicationContext()
-                .getSystemService(CarrierConfigManager.class);
-        String[] redirectURLs = configManager.getConfigForSubId(subId).getStringArray(
-                CarrierConfigManager.KEY_CARRIER_DEFAULT_REDIRECTION_URL_STRING_ARRAY);
-        if (ArrayUtils.isEmpty(redirectURLs)) {
-            if (DBG) logd("match is unnecessary without any configured redirection url");
-            return true;
-        }
-        for (String redirectURL : redirectURLs) {
-            if (url.startsWith(redirectURL)) {
-                return true;
-            }
-        }
-        if (DBG) loge("no match found for configured redirection url");
-        return false;
-    }
-
-    private static void logd(String s) {
-        Rlog.d(TAG, s);
-    }
-
-    private static void loge(String s) {
-        Rlog.d(TAG, s);
-    }
-}
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
new file mode 100644
index 0000000..a5820f2
--- /dev/null
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
@@ -0,0 +1,434 @@
+/*
+ * 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.carrierdefaultapp;
+
+import android.app.Activity;
+import android.app.LoadedApk;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
+import android.net.Proxy;
+import android.net.TrafficStats;
+import android.net.Uri;
+import android.net.http.SslError;
+import android.os.Bundle;
+import android.telephony.CarrierConfigManager;
+import android.telephony.Rlog;
+import android.telephony.SubscriptionManager;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.TypedValue;
+import android.webkit.SslErrorHandler;
+import android.webkit.WebChromeClient;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.util.ArrayUtils;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Random;
+
+/**
+ * Activity that launches in response to the captive portal notification
+ * @see com.android.carrierdefaultapp.CarrierActionUtils#CARRIER_ACTION_SHOW_PORTAL_NOTIFICATION
+ * This activity requests network connection if there is no available one before loading the real
+ * portal page and apply carrier actions on the portal activation result.
+ */
+public class CaptivePortalLoginActivity extends Activity {
+    private static final String TAG = CaptivePortalLoginActivity.class.getSimpleName();
+    private static final boolean DBG = true;
+
+    private static final int SOCKET_TIMEOUT_MS = 10 * 1000;
+    public static final int NETWORK_REQUEST_TIMEOUT_MS = 5 * 1000;
+
+    private URL mUrl;
+    private Network mNetwork;
+    private NetworkCallback mNetworkCallback;
+    private ConnectivityManager mCm;
+    private WebView mWebView;
+    private MyWebViewClient mWebViewClient;
+    private boolean mLaunchBrowser = false;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mCm = ConnectivityManager.from(this);
+        mUrl = getUrlForCaptivePortal();
+        if (mUrl == null) {
+            done(false);
+            return;
+        }
+        if (DBG) logd(String.format("onCreate for %s", mUrl.toString()));
+        setContentView(R.layout.activity_captive_portal_login);
+        getActionBar().setDisplayShowHomeEnabled(false);
+
+        mWebView = (WebView) findViewById(R.id.webview);
+        mWebView.clearCache(true);
+        WebSettings webSettings = mWebView.getSettings();
+        webSettings.setJavaScriptEnabled(true);
+        webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE);
+        mWebViewClient = new MyWebViewClient();
+        mWebView.setWebViewClient(mWebViewClient);
+        mWebView.setWebChromeClient(new MyWebChromeClient());
+
+        mNetwork = getNetworkForCaptivePortal();
+        if (mNetwork == null) {
+            requestNetworkForCaptivePortal();
+        } else {
+            mCm.bindProcessToNetwork(mNetwork);
+            // Start initial page load so WebView finishes loading proxy settings.
+            // Actual load of mUrl is initiated by MyWebViewClient.
+            mWebView.loadData("", "text/html", null);
+        }
+    }
+
+    @Override
+    public void onBackPressed() {
+        WebView myWebView = (WebView) findViewById(R.id.webview);
+        if (myWebView.canGoBack() && mWebViewClient.allowBack()) {
+            myWebView.goBack();
+        } else {
+            super.onBackPressed();
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        releaseNetworkRequest();
+        if (mLaunchBrowser) {
+            // Give time for this network to become default. After 500ms just proceed.
+            for (int i = 0; i < 5; i++) {
+                // TODO: This misses when mNetwork underlies a VPN.
+                if (mNetwork.equals(mCm.getActiveNetwork())) break;
+                try {
+                    Thread.sleep(100);
+                } catch (InterruptedException e) {
+                }
+            }
+            final String url = mUrl.toString();
+            if (DBG) logd("starting activity with intent ACTION_VIEW for " + url);
+            startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
+        }
+    }
+
+    // Find WebView's proxy BroadcastReceiver and prompt it to read proxy system properties.
+    private void setWebViewProxy() {
+        LoadedApk loadedApk = getApplication().mLoadedApk;
+        try {
+            Field receiversField = LoadedApk.class.getDeclaredField("mReceivers");
+            receiversField.setAccessible(true);
+            ArrayMap receivers = (ArrayMap) receiversField.get(loadedApk);
+            for (Object receiverMap : receivers.values()) {
+                for (Object rec : ((ArrayMap) receiverMap).keySet()) {
+                    Class clazz = rec.getClass();
+                    if (clazz.getName().contains("ProxyChangeListener")) {
+                        Method onReceiveMethod = clazz.getDeclaredMethod("onReceive", Context.class,
+                                Intent.class);
+                        Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
+                        onReceiveMethod.invoke(rec, getApplicationContext(), intent);
+                        Log.v(TAG, "Prompting WebView proxy reload.");
+                    }
+                }
+            }
+        } catch (Exception e) {
+            loge("Exception while setting WebView proxy: " + e);
+        }
+    }
+
+    private void done(boolean success) {
+        if (DBG) logd(String.format("Result success %b for %s", success, mUrl.toString()));
+        if (success) {
+            // Trigger re-evaluation upon success http response code
+            CarrierActionUtils.applyCarrierAction(
+                    CarrierActionUtils.CARRIER_ACTION_ENABLE_RADIO, getIntent(),
+                    getApplicationContext());
+            CarrierActionUtils.applyCarrierAction(
+                    CarrierActionUtils.CARRIER_ACTION_ENABLE_METERED_APNS, getIntent(),
+                    getApplicationContext());
+            CarrierActionUtils.applyCarrierAction(
+                    CarrierActionUtils.CARRIER_ACTION_CANCEL_ALL_NOTIFICATIONS, getIntent(),
+                    getApplicationContext());
+
+        }
+        finishAndRemoveTask();
+    }
+
+    private URL getUrlForCaptivePortal() {
+        String url = getIntent().getStringExtra(TelephonyIntents.EXTRA_REDIRECTION_URL_KEY);
+        if (url.isEmpty()) {
+            url = mCm.getCaptivePortalServerUrl();
+        }
+        final CarrierConfigManager configManager = getApplicationContext()
+                .getSystemService(CarrierConfigManager.class);
+        final int subId = getIntent().getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
+                SubscriptionManager.getDefaultVoiceSubscriptionId());
+        final String[] portalURLs = configManager.getConfigForSubId(subId).getStringArray(
+                CarrierConfigManager.KEY_CARRIER_DEFAULT_REDIRECTION_URL_STRING_ARRAY);
+        if (!ArrayUtils.isEmpty(portalURLs)) {
+            for (String portalUrl : portalURLs) {
+                if (url.startsWith(portalUrl)) {
+                    break;
+                }
+            }
+            url = null;
+        }
+        try {
+            return new URL(url);
+        } catch (MalformedURLException e) {
+            loge("Invalid captive portal URL " + url);
+        }
+        return null;
+    }
+
+    private void testForCaptivePortal() {
+        new Thread(new Runnable() {
+            public void run() {
+                // Give time for captive portal to open.
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                }
+                HttpURLConnection urlConnection = null;
+                int httpResponseCode = 500;
+                int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_PROBE);
+                try {
+                    urlConnection = (HttpURLConnection) mNetwork.openConnection(mUrl);
+                    urlConnection.setInstanceFollowRedirects(false);
+                    urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
+                    urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS);
+                    urlConnection.setUseCaches(false);
+                    urlConnection.getInputStream();
+                    httpResponseCode = urlConnection.getResponseCode();
+                } catch (IOException e) {
+                } finally {
+                    if (urlConnection != null) urlConnection.disconnect();
+                    TrafficStats.setThreadStatsTag(oldTag);
+                }
+                if (httpResponseCode == 204) {
+                    done(true);
+                }
+            }
+        }).start();
+    }
+
+    private Network getNetworkForCaptivePortal() {
+        Network[] info = mCm.getAllNetworks();
+        if (!ArrayUtils.isEmpty(info)) {
+            for (Network nw : info) {
+                final NetworkCapabilities nc = mCm.getNetworkCapabilities(nw);
+                if (nc.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
+                        && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
+                    return nw;
+                }
+            }
+        }
+        return null;
+    }
+
+    private void requestNetworkForCaptivePortal() {
+        NetworkRequest request = new NetworkRequest.Builder()
+                .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+                .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+                .build();
+
+        mNetworkCallback = new ConnectivityManager.NetworkCallback() {
+            @Override
+            public void onAvailable(Network network) {
+                if (DBG) logd("Network available: " + network);
+                mCm.bindProcessToNetwork(network);
+                mNetwork = network;
+                runOnUiThreadIfNotFinishing(() -> {
+                    // Start initial page load so WebView finishes loading proxy settings.
+                    // Actual load of mUrl is initiated by MyWebViewClient.
+                    mWebView.loadData("", "text/html", null);
+                });
+            }
+
+            @Override
+            public void onUnavailable() {
+                if (DBG) logd("Network unavailable");
+                runOnUiThreadIfNotFinishing(() -> {
+                    // Instead of not loading anything in webview, simply load the page and return
+                    // HTTP error page in the absence of network connection.
+                    mWebView.loadUrl(mUrl.toString());
+                });
+            }
+        };
+        logd("request Network for captive portal");
+        mCm.requestNetwork(request, mNetworkCallback, NETWORK_REQUEST_TIMEOUT_MS);
+    }
+
+    private void releaseNetworkRequest() {
+        logd("release Network for captive portal");
+        if (mNetworkCallback != null) {
+            mCm.unregisterNetworkCallback(mNetworkCallback);
+            mNetworkCallback = null;
+            mNetwork = null;
+        }
+    }
+
+    private class MyWebViewClient extends WebViewClient {
+        private static final String INTERNAL_ASSETS = "file:///android_asset/";
+        private final String mBrowserBailOutToken = Long.toString(new Random().nextLong());
+        // How many Android device-independent-pixels per scaled-pixel
+        // dp/sp = (px/sp) / (px/dp) = (1/sp) / (1/dp)
+        private final float mDpPerSp = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 1,
+                    getResources().getDisplayMetrics())
+                / TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1,
+                    getResources().getDisplayMetrics());
+        private int mPagesLoaded;
+
+        // If we haven't finished cleaning up the history, don't allow going back.
+        public boolean allowBack() {
+            return mPagesLoaded > 1;
+        }
+
+        @Override
+        public void onPageStarted(WebView view, String url, Bitmap favicon) {
+            if (url.contains(mBrowserBailOutToken)) {
+                mLaunchBrowser = true;
+                done(false);
+                return;
+            }
+            // The first page load is used only to cause the WebView to
+            // fetch the proxy settings.  Don't update the URL bar, and
+            // don't check if the captive portal is still there.
+            if (mPagesLoaded == 0) return;
+            // For internally generated pages, leave URL bar listing prior URL as this is the URL
+            // the page refers to.
+            if (!url.startsWith(INTERNAL_ASSETS)) {
+                final TextView myUrlBar = (TextView) findViewById(R.id.url_bar);
+                myUrlBar.setText(url);
+            }
+            if (mNetwork != null) {
+                testForCaptivePortal();
+            }
+        }
+
+        @Override
+        public void onPageFinished(WebView view, String url) {
+            mPagesLoaded++;
+            if (mPagesLoaded == 1) {
+                // Now that WebView has loaded at least one page we know it has read in the proxy
+                // settings.  Now prompt the WebView read the Network-specific proxy settings.
+                setWebViewProxy();
+                // Load the real page.
+                view.loadUrl(mUrl.toString());
+                return;
+            } else if (mPagesLoaded == 2) {
+                // Prevent going back to empty first page.
+                view.clearHistory();
+            }
+            if (mNetwork != null) {
+                testForCaptivePortal();
+            }
+        }
+
+        // Convert Android device-independent-pixels (dp) to HTML size.
+        private String dp(int dp) {
+            // HTML px's are scaled just like dp's, so just add "px" suffix.
+            return Integer.toString(dp) + "px";
+        }
+
+        // Convert Android scaled-pixels (sp) to HTML size.
+        private String sp(int sp) {
+            // Convert sp to dp's.
+            float dp = sp * mDpPerSp;
+            // Apply a scale factor to make things look right.
+            dp *= 1.3;
+            // Convert dp's to HTML size.
+            return dp((int) dp);
+        }
+
+        // A web page consisting of a large broken lock icon to indicate SSL failure.
+        private final String SSL_ERROR_HTML = "<html><head><style>"
+                + "body { margin-left:" + dp(48) + "; margin-right:" + dp(48) + "; "
+                + "margin-top:" + dp(96) + "; background-color:#fafafa; }"
+                + "img { width:" + dp(48) + "; height:" + dp(48) + "; }"
+                + "div.warn { font-size:" + sp(16) + "; margin-top:" + dp(16) + "; "
+                + "           opacity:0.87; line-height:1.28; }"
+                + "div.example { font-size:" + sp(14) + "; margin-top:" + dp(16) + "; "
+                + "              opacity:0.54; line-height:1.21905; }"
+                + "a { font-size:" + sp(14) + "; text-decoration:none; text-transform:uppercase; "
+                + "    margin-top:" + dp(24) + "; display:inline-block; color:#4285F4; "
+                + "    height:" + dp(48) + "; font-weight:bold; }"
+                + "</style></head><body><p><img src=quantum_ic_warning_amber_96.png><br>"
+                + "<div class=warn>%s</div>"
+                + "<div class=example>%s</div>" + "<a href=%s>%s</a></body></html>";
+
+        @Override
+        public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
+            Log.w(TAG, "SSL error (error: " + error.getPrimaryError() + " host: "
+                    // Only show host to avoid leaking private info.
+                    + Uri.parse(error.getUrl()).getHost() + " certificate: "
+                    + error.getCertificate() + "); displaying SSL warning.");
+            final String html = String.format(SSL_ERROR_HTML, getString(R.string.ssl_error_warning),
+                    getString(R.string.ssl_error_example), mBrowserBailOutToken,
+                    getString(R.string.ssl_error_continue));
+            view.loadDataWithBaseURL(INTERNAL_ASSETS, html, "text/HTML", "UTF-8", null);
+        }
+
+        @Override
+        public boolean shouldOverrideUrlLoading(WebView view, String url) {
+            if (url.startsWith("tel:")) {
+                startActivity(new Intent(Intent.ACTION_DIAL, Uri.parse(url)));
+                return true;
+            }
+            return false;
+        }
+    }
+
+    private class MyWebChromeClient extends WebChromeClient {
+        @Override
+        public void onProgressChanged(WebView view, int newProgress) {
+            final ProgressBar myProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
+            myProgressBar.setProgress(newProgress);
+        }
+    }
+
+    private void runOnUiThreadIfNotFinishing(Runnable r) {
+        if (!isFinishing()) {
+            runOnUiThread(r);
+        }
+    }
+
+    private static void logd(String s) {
+        Rlog.d(TAG, s);
+    }
+
+    private static void loge(String s) {
+        Rlog.d(TAG, s);
+    }
+
+}
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java
index d9bd2fc..73ff3a9 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java
@@ -112,8 +112,10 @@
         logd("onShowCaptivePortalNotification");
         final NotificationManager notificationMgr = context.getSystemService(
                 NotificationManager.class);
-        Intent portalIntent = new Intent(context, CaptivePortalLaunchActivity.class);
+        Intent portalIntent = new Intent(context, CaptivePortalLoginActivity.class);
         portalIntent.putExtras(intent);
+        portalIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT
+                | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
         PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, portalIntent,
                 PendingIntent.FLAG_UPDATE_CURRENT);
         Notification notification = getNotification(context, R.string.portal_notification_id,
diff --git a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/LaunchCaptivePortalActivityTest.java b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/LaunchCaptivePortalActivityTest.java
deleted file mode 100644
index 8a18d72..0000000
--- a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/LaunchCaptivePortalActivityTest.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package com.android.carrierdefaultapp;
-
-import android.annotation.TargetApi;
-import android.content.Intent;
-import android.net.ConnectivityManager;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.net.NetworkRequest;
-
-import com.android.internal.telephony.TelephonyIntents;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.atLeast;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-public class LaunchCaptivePortalActivityTest extends
-        CarrierDefaultActivityTestCase<CaptivePortalLaunchActivity> {
-
-    @Mock
-    private ConnectivityManager mCm;
-    @Mock
-    private NetworkInfo mNetworkInfo;
-    @Mock
-    private Network mNetwork;
-
-    @Captor
-    private ArgumentCaptor<Integer> mInt;
-    @Captor
-    private ArgumentCaptor<NetworkRequest> mNetworkReq;
-
-    private NetworkCapabilities mNetworkCapabilities;
-
-    public LaunchCaptivePortalActivityTest() {
-        super(CaptivePortalLaunchActivity.class);
-    }
-
-    @Before
-    public void setUp() throws Exception {
-        super.setUp();
-        injectSystemService(ConnectivityManager.class, mCm);
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        super.tearDown();
-    }
-
-    @Override
-    protected Intent createActivityIntent() {
-        Intent intent = new Intent(getInstrumentation().getTargetContext(),
-                CaptivePortalLaunchActivity.class);
-        intent.putExtra(TelephonyIntents.EXTRA_REDIRECTION_URL_KEY, "url");
-        return intent;
-    }
-
-    @Test
-    public void testWithoutInternetConnection() throws Throwable {
-        startActivity();
-        TestContext.waitForMs(100);
-        verify(mCm, atLeast(1)).requestNetwork(mNetworkReq.capture(), any(), mInt.capture());
-        // verify network request
-        assert(mNetworkReq.getValue().networkCapabilities.hasCapability(
-                NetworkCapabilities.NET_CAPABILITY_INTERNET));
-        assert(mNetworkReq.getValue().networkCapabilities.hasTransport(
-                NetworkCapabilities.TRANSPORT_CELLULAR));
-        assertFalse(mNetworkReq.getValue().networkCapabilities.hasCapability(
-                NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED));
-        assertEquals(CaptivePortalLaunchActivity.NETWORK_REQUEST_TIMEOUT_IN_MS,
-                (int) mInt.getValue());
-        // verify captive portal app is not launched due to unavailable network
-        assertNull(getStartedActivityIntent());
-        stopActivity();
-    }
-
-    @Test
-    public void testWithInternetConnection() throws Throwable {
-        // Mock internet connection
-        mNetworkCapabilities = new NetworkCapabilities()
-                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-                .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
-        doReturn(new Network[]{mNetwork}).when(mCm).getAllNetworks();
-        doReturn(mNetworkCapabilities).when(mCm).getNetworkCapabilities(eq(mNetwork));
-        doReturn(mNetworkInfo).when(mCm).getNetworkInfo(eq(mNetwork));
-        doReturn(true).when(mNetworkInfo).isConnected();
-
-        startActivity();
-        TestContext.waitForMs(100);
-        // verify there is no network request with internet connection
-        verify(mCm, times(0)).requestNetwork(any(), any(), anyInt());
-        // verify captive portal app is launched
-        assertNotNull(getStartedActivityIntent());
-        assertEquals(ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN,
-                getStartedActivityIntent().getAction());
-        stopActivity();
-    }
-}
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..c64574f 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 -->
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/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/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..0547cbb 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -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);
@@ -398,6 +400,7 @@
     }
 
     private void updateDismissFraction(float fraction) {
+        setVisible(true);
         int alpha;
         if (mMenuVisible) {
             mMenuContainer.setAlpha(1-fraction);
@@ -416,6 +419,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/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index c0fb4d5..198cb9e 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,7 @@
     }
 
     private final Callback mKeyguardCallback = () -> {
-        if (Dependency.get(KeyguardMonitor.class).isShowing()) {
+        if (Dependency.get(KeyguardMonitor.class).isShowing() && !mOpening) {
             hide(0, 0);
         }
     };
@@ -237,11 +239,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/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/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 8a3c4e3..2b52b48 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -35,6 +35,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.res.Configuration;
+import android.database.ContentObserver;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.inputmethodservice.InputMethodService;
@@ -46,6 +47,7 @@
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.support.annotation.VisibleForTesting;
 import android.telecom.TelecomManager;
 import android.text.TextUtils;
@@ -104,6 +106,7 @@
     private int mNavigationIconHints = 0;
     private int mNavigationBarMode;
     private AccessibilityManager mAccessibilityManager;
+    private MagnificationContentObserver mMagnificationObserver;
 
     private int mDisabledFlags1;
     private StatusBar mStatusBar;
@@ -135,6 +138,12 @@
         mAccessibilityManager = getContext().getSystemService(AccessibilityManager.class);
         mAccessibilityManager.addAccessibilityServicesStateChangeListener(
                 this::updateAccessibilityServicesState);
+        mMagnificationObserver = new MagnificationContentObserver(
+                getContext().getMainThreadHandler());
+        getContext().getContentResolver().registerContentObserver(Settings.Secure.getUriFor(
+                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED), false,
+                mMagnificationObserver);
+
         if (savedInstanceState != null) {
             mDisabledFlags1 = savedInstanceState.getInt(EXTRA_DISABLE_STATE, 0);
         }
@@ -154,6 +163,7 @@
         mCommandQueue.removeCallbacks(this);
         mAccessibilityManager.removeAccessibilityServicesStateChangeListener(
                 this::updateAccessibilityServicesState);
+        getContext().getContentResolver().unregisterContentObserver(mMagnificationObserver);
         try {
             WindowManagerGlobal.getWindowManagerService()
                     .removeRotationWatcher(mRotationWatcher);
@@ -387,6 +397,7 @@
         ButtonDispatcher accessibilityButton = mNavigationBarView.getAccessibilityButton();
         accessibilityButton.setOnClickListener(this::onAccessibilityClick);
         accessibilityButton.setOnLongClickListener(this::onAccessibilityLongClick);
+        updateAccessibilityServicesState();
     }
 
     private boolean onHomeTouch(View v, MotionEvent event) {
@@ -550,10 +561,18 @@
     }
 
     private void updateAccessibilityServicesState() {
+        int requestingServices = 0;
+        try {
+            if (Settings.Secure.getInt(getContext().getContentResolver(),
+                    Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED) == 1) {
+                requestingServices++;
+            }
+        } catch (Settings.SettingNotFoundException e) {
+        }
+
         final List<AccessibilityServiceInfo> services =
                 mAccessibilityManager.getEnabledAccessibilityServiceList(
                         AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
-        int requestingServices = 0;
         for (int i = services.size() - 1; i >= 0; --i) {
             AccessibilityServiceInfo info = services.get(i);
             if ((info.flags & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0) {
@@ -600,6 +619,18 @@
         mNavigationBarView.getBarTransitions().finishAnimations();
     }
 
+    private class MagnificationContentObserver extends ContentObserver {
+
+        public MagnificationContentObserver(Handler handler) {
+            super(handler);
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            NavigationBarFragment.this.updateAccessibilityServicesState();
+        }
+    }
+
     private final Stub mRotationWatcher = new Stub() {
         @Override
         public void onRotationChanged(int rotation) throws RemoteException {
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..10ff8ad 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) \
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 03582ea..58e020f 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -1180,7 +1180,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 +3227,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
@@ -3604,6 +3604,74 @@
     // ACTION: Settings > Search > Click saved queries
     ACTION_CLICK_SETTINGS_SEARCH_SAVED_QUERY = 881;
 
+    // OPEN: Settings > Security & screen lock -> Lock screen preferences
+    // 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;
+
     // ---- End O Constants, all O constants go above this line ----
 
     // Add new aosp constants above this line.
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index fd93865..9e4d89c 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -77,9 +77,6 @@
      */
     static final int FLAG_FEATURE_INJECT_MOTION_EVENTS = 0x00000010;
 
-    static final int FEATURES_AFFECTING_MOTION_EVENTS = FLAG_FEATURE_INJECT_MOTION_EVENTS
-            | FLAG_FEATURE_AUTOCLICK | FLAG_FEATURE_TOUCH_EXPLORATION
-            | FLAG_FEATURE_SCREEN_MAGNIFIER;
     /**
      * Flag for enabling the feature to control the screen magnifier. If
      * {@link #FLAG_FEATURE_SCREEN_MAGNIFIER} is set this flag is ignored
@@ -90,6 +87,16 @@
      */
     static final int FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER = 0x00000020;
 
+    /**
+     * Flag for enabling the feature to trigger the screen magnifier
+     * from another on-device interaction.
+     */
+    static final int FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER = 0x00000040;
+
+    static final int FEATURES_AFFECTING_MOTION_EVENTS = FLAG_FEATURE_INJECT_MOTION_EVENTS
+            | FLAG_FEATURE_AUTOCLICK | FLAG_FEATURE_TOUCH_EXPLORATION
+            | FLAG_FEATURE_SCREEN_MAGNIFIER | FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER;
+
     private final Runnable mProcessBatchedEventsRunnable = new Runnable() {
         @Override
         public void run() {
@@ -379,6 +386,12 @@
         }
     }
 
+    void notifyAccessibilityButtonClicked() {
+        if (mMagnificationGestureHandler != null) {
+            mMagnificationGestureHandler.notifyShortcutTriggered();
+        }
+    }
+
     private void enableFeatures() {
         resetStreamState();
 
@@ -393,11 +406,14 @@
         }
 
         if ((mEnabledFeatures & FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER) != 0
-                || (mEnabledFeatures  & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0) {
+                || ((mEnabledFeatures & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0)
+                || ((mEnabledFeatures & FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER) != 0)) {
             final boolean detectControlGestures = (mEnabledFeatures
                     & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0;
+            final boolean triggerable = (mEnabledFeatures
+                    & FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER) != 0;
             mMagnificationGestureHandler = new MagnificationGestureHandler(
-                    mContext, mAms, detectControlGestures);
+                    mContext, mAms, detectControlGestures, triggerable);
             addFirstEventHandler(mMagnificationGestureHandler);
         }
 
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 98ce00e..397938a 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -781,6 +781,7 @@
                 userState.mIsTouchExplorationEnabled = false;
                 userState.mIsEnhancedWebAccessibilityEnabled = false;
                 userState.mIsDisplayMagnificationEnabled = false;
+                userState.mIsNavBarMagnificationEnabled = false;
                 userState.mIsAutoclickEnabled = false;
                 userState.mEnabledServices.clear();
             }
@@ -831,6 +832,7 @@
             userState.mIsTouchExplorationEnabled = touchExplorationEnabled;
             userState.mIsEnhancedWebAccessibilityEnabled = false;
             userState.mIsDisplayMagnificationEnabled = false;
+            userState.mIsNavBarMagnificationEnabled = false;
             userState.mIsAutoclickEnabled = false;
             userState.mEnabledServices.clear();
             userState.mEnabledServices.add(service);
@@ -1152,11 +1154,16 @@
 
     private void notifyAccessibilityButtonClickedLocked() {
         final UserState state = getCurrentUserStateLocked();
-        for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
-            final Service service = state.mBoundServices.get(i);
-            // TODO(b/34720082): Only notify a single user-defined service
-            if (service.mRequestAccessibilityButton) {
-                service.notifyAccessibilityButtonClickedLocked();
+        if (state.mIsNavBarMagnificationEnabled) {
+            mMainHandler.obtainMessage(
+                    MainHandler.MSG_SEND_ACCESSIBILITY_BUTTON_TO_INPUT_FILTER).sendToTarget();
+        } else {
+            for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
+                final Service service = state.mBoundServices.get(i);
+                // TODO(b/34720082): Only notify a single user-defined service
+                if (service.mRequestAccessibilityButton) {
+                    service.notifyAccessibilityButtonClickedLocked();
+                }
             }
         }
     }
@@ -1548,6 +1555,9 @@
             if (userState.mIsDisplayMagnificationEnabled) {
                 flags |= AccessibilityInputFilter.FLAG_FEATURE_SCREEN_MAGNIFIER;
             }
+            if (userState.mIsNavBarMagnificationEnabled) {
+                flags |= AccessibilityInputFilter.FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER;
+            }
             if (userHasMagnificationServicesLocked(userState)) {
                 flags |= AccessibilityInputFilter.FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER;
             }
@@ -1781,7 +1791,7 @@
         somethingChanged |= readTouchExplorationEnabledSettingLocked(userState);
         somethingChanged |= readHighTextContrastEnabledSettingLocked(userState);
         somethingChanged |= readEnhancedWebAccessibilityEnabledChangedLocked(userState);
-        somethingChanged |= readDisplayMagnificationEnabledSettingLocked(userState);
+        somethingChanged |= readMagnificationEnabledSettingsLocked(userState);
         somethingChanged |= readAutoclickEnabledSettingLocked(userState);
         somethingChanged |= readAccessibilityShortcutSettingLocked(userState);
         return somethingChanged;
@@ -1810,13 +1820,19 @@
         return false;
     }
 
-    private boolean readDisplayMagnificationEnabledSettingLocked(UserState userState) {
+    private boolean readMagnificationEnabledSettingsLocked(UserState userState) {
         final boolean displayMagnificationEnabled = Settings.Secure.getIntForUser(
                 mContext.getContentResolver(),
                 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
                 0, userState.mUserId) == 1;
-        if (displayMagnificationEnabled != userState.mIsDisplayMagnificationEnabled) {
+        final boolean navBarMagnificationEnabled = Settings.Secure.getIntForUser(
+                mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED,
+                0, userState.mUserId) == 1;
+        if ((displayMagnificationEnabled != userState.mIsDisplayMagnificationEnabled)
+                || (navBarMagnificationEnabled != userState.mIsNavBarMagnificationEnabled)) {
             userState.mIsDisplayMagnificationEnabled = displayMagnificationEnabled;
+            userState.mIsNavBarMagnificationEnabled = navBarMagnificationEnabled;
             return true;
         }
         return false;
@@ -2018,8 +2034,8 @@
             return;
         }
 
-        if (userState.mIsDisplayMagnificationEnabled ||
-                userHasListeningMagnificationServicesLocked(userState)) {
+        if (userState.mIsDisplayMagnificationEnabled || userState.mIsNavBarMagnificationEnabled
+                || userHasListeningMagnificationServicesLocked(userState)) {
             // Initialize the magnification controller if necessary
             getMagnificationController();
             mMagnificationController.register();
@@ -2241,6 +2257,8 @@
                 pw.append(", touchExplorationEnabled=" + userState.mIsTouchExplorationEnabled);
                 pw.append(", displayMagnificationEnabled="
                         + userState.mIsDisplayMagnificationEnabled);
+                pw.append(", navBarMagnificationEnabled="
+                        + userState.mIsNavBarMagnificationEnabled);
                 pw.append(", autoclickEnabled=" + userState.mIsAutoclickEnabled);
                 if (userState.mUiAutomationService != null) {
                     pw.append(", ");
@@ -2320,6 +2338,7 @@
         public static final int MSG_SEND_SERVICES_STATE_CHANGED_TO_CLIENTS = 10;
         public static final int MSG_UPDATE_FINGERPRINT = 11;
         public static final int MSG_SEND_RELEVANT_EVENTS_CHANGED_TO_CLIENTS = 12;
+        public static final int MSG_SEND_ACCESSIBILITY_BUTTON_TO_INPUT_FILTER = 13;
 
         public MainHandler(Looper looper) {
             super(looper);
@@ -2406,6 +2425,14 @@
                         }
                     });
                 } break;
+
+               case MSG_SEND_ACCESSIBILITY_BUTTON_TO_INPUT_FILTER: {
+                    synchronized (mLock) {
+                        if (mHasInputFilter && mInputFilter != null) {
+                            mInputFilter.notifyAccessibilityButtonClicked();
+                        }
+                    }
+                }
             }
         }
 
@@ -4788,6 +4815,7 @@
         public boolean mIsTextHighContrastEnabled;
         public boolean mIsEnhancedWebAccessibilityEnabled;
         public boolean mIsDisplayMagnificationEnabled;
+        public boolean mIsNavBarMagnificationEnabled;
         public boolean mIsAutoclickEnabled;
         public boolean mIsPerformGesturesEnabled;
         public boolean mIsFilterKeyEventsEnabled;
@@ -4856,6 +4884,7 @@
             mIsTouchExplorationEnabled = false;
             mIsEnhancedWebAccessibilityEnabled = false;
             mIsDisplayMagnificationEnabled = false;
+            mIsNavBarMagnificationEnabled = false;
             mIsAutoclickEnabled = false;
             mSoftKeyboardShowMode = 0;
 
@@ -4888,6 +4917,9 @@
         private final Uri mDisplayMagnificationEnabledUri = Settings.Secure.getUriFor(
                 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED);
 
+        private final Uri mNavBarMagnificationEnabledUri = Settings.Secure.getUriFor(
+                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED);
+
         private final Uri mAutoclickEnabledUri = Settings.Secure.getUriFor(
                 Settings.Secure.ACCESSIBILITY_AUTOCLICK_ENABLED);
 
@@ -4927,6 +4959,8 @@
                     false, this, UserHandle.USER_ALL);
             contentResolver.registerContentObserver(mDisplayMagnificationEnabledUri,
                     false, this, UserHandle.USER_ALL);
+            contentResolver.registerContentObserver(mNavBarMagnificationEnabledUri,
+                    false, this, UserHandle.USER_ALL);
             contentResolver.registerContentObserver(mAutoclickEnabledUri,
                     false, this, UserHandle.USER_ALL);
             contentResolver.registerContentObserver(mEnabledAccessibilityServicesUri,
@@ -4966,8 +5000,9 @@
                     if (readTouchExplorationEnabledSettingLocked(userState)) {
                         onUserStateChangedLocked(userState);
                     }
-                } else if (mDisplayMagnificationEnabledUri.equals(uri)) {
-                    if (readDisplayMagnificationEnabledSettingLocked(userState)) {
+                } else if (mDisplayMagnificationEnabledUri.equals(uri)
+                        || mNavBarMagnificationEnabledUri.equals(uri)) {
+                    if (readMagnificationEnabledSettingsLocked(userState)) {
                         onUserStateChangedLocked(userState);
                     }
                 } else if (mAutoclickEnabledUri.equals(uri)) {
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
index f65046c..caa74b9 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
@@ -685,6 +685,12 @@
         }
     }
 
+    void setForceShowMagnifiableBounds(boolean show) {
+        if (mRegistered) {
+            mWindowManager.setForceShowMagnifiableBounds(show);
+        }
+    }
+
     private void getMagnifiedFrameInContentCoordsLocked(Rect outFrame) {
         final float scale = getSentScale();
         final float offsetX = getSentOffsetX();
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
index f6e5340..7e82eda 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
@@ -16,7 +16,10 @@
 
 package com.android.server.accessibility;
 
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.os.Handler;
 import android.os.Message;
 import android.util.MathUtils;
@@ -57,22 +60,30 @@
  *    be the same but when the finger goes up the screen will stay magnified.
  *    In other words, the initial magnified state is sticky.
  *
- * 3. Pinching with any number of additional fingers when viewport dragging
+ * 3. Magnification can optionally be "triggered" by some external shortcut
+ *    affordance. When this occurs via {@link #notifyShortcutTriggered()} a
+ *    subsequent tap in a magnifiable region will engage permanent screen
+ *    magnification as described in #1. Alternatively, a subsequent long-press
+ *    or drag will engage magnification with viewport dragging as described in
+ *    #2. Once magnified, all following behaviors apply whether magnification
+ *    was engaged via a triple-tap or by a triggered shortcut.
+ *
+ * 4. Pinching with any number of additional fingers when viewport dragging
  *    is enabled, i.e. the user triple tapped and holds, would adjust the
  *    magnification scale which will become the current default magnification
  *    scale. The next time the user magnifies the same magnification scale
  *    would be used.
  *
- * 4. When in a permanent magnified state the user can use two or more fingers
+ * 5. When in a permanent magnified state the user can use two or more fingers
  *    to pan the viewport. Note that in this mode the content is panned as
  *    opposed to the viewport dragging mode in which the viewport is moved.
  *
- * 5. When in a permanent magnified state the user can use two or more
+ * 6. When in a permanent magnified state the user can use two or more
  *    fingers to change the magnification scale which will become the current
  *    default magnification scale. The next time the user magnifies the same
  *    magnification scale would be used.
  *
- * 6. The magnification scale will be persisted in settings and in the cloud.
+ * 7. The magnification scale will be persisted in settings and in the cloud.
  */
 class MagnificationGestureHandler implements EventStreamTransformation {
     private static final String LOG_TAG = "MagnificationEventHandler";
@@ -94,8 +105,10 @@
     private final MagnifiedContentInteractionStateHandler mMagnifiedContentInteractionStateHandler;
     private final StateViewportDraggingHandler mStateViewportDraggingHandler;
 
+    private final ScreenStateReceiver mScreenStateReceiver;
 
-    private final boolean mDetectControlGestures;
+    private final boolean mDetectTripleTap;
+    private final boolean mTriggerable;
 
     private EventStreamTransformation mNext;
 
@@ -104,19 +117,39 @@
 
     private boolean mTranslationEnabledBeforePan;
 
+    private boolean mShortcutTriggered;
+
     private PointerCoords[] mTempPointerCoords;
     private PointerProperties[] mTempPointerProperties;
 
     private long mDelegatingStateDownTime;
 
+    /**
+     * @param context Context for resolving various magnification-related resources
+     * @param ams AccessibilityManagerService used to obtain a {@link MagnificationController}
+     * @param detectTripleTap {@code true} if this detector should detect and respond to triple-tap
+     *                                    gestures for engaging and disengaging magnification,
+     *                                    {@code false} if it should ignore such gestures
+     * @param triggerable {@code true} if this detector should be "triggerable" by some external
+     *                                shortcut invoking {@link #notifyShortcutTriggered}, {@code
+     *                                false} if it should ignore such triggers.
+     */
     public MagnificationGestureHandler(Context context, AccessibilityManagerService ams,
-            boolean detectControlGestures) {
+            boolean detectTripleTap, boolean triggerable) {
         mMagnificationController = ams.getMagnificationController();
         mDetectingStateHandler = new DetectingStateHandler(context);
         mStateViewportDraggingHandler = new StateViewportDraggingHandler();
         mMagnifiedContentInteractionStateHandler =
                 new MagnifiedContentInteractionStateHandler(context);
-        mDetectControlGestures = detectControlGestures;
+        mDetectTripleTap = detectTripleTap;
+        mTriggerable = triggerable;
+
+        if (triggerable) {
+            mScreenStateReceiver = new ScreenStateReceiver(context, this);
+            mScreenStateReceiver.register();
+        } else {
+            mScreenStateReceiver = null;
+        }
 
         transitionToState(STATE_DETECTING);
     }
@@ -129,7 +162,7 @@
             }
             return;
         }
-        if (!mDetectControlGestures) {
+        if (!mDetectTripleTap && !mTriggerable) {
             if (mNext != null) {
                 dispatchTransformedEvent(event, rawEvent, policyFlags);
             }
@@ -151,7 +184,7 @@
             break;
             case STATE_MAGNIFIED_INTERACTION: {
                 // mMagnifiedContentInteractionStateHandler handles events only
-                // if this is the current state since it uses ScaleGestureDetecotr
+                // if this is the current state since it uses ScaleGestureDetector
                 // and a GestureDetector which need well formed event stream.
             }
             break;
@@ -193,11 +226,34 @@
 
     @Override
     public void onDestroy() {
+        if (mScreenStateReceiver != null) {
+            mScreenStateReceiver.unregister();
+        }
         clear();
     }
 
+    void notifyShortcutTriggered() {
+        if (mTriggerable) {
+            if (mMagnificationController.resetIfNeeded(true)) {
+                clear();
+            } else {
+                setMagnificationShortcutTriggered(!mShortcutTriggered);
+            }
+        }
+    }
+
+    private void setMagnificationShortcutTriggered(boolean state) {
+        if (mShortcutTriggered == state) {
+            return;
+        }
+
+        mShortcutTriggered = state;
+        mMagnificationController.setForceShowMagnifiableBounds(state);
+    }
+
     private void clear() {
         mCurrentState = STATE_DETECTING;
+        setMagnificationShortcutTriggered(false);
         mDetectingStateHandler.clear();
         mStateViewportDraggingHandler.clear();
         mMagnifiedContentInteractionStateHandler.clear();
@@ -575,31 +631,51 @@
                     mHandler.removeMessages(MESSAGE_TRANSITION_TO_DELEGATING_STATE);
                     if (!mMagnificationController.magnificationRegionContains(
                             event.getX(), event.getY())) {
-                        transitionToDelegatingStateAndClear();
+                        transitionToDelegatingState(!mShortcutTriggered);
                         return;
                     }
-                    if (mTapCount == ACTION_TAP_COUNT - 1 && mLastDownEvent != null
-                            && GestureUtils.isMultiTap(mLastDownEvent, event,
-                            mMultiTapTimeSlop, mMultiTapDistanceSlop, 0)) {
+                    if (mShortcutTriggered) {
                         Message message = mHandler.obtainMessage(MESSAGE_ON_ACTION_TAP_AND_HOLD,
                                 policyFlags, 0, event);
                         mHandler.sendMessageDelayed(message,
                                 ViewConfiguration.getLongPressTimeout());
-                    } else if (mTapCount < ACTION_TAP_COUNT) {
+                        return;
+                    }
+                    if (mDetectTripleTap) {
+                        if ((mTapCount == ACTION_TAP_COUNT - 1) && (mLastDownEvent != null)
+                                && GestureUtils.isMultiTap(mLastDownEvent, event, mMultiTapTimeSlop,
+                                        mMultiTapDistanceSlop, 0)) {
+                            Message message = mHandler.obtainMessage(MESSAGE_ON_ACTION_TAP_AND_HOLD,
+                                    policyFlags, 0, event);
+                            mHandler.sendMessageDelayed(message,
+                                    ViewConfiguration.getLongPressTimeout());
+                        } else if (mTapCount < ACTION_TAP_COUNT) {
+                            Message message = mHandler.obtainMessage(
+                                    MESSAGE_TRANSITION_TO_DELEGATING_STATE);
+                            mHandler.sendMessageDelayed(message, mMultiTapTimeSlop);
+                        }
+                        clearLastDownEvent();
+                        mLastDownEvent = MotionEvent.obtain(event);
+                    } else if (mMagnificationController.isMagnifying()) {
+                        // If magnified, consume an ACTION_DOWN until mMultiTapTimeSlop or
+                        // mTapDistanceSlop is reached to ensure MAGNIFIED_INTERACTION is reachable.
                         Message message = mHandler.obtainMessage(
                                 MESSAGE_TRANSITION_TO_DELEGATING_STATE);
                         mHandler.sendMessageDelayed(message, mMultiTapTimeSlop);
+                        return;
+                    } else {
+                        transitionToDelegatingState(true);
+                        return;
                     }
-                    clearLastDownEvent();
-                    mLastDownEvent = MotionEvent.obtain(event);
                 }
                 break;
                 case MotionEvent.ACTION_POINTER_DOWN: {
                     if (mMagnificationController.isMagnifying()) {
+                        mHandler.removeMessages(MESSAGE_TRANSITION_TO_DELEGATING_STATE);
                         transitionToState(STATE_MAGNIFIED_INTERACTION);
                         clear();
                     } else {
-                        transitionToDelegatingStateAndClear();
+                        transitionToDelegatingState(true);
                     }
                 }
                 break;
@@ -608,29 +684,34 @@
                         final double distance = GestureUtils.computeDistance(mLastDownEvent,
                                 event, 0);
                         if (Math.abs(distance) > mTapDistanceSlop) {
-                            transitionToDelegatingStateAndClear();
+                            transitionToDelegatingState(true);
                         }
                     }
                 }
                 break;
                 case MotionEvent.ACTION_UP: {
+                    if (!mMagnificationController.magnificationRegionContains(
+                            event.getX(), event.getY())) {
+                        transitionToDelegatingState(!mShortcutTriggered);
+                        return;
+                    }
+                    if (mShortcutTriggered) {
+                        clear();
+                        onActionTap(event, policyFlags);
+                        return;
+                    }
                     if (mLastDownEvent == null) {
                         return;
                     }
                     mHandler.removeMessages(MESSAGE_ON_ACTION_TAP_AND_HOLD);
-                    if (!mMagnificationController.magnificationRegionContains(
-                            event.getX(), event.getY())) {
-                        transitionToDelegatingStateAndClear();
-                        return;
-                    }
                     if (!GestureUtils.isTap(mLastDownEvent, event, mTapTimeSlop,
                             mTapDistanceSlop, 0)) {
-                        transitionToDelegatingStateAndClear();
+                        transitionToDelegatingState(true);
                         return;
                     }
-                    if (mLastTapUpEvent != null && !GestureUtils.isMultiTap(mLastTapUpEvent,
-                            event, mMultiTapTimeSlop, mMultiTapDistanceSlop, 0)) {
-                        transitionToDelegatingStateAndClear();
+                    if (mLastTapUpEvent != null && !GestureUtils.isMultiTap(
+                            mLastTapUpEvent, event, mMultiTapTimeSlop, mMultiTapDistanceSlop, 0)) {
+                        transitionToDelegatingState(true);
                         return;
                     }
                     mTapCount++;
@@ -655,6 +736,7 @@
 
         @Override
         public void clear() {
+            setMagnificationShortcutTriggered(false);
             mHandler.removeMessages(MESSAGE_ON_ACTION_TAP_AND_HOLD);
             mHandler.removeMessages(MESSAGE_TRANSITION_TO_DELEGATING_STATE);
             clearTapDetectionState();
@@ -714,10 +796,12 @@
             }
         }
 
-        private void transitionToDelegatingStateAndClear() {
+        private void transitionToDelegatingState(boolean andClear) {
             transitionToState(STATE_DELEGATING);
             sendDelayedMotionEvents();
-            clear();
+            if (andClear) {
+                clear();
+            }
         }
 
         private void onActionTap(MotionEvent up, int policyFlags) {
@@ -820,4 +904,30 @@
             mPolicyFlags = 0;
         }
     }
+
+    /**
+     * BroadcastReceiver used to cancel the magnification shortcut when the screen turns off
+     */
+    private static class ScreenStateReceiver extends BroadcastReceiver {
+        private final Context mContext;
+        private final MagnificationGestureHandler mGestureHandler;
+
+        public ScreenStateReceiver(Context context, MagnificationGestureHandler gestureHandler) {
+            mContext = context;
+            mGestureHandler = gestureHandler;
+        }
+
+        public void register() {
+            mContext.registerReceiver(this, new IntentFilter(Intent.ACTION_SCREEN_OFF));
+        }
+
+        public void unregister() {
+            mContext.unregisterReceiver(this);
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            mGestureHandler.setMagnificationShortcutTriggered(false);
+        }
+    }
 }
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index a372f95..af1193d 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -316,13 +316,13 @@
         @Override
         public void startSession(IBinder activityToken, IBinder windowToken, IBinder appCallback,
                 AutofillId autofillId, Rect bounds, AutofillValue value, int userId,
-                boolean hasCallback) {
+                boolean hasCallback, int flags) {
             // TODO(b/33197203): make sure it's called by resumed / focused activity
 
             synchronized (mLock) {
                 final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
                 service.startSessionLocked(activityToken, windowToken, appCallback,
-                        autofillId, bounds, value, hasCallback);
+                        autofillId, bounds, value, hasCallback, flags);
             }
         }
 
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 4786cbe..3e5ad82 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -74,7 +74,6 @@
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Map;
 import java.util.Map.Entry;
 
@@ -171,7 +170,7 @@
             structure.sanitizeForParceling(true);
 
             // TODO(b/33197203): Need to pipe the bundle
-            session.mRemoteFillService.onFillRequest(structure, null);
+            session.mRemoteFillService.onFillRequest(structure, null, session.mFlags);
         }
     };
 
@@ -286,7 +285,8 @@
     }
 
     void startSessionLocked(IBinder activityToken, IBinder windowToken, IBinder appCallbackToken,
-            AutofillId autofillId,  Rect bounds, AutofillValue value, boolean hasCallback) {
+            AutofillId autofillId,  Rect bounds, AutofillValue value, boolean hasCallback,
+            int flags) {
         if (!hasService()) {
             return;
         }
@@ -294,7 +294,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 +305,7 @@
         }
 
         final Session newSession = createSessionByTokenLocked(activityToken,
-                windowToken, appCallbackToken, hasCallback);
+                windowToken, appCallbackToken, hasCallback, flags);
         newSession.updateLocked(autofillId, bounds, value, FLAG_START_SESSION);
     }
 
@@ -338,9 +338,9 @@
     }
 
     private Session createSessionByTokenLocked(IBinder activityToken, IBinder windowToken,
-            IBinder appCallbackToken, boolean hasCallback) {
+            IBinder appCallbackToken, boolean hasCallback, int flags) {
         final Session newSession = new Session(mContext, activityToken,
-                windowToken, appCallbackToken, hasCallback);
+                windowToken, appCallbackToken, hasCallback, flags);
         mSessions.put(activityToken, newSession);
 
         /*
@@ -630,13 +630,19 @@
          */
         private boolean mHasCallback;
 
+        /**
+         * Flags used to start the session.
+         */
+        private int mFlags;
+
         private Session(Context context, IBinder activityToken, IBinder windowToken,
-                IBinder client, boolean hasCallback) {
+                IBinder client, boolean hasCallback, int flags) {
             mRemoteFillService = new RemoteFillService(context,
                     mInfo.getServiceInfo().getComponentName(), mUserId, this);
             mActivityToken = activityToken;
             mWindowToken = windowToken;
             mHasCallback = hasCallback;
+            mFlags = flags;
 
             mClient = IAutoFillManagerClient.Stub.asInterface(client);
             try {
@@ -856,7 +862,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;
@@ -1101,6 +1108,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);
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 47251db..b1cc89b 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -132,9 +132,10 @@
         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();
     }
 
@@ -418,11 +419,13 @@
         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,7 +472,7 @@
             if (remoteService != null) {
                 try {
                     remoteService.mAutoFillService.onFillRequest(mStructure,
-                            mExtras, mCallback);
+                            mExtras, mCallback, mFlags);
                     synchronized (mLock) {
                         mStructure = null;
                         mExtras = null;
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..34c73d2 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);
 
@@ -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/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/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/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index be8aaf0..8280946 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -159,6 +159,8 @@
 
 import libcore.io.IoUtils;
 
+import com.google.android.collect.Lists;
+
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.xmlpull.v1.XmlPullParser;
@@ -1658,8 +1660,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 +1676,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 +1720,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();
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/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 7aa96cf..d8900c0 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;
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 4ac1cce..4640d20 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;
@@ -16850,11 +16850,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/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 1510dd1..5abc4e4 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -222,6 +222,14 @@
                 || mWindowsForAccessibilityObserver != null);
     }
 
+    /** NOTE: This has to be called within a surface transaction. */
+    public void setForceShowMagnifiableBoundsLocked(boolean show) {
+        if (mDisplayMagnifier != null) {
+            mDisplayMagnifier.setForceShowMagnifiableBoundsLocked(show);
+            mDisplayMagnifier.drawMagnifiedRegionBorderIfNeededLocked();
+        }
+    }
+
     private static void populateTransformationMatrixLocked(WindowState windowState,
             Matrix outMatrix) {
         sTempFloats[Matrix.MSCALE_X] = windowState.mWinAnimator.mDsDx;
@@ -266,6 +274,8 @@
 
         private final long mLongAnimationDuration;
 
+        private boolean mForceShowMagnifiableBounds = false;
+
         public DisplayMagnifier(WindowManagerService windowManagerService,
                 MagnificationCallbacks callbacks) {
             mContext = windowManagerService.mContext;
@@ -283,6 +293,15 @@
             mWindowManagerService.scheduleAnimationLocked();
         }
 
+        public void setForceShowMagnifiableBoundsLocked(boolean show) {
+            mForceShowMagnifiableBounds = show;
+            mMagnifedViewport.setMagnifiedRegionBorderShownLocked(show, true);
+        }
+
+        public boolean isForceShowingMagnifiableBoundsLocked() {
+            return mForceShowMagnifiableBounds;
+        }
+
         public void onRectangleOnScreenRequestedLocked(Rect rectangle) {
             if (DEBUG_RECTANGLE_REQUESTED) {
                 Slog.i(LOG_TAG, "Rectangle on screen requested: " + rectangle);
@@ -488,7 +507,8 @@
                 // to show the border. We will do so when the pending message is handled.
                 if (!mHandler.hasMessages(
                         MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED)) {
-                    setMagnifiedRegionBorderShownLocked(isMagnifyingLocked(), true);
+                    setMagnifiedRegionBorderShownLocked(
+                            isMagnifyingLocked() || isForceShowingMagnifiableBoundsLocked(), true);
                 }
             }
 
@@ -600,11 +620,11 @@
             }
 
             public void onRotationChangedLocked() {
-                // If we are magnifying, hide the magnified border window immediately so
+                // If we are showing the magnification border, hide it immediately so
                 // the user does not see strange artifacts during rotation. The screenshot
-                // used for rotation has already the border. After the rotation is complete
+                // used for rotation already has the border. After the rotation is complete
                 // we will show the border.
-                if (isMagnifyingLocked()) {
+                if (isMagnifyingLocked() || isForceShowingMagnifiableBoundsLocked()) {
                     setMagnifiedRegionBorderShownLocked(false, false);
                     final long delay = (long) (mLongAnimationDuration
                             * mWindowManagerService.getWindowAnimationScaleLocked());
@@ -926,7 +946,8 @@
 
                     case MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED : {
                         synchronized (mWindowManagerService.mWindowMap) {
-                            if (mMagnifedViewport.isMagnifyingLocked()) {
+                            if (mMagnifedViewport.isMagnifyingLocked()
+                                    || isForceShowingMagnifiableBoundsLocked()) {
                                 mMagnifedViewport.setMagnifiedRegionBorderShownLocked(true, true);
                                 mWindowManagerService.scheduleAnimationLocked();
                             }
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..4df513e 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -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);
     }
@@ -235,10 +228,6 @@
         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/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index b063e01..5551afe 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1808,64 +1808,6 @@
         }
     }
 
-    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,
@@ -2210,23 +2152,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();
 
@@ -7158,6 +7083,17 @@
         }
 
         @Override
+        public void setForceShowMagnifiableBounds(boolean show) {
+            synchronized (mWindowMap) {
+                if (mAccessibilityController != null) {
+                    mAccessibilityController.setForceShowMagnifiableBoundsLocked(show);
+                } else {
+                    throw new IllegalStateException("Magnification callbacks not set!");
+                }
+            }
+        }
+
+        @Override
         public void getMagnificationRegion(@NonNull Region magnificationRegion) {
             synchronized (mWindowMap) {
                 if (mAccessibilityController != null) {
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/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index a8423e2..f84bfef 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;
@@ -1428,11 +1429,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..3e3a19b 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -23,6 +23,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,10 +35,12 @@
 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.text.TextUtils;
 import android.util.LocalLog;
@@ -1027,14 +1030,16 @@
 
     private boolean startIPv6() {
         // Set privacy extensions.
+        final String PREFER_TEMPADDRS = "2";
         try {
-            mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
+            NetdService.run((INetd netd) -> {
+                netd.setProcSysNet(
+                        INetd.IPV6, INetd.CONF, mInterfaceName, "use_tempaddr",
+                        PREFER_TEMPADDRS);
+            });
             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/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/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/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/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 51b91f4..7862523 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -5276,23 +5276,42 @@
         }
     }
 
+
+    /**
+     * @deprecated use {@link #isDataEnabled()} instead.
+     * @hide
+     */
+    @SystemApi
+    @Deprecated
+    public boolean getDataEnabled() {
+        return isDataEnabled();
+    }
+
     /**
      * Returns whether mobile data is enabled or not.
      *
-     * <p>Requires Permission:
-     *     {@link android.Manifest.permission#ACCESS_NETWORK_STATE ACCESS_NETWORK_STATE},
-     *     {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}, or that the
-     *     calling app has carrier privileges.
+     * <p>Requires one of the following permissions:
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE ACCESS_NETWORK_STATE},
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}, or that the
+     * calling app has carrier privileges.
+     *
+     * <p>Note that this does not take into account any data restrictions that may be present on the
+     * calling app. Such restrictions may be inspected with
+     * {@link ConnectivityManager#getRestrictBackgroundStatus}.
      *
      * @return true if mobile data is enabled.
      *
      * @see #hasCarrierPrivileges
      */
-    public boolean getDataEnabled() {
+    @SuppressWarnings("deprecation")
+    public boolean isDataEnabled() {
         return getDataEnabled(getSubId());
     }
 
-    /** @hide */
+    /**
+     * @deprecated use {@link #isDataEnabled(int)} instead.
+     * @hide
+     */
     @SystemApi
     public boolean getDataEnabled(int subId) {
         boolean retVal = false;
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 58511b9..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());
             }
         }
@@ -315,14 +315,15 @@
     }
 
     static ConnectivityMetricsEvent expectedEvent(int timestamp) {
-        return new ConnectivityMetricsEvent((long)timestamp, 0, 0, FAKE_EV);
+        ConnectivityMetricsEvent ev = new ConnectivityMetricsEvent();
+        ev.timestamp = timestamp;
+        ev.data = FAKE_EV;
+        return ev;
     }
 
     /** Outer equality for ConnectivityMetricsEvent to avoid overriding equals() and hashCode(). */
     static void assertEventsEqual(ConnectivityMetricsEvent expected, ConnectivityMetricsEvent got) {
         assertEquals(expected.timestamp, got.timestamp);
-        assertEquals(expected.componentTag, got.componentTag);
-        assertEquals(expected.eventTag, got.eventTag);
         assertEquals(expected.data, got.data);
     }
 
diff --git a/tests/net/java/com/android/server/connectivity/MetricsTestUtil.java b/tests/net/java/com/android/server/connectivity/MetricsTestUtil.java
index c5965e8..5064b9b 100644
--- a/tests/net/java/com/android/server/connectivity/MetricsTestUtil.java
+++ b/tests/net/java/com/android/server/connectivity/MetricsTestUtil.java
@@ -28,7 +28,10 @@
     }
 
     static ConnectivityMetricsEvent ev(Parcelable p) {
-        return new ConnectivityMetricsEvent(1L, 0, 0, p);
+        ConnectivityMetricsEvent ev = new ConnectivityMetricsEvent();
+        ev.timestamp = 1L;
+        ev.data = p;
+        return ev;
     }
 
     static ConnectivityMetricsEvent describeIpEvent(Consumer<Parcel>... fs) {
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/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/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index 7582fda..4dfe47b 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
@@ -96,18 +96,6 @@
     }
 
     @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/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)