Merge "Update configuration to activiy after letterbox."
diff --git a/Android.bp b/Android.bp
index 834c9b0..54b6619 100644
--- a/Android.bp
+++ b/Android.bp
@@ -889,7 +889,12 @@
         "core/java/android/net/IIpMemoryStore.aidl",
         "core/java/android/net/INetworkStackConnector.aidl",
         "core/java/android/net/INetworkStackStatusCallback.aidl",
+        "core/java/android/net/IpPrefixParcelable.aidl",
+        "core/java/android/net/LinkAddressParcelable.aidl",
+        "core/java/android/net/LinkPropertiesParcelable.aidl",
         "core/java/android/net/PrivateDnsConfigParcel.aidl",
+        "core/java/android/net/ProxyInfoParcelable.aidl",
+        "core/java/android/net/RouteInfoParcelable.aidl",
         "core/java/android/net/dhcp/DhcpServingParamsParcel.aidl",
         "core/java/android/net/dhcp/IDhcpServer.aidl",
         "core/java/android/net/dhcp/IDhcpServerCallbacks.aidl",
diff --git a/api/current.txt b/api/current.txt
index 6316ee8..7e7f037 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6784,9 +6784,11 @@
     method public void wipeData(int);
     method public void wipeData(int, java.lang.CharSequence);
     field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
+    field public static final java.lang.String ACTION_ADMIN_POLICY_COMPLIANCE = "android.app.action.ADMIN_POLICY_COMPLIANCE";
     field public static final java.lang.String ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED = "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED";
     field public static final java.lang.String ACTION_DEVICE_ADMIN_SERVICE = "android.app.action.DEVICE_ADMIN_SERVICE";
     field public static final java.lang.String ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED";
+    field public static final java.lang.String ACTION_GET_PROVISIONING_MODE = "android.app.action.GET_PROVISIONING_MODE";
     field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
     field public static final java.lang.String ACTION_PROFILE_OWNER_CHANGED = "android.app.action.PROFILE_OWNER_CHANGED";
     field public static final java.lang.String ACTION_PROVISIONING_SUCCESSFUL = "android.app.action.PROVISIONING_SUCCESSFUL";
@@ -6829,12 +6831,15 @@
     field public static final java.lang.String EXTRA_PROVISIONING_DISCLAIMER_CONTENT = "android.app.extra.PROVISIONING_DISCLAIMER_CONTENT";
     field public static final java.lang.String EXTRA_PROVISIONING_DISCLAIMER_HEADER = "android.app.extra.PROVISIONING_DISCLAIMER_HEADER";
     field public static final deprecated java.lang.String EXTRA_PROVISIONING_EMAIL_ADDRESS = "android.app.extra.PROVISIONING_EMAIL_ADDRESS";
+    field public static final java.lang.String EXTRA_PROVISIONING_IMEI = "android.app.extra.PROVISIONING_IMEI";
     field public static final java.lang.String EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION = "android.app.extra.PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION";
     field public static final java.lang.String EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED = "android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCAL_TIME = "android.app.extra.PROVISIONING_LOCAL_TIME";
     field public static final java.lang.String EXTRA_PROVISIONING_LOGO_URI = "android.app.extra.PROVISIONING_LOGO_URI";
     field public static final java.lang.String EXTRA_PROVISIONING_MAIN_COLOR = "android.app.extra.PROVISIONING_MAIN_COLOR";
+    field public static final java.lang.String EXTRA_PROVISIONING_MODE = "android.app.extra.PROVISIONING_MODE";
+    field public static final java.lang.String EXTRA_PROVISIONING_SERIAL_NUMBER = "android.app.extra.PROVISIONING_SERIAL_NUMBER";
     field public static final java.lang.String EXTRA_PROVISIONING_SKIP_ENCRYPTION = "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
     field public static final java.lang.String EXTRA_PROVISIONING_SKIP_USER_CONSENT = "android.app.extra.PROVISIONING_SKIP_USER_CONSENT";
     field public static final java.lang.String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.PROVISIONING_TIME_ZONE";
@@ -6911,6 +6916,9 @@
     field public static final int PRIVATE_DNS_SET_ERROR_FAILURE_SETTING = 2; // 0x2
     field public static final int PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING = 1; // 0x1
     field public static final int PRIVATE_DNS_SET_SUCCESS = 0; // 0x0
+    field public static final int PROVISIONING_MODE_FULLY_MANAGED_DEVICE = 1; // 0x1
+    field public static final int PROVISIONING_MODE_MANAGED_PROFILE = 2; // 0x2
+    field public static final int PROVISIONING_MODE_MANAGED_PROFILE_ON_FULLY_MANAGED_DEVICE = 3; // 0x3
     field public static final int RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT = 2; // 0x2
     field public static final int RESET_PASSWORD_REQUIRE_ENTRY = 1; // 0x1
     field public static final int SKIP_SETUP_WIZARD = 1; // 0x1
@@ -12282,6 +12290,7 @@
     method public void parseBundleExtra(java.lang.String, android.util.AttributeSet, android.os.Bundle) throws org.xmlpull.v1.XmlPullParserException;
     method public void parseBundleExtras(android.content.res.XmlResourceParser, android.os.Bundle) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public deprecated void updateConfiguration(android.content.res.Configuration, android.util.DisplayMetrics);
+    field public static final int ID_NULL = 0; // 0x0
   }
 
   public static class Resources.NotFoundException extends java.lang.RuntimeException {
@@ -24138,6 +24147,7 @@
     method public int dequeueOutputBuffer(android.media.MediaCodec.BufferInfo, long);
     method protected void finalize();
     method public void flush();
+    method public java.lang.String getCanonicalName();
     method public android.media.MediaCodecInfo getCodecInfo();
     method public java.nio.ByteBuffer getInputBuffer(int);
     method public deprecated java.nio.ByteBuffer[] getInputBuffers();
@@ -24264,10 +24274,15 @@
   }
 
   public final class MediaCodecInfo {
+    method public java.lang.String getCanonicalName();
     method public android.media.MediaCodecInfo.CodecCapabilities getCapabilitiesForType(java.lang.String);
     method public java.lang.String getName();
     method public java.lang.String[] getSupportedTypes();
+    method public boolean isAlias();
     method public boolean isEncoder();
+    method public boolean isHardwareAccelerated();
+    method public boolean isSoftwareOnly();
+    method public boolean isVendor();
   }
 
   public static final class MediaCodecInfo.AudioCapabilities {
@@ -24343,7 +24358,10 @@
     field public static final deprecated int COLOR_QCOM_FormatYUV420SemiPlanar = 2141391872; // 0x7fa30c00
     field public static final deprecated int COLOR_TI_FormatYUV420PackedSemiPlanar = 2130706688; // 0x7f000100
     field public static final java.lang.String FEATURE_AdaptivePlayback = "adaptive-playback";
+    field public static final java.lang.String FEATURE_DynamicTimestamp = "dynamic-timestamp";
+    field public static final java.lang.String FEATURE_FrameParsing = "frame-parsing";
     field public static final java.lang.String FEATURE_IntraRefresh = "intra-refresh";
+    field public static final java.lang.String FEATURE_MultipleFrames = "multiple-frames";
     field public static final java.lang.String FEATURE_PartialFrame = "partial-frame";
     field public static final java.lang.String FEATURE_SecurePlayback = "secure-playback";
     field public static final java.lang.String FEATURE_TunneledPlayback = "tunneled-playback";
@@ -24365,6 +24383,33 @@
     field public static final int AACObjectSSR = 3; // 0x3
     field public static final int AACObjectScalable = 6; // 0x6
     field public static final int AACObjectXHE = 42; // 0x2a
+    field public static final int AV1Level2 = 1; // 0x1
+    field public static final int AV1Level21 = 2; // 0x2
+    field public static final int AV1Level22 = 4; // 0x4
+    field public static final int AV1Level23 = 8; // 0x8
+    field public static final int AV1Level3 = 16; // 0x10
+    field public static final int AV1Level31 = 32; // 0x20
+    field public static final int AV1Level32 = 64; // 0x40
+    field public static final int AV1Level33 = 128; // 0x80
+    field public static final int AV1Level4 = 256; // 0x100
+    field public static final int AV1Level41 = 512; // 0x200
+    field public static final int AV1Level42 = 1024; // 0x400
+    field public static final int AV1Level43 = 2048; // 0x800
+    field public static final int AV1Level5 = 4096; // 0x1000
+    field public static final int AV1Level51 = 8192; // 0x2000
+    field public static final int AV1Level52 = 16384; // 0x4000
+    field public static final int AV1Level53 = 32768; // 0x8000
+    field public static final int AV1Level6 = 65536; // 0x10000
+    field public static final int AV1Level61 = 131072; // 0x20000
+    field public static final int AV1Level62 = 262144; // 0x40000
+    field public static final int AV1Level63 = 524288; // 0x80000
+    field public static final int AV1Level7 = 1048576; // 0x100000
+    field public static final int AV1Level71 = 2097152; // 0x200000
+    field public static final int AV1Level72 = 4194304; // 0x400000
+    field public static final int AV1Level73 = 8388608; // 0x800000
+    field public static final int AV1Profile0 = 1; // 0x1
+    field public static final int AV1Profile1 = 2; // 0x2
+    field public static final int AV1Profile2 = 4; // 0x4
     field public static final int AVCLevel1 = 1; // 0x1
     field public static final int AVCLevel11 = 4; // 0x4
     field public static final int AVCLevel12 = 8; // 0x8
@@ -24382,6 +24427,9 @@
     field public static final int AVCLevel5 = 16384; // 0x4000
     field public static final int AVCLevel51 = 32768; // 0x8000
     field public static final int AVCLevel52 = 65536; // 0x10000
+    field public static final int AVCLevel6 = 131072; // 0x20000
+    field public static final int AVCLevel61 = 262144; // 0x40000
+    field public static final int AVCLevel62 = 524288; // 0x80000
     field public static final int AVCProfileBaseline = 1; // 0x1
     field public static final int AVCProfileConstrainedBaseline = 65536; // 0x10000
     field public static final int AVCProfileConstrainedHigh = 524288; // 0x80000
@@ -24544,12 +24592,53 @@
     method public android.util.Range<java.lang.Double> getSupportedFrameRatesFor(int, int);
     method public android.util.Range<java.lang.Integer> getSupportedHeights();
     method public android.util.Range<java.lang.Integer> getSupportedHeightsFor(int);
+    method public java.util.List<android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint> getSupportedPerformancePoints();
     method public android.util.Range<java.lang.Integer> getSupportedWidths();
     method public android.util.Range<java.lang.Integer> getSupportedWidthsFor(int);
     method public int getWidthAlignment();
     method public boolean isSizeSupported(int, int);
   }
 
+  public static final class MediaCodecInfo.VideoCapabilities.PerformancePoint {
+    method public boolean covers(android.media.MediaFormat);
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_100;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_120;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_200;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_24;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_240;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_25;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_30;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_50;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_60;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_100;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_120;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_200;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_24;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_240;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_25;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_30;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_50;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_60;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_24;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_25;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_30;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_48;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_50;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_60;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_100;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_120;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_200;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_24;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_240;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_25;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_30;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_50;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_60;
+    field public final int frameRate;
+    field public final int height;
+    field public final int width;
+  }
+
   public final class MediaCodecList {
     ctor public MediaCodecList(int);
     method public java.lang.String findDecoderForFormat(android.media.MediaFormat);
@@ -25002,6 +25091,7 @@
     field public static final java.lang.String MIMETYPE_TEXT_CEA_708 = "text/cea-708";
     field public static final java.lang.String MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
     field public static final java.lang.String MIMETYPE_TEXT_VTT = "text/vtt";
+    field public static final java.lang.String MIMETYPE_VIDEO_AV1 = "video/av01";
     field public static final java.lang.String MIMETYPE_VIDEO_AVC = "video/avc";
     field public static final java.lang.String MIMETYPE_VIDEO_DOLBY_VISION = "video/dolby-vision";
     field public static final java.lang.String MIMETYPE_VIDEO_H263 = "video/3gpp";
@@ -54245,6 +54335,8 @@
     method public static java.lang.ClassLoader getWebViewClassLoader();
     method public android.webkit.WebViewClient getWebViewClient();
     method public android.os.Looper getWebViewLooper();
+    method public android.webkit.WebViewRenderer getWebViewRenderer();
+    method public android.webkit.WebViewRendererClient getWebViewRendererClient();
     method public void goBack();
     method public void goBackOrForward(int);
     method public void goForward();
@@ -54294,6 +54386,8 @@
     method public void setWebChromeClient(android.webkit.WebChromeClient);
     method public static void setWebContentsDebuggingEnabled(boolean);
     method public void setWebViewClient(android.webkit.WebViewClient);
+    method public void setWebViewRendererClient(java.util.concurrent.Executor, android.webkit.WebViewRendererClient);
+    method public void setWebViewRendererClient(android.webkit.WebViewRendererClient);
     method public deprecated boolean shouldDelayChildPressedState();
     method public deprecated boolean showFindDialog(java.lang.String, boolean);
     method public static void startSafeBrowsing(android.content.Context, android.webkit.ValueCallback<java.lang.Boolean>);
@@ -54409,6 +54503,16 @@
     method public android.webkit.WebView getWebView();
   }
 
+  public abstract class WebViewRenderer {
+    method public abstract boolean terminate();
+  }
+
+  public abstract class WebViewRendererClient {
+    ctor public WebViewRendererClient();
+    method public abstract void onRendererResponsive(android.webkit.WebView, android.webkit.WebViewRenderer);
+    method public abstract void onRendererUnresponsive(android.webkit.WebView, android.webkit.WebViewRenderer);
+  }
+
 }
 
 package android.widget {
diff --git a/api/system-current.txt b/api/system-current.txt
index acbc2a7..ed53fcf 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -128,6 +128,7 @@
     field public static final java.lang.String QUERY_TIME_ZONE_RULES = "android.permission.QUERY_TIME_ZONE_RULES";
     field public static final java.lang.String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
     field public static final java.lang.String READ_CONTENT_RATING_SYSTEMS = "android.permission.READ_CONTENT_RATING_SYSTEMS";
+    field public static final java.lang.String READ_DEVICE_CONFIG = "android.permission.READ_DEVICE_CONFIG";
     field public static final java.lang.String READ_DREAM_STATE = "android.permission.READ_DREAM_STATE";
     field public static final java.lang.String READ_INSTALL_SESSIONS = "android.permission.READ_INSTALL_SESSIONS";
     field public static final java.lang.String READ_NETWORK_USAGE_HISTORY = "android.permission.READ_NETWORK_USAGE_HISTORY";
@@ -184,6 +185,7 @@
     field public static final java.lang.String UPDATE_TIME_ZONE_RULES = "android.permission.UPDATE_TIME_ZONE_RULES";
     field public static final java.lang.String USER_ACTIVITY = "android.permission.USER_ACTIVITY";
     field public static final java.lang.String USE_RESERVED_DISK = "android.permission.USE_RESERVED_DISK";
+    field public static final java.lang.String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG";
     field public static final java.lang.String WRITE_DREAM_STATE = "android.permission.WRITE_DREAM_STATE";
     field public static final java.lang.String WRITE_EMBEDDED_SUBSCRIPTIONS = "android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS";
     field public static final java.lang.String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE";
@@ -195,6 +197,7 @@
   }
 
   public static final class R.array {
+    field public static final int config_defaultRoleHolders = 17235974; // 0x1070006
     field public static final int config_keySystemUuidMapping = 17235973; // 0x1070005
   }
 
@@ -1559,6 +1562,7 @@
 
   public class PermissionInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
     field public static final int FLAG_REMOVED = 2; // 0x2
+    field public static final int PROTECTION_FLAG_CONFIGURATOR = 524288; // 0x80000
     field public static final int PROTECTION_FLAG_DOCUMENTER = 262144; // 0x40000
     field public static final int PROTECTION_FLAG_OEM = 16384; // 0x4000
     field public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000
@@ -8500,6 +8504,8 @@
     method public abstract int getVisibleTitleHeight();
     method public abstract android.webkit.WebChromeClient getWebChromeClient();
     method public abstract android.webkit.WebViewClient getWebViewClient();
+    method public abstract android.webkit.WebViewRenderer getWebViewRenderer();
+    method public abstract android.webkit.WebViewRendererClient getWebViewRendererClient();
     method public abstract android.view.View getZoomControls();
     method public abstract void goBack();
     method public abstract void goBackOrForward(int);
@@ -8549,6 +8555,7 @@
     method public abstract void setVerticalScrollbarOverlay(boolean);
     method public abstract void setWebChromeClient(android.webkit.WebChromeClient);
     method public abstract void setWebViewClient(android.webkit.WebViewClient);
+    method public abstract void setWebViewRendererClient(java.util.concurrent.Executor, android.webkit.WebViewRendererClient);
     method public abstract boolean showFindDialog(java.lang.String, boolean);
     method public abstract void stopLoading();
     method public abstract boolean zoomBy(float);
diff --git a/api/test-current.txt b/api/test-current.txt
index 6ddb341..5fcbb5e 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -420,6 +420,7 @@
   }
 
   public class PermissionInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
+    field public static final int PROTECTION_FLAG_CONFIGURATOR = 524288; // 0x80000
     field public static final int PROTECTION_FLAG_DOCUMENTER = 262144; // 0x40000
     field public static final int PROTECTION_FLAG_OEM = 16384; // 0x4000
     field public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000
@@ -579,6 +580,8 @@
 
   public final class BrightnessConfiguration implements android.os.Parcelable {
     method public int describeContents();
+    method public android.hardware.display.BrightnessCorrection getCorrectionByCategory(int);
+    method public android.hardware.display.BrightnessCorrection getCorrectionByPackageName(java.lang.String);
     method public android.util.Pair<float[], float[]> getCurve();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessConfiguration> CREATOR;
@@ -586,10 +589,22 @@
 
   public static class BrightnessConfiguration.Builder {
     ctor public BrightnessConfiguration.Builder(float[], float[]);
+    method public android.hardware.display.BrightnessConfiguration.Builder addCorrectionByCategory(int, android.hardware.display.BrightnessCorrection);
+    method public android.hardware.display.BrightnessConfiguration.Builder addCorrectionByPackageName(java.lang.String, android.hardware.display.BrightnessCorrection);
     method public android.hardware.display.BrightnessConfiguration build();
+    method public int getMaxCorrectionsByCategory();
+    method public int getMaxCorrectionsByPackageName();
     method public android.hardware.display.BrightnessConfiguration.Builder setDescription(java.lang.String);
   }
 
+  public final class BrightnessCorrection implements android.os.Parcelable {
+    method public float apply(float);
+    method public static android.hardware.display.BrightnessCorrection createScaleAndTranslateLog(float, float);
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessCorrection> CREATOR;
+  }
+
   public final class DisplayManager {
     method public java.util.List<android.hardware.display.AmbientBrightnessDayStats> getAmbientBrightnessStats();
     method public android.hardware.display.BrightnessConfiguration getBrightnessConfiguration();
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index d374f1c..836627e 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -124,6 +124,7 @@
 import android.view.autofill.IAutofillWindowPresenter;
 import android.view.contentcapture.ContentCaptureContext;
 import android.view.contentcapture.ContentCaptureManager;
+import android.view.contentcapture.ContentCaptureSession;
 import android.widget.AdapterView;
 import android.widget.Toast;
 import android.widget.Toolbar;
@@ -1034,13 +1035,15 @@
     }
 
     /** @hide */ private static final int CONTENT_CAPTURE_START = 1;
-    /** @hide */ private static final int CONTENT_CAPTURE_FLUSH = 2;
-    /** @hide */ private static final int CONTENT_CAPTURE_STOP = 3;
+    /** @hide */ private static final int CONTENT_CAPTURE_PAUSE = 2;
+    /** @hide */ private static final int CONTENT_CAPTURE_RESUME = 3;
+    /** @hide */ private static final int CONTENT_CAPTURE_STOP = 4;
 
     /** @hide */
     @IntDef(prefix = { "CONTENT_CAPTURE_" }, value = {
             CONTENT_CAPTURE_START,
-            CONTENT_CAPTURE_FLUSH,
+            CONTENT_CAPTURE_PAUSE,
+            CONTENT_CAPTURE_RESUME,
             CONTENT_CAPTURE_STOP
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -1062,8 +1065,11 @@
                 }
                 cm.onActivityStarted(mToken, getComponentName(), flags);
                 break;
-            case CONTENT_CAPTURE_FLUSH:
-                cm.flush();
+            case CONTENT_CAPTURE_PAUSE:
+                cm.flush(ContentCaptureSession.FLUSH_REASON_ACTIVITY_PAUSED);
+                break;
+            case CONTENT_CAPTURE_RESUME:
+                cm.flush(ContentCaptureSession.FLUSH_REASON_ACTIVITY_RESUMED);
                 break;
             case CONTENT_CAPTURE_STOP:
                 cm.onActivityStopped();
@@ -1755,7 +1761,7 @@
             }
         }
         mCalled = true;
-        notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_FLUSH);
+        notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_RESUME);
     }
 
     /**
@@ -2149,7 +2155,7 @@
             }
         }
         mCalled = true;
-        notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_FLUSH);
+        notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_PAUSE);
     }
 
     /**
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 9247486..6d7c547 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2168,6 +2168,74 @@
     public @interface SetPrivateDnsModeResultConstants {}
 
     /**
+     * Activity action: Starts the administrator to get the mode for the provisioning.
+     * This intent may contain the following extras:
+     * <ul>
+     *     <li>{@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}</li>
+     *     <li>{@link #EXTRA_PROVISIONING_IMEI}</li>
+     *     <li>{@link #EXTRA_PROVISIONING_SERIAL_NUMBER}</li>
+     * </ul>
+     *
+     * <p>The target activity should return one of the following values in
+     * {@link #EXTRA_PROVISIONING_MODE} as result:
+     * <ul>
+     *     <li>{@link #PROVISIONING_MODE_FULLY_MANAGED_DEVICE}</li>
+     *     <li>{@link #PROVISIONING_MODE_MANAGED_PROFILE}</li>
+     *     <li>{@link #PROVISIONING_MODE_MANAGED_PROFILE_ON_FULLY_MANAGED_DEVICE}</li>
+     * </ul>
+     *
+     * <p>The target activity may also return the account that needs to be migrated from primary
+     * user to managed profile in case of a profile owner provisioning in
+     * {@link #EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE} as result.
+     */
+    public static final String ACTION_GET_PROVISIONING_MODE =
+            "android.app.action.GET_PROVISIONING_MODE";
+
+    /**
+     * A string extra holding the IMEI (International Mobile Equipment Identity) of the device.
+     */
+    public static final String EXTRA_PROVISIONING_IMEI = "android.app.extra.PROVISIONING_IMEI";
+
+    /**
+     * A string extra holding the serial number of the device.
+     */
+    public static final String EXTRA_PROVISIONING_SERIAL_NUMBER =
+            "android.app.extra.PROVISIONING_SERIAL_NUMBER";
+
+    /**
+     * An intent extra holding the provisioning mode returned by the administrator.
+     * The value for this extra should be one of the following:
+     * <ul>
+     *     <li>{@link #PROVISIONING_MODE_FULLY_MANAGED_DEVICE}</li>
+     *     <li>{@link #PROVISIONING_MODE_MANAGED_PROFILE}</li>
+     *     <li>{@link #PROVISIONING_MODE_MANAGED_PROFILE_ON_FULLY_MANAGED_DEVICE}</li>
+     * </ul>
+     */
+    public static final String EXTRA_PROVISIONING_MODE =
+            "android.app.extra.PROVISIONING_MODE";
+
+    /**
+     * The provisioning mode for fully managed device.
+     */
+    public static final int PROVISIONING_MODE_FULLY_MANAGED_DEVICE = 1;
+
+    /**
+     * The provisioning mode for managed profile.
+     */
+    public static final int PROVISIONING_MODE_MANAGED_PROFILE = 2;
+
+    /**
+     * The provisioning mode for managed profile on a fully managed device.
+     */
+    public static final int PROVISIONING_MODE_MANAGED_PROFILE_ON_FULLY_MANAGED_DEVICE = 3;
+
+    /**
+     * Activity action: Starts the administrator to show policy compliance for the provisioning.
+     */
+    public static final String ACTION_ADMIN_POLICY_COMPLIANCE =
+            "android.app.action.ADMIN_POLICY_COMPLIANCE";
+
+    /**
      * Return true if the given administrator component is currently active (enabled) in the system.
      *
      * @param admin The administrator component to check for.
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 45b5dca..359adbd 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -55,6 +55,7 @@
     public static final int PACKAGE_PERMISSION_CONTROLLER = 6;
     public static final int PACKAGE_WELLBEING = 7;
     public static final int PACKAGE_DOCUMENTER = 8;
+    public static final int PACKAGE_CONFIGURATOR = 9;
     @IntDef(value = {
         PACKAGE_SYSTEM,
         PACKAGE_SETUP_WIZARD,
@@ -65,6 +66,7 @@
         PACKAGE_PERMISSION_CONTROLLER,
         PACKAGE_WELLBEING,
         PACKAGE_DOCUMENTER,
+        PACKAGE_CONFIGURATOR,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface KnownPackage {}
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index a3395ac..5d2cf0a 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -203,6 +203,16 @@
     @TestApi
     public static final int PROTECTION_FLAG_DOCUMENTER = 0x40000;
 
+    /**
+     * Additional flag for {@link #protectionLevel}, corresponding to the
+     * {@code configurator} value of {@link android.R.attr#protectionLevel}.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public static final int PROTECTION_FLAG_CONFIGURATOR = 0x80000;
+
 
     /** @hide */
     @IntDef(flag = true, prefix = { "PROTECTION_FLAG_" }, value = {
@@ -222,6 +232,7 @@
             PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER,
             PROTECTION_FLAG_WELLBEING,
             PROTECTION_FLAG_DOCUMENTER,
+            PROTECTION_FLAG_CONFIGURATOR,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ProtectionFlags {}
@@ -417,6 +428,9 @@
         if ((level & PermissionInfo.PROTECTION_FLAG_DOCUMENTER) != 0) {
             protLevel += "|documenter";
         }
+        if ((level & PROTECTION_FLAG_CONFIGURATOR) != 0) {
+            protLevel += "|configurator";
+        }
         return protLevel;
     }
 
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index c4b315e..dcd6e2e 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -98,6 +98,12 @@
  * href="{@docRoot}guide/topics/resources/index.html">Application Resources</a>.</p>
  */
 public class Resources {
+    /**
+     * The {@code null} resource ID. This denotes an invalid resource ID that is returned by the
+     * system when a resource is not found or the value is set to {@code @null} in XML.
+     */
+    public static final @AnyRes int ID_NULL = 0;
+
     static final String TAG = "Resources";
 
     private static final Object sSync = new Object();
diff --git a/core/java/android/hardware/display/BrightnessConfiguration.java b/core/java/android/hardware/display/BrightnessConfiguration.java
index be054297..8c74ddc 100644
--- a/core/java/android/hardware/display/BrightnessConfiguration.java
+++ b/core/java/android/hardware/display/BrightnessConfiguration.java
@@ -91,9 +91,7 @@
      *
      * @return The matching brightness correction, or null.
      *
-     * @hide
      */
-    @SystemApi
     @Nullable
     public BrightnessCorrection getCorrectionByPackageName(String packageName) {
         return mCorrectionsByPackageName.get(packageName);
@@ -106,10 +104,7 @@
      *      The app category.
      *
      * @return The matching brightness correction, or null.
-     *
-     * @hide
      */
-    @SystemApi
     @Nullable
     public BrightnessCorrection getCorrectionByCategory(int category) {
         return mCorrectionsByCategory.get(category);
@@ -416,9 +411,7 @@
          *
          * @return The maximum number of corrections by package name allowed.
          *
-         * @hide
          */
-        @SystemApi
         public int getMaxCorrectionsByPackageName() {
             return MAX_CORRECTIONS_BY_PACKAGE_NAME;
         }
@@ -428,9 +421,7 @@
          *
          * @return The maximum number of corrections by category allowed.
          *
-         * @hide
          */
-        @SystemApi
         public int getMaxCorrectionsByCategory() {
             return MAX_CORRECTIONS_BY_CATEGORY;
         }
@@ -451,9 +442,7 @@
          *      Maximum number of corrections by package name exceeded (see
          *      {@link #getMaxCorrectionsByPackageName}).
          *
-         * @hide
          */
-        @SystemApi
         public Builder addCorrectionByPackageName(String packageName,
                 BrightnessCorrection correction) {
             if (mCorrectionsByPackageName.size() >= getMaxCorrectionsByPackageName()) {
@@ -479,9 +468,7 @@
          *      Maximum number of corrections by category exceeded (see
          *      {@link #getMaxCorrectionsByCategory}).
          *
-         * @hide
          */
-        @SystemApi
         public Builder addCorrectionByCategory(@ApplicationInfo.Category int category,
                 BrightnessCorrection correction) {
             if (mCorrectionsByCategory.size() >= getMaxCorrectionsByCategory()) {
@@ -504,8 +491,6 @@
 
         /**
          * Builds the {@link BrightnessConfiguration}.
-         *
-         * A brightness curve <b>must</b> be set before calling this.
          */
         public BrightnessConfiguration build() {
             if (mCurveLux == null || mCurveNits == null) {
diff --git a/core/java/android/hardware/display/BrightnessCorrection.java b/core/java/android/hardware/display/BrightnessCorrection.java
index c4e0e3b..6a073ff 100644
--- a/core/java/android/hardware/display/BrightnessCorrection.java
+++ b/core/java/android/hardware/display/BrightnessCorrection.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.MathUtils;
@@ -41,6 +42,7 @@
  * @hide
  */
 @SystemApi
+@TestApi
 public final class BrightnessCorrection implements Parcelable {
 
     private static final int SCALE_AND_TRANSLATE_LOG = 1;
@@ -98,6 +100,24 @@
         return mImplementation.toString();
     }
 
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        }
+        if (!(o instanceof BrightnessCorrection)) {
+            return false;
+        }
+        BrightnessCorrection other = (BrightnessCorrection) o;
+        return other.mImplementation.equals(mImplementation);
+    }
+
+    @Override
+    public int hashCode() {
+        return mImplementation.hashCode();
+    }
+
     public static final Creator<BrightnessCorrection> CREATOR =
             new Creator<BrightnessCorrection>() {
                 public BrightnessCorrection createFromParcel(Parcel in) {
@@ -215,6 +235,26 @@
         }
 
         @Override
+        public boolean equals(Object o) {
+            if (o == this) {
+                return true;
+            }
+            if (!(o instanceof ScaleAndTranslateLog)) {
+                return false;
+            }
+            ScaleAndTranslateLog other = (ScaleAndTranslateLog) o;
+            return other.mScale == mScale && other.mTranslate == mTranslate;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = 1;
+            result = result * 31 + Float.hashCode(mScale);
+            result = result * 31 + Float.hashCode(mTranslate);
+            return result;
+        }
+
+        @Override
         public void writeToParcel(Parcel dest) {
             dest.writeInt(SCALE_AND_TRANSLATE_LOG);
             dest.writeFloat(mScale);
diff --git a/core/java/android/net/IpPrefixParcelable.aidl b/core/java/android/net/IpPrefixParcelable.aidl
new file mode 100644
index 0000000..93a8d41
--- /dev/null
+++ b/core/java/android/net/IpPrefixParcelable.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2019 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.net;
+
+parcelable IpPrefixParcelable {
+    String address;
+    int prefixLength;
+}
\ No newline at end of file
diff --git a/core/java/android/net/LinkAddressParcelable.aidl b/core/java/android/net/LinkAddressParcelable.aidl
new file mode 100644
index 0000000..af8e79b
--- /dev/null
+++ b/core/java/android/net/LinkAddressParcelable.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2019 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.net;
+
+parcelable LinkAddressParcelable {
+    String address;
+    int prefixLength;
+    int flags;
+    int scope;
+}
\ No newline at end of file
diff --git a/core/java/android/net/LinkPropertiesParcelable.aidl b/core/java/android/net/LinkPropertiesParcelable.aidl
new file mode 100644
index 0000000..b153dc7
--- /dev/null
+++ b/core/java/android/net/LinkPropertiesParcelable.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 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.net;
+
+import android.net.IpPrefixParcelable;
+import android.net.LinkAddressParcelable;
+import android.net.ProxyInfoParcelable;
+import android.net.RouteInfoParcelable;
+
+parcelable LinkPropertiesParcelable {
+    String ifaceName;
+    LinkAddressParcelable[] linkAddresses;
+    String[] dnses;
+    String[] pcscfs;
+    String[] validatedPrivateDnses;
+    boolean usePrivateDns;
+    String privateDnsServerName;
+    String domains;
+    RouteInfoParcelable[] routes;
+    ProxyInfoParcelable httpProxy;
+    int mtu;
+    String tcpBufferSizes;
+    IpPrefixParcelable nat64Prefix;
+    LinkPropertiesParcelable[] stackedLinks;
+}
\ No newline at end of file
diff --git a/core/java/android/net/ProxyInfoParcelable.aidl b/core/java/android/net/ProxyInfoParcelable.aidl
new file mode 100644
index 0000000..59fd846
--- /dev/null
+++ b/core/java/android/net/ProxyInfoParcelable.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2019 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.net;
+
+parcelable ProxyInfoParcelable {
+    String host;
+    int port;
+    String[] exclusionList;
+    String pacFileUrl;
+}
diff --git a/core/java/android/net/RouteInfoParcelable.aidl b/core/java/android/net/RouteInfoParcelable.aidl
new file mode 100644
index 0000000..15bcdcf
--- /dev/null
+++ b/core/java/android/net/RouteInfoParcelable.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2019 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.net;
+
+import android.net.IpPrefixParcelable;
+
+parcelable RouteInfoParcelable {
+    IpPrefixParcelable destination;
+    String gatewayAddr;
+    String ifaceName;
+    int type;
+}
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index e4622db..f51ba9a 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -306,9 +306,18 @@
                                                 String packageName,
                                                 String paths,
                                                 String devOptIn) {
-        // Check for temporary rules if debuggable or root
-        if (!isDebuggable(context) && !(getCanLoadSystemLibraries() == 1)) {
-            Log.v(TAG, "Skipping loading temporary rules file");
+        /**
+         * We only want to load a temp rules file for:
+         *  - apps that are marked 'debuggable' in their manifest
+         *  - devices that are running a userdebug build (ro.debuggable) or can inject libraries for
+         *    debugging (PR_SET_DUMPABLE).
+         */
+        boolean appIsDebuggable = isDebuggable(context);
+        boolean deviceIsDebuggable = getCanLoadSystemLibraries() == 1;
+        if (!(appIsDebuggable || deviceIsDebuggable)) {
+            Log.v(TAG, "Skipping loading temporary rules file: "
+                    + "appIsDebuggable = " + appIsDebuggable + ", "
+                    + "adbRootEnabled = " + deviceIsDebuggable);
             return false;
         }
 
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index c795895..44cb221 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -16,9 +16,13 @@
 
 package android.provider;
 
+import static android.Manifest.permission.READ_DEVICE_CONFIG;
+import static android.Manifest.permission.WRITE_DEVICE_CONFIG;
+
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.app.ActivityThread;
 import android.content.ContentResolver;
@@ -78,6 +82,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(READ_DEVICE_CONFIG)
     public static String getProperty(String namespace, String name) {
         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
         String compositeName = createCompositeName(namespace, name);
@@ -105,6 +110,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(WRITE_DEVICE_CONFIG)
     public static boolean setProperty(
             String namespace, String name, String value, boolean makeDefault) {
         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
@@ -125,6 +131,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(WRITE_DEVICE_CONFIG)
     public static void resetToDefaults(@ResetMode int resetMode, @Nullable String namespace) {
         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
         Settings.Config.resetToDefaults(contentResolver, resetMode, namespace);
@@ -146,10 +153,12 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(READ_DEVICE_CONFIG)
     public static void addOnPropertyChangedListener(
             @NonNull String namespace,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull OnPropertyChangedListener onPropertyChangedListener) {
+        // TODO enforce READ_DEVICE_CONFIG permission
         synchronized (sLock) {
             Pair<String, Executor> oldNamespace = sListeners.get(onPropertyChangedListener);
             if (oldNamespace == null) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 757c03e..b39d871 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -14126,7 +14126,7 @@
          *
          * @hide
          */
-        // TODO(b/117663715): require a new read permission
+        @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
         static String getString(ContentResolver resolver, String name) {
             return sNameValueCache.getStringForUser(resolver, name, resolver.getUserId());
         }
@@ -14149,8 +14149,7 @@
          *
          * @hide
          */
-        // TODO(b/117663715): require a new write permission restricted to a single source
-        @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+        @RequiresPermission(Manifest.permission.WRITE_DEVICE_CONFIG)
         static boolean putString(@NonNull ContentResolver resolver, @NonNull String name,
                 @Nullable String value, boolean makeDefault) {
             return sNameValueCache.putStringForUser(resolver, name, value, null, makeDefault,
@@ -14172,7 +14171,7 @@
          * @hide
          */
         // TODO(b/117663715): require a new write permission restricted to a single source
-        @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+        @RequiresPermission(Manifest.permission.WRITE_DEVICE_CONFIG)
         static void resetToDefaults(@NonNull ContentResolver resolver, @ResetMode int resetMode,
                 @Nullable String prefix) {
             try {
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index ffd4156..878b6b6 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -29,6 +29,7 @@
 import android.os.Build;
 import android.os.Handler;
 import android.os.Message;
+import android.os.SystemProperties;
 import android.os.Trace;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -38,6 +39,9 @@
 
 import com.android.internal.R;
 
+import dalvik.system.PathClassLoader;
+import java.io.File;
+import java.lang.reflect.Method;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -72,6 +76,10 @@
     private static final String TAG = LayoutInflater.class.getSimpleName();
     private static final boolean DEBUG = false;
 
+    private static final String USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY
+        = "view.precompiled_layout_enabled";
+    private static final String COMPILED_VIEW_DEX_FILE_NAME = "/compiled_view.dex";
+
     /** Empty stack trace used to avoid log spam in re-throw exceptions. */
     private static final StackTraceElement[] EMPTY_STACK_TRACE = new StackTraceElement[0];
 
@@ -93,6 +101,13 @@
     private Factory2 mPrivateFactory;
     private Filter mFilter;
 
+    // Indicates whether we should try to inflate layouts using a precompiled layout instead of
+    // inflating from the XML resource.
+    private boolean mUseCompiledView;
+    // This variable holds the classloader that will be used to look for precompiled layouts. The
+    // The classloader includes the generated compiled_view.dex file.
+    private ClassLoader mPrecompiledClassLoader;
+
     @UnsupportedAppUsage
     final Object[] mConstructorArgs = new Object[2];
 
@@ -223,6 +238,7 @@
      */
     protected LayoutInflater(Context context) {
         mContext = context;
+        initPrecompiledViews();
     }
 
     /**
@@ -239,6 +255,7 @@
         mFactory2 = original.mFactory2;
         mPrivateFactory = original.mPrivateFactory;
         setFilter(original.mFilter);
+        initPrecompiledViews();
     }
 
     /**
@@ -380,6 +397,29 @@
         }
     }
 
+    private void initPrecompiledViews() {
+        try {
+            mUseCompiledView =
+                SystemProperties.getBoolean(USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY, false);
+            if (mUseCompiledView) {
+                mPrecompiledClassLoader = mContext.getClassLoader();
+                String dexFile = mContext.getCodeCacheDir() + COMPILED_VIEW_DEX_FILE_NAME;
+                if (new File(dexFile).exists()) {
+                    mPrecompiledClassLoader = new PathClassLoader(dexFile, mPrecompiledClassLoader);
+                } else {
+                    // If the precompiled layout file doesn't exist, then disable precompiled
+                    // layouts.
+                    mUseCompiledView = false;
+                }
+            }
+        } catch (Throwable e) {
+            if (DEBUG) {
+                Log.e(TAG, "Failed to initialized precompiled views layouts", e);
+            }
+            mUseCompiledView = false;
+        }
+    }
+
     /**
      * Inflate a new view hierarchy from the specified xml resource. Throws
      * {@link InflateException} if there is an error.
@@ -436,10 +476,14 @@
         final Resources res = getContext().getResources();
         if (DEBUG) {
             Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
-                    + Integer.toHexString(resource) + ")");
+                  + Integer.toHexString(resource) + ")");
         }
 
-        final XmlResourceParser parser = res.getLayout(resource);
+        View view = tryInflatePrecompiled(resource, res, root, attachToRoot);
+        if (view != null) {
+            return view;
+        }
+        XmlResourceParser parser = res.getLayout(resource);
         try {
             return inflate(parser, root, attachToRoot);
         } finally {
@@ -447,6 +491,73 @@
         }
     }
 
+    private @Nullable
+    View tryInflatePrecompiled(@LayoutRes int resource, Resources res, @Nullable ViewGroup root,
+        boolean attachToRoot) {
+        if (!mUseCompiledView) {
+            return null;
+        }
+
+        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate (precompiled)");
+
+        // Try to inflate using a precompiled layout.
+        String pkg = res.getResourcePackageName(resource);
+        String layout = res.getResourceEntryName(resource);
+
+        try {
+            Class clazz = mPrecompiledClassLoader.loadClass("" + pkg + ".CompiledView");
+            Method inflater = clazz.getMethod(layout, Context.class, int.class);
+            View view = (View) inflater.invoke(null, mContext, resource);
+
+            if (view != null && root != null) {
+                // We were able to use the precompiled inflater, but now we need to do some work to
+                // attach the view to the root correctly.
+                XmlResourceParser parser = res.getLayout(resource);
+                try {
+                    AttributeSet attrs = Xml.asAttributeSet(parser);
+                    advanceToRootNode(parser);
+                    ViewGroup.LayoutParams params = root.generateLayoutParams(attrs);
+
+                    if (attachToRoot) {
+                        root.addView(view, params);
+                    } else {
+                        view.setLayoutParams(params);
+                    }
+                } finally {
+                    parser.close();
+                }
+            }
+
+            return view;
+        } catch (Throwable e) {
+            if (DEBUG) {
+                Log.e(TAG, "Failed to use precompiled view", e);
+            }
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+        }
+        return null;
+    }
+
+    /**
+     * Advances the given parser to the first START_TAG. Throws InflateException if no start tag is
+     * found.
+     */
+    private void advanceToRootNode(XmlPullParser parser)
+        throws InflateException, IOException, XmlPullParserException {
+        // Look for the root node.
+        int type;
+        while ((type = parser.next()) != XmlPullParser.START_TAG &&
+            type != XmlPullParser.END_DOCUMENT) {
+            // Empty
+        }
+
+        if (type != XmlPullParser.START_TAG) {
+            throw new InflateException(parser.getPositionDescription()
+                + ": No start tag found!");
+        }
+    }
+
     /**
      * Inflate a new view hierarchy from the specified XML node. Throws
      * {@link InflateException} if there is an error.
@@ -480,18 +591,7 @@
             View result = root;
 
             try {
-                // Look for the root node.
-                int type;
-                while ((type = parser.next()) != XmlPullParser.START_TAG &&
-                        type != XmlPullParser.END_DOCUMENT) {
-                    // Empty
-                }
-
-                if (type != XmlPullParser.START_TAG) {
-                    throw new InflateException(parser.getPositionDescription()
-                            + ": No start tag found!");
-                }
-
+                advanceToRootNode(parser);
                 final String name = parser.getName();
 
                 if (DEBUG) {
@@ -994,82 +1094,85 @@
                 + "reference. The layout ID " + value + " is not valid.");
         }
 
-        final XmlResourceParser childParser = context.getResources().getLayout(layout);
+        final View precompiled = tryInflatePrecompiled(layout, context.getResources(),
+            (ViewGroup) parent, /*attachToRoot=*/true);
+        if (precompiled == null) {
+            final XmlResourceParser childParser = context.getResources().getLayout(layout);
 
-        try {
-            final AttributeSet childAttrs = Xml.asAttributeSet(childParser);
+            try {
+                final AttributeSet childAttrs = Xml.asAttributeSet(childParser);
 
-            while ((type = childParser.next()) != XmlPullParser.START_TAG &&
-                type != XmlPullParser.END_DOCUMENT) {
-                // Empty.
+                while ((type = childParser.next()) != XmlPullParser.START_TAG &&
+                    type != XmlPullParser.END_DOCUMENT) {
+                    // Empty.
+                }
+
+                if (type != XmlPullParser.START_TAG) {
+                    throw new InflateException(childParser.getPositionDescription() +
+                        ": No start tag found!");
+                }
+
+                final String childName = childParser.getName();
+
+                if (TAG_MERGE.equals(childName)) {
+                    // The <merge> tag doesn't support android:theme, so
+                    // nothing special to do here.
+                    rInflate(childParser, parent, context, childAttrs, false);
+                } else {
+                    final View view = createViewFromTag(parent, childName,
+                        context, childAttrs, hasThemeOverride);
+                    final ViewGroup group = (ViewGroup) parent;
+
+                    final TypedArray a = context.obtainStyledAttributes(
+                        attrs, R.styleable.Include);
+                    final int id = a.getResourceId(R.styleable.Include_id, View.NO_ID);
+                    final int visibility = a.getInt(R.styleable.Include_visibility, -1);
+                    a.recycle();
+
+                    // We try to load the layout params set in the <include /> tag.
+                    // If the parent can't generate layout params (ex. missing width
+                    // or height for the framework ViewGroups, though this is not
+                    // necessarily true of all ViewGroups) then we expect it to throw
+                    // a runtime exception.
+                    // We catch this exception and set localParams accordingly: true
+                    // means we successfully loaded layout params from the <include>
+                    // tag, false means we need to rely on the included layout params.
+                    ViewGroup.LayoutParams params = null;
+                    try {
+                        params = group.generateLayoutParams(attrs);
+                    } catch (RuntimeException e) {
+                        // Ignore, just fail over to child attrs.
+                    }
+                    if (params == null) {
+                        params = group.generateLayoutParams(childAttrs);
+                    }
+                    view.setLayoutParams(params);
+
+                    // Inflate all children.
+                    rInflateChildren(childParser, view, childAttrs, true);
+
+                    if (id != View.NO_ID) {
+                        view.setId(id);
+                    }
+
+                    switch (visibility) {
+                        case 0:
+                            view.setVisibility(View.VISIBLE);
+                            break;
+                        case 1:
+                            view.setVisibility(View.INVISIBLE);
+                            break;
+                        case 2:
+                            view.setVisibility(View.GONE);
+                            break;
+                    }
+
+                    group.addView(view);
+                }
+            } finally {
+                childParser.close();
             }
-
-            if (type != XmlPullParser.START_TAG) {
-                throw new InflateException(childParser.getPositionDescription() +
-                    ": No start tag found!");
-            }
-
-            final String childName = childParser.getName();
-
-            if (TAG_MERGE.equals(childName)) {
-                // The <merge> tag doesn't support android:theme, so
-                // nothing special to do here.
-                rInflate(childParser, parent, context, childAttrs, false);
-            } else {
-                final View view = createViewFromTag(parent, childName,
-                    context, childAttrs, hasThemeOverride);
-                final ViewGroup group = (ViewGroup) parent;
-
-                final TypedArray a = context.obtainStyledAttributes(
-                    attrs, R.styleable.Include);
-                final int id = a.getResourceId(R.styleable.Include_id, View.NO_ID);
-                final int visibility = a.getInt(R.styleable.Include_visibility, -1);
-                a.recycle();
-
-                // We try to load the layout params set in the <include /> tag.
-                // If the parent can't generate layout params (ex. missing width
-                // or height for the framework ViewGroups, though this is not
-                // necessarily true of all ViewGroups) then we expect it to throw
-                // a runtime exception.
-                // We catch this exception and set localParams accordingly: true
-                // means we successfully loaded layout params from the <include>
-                // tag, false means we need to rely on the included layout params.
-                ViewGroup.LayoutParams params = null;
-                try {
-                    params = group.generateLayoutParams(attrs);
-                } catch (RuntimeException e) {
-                    // Ignore, just fail over to child attrs.
-                }
-                if (params == null) {
-                    params = group.generateLayoutParams(childAttrs);
-                }
-                view.setLayoutParams(params);
-
-                // Inflate all children.
-                rInflateChildren(childParser, view, childAttrs, true);
-
-                if (id != View.NO_ID) {
-                    view.setId(id);
-                }
-
-                switch (visibility) {
-                    case 0:
-                        view.setVisibility(View.VISIBLE);
-                        break;
-                    case 1:
-                        view.setVisibility(View.INVISIBLE);
-                        break;
-                    case 2:
-                        view.setVisibility(View.GONE);
-                        break;
-                }
-
-                group.addView(view);
-            }
-        } finally {
-            childParser.close();
         }
-
         LayoutInflater.consumeChildElements(parser);
     }
 
diff --git a/core/java/android/view/contentcapture/ChildContentCaptureSession.java b/core/java/android/view/contentcapture/ChildContentCaptureSession.java
index 04e725e..cb4c4b4 100644
--- a/core/java/android/view/contentcapture/ChildContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ChildContentCaptureSession.java
@@ -68,8 +68,8 @@
     }
 
     @Override
-    void flush() {
-        mParent.flush();
+    void flush(@FlushReason int reason) {
+        mParent.flush(reason);
     }
 
     @Override
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 81b2e01..209dc2c 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -28,6 +28,7 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
+import android.view.contentcapture.ContentCaptureSession.FlushReason;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.os.IResultReceiver;
@@ -154,8 +155,8 @@
      *
      * @hide
      */
-    public void flush() {
-        getMainContentCaptureSession().flush();
+    public void flush(@FlushReason int reason) {
+        getMainContentCaptureSession().flush(reason);
     }
 
     /**
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index 7bfc5b4..a9e7b5e 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -19,6 +19,7 @@
 import static android.view.contentcapture.ContentCaptureManager.VERBOSE;
 
 import android.annotation.CallSuper;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.util.DebugUtils;
@@ -35,6 +36,8 @@
 import dalvik.system.CloseGuard;
 
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.UUID;
 
@@ -125,6 +128,32 @@
 
     private static final int INITIAL_CHILDREN_CAPACITY = 5;
 
+    /** @hide */
+    public static final int FLUSH_REASON_FULL = 1;
+    /** @hide */
+    public static final int FLUSH_REASON_ACTIVITY_PAUSED = 2;
+    /** @hide */
+    public static final int FLUSH_REASON_ACTIVITY_RESUMED = 3;
+    /** @hide */
+    public static final int FLUSH_REASON_SESSION_STARTED = 4;
+    /** @hide */
+    public static final int FLUSH_REASON_SESSION_FINISHED = 5;
+    /** @hide */
+    public static final int FLUSH_REASON_IDLE_TIMEOUT = 6;
+
+    /** @hide */
+    @IntDef(prefix = { "FLUSH_REASON_" }, value = {
+            FLUSH_REASON_FULL,
+            FLUSH_REASON_ACTIVITY_PAUSED,
+            FLUSH_REASON_ACTIVITY_RESUMED,
+            FLUSH_REASON_SESSION_STARTED,
+            FLUSH_REASON_SESSION_FINISHED,
+            FLUSH_REASON_IDLE_TIMEOUT
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface FlushReason{}
+
+
     private final CloseGuard mCloseGuard = CloseGuard.get();
 
     private final Object mLock = new Object();
@@ -212,7 +241,7 @@
     /**
      * Flushes the buffered events to the service.
      */
-    abstract void flush();
+    abstract void flush(@FlushReason int reason);
 
     /**
      * Destroys this session, flushing out all pending notifications to the service.
@@ -250,7 +279,7 @@
         }
 
         try {
-            flush();
+            flush(FLUSH_REASON_SESSION_FINISHED);
         } finally {
             onDestroy();
         }
@@ -407,12 +436,31 @@
         return mId;
     }
 
-    /**
-     * @hide
-     */
+    /** @hide */
     @NonNull
     protected static String getStateAsString(int state) {
         return state + " (" + (state == UNKNWON_STATE ? "UNKNOWN"
                 : DebugUtils.flagsToString(ContentCaptureSession.class, "STATE_", state)) + ")";
     }
+
+    /** @hide */
+    @NonNull
+    static String getflushReasonAsString(@FlushReason int reason) {
+        switch (reason) {
+            case FLUSH_REASON_FULL:
+                return "FULL";
+            case FLUSH_REASON_ACTIVITY_PAUSED:
+                return "PAUSED";
+            case FLUSH_REASON_ACTIVITY_RESUMED:
+                return "RESUMED";
+            case FLUSH_REASON_SESSION_STARTED:
+                return "STARTED";
+            case FLUSH_REASON_SESSION_FINISHED:
+                return "FINISHED";
+            case FLUSH_REASON_IDLE_TIMEOUT:
+                return "IDLE";
+            default:
+                return "UNKOWN-" + reason;
+        }
+    }
 }
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index a3ff8c0..f0778fa 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -35,7 +35,7 @@
 import android.os.IBinder;
 import android.os.IBinder.DeathRecipient;
 import android.os.RemoteException;
-import android.os.SystemClock;
+import android.util.LocalLog;
 import android.util.Log;
 import android.util.TimeUtils;
 import android.view.autofill.AutofillId;
@@ -131,6 +131,9 @@
     // Used just for debugging purposes (on dump)
     private long mNextFlush;
 
+    // TODO(b/121044064): use settings to set size
+    private final LocalLog mFlushHistory = new LocalLog(10);
+
     /** @hide */
     protected MainContentCaptureSession(@NonNull Context context, @NonNull Handler handler,
             @Nullable IContentCaptureManager systemServerInterface,
@@ -172,8 +175,9 @@
     }
 
     @Override
-    void flush() {
-        mHandler.sendMessage(obtainMessage(MainContentCaptureSession::handleForceFlush, this));
+    void flush(@FlushReason int reason) {
+        mHandler.sendMessage(
+                obtainMessage(MainContentCaptureSession::handleForceFlush, this, reason));
     }
 
     @Override
@@ -264,24 +268,25 @@
     }
 
     private void handleSendEvent(@NonNull ContentCaptureEvent event, boolean forceFlush) {
-        if (!handleHasStarted()
-                && event.getType() != ContentCaptureEvent.TYPE_SESSION_STARTED) {
+        final int eventType = event.getType();
+        if (!handleHasStarted() && eventType != ContentCaptureEvent.TYPE_SESSION_STARTED) {
             // TODO(b/120494182): comment when this could happen (dialogs?)
             Log.v(TAG, "handleSendEvent(" + getDebugState() + ", "
-                    + ContentCaptureEvent.getTypeAsString(event.getType())
+                    + ContentCaptureEvent.getTypeAsString(eventType)
                     + "): session not started yet");
             return;
         }
+        if (VERBOSE) Log.v(TAG, "handleSendEvent(" + getDebugState() + "): " + event);
         if (mEvents == null) {
             if (VERBOSE) {
                 Log.v(TAG, "handleSendEvent(" + getDebugState() + ", "
-                        + ContentCaptureEvent.getTypeAsString(event.getType())
-                        + "): cCreating buffer for " + MAX_BUFFER_SIZE + " events");
+                        + ContentCaptureEvent.getTypeAsString(eventType)
+                        + "): creating buffer for " + MAX_BUFFER_SIZE + " events");
             }
             mEvents = new ArrayList<>(MAX_BUFFER_SIZE);
         }
 
-        if (!mEvents.isEmpty() && event.getType() == TYPE_VIEW_TEXT_CHANGED) {
+        if (!mEvents.isEmpty() && eventType == TYPE_VIEW_TEXT_CHANGED) {
             final ContentCaptureEvent lastEvent = mEvents.get(mEvents.size() - 1);
 
             // TODO(b/121045053): check if flags match
@@ -304,7 +309,7 @@
         final boolean bufferEvent = numberEvents < MAX_BUFFER_SIZE;
 
         if (bufferEvent && !forceFlush) {
-            handleScheduleFlush(/* checkExisting= */ true);
+            handleScheduleFlush(FLUSH_REASON_IDLE_TIMEOUT, /* checkExisting= */ true);
             return;
         }
 
@@ -323,15 +328,26 @@
             // when it's launched again
             return;
         }
+        final int flushReason;
+        switch (eventType) {
+            case ContentCaptureEvent.TYPE_SESSION_STARTED:
+                flushReason = FLUSH_REASON_SESSION_STARTED;
+                break;
+            case ContentCaptureEvent.TYPE_SESSION_FINISHED:
+                flushReason = FLUSH_REASON_SESSION_FINISHED;
+                break;
+            default:
+                flushReason = FLUSH_REASON_FULL;
+        }
 
-        handleForceFlush();
+        handleForceFlush(flushReason);
     }
 
     private boolean handleHasStarted() {
         return mState != UNKNWON_STATE;
     }
 
-    private void handleScheduleFlush(boolean checkExisting) {
+    private void handleScheduleFlush(@FlushReason int reason, boolean checkExisting) {
         if (!handleHasStarted()) {
             Log.v(TAG, "handleScheduleFlush(" + getDebugState() + "): session not started yet");
             return;
@@ -340,43 +356,51 @@
             // "Renew" the flush message by removing the previous one
             mHandler.removeMessages(MSG_FLUSH);
         }
-        mNextFlush = SystemClock.elapsedRealtime() + FLUSHING_FREQUENCY_MS;
+        mNextFlush = System.currentTimeMillis() + FLUSHING_FREQUENCY_MS;
         if (VERBOSE) {
-            Log.v(TAG, "handleScheduleFlush(" + getDebugState() + "): scheduled to flush in "
-                    + FLUSHING_FREQUENCY_MS + "ms: " + TimeUtils.formatUptime(mNextFlush));
+            Log.v(TAG, "handleScheduleFlush(" + getDebugState()
+                    + ", reason=" + getflushReasonAsString(reason) + "): scheduled to flush in "
+                    + FLUSHING_FREQUENCY_MS + "ms: " + TimeUtils.logTimeOfDay(mNextFlush));
         }
         mHandler.sendMessageDelayed(
-                obtainMessage(MainContentCaptureSession::handleFlushIfNeeded, this)
+                obtainMessage(MainContentCaptureSession::handleFlushIfNeeded, this, reason)
                 .setWhat(MSG_FLUSH), FLUSHING_FREQUENCY_MS);
     }
 
-    private void handleFlushIfNeeded() {
+    private void handleFlushIfNeeded(@FlushReason int reason) {
         if (mEvents.isEmpty()) {
             if (VERBOSE) Log.v(TAG, "Nothing to flush");
             return;
         }
-        handleForceFlush();
+        handleForceFlush(reason);
     }
 
-    private void handleForceFlush() {
+    private void handleForceFlush(@FlushReason int reason) {
         if (mEvents == null) return;
 
         if (mDirectServiceInterface == null) {
             if (VERBOSE) {
                 Log.v(TAG, "handleForceFlush(" + getDebugState()
+                        + ", reason=" + getflushReasonAsString(reason)
                         + "): hold your horses, client not ready: " + mEvents);
             }
             if (!mHandler.hasMessages(MSG_FLUSH)) {
-                handleScheduleFlush(/* checkExisting= */ false);
+                handleScheduleFlush(reason, /* checkExisting= */ false);
             }
             return;
         }
 
         final int numberEvents = mEvents.size();
+        final String reasonString = getflushReasonAsString(reason);
+        if (DEBUG) {
+            Log.d(TAG, "Flushing " + numberEvents + " event(s) for " + getDebugState()
+                    + ". Reason: " + reasonString);
+        }
+        // Logs reason, size, max size, idle timeout
+        final String logRecord = "r=" + reasonString + " s=" + numberEvents
+                + " m=" + MAX_BUFFER_SIZE + " i=" + FLUSHING_FREQUENCY_MS;
         try {
-            if (DEBUG) {
-                Log.d(TAG, "Flushing " + numberEvents + " event(s) for " + getDebugState());
-            }
+            mFlushHistory.log(logRecord);
             mHandler.removeMessages(MSG_FLUSH);
 
             final ParceledListSlice<ContentCaptureEvent> events = handleClearEvents();
@@ -500,7 +524,6 @@
 
     @Override
     void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
-        pw.print(prefix); pw.print("id: "); pw.println(mId);
         pw.print(prefix); pw.print("mContext: "); pw.println(mContext);
         pw.print(prefix); pw.print("user: "); pw.println(mContext.getUserId());
         if (mSystemServerInterface != null) {
@@ -535,8 +558,12 @@
             }
             pw.print(prefix); pw.print("flush frequency: "); pw.println(FLUSHING_FREQUENCY_MS);
             pw.print(prefix); pw.print("next flush: ");
-            TimeUtils.formatDuration(mNextFlush - SystemClock.elapsedRealtime(), pw); pw.println();
+            TimeUtils.formatDuration(mNextFlush - System.currentTimeMillis(), pw);
+            pw.print(" ("); pw.print(TimeUtils.logTimeOfDay(mNextFlush)); pw.println(")");
         }
+        pw.print(prefix); pw.println("flush history:");
+        mFlushHistory.reverseDump(/* fd= */ null, pw, /* args= */ null); pw.println();
+
         super.dump(prefix, pw);
     }
 
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index bad2dbf..6039350 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -16,6 +16,7 @@
 
 package android.webkit;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -69,6 +70,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.Executor;
 
 /**
  * A View that displays web pages.
@@ -1688,6 +1690,84 @@
         return mProvider.getWebViewClient();
     }
 
+
+    /**
+     * Gets the WebView renderer associated with this WebView.
+     *
+     * <p>In {@link android.os.Build.VERSION_CODES#O} and above, WebView may
+     * run in "multiprocess" mode. In multiprocess mode, rendering of web
+     * content is performed by a sandboxed renderer process separate to the
+     * application process.  This renderer process may be shared with other
+     * WebViews in the application, but is not shared with other application
+     * processes.
+     *
+     * <p>If WebView is running in multiprocess mode, this method returns a
+     * handle to the renderer process associated with the WebView, which can
+     * be used to control the renderer process.
+     *
+     * @return the {@link WebViewRenderer} renderer handle associated
+     *         with this {@link WebView}, or {@code null} if
+     *         WebView is not runing in multiprocess mode.
+     */
+    @Nullable
+    public WebViewRenderer getWebViewRenderer() {
+        checkThread();
+        return mProvider.getWebViewRenderer();
+    }
+
+    /**
+     * Sets the renderer client object associated with this WebView.
+     *
+     * <p>The renderer client encapsulates callbacks relevant to WebView renderer
+     * state. See {@link WebViewRendererClient} for details.
+     *
+     * <p>Although many WebView instances may share a single underlying
+     * renderer, and renderers may live either in the application
+     * process, or in a sandboxed process that is isolated from the
+     * application process, instances of {@link WebViewRendererClient}
+     * are set per-WebView.  Callbacks represent renderer events from
+     * the perspective of this WebView, and may or may not be correlated
+     * with renderer events affecting other WebViews.
+     *
+     * @param executor the Executor on which {@link WebViewRendererClient} callbacks will execute.
+     * @param webViewRendererClient the {@link WebViewRendererClient} object.
+     */
+    public void setWebViewRendererClient(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull WebViewRendererClient webViewRendererClient) {
+        checkThread();
+        mProvider.setWebViewRendererClient(executor, webViewRendererClient);
+    }
+
+    /**
+     * Sets the renderer client object associated with this WebView.
+     *
+     * See {@link #setWebViewRendererClient(Executor,WebViewRendererClient)} for details.
+     *
+     * <p> {@link WebViewRendererClient} callbacks will run on the thread that this WebView was
+     * initialized on.
+     *
+     * @param webViewRendererClient the {@link WebViewRendererClient} object.
+     */
+    public void setWebViewRendererClient(
+            @Nullable WebViewRendererClient webViewRendererClient) {
+        checkThread();
+        mProvider.setWebViewRendererClient(null, webViewRendererClient);
+    }
+
+    /**
+     * Gets the renderer client object associated with this WebView.
+     *
+     * @return the {@link WebViewRendererClient} object associated with this WebView, if one has
+     * been set via {@link #setWebViewRendererClient(WebViewRendererClient)} or {@code null}
+     * otherwise.
+     */
+    @Nullable
+    public WebViewRendererClient getWebViewRendererClient() {
+        checkThread();
+        return mProvider.getWebViewRendererClient();
+    }
+
     /**
      * Registers the interface to be used when content can not be handled by
      * the rendering engine, and should be downloaded instead. This will replace
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index 95e7a986..baf5826 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -54,6 +54,7 @@
 import java.io.BufferedWriter;
 import java.io.File;
 import java.util.Map;
+import java.util.concurrent.Executor;
 
 /**
  * WebView backend provider interface: this interface is the abstract backend to a WebView
@@ -237,6 +238,14 @@
 
     public WebViewClient getWebViewClient();
 
+    public WebViewRenderer getWebViewRenderer();
+
+    public void setWebViewRendererClient(
+            @Nullable Executor executor,
+            @Nullable WebViewRendererClient client);
+
+    public WebViewRendererClient getWebViewRendererClient();
+
     public void setDownloadListener(DownloadListener listener);
 
     public void setWebChromeClient(WebChromeClient client);
diff --git a/core/java/android/webkit/WebViewRenderer.java b/core/java/android/webkit/WebViewRenderer.java
new file mode 100644
index 0000000..5328254
--- /dev/null
+++ b/core/java/android/webkit/WebViewRenderer.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2019 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.webkit;
+
+/**
+ * WebViewRenderer provides an opaque handle to a {@link WebView} renderer.
+ */
+public abstract class WebViewRenderer {
+    /**
+     * Cause this renderer to terminate.
+     *
+     * <p>Calling this on a not yet started, or an already terminated renderer will have no effect.
+     *
+     * <p>Terminating a renderer process may have an effect on multiple {@link WebView} instances.
+     *
+     * <p>Renderer termination must be handled by properly overriding
+     * {@link WebViewClient#onRenderProcessGone} for every WebView that shares this
+     * renderer. If termination is not handled by all associated WebViews, then the application
+     * process will also be terminated.
+     *
+     * @return {@code true} if it was possible to terminate this renderer, {@code false} otherwise.
+     */
+    public abstract boolean terminate();
+
+    /**
+     * This class cannot be created by applications.
+     * @hide
+     */
+    public WebViewRenderer() {
+    }
+}
diff --git a/core/java/android/webkit/WebViewRendererClient.java b/core/java/android/webkit/WebViewRendererClient.java
new file mode 100644
index 0000000..2fadf54
--- /dev/null
+++ b/core/java/android/webkit/WebViewRendererClient.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2019 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.webkit;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+/**
+ * Used to receive callbacks on {@link WebView} renderer events.
+ *
+ * WebViewRendererClient instances may be set or retrieved via {@link
+ * WebView#setWebViewRendererClient(WebViewRendererClient)} and {@link
+ * WebView#getWebViewRendererClient()}.
+ *
+ * Instances may be attached to multiple WebViews, and thus a single renderer event may cause
+ * a callback to be called multiple times with different WebView parameters.
+ */
+public abstract class WebViewRendererClient {
+    /**
+     * Called when the renderer currently associated with {@code view} becomes unresponsive as a
+     * result of a long running blocking task such as the execution of JavaScript.
+     *
+     * <p>If a WebView fails to process an input event, or successfully navigate to a new URL within
+     * a reasonable time frame, the renderer is considered to be unresponsive, and this callback
+     * will be called.
+     *
+     * <p>This callback will continue to be called at regular intervals as long as the renderer
+     * remains unresponsive. If the renderer becomes responsive again, {@link
+     * WebViewRendererClient#onRendererResponsive} will be called once, and this method will not
+     * subsequently be called unless another period of unresponsiveness is detected.
+     *
+     * <p>No action is taken by WebView as a result of this method call. Applications may
+     * choose to terminate the associated renderer via the object that is passed to this callback,
+     * if in multiprocess mode, however this must be accompanied by correctly handling
+     * {@link WebViewClient#onRenderProcessGone} for this WebView, and all other WebViews associated
+     * with the same renderer. Failure to do so will result in application termination.
+     *
+     * @param view The {@link WebView} for which unresponsiveness was detected.
+     * @param renderer The {@link WebViewRenderer} that has become unresponsive,
+     * or {@code null} if WebView is running in single process mode.
+     */
+    public abstract void onRendererUnresponsive(
+            @NonNull WebView view, @Nullable WebViewRenderer renderer);
+
+    /**
+     * Called once when an unresponsive renderer currently associated with {@code view} becomes
+     * responsive.
+     *
+     * <p>After a WebView renderer becomes unresponsive, which is notified to the application by
+     * {@link WebViewRendererClient#onRendererUnresponsive}, it is possible for the blocking
+     * renderer task to complete, returning the renderer to a responsive state. In that case,
+     * this method is called once to indicate responsiveness.
+     *
+     * <p>No action is taken by WebView as a result of this method call.
+     *
+     * @param view The {@link WebView} for which responsiveness was detected.
+     *
+     * @param renderer The {@link WebViewRenderer} that has become responsive, or {@code null} if
+     * WebView is running in single process mode.
+     */
+    public abstract void onRendererResponsive(
+            @NonNull WebView view, @Nullable WebViewRenderer renderer);
+}
diff --git a/core/java/com/android/internal/infra/AbstractRemoteService.java b/core/java/com/android/internal/infra/AbstractRemoteService.java
index 5945958..72c67d7 100644
--- a/core/java/com/android/internal/infra/AbstractRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractRemoteService.java
@@ -139,6 +139,14 @@
         return mDestroyed;
     }
 
+    /**
+     * Gets the name of the service.
+     */
+    @NonNull
+    public final ComponentName getComponentName() {
+        return mComponentName;
+    }
+
     private void handleOnConnectedStateChangedInternal(boolean connected) {
         if (connected) {
             handlePendingRequests();
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 12a8343b4..67c3064 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -841,6 +841,43 @@
     return jStatus;
 }
 
+static int android_media_AudioRecord_set_microphone_direction(JNIEnv *env, jobject thiz,
+                                                              jint direction) {
+    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
+    if (lpRecorder == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioRecord pointer for setMicrophoneDirection()");
+        return (jint)AUDIO_JAVA_ERROR;
+    }
+
+    jint jStatus = AUDIO_JAVA_SUCCESS;
+    status_t status =
+        lpRecorder->setMicrophoneDirection(static_cast<audio_microphone_direction_t>(direction));
+    if (status != NO_ERROR) {
+        jStatus = nativeToJavaStatus(status);
+    }
+
+    return jStatus;
+}
+
+static int android_media_AudioRecord_set_microphone_field_dimension(JNIEnv *env, jobject thiz,
+                                                                    jfloat zoom) {
+    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
+    if (lpRecorder == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioRecord pointer for setMicrophoneFieldDimension()");
+        return (jint)AUDIO_JAVA_ERROR;
+    }
+
+    jint jStatus = AUDIO_JAVA_SUCCESS;
+    status_t status = lpRecorder->setMicrophoneFieldDimension(zoom);
+    if (status != NO_ERROR) {
+        jStatus = nativeToJavaStatus(status);
+    }
+
+    return jStatus;
+}
+
 // ----------------------------------------------------------------------------
 static jint android_media_AudioRecord_get_port_id(JNIEnv *env,  jobject thiz) {
     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
@@ -896,6 +933,10 @@
     {"native_get_active_microphones", "(Ljava/util/ArrayList;)I",
                                         (void *)android_media_AudioRecord_get_active_microphones},
     {"native_getPortId", "()I", (void *)android_media_AudioRecord_get_port_id},
+    {"native_set_microphone_direction", "(I)I",
+                                (void *)android_media_AudioRecord_set_microphone_direction},
+    {"native_set_microphone_field_dimension", "(F)I",
+                                (void *)android_media_AudioRecord_set_microphone_field_dimension},
 };
 
 // field names found in android/media/AudioRecord.java
diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp
index 10da892..aa10a2f 100644
--- a/core/jni/android_view_InputEventSender.cpp
+++ b/core/jni/android_view_InputEventSender.cpp
@@ -138,6 +138,7 @@
                 event->getDeviceId(), event->getSource(), event->getDisplayId(),
                 event->getAction(), event->getActionButton(), event->getFlags(),
                 event->getEdgeFlags(), event->getMetaState(), event->getButtonState(),
+                event->getClassification(),
                 event->getXOffset(), event->getYOffset(),
                 event->getXPrecision(), event->getYPrecision(),
                 event->getDownTime(), event->getHistoricalEventTime(i),
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 7813128..cf1f7bb 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2532,6 +2532,16 @@
     <permission android:name="android.permission.WRITE_GSERVICES"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi @hide Allows an application to modify config settings.
+    <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.WRITE_DEVICE_CONFIG"
+        android:protectionLevel="signature|configurator"/>
+
+    <!-- @SystemApi @hide Allows an application to read config settings.
+    <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.READ_DEVICE_CONFIG"
+        android:protectionLevel="signature|preinstalled" />
+
     <!-- @SystemApi @TestApi Allows an application to call
         {@link android.app.ActivityManager#forceStopPackage}.
         @hide -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 18a42bc..b15f72e 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -274,6 +274,9 @@
         <!-- Additional flag from base permission type: this permission can be automatically
             granted to the document manager -->
         <flag name="documenter" value="0x40000" />
+        <!-- Additional flag from base permission type: this permission automatically
+            granted to device configurator -->
+        <flag name="configurator" value="0x80000" />
     </attr>
 
     <!-- Flags indicating more context for a permission group. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 9a1360b..bc3e9d7 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -618,15 +618,6 @@
     <!-- Integer indicating wpa_supplicant scan interval when p2p is connected in milliseconds -->
     <integer translatable="false" name="config_wifi_scan_interval_p2p_connected">60000</integer>
 
-    <!-- Integer indicating the framework scan interval in milliseconds. This is used in the scenario
-         where the chipset does not support background scanning (config_wifi_background_scan_suport
-         is false) to set up a periodic wake up scan so that the device can connect to a new access
-         point on the move. A value of 0 means no periodic scans will be used in the framework. -->
-    <integer translatable="false" name="config_wifi_framework_scan_interval">300000</integer>
-
-    <!-- Integer indicating the framework no networks periodic scan interval in milliseconds. -->
-    <integer translatable="false" name="config_wifi_no_network_periodic_scan_interval">300000</integer>
-
     <!-- Integer indicating disconnect mode short scan interval in milliseconds -->
     <integer translatable="false" name="config_wifi_disconnected_short_scan_interval">15000</integer>
 
@@ -699,6 +690,9 @@
          for automotive builds only (the one that have PackageManager#FEATURE_AUTOMOTIVE) -->
     <bool translatable="false" name="config_wifi_local_only_hotspot_5ghz">false</bool>
 
+    <!-- Indicates that connected MAC randomization is supported on this device -->
+    <bool translatable="false" name="config_wifi_connected_mac_randomization_supported">false</bool>
+
     <!-- Flag indicating whether we should enable the automatic brightness.
          Software implementation will be used if config_hardware_auto_brightness_available is not set -->
     <bool name="config_automatic_brightness_available">false</bool>
@@ -1892,6 +1886,8 @@
                cell broadcasting sms, and MMS. -->
     <bool name="config_sms_capable">true</bool>
 
+    <!-- TODO: STOPSHIP(b/110557011): Remove this from framework and overlays as we use
+         config_defaultRoleHolders now. -->
     <!-- Default SMS Application. This will be the default SMS application when
          the phone first boots. The user can then change the default app to one
          of their choosing.
@@ -1910,6 +1906,12 @@
          the behavior will be as though no app was named as an explicit default. -->
     <string name="default_browser" translatable="false"></string>
 
+    <!-- Default role holders. This will be an array of roles and package names of their default
+         holders, with each item in the format of "ROLE_NAME: PACKAGE_NAME_1, PACKAGE_NAME_2". -->
+    <string-array name="config_defaultRoleHolders" translatable="false">
+        <item>android.app.role.SMS: com.android.messaging</item>
+    </string-array>
+
     <!-- Enable/disable default bluetooth profiles:
         HSP_AG, ObexObjectPush, Audio, NAP -->
     <bool name="config_bluetooth_default_profiles">true</bool>
@@ -2805,6 +2807,9 @@
     <!-- Flag indicating which package name can access the persistent data partition -->
     <string name="config_persistentDataPackageName" translatable="false"></string>
 
+    <!-- Flag indicating which package name can access DeviceConfig table -->
+    <string name="config_deviceConfiguratorPackageName" translatable="false"></string>
+
     <!-- Flag indicating apps will skip sending hold request before merge. In this case
         IMS service implementation will do both.i.e.hold followed by merge. -->
     <bool name="skipHoldBeforeMerge">true</bool>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index b3b30e9..777886a 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2985,6 +2985,11 @@
         <public name="system_notification_accent_color" />
     </public-group>
 
+    <public-group type="array" first-id="0x01070006">
+      <!-- @hide @SystemApi -->
+      <public name="config_defaultRoleHolders" />
+    </public-group>
+
   <!-- ===============================================================
        DO NOT ADD UN-GROUPED ITEMS HERE
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index cd1ee2b..d95c7a9 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -458,9 +458,7 @@
   <java-symbol type="integer" name="config_toastDefaultGravity" />
   <java-symbol type="integer" name="config_triplePressOnPowerBehavior" />
   <java-symbol type="integer" name="config_shortPressOnSleepBehavior" />
-  <java-symbol type="integer" name="config_wifi_framework_scan_interval" />
   <java-symbol type="integer" name="config_wifi_supplicant_scan_interval" />
-  <java-symbol type="integer" name="config_wifi_no_network_periodic_scan_interval" />
   <java-symbol type="integer" name="config_wifi_scan_interval_p2p_connected" />
   <java-symbol type="integer" name="config_windowOutsetBottom" />
   <java-symbol type="integer" name="db_connection_pool_size" />
@@ -1880,6 +1878,7 @@
   <java-symbol type="bool" name="config_wifi_dual_band_support" />
   <java-symbol type="bool" name="config_wifi_convert_apband_5ghz_to_any" />
   <java-symbol type="bool" name="config_wifi_local_only_hotspot_5ghz" />
+  <java-symbol type="bool" name="config_wifi_connected_mac_randomization_supported" />
   <java-symbol type="bool" name="config_wifi_fast_bss_transition_enabled" />
   <java-symbol type="bool" name="config_wimaxEnabled" />
   <java-symbol type="bool" name="show_ongoing_ime_switcher" />
@@ -2140,6 +2139,7 @@
   <java-symbol type="string" name="config_carrierAppInstallDialogComponent" />
   <java-symbol type="string" name="config_defaultNetworkScorerPackageName" />
   <java-symbol type="string" name="config_persistentDataPackageName" />
+  <java-symbol type="string" name="config_deviceConfiguratorPackageName" />
 
   <java-symbol type="layout" name="resolver_list" />
   <java-symbol type="id" name="resolver_list" />
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index e80cb6d..86818c6 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -56,6 +56,7 @@
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.INJECT_EVENTS" />
     <uses-permission android:name="android.permission.READ_CONTACTS" />
+    <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
     <uses-permission android:name="android.permission.READ_DREAM_STATE" />
     <uses-permission android:name="android.permission.WRITE_DREAM_STATE" />
     <uses-permission android:name="android.permission.READ_LOGS"/>
@@ -65,6 +66,7 @@
     <uses-permission android:name="android.permission.USE_CREDENTIALS" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <uses-permission android:name="android.permission.WRITE_CONTACTS" />
+    <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.WRITE_SETTINGS" />
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
index a2f0eba..6ecb63a 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
@@ -115,7 +115,7 @@
         }
 
         @Override
-        void flush() {
+        void flush(int reason) {
             throw new UnsupportedOperationException("should not have been called");
         }
 
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java
new file mode 100644
index 0000000..c03d1f3
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.os.SystemClock;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.internal.os.KernelCpuThreadReader.ProcessCpuUsage;
+import com.android.internal.os.KernelCpuThreadReader.ThreadCpuUsage;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.time.Duration;
+import java.util.Arrays;
+import java.util.List;
+import java.util.OptionalDouble;
+import java.util.concurrent.CountDownLatch;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+
+/**
+ * End to end test for {@link KernelCpuThreadReader} that checks the accuracy of the reported times
+ * by spawning threads that do a predictable amount of work
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class KernelCpuThreadReaderEndToEndTest {
+
+    private static final int TIMED_NUM_SAMPLES = 5;
+    private static final int TIMED_START_MILLIS = 500;
+    private static final int TIMED_END_MILLIS = 2000;
+    private static final int TIMED_INCREMENT_MILLIS = 500;
+    private static final int TIMED_COMPARISON_DELTA_MILLIS = 200;
+
+    private static final int ITERATIVE_NUM_SAMPLES = 100;
+    private static final long ITERATIVE_LOW_ITERATIONS = (long) 1e8;
+    private static final long ITERATIVE_HIGH_ITERATIONS = (long) 2e8;
+    private static final double ITERATIONS_COMPARISONS_DELTA = 0.25;
+
+    /**
+     * Test that when we busy-wait for the thread-local time to reach N seconds, the time reported
+     * is also N seconds. Takes ~10s.
+     */
+    @Test
+    public void testTimedWork() throws InterruptedException {
+        for (int millis = TIMED_START_MILLIS;
+                millis <= TIMED_END_MILLIS;
+                millis += TIMED_INCREMENT_MILLIS) {
+            final Duration targetDuration = Duration.ofMillis(millis);
+            final Runnable work = timedWork(targetDuration);
+            Duration resultDuration = getAverageWorkTime(
+                    work, String.format("timed%dms", millis), TIMED_NUM_SAMPLES);
+            assertEquals(
+                    "Time worked according to currentThreadTimeMillis doesn't match "
+                            + "KernelCpuThreadReader",
+                    targetDuration.toMillis(), resultDuration.toMillis(),
+                    TIMED_COMPARISON_DELTA_MILLIS);
+        }
+    }
+
+    /**
+     * Test that when we scale up the amount of work by N, the time reported also scales by N. Takes
+     * ~15s.
+     */
+    @Test
+    public void testIterativeWork() throws InterruptedException {
+        final Runnable lowAmountWork = iterativeWork(ITERATIVE_LOW_ITERATIONS);
+        final Runnable highAmountWork = iterativeWork(ITERATIVE_HIGH_ITERATIONS);
+        final Duration lowResultDuration =
+                getAverageWorkTime(lowAmountWork, "iterlow", ITERATIVE_NUM_SAMPLES);
+        final Duration highResultDuration =
+                getAverageWorkTime(highAmountWork, "iterhigh", ITERATIVE_NUM_SAMPLES);
+        assertEquals(
+                "Work scale and CPU time scale do not match",
+                ((double) ITERATIVE_HIGH_ITERATIONS) / ((double) ITERATIVE_LOW_ITERATIONS),
+                ((double) highResultDuration.toMillis()) / ((double) lowResultDuration.toMillis()),
+                ITERATIONS_COMPARISONS_DELTA);
+    }
+
+    /**
+     * Run some work {@code numSamples} times, and take the average CPU duration used for that work
+     * according to {@link KernelCpuThreadReader}
+     */
+    private Duration getAverageWorkTime(
+            Runnable work, String tag, int numSamples) throws InterruptedException {
+        // Count down every time a thread finishes work, so that we can wait for work to complete
+        final CountDownLatch workFinishedLatch = new CountDownLatch(numSamples);
+        // Count down once when threads can terminate (after we get them from
+        // `KernelCpuThreadReader`)
+        final CountDownLatch threadFinishedLatch = new CountDownLatch(1);
+
+        // Start `NUM_SAMPLE` threads to do the work
+        for (int i = 0; i < numSamples; i++) {
+            final String threadName = String.format("%s%d", tag, i);
+            // Check the thread name, as we rely on it later to identify threads
+            assertTrue("Max name length for linux threads is 15", threadName.length() <= 15);
+            doWork(work, threadName, workFinishedLatch, threadFinishedLatch);
+        }
+
+        // Wait for threads to finish
+        workFinishedLatch.await();
+
+        // Get thread data from KernelCpuThreadReader
+        final KernelCpuThreadReader kernelCpuThreadReader = KernelCpuThreadReader.create();
+        assertNotNull(kernelCpuThreadReader);
+        final ProcessCpuUsage currentProcessCpuUsage =
+                kernelCpuThreadReader.getCurrentProcessCpuUsage();
+
+        // Threads can terminate, as we've finished crawling them from /proc
+        threadFinishedLatch.countDown();
+
+        // Check that we've got times for every thread we spawned
+        final List<ThreadCpuUsage> threadCpuUsages = currentProcessCpuUsage.threadCpuUsages
+                .stream()
+                .filter((thread) -> thread.threadName.startsWith(tag))
+                .collect(Collectors.toList());
+        assertEquals(
+                "Incorrect number of threads returned by KernelCpuThreadReader",
+                numSamples, threadCpuUsages.size());
+
+        // Calculate the average time spent working
+        final OptionalDouble averageWorkTimeMillis = threadCpuUsages.stream()
+                .mapToDouble((t) -> Arrays.stream(t.usageTimesMillis).sum())
+                .average();
+        assertTrue(averageWorkTimeMillis.isPresent());
+        return Duration.ofMillis((long) averageWorkTimeMillis.getAsDouble());
+    }
+
+    /**
+     * Work that lasts {@code duration} according to {@link SystemClock#currentThreadTimeMillis()}
+     */
+    private Runnable timedWork(Duration duration) {
+        return () -> {
+            // Busy loop until `duration` has elapsed for the thread timer
+            final long startTimeMillis = SystemClock.currentThreadTimeMillis();
+            final long durationMillis = duration.toMillis();
+            while (true) {
+                final long elapsedMillis = SystemClock.currentThreadTimeMillis() - startTimeMillis;
+                if (elapsedMillis >= durationMillis) {
+                    break;
+                }
+            }
+        };
+    }
+
+    /**
+     * Work that iterates {@code iterations} times
+     */
+    private Runnable iterativeWork(long iterations) {
+        Consumer<Long> empty = (i) -> {
+        };
+        return () -> {
+            long count = 0;
+            for (long i = 0; i < iterations; i++) {
+                // Alternate branching to reduce effect of branch prediction
+                if (i % 2 == 0) {
+                    count++;
+                }
+            }
+            // Call empty function with value to avoid loop getting optimized away
+            empty.accept(count);
+        };
+    }
+
+    /**
+     * Perform some work in another thread
+     *
+     * @param work                the work to perform
+     * @param threadName          the name of the spawned thread
+     * @param workFinishedLatch   latch to register that the work has been completed
+     * @param threadFinishedLatch latch to pause termination of the thread until the latch is
+     *                            decremented
+     */
+    private void doWork(
+            Runnable work,
+            String threadName,
+            CountDownLatch workFinishedLatch,
+            CountDownLatch threadFinishedLatch) {
+        Runnable workWrapped = () -> {
+            // Do the work
+            work.run();
+            // Notify that the work is finished
+            workFinishedLatch.countDown();
+            // Wait until `threadFinishLatch` has been released in order to keep the thread alive so
+            // we can see it in `proc` filesystem
+            try {
+                threadFinishedLatch.await();
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        };
+        new Thread(workWrapped, threadName).start();
+    }
+}
diff --git a/media/Android.bp b/media/Android.bp
index d5da6f2..8ebc91a 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -1,4 +1,21 @@
 java_library {
+    name: "media1",
+
+    srcs: [
+        ":media1-srcs",
+    ],
+
+    sdk_version: "system_current",
+}
+
+filegroup {
+    name: "media1-srcs",
+    srcs: [
+        "java/android/media/session/MediaSessionProviderService.java",
+    ],
+}
+
+java_library {
     // TODO: include media2.jar in the media apex and add it to the bootclasspath.
     name: "media2",
 
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 33f81f1..92afe7e 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -61,7 +61,8 @@
  * been read yet. Data should be read from the audio hardware in chunks of sizes inferior to
  * the total recording buffer size.
  */
-public class AudioRecord implements AudioRouting, AudioRecordingMonitor, AudioRecordingMonitorClient
+public class AudioRecord implements AudioRouting, MicrophoneDirection,
+        AudioRecordingMonitor, AudioRecordingMonitorClient
 {
     //---------------------------------------------------------
     // Constants
@@ -1657,7 +1658,6 @@
         return activeMicrophones;
     }
 
-
     //--------------------------------------------------------------------------
     // Implementation of AudioRecordingMonitor interface
     //--------------------
@@ -1707,6 +1707,33 @@
         return native_getPortId();
     }
 
+    //--------------------------------------------------------------------------
+    // MicrophoneDirection
+    //--------------------
+    /**
+     * Specifies the logical microphone (for processing).
+     *
+     * @param direction Direction constant (MicrophoneDirection.MIC_DIRECTION_*)
+     * @return retval OK if the call is successful, an error code otherwise.
+     * @hide
+     */
+    public int setMicrophoneDirection(int direction) {
+        return native_set_microphone_direction(direction);
+    }
+
+    /**
+     * Specifies the zoom factor (i.e. the field dimension) for the selected microphone
+     * (for processing). The selected microphone is determined by the use-case for the stream.
+     *
+     * @param zoom the desired field dimension of microphone capture. Range is from -1 (wide angle),
+     * though 0 (no zoom) to 1 (maximum zoom).
+     * @return retval OK if the call is successful, an error code otherwise.
+     * @hide
+     */
+    public int setMicrophoneFieldDimension(float zoom) {
+        return native_set_microphone_field_dimension(zoom);
+    }
+
     //---------------------------------------------------------
     // Interface definitions
     //--------------------
@@ -1860,6 +1887,9 @@
 
     private native int native_getPortId();
 
+    private native int native_set_microphone_direction(int direction);
+    private native int native_set_microphone_field_dimension(float zoom);
+
     //---------------------------------------------------------
     // Utility methods
     //------------------
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index bc9500d..f756658 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -1829,9 +1829,14 @@
 
         mBufferLock = new Object();
 
+        // save name used at creation
+        mNameAtCreation = nameIsType ? null : name;
+
         native_setup(name, nameIsType, encoder);
     }
 
+    private String mNameAtCreation;
+
     @Override
     protected void finalize() {
         native_finalize();
@@ -3317,12 +3322,36 @@
     private native void native_setAudioPresentation(int presentationId, int programId);
 
     /**
-     * Get the component name. If the codec was created by createDecoderByType
-     * or createEncoderByType, what component is chosen is not known beforehand.
+     * Retrieve the codec name.
+     *
+     * If the codec was created by createDecoderByType or createEncoderByType, what component is
+     * chosen is not known beforehand. This method returns the name of the codec that was
+     * selected by the platform.
+     *
+     * <strong>Note:</strong> Implementations may provide multiple aliases (codec
+     * names) for the same underlying codec, any of which can be used to instantiate the same
+     * underlying codec in {@link MediaCodec#createByCodecName}. This method returns the
+     * name used to create the codec in this case.
+     *
      * @throws IllegalStateException if in the Released state.
      */
     @NonNull
-    public native final String getName();
+    public final String getName() {
+        // get canonical name to handle exception
+        String canonicalName = getCanonicalName();
+        return mNameAtCreation != null ? mNameAtCreation : canonicalName;
+    }
+
+    /**
+     * Retrieve the underlying codec name.
+     *
+     * This method is similar to {@link #getName}, except that it returns the underlying component
+     * name even if an alias was used to create this MediaCodec object by name,
+     *
+     * @throws IllegalStateException if in the Released state.
+     */
+    @NonNull
+    public native final String getCanonicalName();
 
     /**
      *  Return Metrics data about the current codec instance.
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 10a1e3a..751d57b 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -32,8 +32,10 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.Vector;
 
 /**
  * Provides information about a given media codec available on the device. You can
@@ -61,15 +63,25 @@
  *
  */
 public final class MediaCodecInfo {
-    private boolean mIsEncoder;
+    private static final String TAG = "MediaCodecInfo";
+
+    private static final int FLAG_IS_ENCODER = (1 << 0);
+    private static final int FLAG_IS_VENDOR = (1 << 1);
+    private static final int FLAG_IS_SOFTWARE_ONLY = (1 << 2);
+    private static final int FLAG_IS_HARDWARE_ACCELERATED = (1 << 3);
+
+    private int mFlags;
     private String mName;
+    private String mCanonicalName;
     private Map<String, CodecCapabilities> mCaps;
 
     /* package private */ MediaCodecInfo(
-            String name, boolean isEncoder, CodecCapabilities[] caps) {
+            String name, String canonicalName, int flags, CodecCapabilities[] caps) {
         mName = name;
-        mIsEncoder = isEncoder;
+        mCanonicalName = canonicalName;
+        mFlags = flags;
         mCaps = new HashMap<String, CodecCapabilities>();
+
         for (CodecCapabilities c: caps) {
             mCaps.put(c.getMimeType(), c);
         }
@@ -77,16 +89,69 @@
 
     /**
      * Retrieve the codec name.
+     *
+     * <strong>Note:</strong> Implementations may provide multiple aliases (codec
+     * names) for the same underlying codec, any of which can be used to instantiate the same
+     * underlying codec in {@link MediaCodec#createByCodecName}.
+     *
+     * Applications targeting SDK < {@link android.os.Build.VERSION_CODES#Q}, cannot determine if
+     * the multiple codec names listed in MediaCodecList are in-fact for the same codec.
      */
+    @NonNull
     public final String getName() {
         return mName;
     }
 
     /**
+     * Retrieve the underlying codec name.
+     *
+     * Device implementations may provide multiple aliases (codec names) for the same underlying
+     * codec to maintain backward app compatibility. This method returns the name of the underlying
+     * codec name, which must not be another alias. For non-aliases this is always the name of the
+     * codec.
+     */
+    @NonNull
+    public final String getCanonicalName() {
+        return mCanonicalName;
+    }
+
+    /**
+     * Query if the codec is an alias for another underlying codec.
+     */
+    public final boolean isAlias() {
+        return !mName.equals(mCanonicalName);
+    }
+
+    /**
      * Query if the codec is an encoder.
      */
     public final boolean isEncoder() {
-        return mIsEncoder;
+        return (mFlags & FLAG_IS_ENCODER) != 0;
+    }
+
+    /**
+     * Query if the codec is provided by the Android platform (false) or the device manufacturer
+     * (true).
+     */
+    public final boolean isVendor() {
+        return (mFlags & FLAG_IS_VENDOR) != 0;
+    }
+
+    /**
+     * Query if the codec is software only. Software-only codecs are more secure as they run in
+     * a tighter security sandbox. On the other hand, software-only codecs do not provide any
+     * performance guarantees.
+     */
+    public final boolean isSoftwareOnly() {
+        return (mFlags & FLAG_IS_SOFTWARE_ONLY) != 0;
+    }
+
+    /**
+     * Query if the codec is hardware accelerated. This attribute is provided by the device
+     * manufacturer. Note that it cannot be tested for correctness.
+     */
+    public final boolean isHardwareAccelerated() {
+        return (mFlags & FLAG_IS_HARDWARE_ACCELERATED) != 0;
     }
 
     /**
@@ -163,7 +228,7 @@
         // such as B-frame support, arithmetic coding...
         public CodecProfileLevel[] profileLevels;  // NOTE this array is modifiable by user
 
-        // from OMX_COLOR_FORMATTYPE
+        // from MediaCodecConstants
         /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */
         public static final int COLOR_FormatMonochrome              = 1;
         /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */
@@ -344,7 +409,7 @@
         /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
         public static final int COLOR_TI_FormatYUV420PackedSemiPlanar = 0x7f000100;
         // COLOR_FormatSurface indicates that the data will be a GraphicBuffer metadata reference.
-        // In OMX this is called OMX_COLOR_FormatAndroidOpaque.
+        // Note: in OMX this is called OMX_COLOR_FormatAndroidOpaque.
         public static final int COLOR_FormatSurface                   = 0x7F000789;
 
         /**
@@ -435,8 +500,7 @@
         public static final int COLOR_QCOM_FormatYUV420SemiPlanar     = 0x7fa30c00;
 
         /**
-         * Defined in the OpenMAX IL specs, color format values are drawn from
-         * OMX_COLOR_FORMATTYPE.
+         * The color format for the media. This is one of the color constants defined in this class.
          */
         public int[] colorFormats; // NOTE this array is modifiable by user
 
@@ -462,6 +526,26 @@
         public static final String FEATURE_TunneledPlayback       = "tunneled-playback";
 
         /**
+         * If true, the timestamp of each output buffer is derived from the timestamp of the input
+         * buffer that produced the output. If false, the timestamp of each output buffer is
+         * derived from the timestamp of the first input buffer.
+         */
+        public static final String FEATURE_DynamicTimestamp = "dynamic-timestamp";
+
+        /**
+         * <b>decoder only</b>If true, the codec supports partial (including multiple) access units
+         * per input buffer.
+         */
+        public static final String FEATURE_FrameParsing = "frame-parsing";
+
+        /**
+         * If true, the codec supports multiple access units (for decoding, or to output for
+         * encoders). If false, the codec only supports single access units. Producing multiple
+         * access units for output is an optional feature.
+         */
+        public static final String FEATURE_MultipleFrames = "multiple-frames";
+
+        /**
          * <b>video decoder only</b>: codec supports queuing partial frames.
          */
         public static final String FEATURE_PartialFrame = "partial-frame";
@@ -497,10 +581,15 @@
             new Feature(FEATURE_SecurePlayback,   (1 << 1), false),
             new Feature(FEATURE_TunneledPlayback, (1 << 2), false),
             new Feature(FEATURE_PartialFrame,     (1 << 3), false),
+            new Feature(FEATURE_FrameParsing,     (1 << 4), false),
+            new Feature(FEATURE_MultipleFrames,   (1 << 5), false),
+            new Feature(FEATURE_DynamicTimestamp, (1 << 6), false),
         };
 
         private static final Feature[] encoderFeatures = {
             new Feature(FEATURE_IntraRefresh, (1 << 0), false),
+            new Feature(FEATURE_MultipleFrames, (1 << 1), false),
+            new Feature(FEATURE_DynamicTimestamp, (1 << 2), false),
         };
 
         /** @hide */
@@ -869,7 +958,7 @@
 
             CodecCapabilities ret = new CodecCapabilities(
                 new CodecProfileLevel[] { pl }, new int[0], true /* encoder */,
-                0 /* flags */, defaultFormat, new MediaFormat() /* info */);
+                defaultFormat, new MediaFormat() /* info */);
             if (ret.mError != 0) {
                 return null;
             }
@@ -878,10 +967,10 @@
 
         /* package private */ CodecCapabilities(
                 CodecProfileLevel[] profLevs, int[] colFmts,
-                boolean encoder, int flags,
+                boolean encoder,
                 Map<String, Object>defaultFormatMap,
                 Map<String, Object>capabilitiesMap) {
-            this(profLevs, colFmts, encoder, flags,
+            this(profLevs, colFmts, encoder,
                     new MediaFormat(defaultFormatMap),
                     new MediaFormat(capabilitiesMap));
         }
@@ -889,11 +978,11 @@
         private MediaFormat mCapabilitiesInfo;
 
         /* package private */ CodecCapabilities(
-                CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder, int flags,
+                CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder,
                 MediaFormat defaultFormat, MediaFormat info) {
             final Map<String, Object> map = info.getMap();
             colorFormats = colFmts;
-            mFlagsVerified = flags;
+            mFlagsVerified = 0; // TODO: remove as it is unused
             mDefaultFormat = defaultFormat;
             mCapabilitiesInfo = info;
             mMime = mDefaultFormat.getString(MediaFormat.KEY_MIME);
@@ -1243,6 +1332,7 @@
         private Range<Rational> mBlockAspectRatioRange;
         private Range<Long> mBlocksPerSecondRange;
         private Map<Size, Range<Long>> mMeasuredFrameRates;
+        private Vector<PerformancePoint> mPerformancePoints;
         private Range<Integer> mFrameRateRange;
 
         private int mBlockWidth;
@@ -1524,6 +1614,158 @@
         }
 
         /**
+         * Video performance points are a set of standard performance points defined by pixel rate.
+         */
+        public static final class PerformancePoint {
+            /**
+             * Frame width in pixels.
+             */
+            public final int width;
+
+            /**
+             * Frame height in pixels.
+             */
+            public final int height;
+
+            /**
+             * Frame rate in frames per second.
+             */
+            public final int frameRate;
+
+            /* package private */
+            PerformancePoint(int width_, int height_, int frameRate_) {
+                width = width_;
+                height = height_;
+                frameRate = frameRate_;
+            }
+
+            /**
+             * Checks whether the performance point covers a media format.
+             *
+             * @param format Stream format considered
+             *
+             * @return {@code true} if the performance point covers the format.
+             */
+            public boolean covers(@NonNull MediaFormat format) {
+                // for simplicity, this code assumes a 16x16 block size.
+                long macroBlocks = ((width + 15) / 16) * (long)((height + 15) / 16);
+                long mbps = macroBlocks * frameRate;
+
+                long formatMacroBlocks =
+                    (long)((format.getInteger(MediaFormat.KEY_WIDTH, 0) + 15) / 16)
+                            * ((format.getInteger(MediaFormat.KEY_HEIGHT, 0) + 15) / 16);
+                double formatMbps =
+                    Math.ceil(formatMacroBlocks
+                              * format.getNumber(MediaFormat.KEY_FRAME_RATE, 0).doubleValue());
+                return formatMacroBlocks > 0 && formatMacroBlocks <= macroBlocks
+                        && formatMbps <= mbps;
+            }
+
+            @Override
+            public boolean equals(Object o) {
+                if (o instanceof PerformancePoint) {
+                    PerformancePoint other = (PerformancePoint)o;
+                    return ((long)width * height) == ((long)other.width * other.height)
+                            && frameRate == other.frameRate;
+                }
+                return false;
+            }
+
+            /** 480p 24fps */
+            public static final PerformancePoint SD_24 = new PerformancePoint(720, 480, 24);
+            /** 576p 25fps */
+            public static final PerformancePoint SD_25 = new PerformancePoint(720, 576, 25);
+            /** 480p 30fps */
+            public static final PerformancePoint SD_30 = new PerformancePoint(720, 480, 30);
+            /** 480p 48fps */
+            public static final PerformancePoint SD_48 = new PerformancePoint(720, 480, 48);
+            /** 576p 50fps */
+            public static final PerformancePoint SD_50 = new PerformancePoint(720, 576, 50);
+            /** 480p 60fps */
+            public static final PerformancePoint SD_60 = new PerformancePoint(720, 480, 60);
+
+            /** 720p 24fps */
+            public static final PerformancePoint HD_24 = new PerformancePoint(1280, 720, 24);
+            /** 720p 25fps */
+            public static final PerformancePoint HD_25 = new PerformancePoint(1280, 720, 25);
+            /** 720p 30fps */
+            public static final PerformancePoint HD_30 = new PerformancePoint(1280, 720, 30);
+            /** 720p 50fps */
+            public static final PerformancePoint HD_50 = new PerformancePoint(1280, 720, 50);
+            /** 720p 60fps */
+            public static final PerformancePoint HD_60 = new PerformancePoint(1280, 720, 60);
+            /** 720p 100fps */
+            public static final PerformancePoint HD_100 = new PerformancePoint(1280, 720, 100);
+            /** 720p 120fps */
+            public static final PerformancePoint HD_120 = new PerformancePoint(1280, 720, 120);
+            /** 720p 200fps */
+            public static final PerformancePoint HD_200 = new PerformancePoint(1280, 720, 200);
+            /** 720p 240fps */
+            public static final PerformancePoint HD_240 = new PerformancePoint(1280, 720, 240);
+
+            /** 1080p 24fps */
+            public static final PerformancePoint FHD_24 = new PerformancePoint(1920, 1080, 24);
+            /** 1080p 25fps */
+            public static final PerformancePoint FHD_25 = new PerformancePoint(1920, 1080, 25);
+            /** 1080p 30fps */
+            public static final PerformancePoint FHD_30 = new PerformancePoint(1920, 1080, 30);
+            /** 1080p 50fps */
+            public static final PerformancePoint FHD_50 = new PerformancePoint(1920, 1080, 50);
+            /** 1080p 60fps */
+            public static final PerformancePoint FHD_60 = new PerformancePoint(1920, 1080, 60);
+            /** 1080p 100fps */
+            public static final PerformancePoint FHD_100 = new PerformancePoint(1920, 1080, 100);
+            /** 1080p 120fps */
+            public static final PerformancePoint FHD_120 = new PerformancePoint(1920, 1080, 120);
+            /** 1080p 200fps */
+            public static final PerformancePoint FHD_200 = new PerformancePoint(1920, 1080, 200);
+            /** 1080p 240fps */
+            public static final PerformancePoint FHD_240 = new PerformancePoint(1920, 1080, 240);
+
+            /** 2160p 24fps */
+            public static final PerformancePoint UHD_24 = new PerformancePoint(3840, 2160, 24);
+            /** 2160p 25fps */
+            public static final PerformancePoint UHD_25 = new PerformancePoint(3840, 2160, 25);
+            /** 2160p 30fps */
+            public static final PerformancePoint UHD_30 = new PerformancePoint(3840, 2160, 30);
+            /** 2160p 50fps */
+            public static final PerformancePoint UHD_50 = new PerformancePoint(3840, 2160, 50);
+            /** 2160p 60fps */
+            public static final PerformancePoint UHD_60 = new PerformancePoint(3840, 2160, 60);
+            /** 2160p 100fps */
+            public static final PerformancePoint UHD_100 = new PerformancePoint(3840, 2160, 100);
+            /** 2160p 120fps */
+            public static final PerformancePoint UHD_120 = new PerformancePoint(3840, 2160, 120);
+            /** 2160p 200fps */
+            public static final PerformancePoint UHD_200 = new PerformancePoint(3840, 2160, 200);
+            /** 2160p 240fps */
+            public static final PerformancePoint UHD_240 = new PerformancePoint(3840, 2160, 240);
+        }
+
+        /**
+         * Returns the supported performance points. May return {@code null} if the codec did not
+         * publish any performance point information (e.g. the vendor codecs have not been updated
+         * to the latest android release). May return an empty list if the codec published that
+         * if does not guarantee any performance points.
+         * <p>
+         * This is a performance guarantee provided by the device manufacturer for hardware codecs
+         * based on hardware capabilities of the device.
+         * <p>
+         * The returned list is sorted first by decreasing number of pixels, then by decreasing
+         * width, and finally by decreasing frame rate.
+         * Performance points assume a single active codec. For use cases where multiple
+         * codecs are active, should use that highest pixel count, and add the frame rates of
+         * each individual codec.
+         */
+        @Nullable
+        public List<PerformancePoint> getSupportedPerformancePoints() {
+            if (mPerformancePoints == null) {
+                return null;
+            }
+            return new ArrayList<PerformancePoint>(mPerformancePoints);
+        }
+
+        /**
          * Returns whether a given video size ({@code width} and
          * {@code height}) and {@code frameRate} combination is supported.
          */
@@ -1659,6 +1901,50 @@
             mSmallerDimensionUpperLimit = SIZE_RANGE.getUpper();
         }
 
+        private @Nullable Vector<PerformancePoint> getPerformancePoints(Map<String, Object> map) {
+            Vector<PerformancePoint> ret = new Vector<>();
+            final String prefix = "performance-point-";
+            Set<String> keys = map.keySet();
+            for (String key : keys) {
+                // looking for: performance-point-WIDTHxHEIGHT-range
+                if (!key.startsWith(prefix)) {
+                    continue;
+                }
+                String subKey = key.substring(prefix.length());
+                if (subKey.equals("none") && ret.size() == 0) {
+                    // This means that component knowingly did not publish performance points.
+                    // This is different from when the component forgot to publish performance
+                    // points.
+                    return ret;
+                }
+                String[] temp = key.split("-");
+                if (temp.length != 4) {
+                    continue;
+                }
+                String sizeStr = temp[2];
+                Size size = Utils.parseSize(sizeStr, null);
+                if (size == null || size.getWidth() * size.getHeight() <= 0) {
+                    continue;
+                }
+                Range<Long> range = Utils.parseLongRange(map.get(key), null);
+                if (range == null || range.getLower() < 0 || range.getUpper() < 0) {
+                    continue;
+                }
+                ret.add(new PerformancePoint(
+                        size.getWidth(), size.getHeight(), range.getLower().intValue()));
+            }
+            // check if the component specified no performance point indication
+            if (ret.size() == 0) {
+                return null;
+            }
+
+            // sort reversed by area first, then by frame rate
+            ret.sort((a, b) -> (a.width * a.height != b.width * b.height ?
+                                    (b.width * b.height - a.width * a.height) :
+                                    (b.frameRate - a.frameRate)));
+            return ret;
+        }
+
         private Map<Size, Range<Long>> getMeasuredFrameRates(Map<String, Object> map) {
             Map<Size, Range<Long>> ret = new HashMap<Size, Range<Long>>();
             final String prefix = "measured-frame-rate-";
@@ -1770,6 +2056,7 @@
             blockRates =
                 Utils.parseLongRange(map.get("blocks-per-second-range"), null);
             mMeasuredFrameRates = getMeasuredFrameRates(map);
+            mPerformancePoints = getPerformancePoints(map);
             Pair<Range<Integer>, Range<Integer>> sizeRanges =
                 parseWidthHeightRanges(map.get("size-range"));
             if (sizeRanges != null) {
@@ -2879,7 +3166,9 @@
      * {@link MediaCodecInfo.CodecCapabilities#profileLevels} field.
      */
     public static final class CodecProfileLevel {
-        // from OMX_VIDEO_AVCPROFILETYPE
+        // These constants were originally in-line with OMX values, but this
+        // correspondence is no longer maintained.
+
         public static final int AVCProfileBaseline = 0x01;
         public static final int AVCProfileMain     = 0x02;
         public static final int AVCProfileExtended = 0x04;
@@ -2890,7 +3179,6 @@
         public static final int AVCProfileConstrainedBaseline = 0x10000;
         public static final int AVCProfileConstrainedHigh     = 0x80000;
 
-        // from OMX_VIDEO_AVCLEVELTYPE
         public static final int AVCLevel1       = 0x01;
         public static final int AVCLevel1b      = 0x02;
         public static final int AVCLevel11      = 0x04;
@@ -2908,8 +3196,10 @@
         public static final int AVCLevel5       = 0x4000;
         public static final int AVCLevel51      = 0x8000;
         public static final int AVCLevel52      = 0x10000;
+        public static final int AVCLevel6       = 0x20000;
+        public static final int AVCLevel61      = 0x40000;
+        public static final int AVCLevel62      = 0x80000;
 
-        // from OMX_VIDEO_H263PROFILETYPE
         public static final int H263ProfileBaseline             = 0x01;
         public static final int H263ProfileH320Coding           = 0x02;
         public static final int H263ProfileBackwardCompatible   = 0x04;
@@ -2920,7 +3210,6 @@
         public static final int H263ProfileInterlace            = 0x80;
         public static final int H263ProfileHighLatency          = 0x100;
 
-        // from OMX_VIDEO_H263LEVELTYPE
         public static final int H263Level10      = 0x01;
         public static final int H263Level20      = 0x02;
         public static final int H263Level30      = 0x04;
@@ -2930,7 +3219,6 @@
         public static final int H263Level60      = 0x40;
         public static final int H263Level70      = 0x80;
 
-        // from OMX_VIDEO_MPEG4PROFILETYPE
         public static final int MPEG4ProfileSimple              = 0x01;
         public static final int MPEG4ProfileSimpleScalable      = 0x02;
         public static final int MPEG4ProfileCore                = 0x04;
@@ -2948,7 +3236,6 @@
         public static final int MPEG4ProfileAdvancedScalable    = 0x4000;
         public static final int MPEG4ProfileAdvancedSimple      = 0x8000;
 
-        // from OMX_VIDEO_MPEG4LEVELTYPE
         public static final int MPEG4Level0      = 0x01;
         public static final int MPEG4Level0b     = 0x02;
         public static final int MPEG4Level1      = 0x04;
@@ -2960,7 +3247,6 @@
         public static final int MPEG4Level5      = 0x80;
         public static final int MPEG4Level6      = 0x100;
 
-        // from OMX_VIDEO_MPEG2PROFILETYPE
         public static final int MPEG2ProfileSimple              = 0x00;
         public static final int MPEG2ProfileMain                = 0x01;
         public static final int MPEG2Profile422                 = 0x02;
@@ -2968,14 +3254,12 @@
         public static final int MPEG2ProfileSpatial             = 0x04;
         public static final int MPEG2ProfileHigh                = 0x05;
 
-        // from OMX_VIDEO_MPEG2LEVELTYPE
         public static final int MPEG2LevelLL     = 0x00;
         public static final int MPEG2LevelML     = 0x01;
         public static final int MPEG2LevelH14    = 0x02;
         public static final int MPEG2LevelHL     = 0x03;
         public static final int MPEG2LevelHP     = 0x04;
 
-        // from OMX_AUDIO_AACPROFILETYPE
         public static final int AACObjectMain       = 1;
         public static final int AACObjectLC         = 2;
         public static final int AACObjectSSR        = 3;
@@ -2990,16 +3274,13 @@
         /** xHE-AAC (includes USAC) */
         public static final int AACObjectXHE        = 42;
 
-        // from OMX_VIDEO_VP8LEVELTYPE
         public static final int VP8Level_Version0 = 0x01;
         public static final int VP8Level_Version1 = 0x02;
         public static final int VP8Level_Version2 = 0x04;
         public static final int VP8Level_Version3 = 0x08;
 
-        // from OMX_VIDEO_VP8PROFILETYPE
         public static final int VP8ProfileMain = 0x01;
 
-        // from OMX_VIDEO_VP9PROFILETYPE
         public static final int VP9Profile0 = 0x01;
         public static final int VP9Profile1 = 0x02;
         public static final int VP9Profile2 = 0x04;
@@ -3010,7 +3291,6 @@
         public static final int VP9Profile2HDR10Plus = 0x4000;
         public static final int VP9Profile3HDR10Plus = 0x8000;
 
-        // from OMX_VIDEO_VP9LEVELTYPE
         public static final int VP9Level1  = 0x1;
         public static final int VP9Level11 = 0x2;
         public static final int VP9Level2  = 0x4;
@@ -3026,14 +3306,12 @@
         public static final int VP9Level61 = 0x1000;
         public static final int VP9Level62 = 0x2000;
 
-        // from OMX_VIDEO_HEVCPROFILETYPE
         public static final int HEVCProfileMain        = 0x01;
         public static final int HEVCProfileMain10      = 0x02;
         public static final int HEVCProfileMainStill   = 0x04;
         public static final int HEVCProfileMain10HDR10 = 0x1000;
         public static final int HEVCProfileMain10HDR10Plus = 0x2000;
 
-        // from OMX_VIDEO_HEVCLEVELTYPE
         public static final int HEVCMainTierLevel1  = 0x1;
         public static final int HEVCHighTierLevel1  = 0x2;
         public static final int HEVCMainTierLevel2  = 0x4;
@@ -3067,7 +3345,6 @@
             HEVCHighTierLevel51 | HEVCHighTierLevel52 | HEVCHighTierLevel6 | HEVCHighTierLevel61 |
             HEVCHighTierLevel62;
 
-        // from OMX_VIDEO_DOLBYVISIONPROFILETYPE
         public static final int DolbyVisionProfileDvavPer = 0x1;
         public static final int DolbyVisionProfileDvavPen = 0x2;
         public static final int DolbyVisionProfileDvheDer = 0x4;
@@ -3079,7 +3356,6 @@
         public static final int DolbyVisionProfileDvheSt = 0x100;
         public static final int DolbyVisionProfileDvavSe = 0x200;
 
-        // from OMX_VIDEO_DOLBYVISIONLEVELTYPE
         public static final int DolbyVisionLevelHd24    = 0x1;
         public static final int DolbyVisionLevelHd30    = 0x2;
         public static final int DolbyVisionLevelFhd24   = 0x4;
@@ -3090,17 +3366,44 @@
         public static final int DolbyVisionLevelUhd48   = 0x80;
         public static final int DolbyVisionLevelUhd60   = 0x100;
 
+        public static final int AV1Profile0     = 0x1;
+        public static final int AV1Profile1     = 0x2;
+        public static final int AV1Profile2     = 0x4;
+
+        public static final int AV1Level2       = 0x1;
+        public static final int AV1Level21      = 0x2;
+        public static final int AV1Level22      = 0x4;
+        public static final int AV1Level23      = 0x8;
+        public static final int AV1Level3       = 0x10;
+        public static final int AV1Level31      = 0x20;
+        public static final int AV1Level32      = 0x40;
+        public static final int AV1Level33      = 0x80;
+        public static final int AV1Level4       = 0x100;
+        public static final int AV1Level41      = 0x200;
+        public static final int AV1Level42      = 0x400;
+        public static final int AV1Level43      = 0x800;
+        public static final int AV1Level5       = 0x1000;
+        public static final int AV1Level51      = 0x2000;
+        public static final int AV1Level52      = 0x4000;
+        public static final int AV1Level53      = 0x8000;
+        public static final int AV1Level6       = 0x10000;
+        public static final int AV1Level61      = 0x20000;
+        public static final int AV1Level62      = 0x40000;
+        public static final int AV1Level63      = 0x80000;
+        public static final int AV1Level7       = 0x100000;
+        public static final int AV1Level71      = 0x200000;
+        public static final int AV1Level72      = 0x400000;
+        public static final int AV1Level73      = 0x800000;
+
         /**
-         * Defined in the OpenMAX IL specs, depending on the type of media
-         * this can be OMX_VIDEO_AVCPROFILETYPE, OMX_VIDEO_H263PROFILETYPE,
-         * OMX_VIDEO_MPEG4PROFILETYPE, OMX_VIDEO_VP8PROFILETYPE or OMX_VIDEO_VP9PROFILETYPE.
+         * The profile of the media content. Depending on the type of media this can be
+         * one of the profile values defined in this class.
          */
         public int profile;
 
         /**
-         * Defined in the OpenMAX IL specs, depending on the type of media
-         * this can be OMX_VIDEO_AVCLEVELTYPE, OMX_VIDEO_H263LEVELTYPE
-         * OMX_VIDEO_MPEG4LEVELTYPE, OMX_VIDEO_VP8LEVELTYPE or OMX_VIDEO_VP9LEVELTYPE.
+         * The level of the media content. Depending on the type of media this can be
+         * one of the level values defined in this class.
          *
          * Note that VP9 decoder on platforms before {@link android.os.Build.VERSION_CODES#N} may
          * not advertise a profile level support. For those VP9 decoders, please use
@@ -3157,7 +3460,7 @@
         }
 
         return new MediaCodecInfo(
-                mName, mIsEncoder,
+                mName, mCanonicalName, mFlags,
                 caps.toArray(new CodecCapabilities[caps.size()]));
     }
 }
diff --git a/media/java/android/media/MediaCodecList.java b/media/java/android/media/MediaCodecList.java
index 2e47865..a460954 100644
--- a/media/java/android/media/MediaCodecList.java
+++ b/media/java/android/media/MediaCodecList.java
@@ -111,12 +111,14 @@
             caps[typeIx++] = getCodecCapabilities(index, type);
         }
         return new MediaCodecInfo(
-                getCodecName(index), isEncoder(index), caps);
+                getCodecName(index), getCanonicalName(index), getAttributes(index), caps);
     }
 
     /* package private */ static native final String getCodecName(int index);
 
-    /* package private */ static native final boolean isEncoder(int index);
+    /* package private */ static native final String getCanonicalName(int index);
+
+    /* package private */ static native final int getAttributes(int index);
 
     /* package private */ static native final String[] getSupportedTypes(int index);
 
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 594a224..c82b5f6 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -124,6 +124,7 @@
 public final class MediaFormat {
     public static final String MIMETYPE_VIDEO_VP8 = "video/x-vnd.on2.vp8";
     public static final String MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9";
+    public static final String MIMETYPE_VIDEO_AV1 = "video/av01";
     public static final String MIMETYPE_VIDEO_AVC = "video/avc";
     public static final String MIMETYPE_VIDEO_HEVC = "video/hevc";
     public static final String MIMETYPE_VIDEO_MPEG4 = "video/mp4v-es";
diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java
index dceef34..04999ca 100644
--- a/media/java/android/media/MediaSession2.java
+++ b/media/java/android/media/MediaSession2.java
@@ -239,7 +239,7 @@
         final ControllerInfo controllerInfo = new ControllerInfo(remoteUserInfo,
                 mSessionManager.isTrustedForMediaControl(remoteUserInfo), controller);
         mCallbackExecutor.execute(() -> {
-            boolean accept = false;
+            boolean connected = false;
             try {
                 if (isClosed()) {
                     return;
@@ -249,8 +249,7 @@
                 // Don't reject connection for the request from trusted app.
                 // Otherwise server will fail to retrieve session's information to dispatch
                 // media keys to.
-                accept = controllerInfo.mAllowedCommands != null || controllerInfo.isTrusted();
-                if (!accept) {
+                if (controllerInfo.mAllowedCommands == null && !controllerInfo.isTrusted()) {
                     return;
                 }
                 if (controllerInfo.mAllowedCommands == null) {
@@ -283,13 +282,18 @@
                     return;
                 }
                 controllerInfo.notifyConnected(connectionResult);
+                connected = true;
             } finally {
-                if (!accept) {
+                if (!connected) {
                     if (DEBUG) {
-                        Log.d(TAG, "Rejecting connection, controllerInfo=" + controllerInfo);
+                        Log.d(TAG, "Rejecting connection or notifying that session is closed"
+                                + ", controllerInfo=" + controllerInfo);
                     }
+                    synchronized (mLock) {
+                        mConnectedControllers.remove(controller);
+                    }
+                    controllerInfo.notifyDisconnected();
                 }
-                controllerInfo.notifyDisconnected();
             }
         });
     }
diff --git a/media/java/android/media/MicrophoneDirection.java b/media/java/android/media/MicrophoneDirection.java
new file mode 100644
index 0000000..99201c0
--- /dev/null
+++ b/media/java/android/media/MicrophoneDirection.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+/**
+ * @hide
+ */
+public interface MicrophoneDirection {
+    /**
+     * @hide
+     */
+    int MIC_DIRECTION_UNSPECIFIED = 0;
+
+    /**
+     * @hide
+     */
+    int MIC_DIRECTION_FRONT = 1;
+
+    /**
+     * @hide
+     */
+    int MIC_DIRECTION_BACK = 2;
+
+    /**
+     * @hide
+     */
+    int MIC_DIRECTION_EXTERNAL = 3;
+
+    /**
+     * Specifies the logical microphone (for processing).
+     *
+     * @param direction Direction constant (MicrophoneDirection.MIC_DIRECTION_*)
+     * @return retval OK if the call is successful, an error code otherwise.
+     * @hide
+     */
+    int setMicrophoneDirection(int direction);
+
+    /**
+     * Specifies the zoom factor (i.e. the field dimension) for the selected microphone
+     * (for processing). The selected microphone is determined by the use-case for the stream.
+     *
+     * @param zoom the desired field dimension of microphone capture. Range is from -1 (wide angle),
+     * though 0 (no zoom) to 1 (maximum zoom).
+     * @return retval OK if the call is successful, an error code otherwise.
+     * @hide
+     */
+    int setMicrophoneFieldDimension(float zoom);
+}
diff --git a/media/java/android/media/session/MediaSessionProviderService.java b/media/java/android/media/session/MediaSessionProviderService.java
new file mode 100644
index 0000000..9a346ff
--- /dev/null
+++ b/media/java/android/media/session/MediaSessionProviderService.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 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.session;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+/**
+ * Abstract class for mainline module services.
+ *
+ * @hide  // TODO: Make it as a @SystemApi
+ */
+public abstract class MediaSessionProviderService extends Service {
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        // TODO: Return IMediaSessionProviderService.Stub()
+        return null;
+    }
+}
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 7b07bea3..9c51996 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -648,7 +648,6 @@
 
     capabilities->getSupportedColorFormats(&colorFormats);
     capabilities->getSupportedProfileLevels(&profileLevels);
-    uint32_t flags = capabilities->getFlags();
     sp<AMessage> details = capabilities->getDetails();
 
     jobject defaultFormatObj = NULL;
@@ -687,7 +686,7 @@
 
     return env->NewObject(
             gCodecInfo.capsClazz, gCodecInfo.capsCtorId,
-            profileLevelArray.get(), colorFormatsArray.get(), isEncoder, flags,
+            profileLevelArray.get(), colorFormatsArray.get(), isEncoder,
             defaultFormatRef.get(), detailsRef.get());
 }
 
@@ -700,23 +699,28 @@
         return err;
     }
 
+    // TODO: get alias
     ScopedLocalRef<jstring> nameObject(env,
             env->NewStringUTF(codecInfo->getCodecName()));
 
+    ScopedLocalRef<jstring> canonicalNameObject(env,
+            env->NewStringUTF(codecInfo->getCodecName()));
+
+    MediaCodecInfo::Attributes attributes = codecInfo->getAttributes();
     bool isEncoder = codecInfo->isEncoder();
 
-    Vector<AString> mimes;
-    codecInfo->getSupportedMimes(&mimes);
+    Vector<AString> mediaTypes;
+    codecInfo->getSupportedMediaTypes(&mediaTypes);
 
     ScopedLocalRef<jobjectArray> capsArrayObj(env,
-        env->NewObjectArray(mimes.size(), gCodecInfo.capsClazz, NULL));
+        env->NewObjectArray(mediaTypes.size(), gCodecInfo.capsClazz, NULL));
 
-    for (size_t i = 0; i < mimes.size(); i++) {
+    for (size_t i = 0; i < mediaTypes.size(); i++) {
         const sp<MediaCodecInfo::Capabilities> caps =
-                codecInfo->getCapabilitiesFor(mimes[i].c_str());
+                codecInfo->getCapabilitiesFor(mediaTypes[i].c_str());
 
         ScopedLocalRef<jobject> capsObj(env, getCodecCapabilitiesObject(
-                env, mimes[i].c_str(), isEncoder, caps));
+                env, mediaTypes[i].c_str(), isEncoder, caps));
 
         env->SetObjectArrayElement(capsArrayObj.get(), i, capsObj.get());
     }
@@ -729,7 +733,7 @@
             "(Ljava/lang/String;Z[Landroid/media/MediaCodecInfo$CodecCapabilities;)V");
 
     *codecInfoObject = env->NewObject(codecInfoClazz.get(), codecInfoCtorID,
-            nameObject.get(), isEncoder, capsArrayObj.get());
+            nameObject.get(), canonicalNameObject.get(), attributes, capsArrayObj.get());
 
     return OK;
 }
@@ -2079,7 +2083,7 @@
     gCodecInfo.capsClazz = (jclass)env->NewGlobalRef(clazz.get());
 
     method = env->GetMethodID(clazz.get(), "<init>",
-            "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZI"
+            "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZ"
             "Ljava/util/Map;Ljava/util/Map;)V");
     CHECK(method != NULL);
     gCodecInfo.capsCtorId = method;
@@ -2217,7 +2221,7 @@
     { "getImage", "(ZI)Landroid/media/Image;",
       (void *)android_media_MediaCodec_getImage },
 
-    { "getName", "()Ljava/lang/String;",
+    { "getCanonicalName", "()Ljava/lang/String;",
       (void *)android_media_MediaCodec_getName },
 
     { "getOwnCodecInfo", "()Landroid/media/MediaCodecInfo;",
diff --git a/media/jni/android_media_MediaCodecList.cpp b/media/jni/android_media_MediaCodecList.cpp
index 8de11ca..cf14942 100644
--- a/media/jni/android_media_MediaCodecList.cpp
+++ b/media/jni/android_media_MediaCodecList.cpp
@@ -41,6 +41,21 @@
     return mcl;
 }
 
+static sp<MediaCodecInfo> getCodecInfo(JNIEnv *env, jint index) {
+    sp<IMediaCodecList> mcl = getCodecList(env);
+    if (mcl == NULL) {
+        // Runtime exception already pending.
+        return NULL;
+    }
+
+    sp<MediaCodecInfo> info = mcl->getCodecInfo(index);
+    if (info == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+    }
+
+    return info;
+}
+
 static jint android_media_MediaCodecList_getCodecCount(
         JNIEnv *env, jobject /* thiz */) {
     sp<IMediaCodecList> mcl = getCodecList(env);
@@ -53,15 +68,22 @@
 
 static jstring android_media_MediaCodecList_getCodecName(
         JNIEnv *env, jobject /* thiz */, jint index) {
-    sp<IMediaCodecList> mcl = getCodecList(env);
-    if (mcl == NULL) {
+    sp<MediaCodecInfo> info = getCodecInfo(env, index);
+    if (info == NULL) {
         // Runtime exception already pending.
         return NULL;
     }
 
-    const sp<MediaCodecInfo> &info = mcl->getCodecInfo(index);
+    // TODO: support aliases
+    const char *name = info->getCodecName();
+    return env->NewStringUTF(name);
+}
+
+static jstring android_media_MediaCodecList_getCanonicalName(
+        JNIEnv *env, jobject /* thiz */, jint index) {
+    sp<MediaCodecInfo> info = getCodecInfo(env, index);
     if (info == NULL) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        // Runtime exception already pending.
         return NULL;
     }
 
@@ -94,39 +116,27 @@
     return ret;
 }
 
-static jboolean android_media_MediaCodecList_isEncoder(
+static jboolean android_media_MediaCodecList_getAttributes(
         JNIEnv *env, jobject /* thiz */, jint index) {
-    sp<IMediaCodecList> mcl = getCodecList(env);
-    if (mcl == NULL) {
-        // Runtime exception already pending.
-        return false;
-    }
-
-    const sp<MediaCodecInfo> &info = mcl->getCodecInfo(index);
+    sp<MediaCodecInfo> info = getCodecInfo(env, index);
     if (info == NULL) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
-        return false;
+        // Runtime exception already pending.
+        return 0;
     }
 
-    return info->isEncoder();
+    return info->getAttributes();
 }
 
 static jarray android_media_MediaCodecList_getSupportedTypes(
         JNIEnv *env, jobject /* thiz */, jint index) {
-    sp<IMediaCodecList> mcl = getCodecList(env);
-    if (mcl == NULL) {
+    sp<MediaCodecInfo> info = getCodecInfo(env, index);
+    if (info == NULL) {
         // Runtime exception already pending.
         return NULL;
     }
 
-    const sp<MediaCodecInfo> &info = mcl->getCodecInfo(index);
-    if (info == NULL) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
-        return NULL;
-    }
-
     Vector<AString> types;
-    info->getSupportedMimes(&types);
+    info->getSupportedMediaTypes(&types);
 
     jclass clazz = env->FindClass("java/lang/String");
     CHECK(clazz != NULL);
@@ -150,17 +160,12 @@
         return NULL;
     }
 
-    sp<IMediaCodecList> mcl = getCodecList(env);
-    if (mcl == NULL) {
+    sp<MediaCodecInfo> info = getCodecInfo(env, index);
+    if (info == NULL) {
         // Runtime exception already pending.
         return NULL;
     }
 
-    const sp<MediaCodecInfo> &info = mcl->getCodecInfo(index);
-    if (info == NULL) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
-        return NULL;
-    }
 
     const char *typeStr = env->GetStringUTFChars(type, NULL);
     if (typeStr == NULL) {
@@ -186,7 +191,6 @@
 
     capabilities->getSupportedColorFormats(&colorFormats);
     capabilities->getSupportedProfileLevels(&profileLevels);
-    uint32_t flags = capabilities->getFlags();
     sp<AMessage> details = capabilities->getDetails();
     bool isEncoder = info->isEncoder();
 
@@ -240,11 +244,11 @@
     }
 
     jmethodID capsConstructID = env->GetMethodID(capsClazz, "<init>",
-            "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZI"
+            "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZ"
             "Ljava/util/Map;Ljava/util/Map;)V");
 
     jobject caps = env->NewObject(capsClazz, capsConstructID,
-            profileLevelArray, colorFormatsArray, isEncoder, flags,
+            profileLevelArray, colorFormatsArray, isEncoder,
             defaultFormatObj, infoObj);
 
     env->DeleteLocalRef(profileLevelArray);
@@ -288,9 +292,15 @@
 
 static const JNINativeMethod gMethods[] = {
     { "native_getCodecCount", "()I", (void *)android_media_MediaCodecList_getCodecCount },
+
+    { "getCanonicalName", "(I)Ljava/lang/String;",
+      (void *)android_media_MediaCodecList_getCanonicalName },
+
     { "getCodecName", "(I)Ljava/lang/String;",
       (void *)android_media_MediaCodecList_getCodecName },
-    { "isEncoder", "(I)Z", (void *)android_media_MediaCodecList_isEncoder },
+
+    { "getAttributes", "(I)I", (void *)android_media_MediaCodecList_getAttributes },
+
     { "getSupportedTypes", "(I)[Ljava/lang/String;",
       (void *)android_media_MediaCodecList_getSupportedTypes },
 
diff --git a/media/packages/MediaCore/Android.bp b/media/packages/MediaCore/Android.bp
new file mode 100644
index 0000000..c7fd58b
--- /dev/null
+++ b/media/packages/MediaCore/Android.bp
@@ -0,0 +1,21 @@
+android_app {
+    name: "MediaCore",
+
+    srcs: [
+        "src/**/*.java",
+    ],
+
+    static_libs: [
+        // TODO: Temporarily statically linked. Should go into "libs"
+        "media1",
+    ],
+
+    // System app
+    platform_apis: true,
+
+    // Privileged app
+    privileged: true,
+
+    // Make sure that the implementation only relies on SDK or system APIs.
+    sdk_version: "system_current",
+}
diff --git a/media/packages/MediaCore/AndroidManifest.xml b/media/packages/MediaCore/AndroidManifest.xml
new file mode 100644
index 0000000..4e2b274
--- /dev/null
+++ b/media/packages/MediaCore/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/AndroidManifest.xml
+**
+** Copyright 2019, 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.
+*/
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.media" coreApp="true" android:sharedUserId="android.uid.system"
+    android:sharedUserLabel="@string/android_system_label">
+    <application android:process="system"
+        android:persistent="true"
+        android:directBootAware="true">
+        <service android:name="AmlMediaSessionProviderService" android:singleUser="true">
+            <intent-filter>
+                <action android:name="android.media.session.MediaSessionProviderService"/>
+            </intent-filter>
+        </service>
+    </application>
+</manifest>
diff --git a/media/packages/MediaCore/res/values/strings.xml b/media/packages/MediaCore/res/values/strings.xml
new file mode 100644
index 0000000..59fd635
--- /dev/null
+++ b/media/packages/MediaCore/res/values/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2019 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.
+-->
+
+<resources>
+    <!-- Label for the Android system components when they are shown to the user. -->
+    <string name="android_system_label" translatable="false">Android System</string>
+</resources>
+
diff --git a/media/packages/MediaCore/src/com/android/media/AmlMediaSessionProviderService.java b/media/packages/MediaCore/src/com/android/media/AmlMediaSessionProviderService.java
new file mode 100644
index 0000000..43b95ab
--- /dev/null
+++ b/media/packages/MediaCore/src/com/android/media/AmlMediaSessionProviderService.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 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.media;
+
+import android.content.Context;
+import android.media.session.MediaSessionProviderService;
+import android.os.PowerManager;
+import android.util.Log;
+
+/**
+ * System implementation of MediaSessionProviderService
+ */
+public class AmlMediaSessionProviderService extends MediaSessionProviderService {
+    private static final String TAG = "AmlMediaSessionProviderS";
+    static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private Context mContext;
+
+    public AmlMediaSessionProviderService(Context context) {
+        mContext = context;
+        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+    }
+}
diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp
index 8e58210..c3b2e25 100644
--- a/native/android/sensor.cpp
+++ b/native/android/sensor.cpp
@@ -342,3 +342,8 @@
     RETURN_IF_SENSOR_IS_NULL(ASENSOR_DIRECT_RATE_STOP);
     return static_cast<Sensor const *>(sensor)->getHighestDirectReportRateLevel();
 }
+
+int ASensor_getHandle(ASensor const* sensor) {
+    RETURN_IF_SENSOR_IS_NULL(ASENSOR_INVALID);
+    return static_cast<Sensor const*>(sensor)->getHandle();
+}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index bce5593..5153f9e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1052,7 +1052,7 @@
         }
 
         // TODO(b/117663715): Ensure the caller can access the setting.
-        // enforceSettingReadable(name, SETTINGS_TYPE_CONFIG, UserHandle.getCallingUserId());
+        // enforceReadPermission(READ_DEVICE_CONFIG);
 
         // Get the value.
         synchronized (mLock) {
@@ -1088,8 +1088,9 @@
 
     private boolean mutateConfigSetting(String name, String value, String prefix,
             boolean makeDefault, int operation, int mode) {
-        // TODO(b/117663715): check the new permission when it's added.
-        // enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS);
+
+        // TODO(b/117663715): Ensure the caller can access the setting.
+        // enforceReadPermission(WRITE_DEVICE_CONFIG);
 
         // Perform the mutation.
         synchronized (mLock) {
diff --git a/packages/SettingsProvider/test/AndroidManifest.xml b/packages/SettingsProvider/test/AndroidManifest.xml
index 87a4f60..ebdf9b1 100644
--- a/packages/SettingsProvider/test/AndroidManifest.xml
+++ b/packages/SettingsProvider/test/AndroidManifest.xml
@@ -20,6 +20,8 @@
     <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21" />
 
     <uses-permission android:name="android.permission.WRITE_SETTINGS"/>
+    <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG"/>
+    <uses-permission android:name="android.permission.READ_DEVICE_CONFIG"/>
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
     <uses-permission android:name="android.permission.MANAGE_USERS"/>
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 9b775e0..b903142 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -57,6 +57,8 @@
     <uses-permission android:name="android.permission.SET_PREFERRED_APPLICATIONS" />
     <uses-permission android:name="android.permission.WRITE_SETTINGS" />
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+    <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
+    <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" />
     <uses-permission android:name="android.permission.BROADCAST_STICKY" />
     <uses-permission android:name="android.permission.MANAGE_ACCESSIBILITY" />
     <!-- Development tool permissions granted to the shell. -->
diff --git a/packages/SystemUI/res-keyguard/layout/bubble_clock.xml b/packages/SystemUI/res-keyguard/layout/bubble_clock.xml
index 0d72657..6f7f398 100644
--- a/packages/SystemUI/res-keyguard/layout/bubble_clock.xml
+++ b/packages/SystemUI/res-keyguard/layout/bubble_clock.xml
@@ -19,15 +19,9 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
   >
-  <TextClock
+  <include
       android:id="@+id/digital_clock"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:letterSpacing="0.03"
-      android:singleLine="true"
-      style="@style/widget_big"
-      android:format12Hour="@string/keyguard_widget_12_hours_format"
-      android:format24Hour="@string/keyguard_widget_24_hours_format"
+      layout="@layout/text_clock"
   />
   <com.android.keyguard.clock.ImageClock
       android:id="@+id/analog_clock"
diff --git a/packages/SystemUI/res-keyguard/layout/digital_clock.xml b/packages/SystemUI/res-keyguard/layout/digital_clock.xml
index cf4a573..e88e2c9 100644
--- a/packages/SystemUI/res-keyguard/layout/digital_clock.xml
+++ b/packages/SystemUI/res-keyguard/layout/digital_clock.xml
@@ -20,16 +20,9 @@
     android:layout_height="wrap_content"
     android:layout_gravity="center_horizontal"
     android:layout_alignParentTop="true">
-  <TextClock
+  <include
       android:id="@+id/lock_screen_clock"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:layout_gravity="center_horizontal"
-      android:letterSpacing="0.03"
-      android:singleLine="true"
-      style="@style/widget_big"
-      android:format12Hour="@string/keyguard_widget_12_hours_format"
-      android:format24Hour="@string/keyguard_widget_24_hours_format" />
+      layout="@layout/text_clock"
   />
 </FrameLayout>
 
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
index d52866f..463367b 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
@@ -30,17 +30,9 @@
          android:layout_height="wrap_content"
          android:layout_gravity="center_horizontal"
          android:layout_alignParentTop="true">
-        <TextClock
+        <include
              android:id="@+id/default_clock_view"
-             android:layout_width="wrap_content"
-             android:layout_height="wrap_content"
-             android:layout_gravity="center_horizontal"
-             android:letterSpacing="0.03"
-             android:textColor="?attr/wallpaperTextColor"
-             android:singleLine="true"
-             style="@style/widget_big"
-             android:format12Hour="@string/keyguard_widget_12_hours_format"
-             android:format24Hour="@string/keyguard_widget_24_hours_format" />
+             layout="@layout/text_clock" />
     </FrameLayout>
     <include layout="@layout/keyguard_status_area"
         android:id="@+id/keyguard_status_area"
diff --git a/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml b/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml
index 9033fce..64b676f5 100644
--- a/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml
+++ b/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml
@@ -19,15 +19,9 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
   >
-  <TextClock
+  <include
       android:id="@+id/digital_clock"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:letterSpacing="0.03"
-      android:singleLine="true"
-      style="@style/widget_big"
-      android:format12Hour="@string/keyguard_widget_12_hours_format"
-      android:format24Hour="@string/keyguard_widget_24_hours_format"
+      layout="@layout/text_clock"
   />
   <com.android.keyguard.clock.StretchAnalogClock
       android:id="@+id/analog_clock"
diff --git a/packages/SystemUI/res-keyguard/layout/text_clock.xml b/packages/SystemUI/res-keyguard/layout/text_clock.xml
new file mode 100644
index 0000000..b61ad9c
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/text_clock.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2019 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.
+  -->
+<TextClock
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center_horizontal"
+    android:letterSpacing="0.03"
+    android:textColor="?attr/wallpaperTextColor"
+    android:singleLine="true"
+    style="@style/widget_big"
+    android:format12Hour="@string/keyguard_widget_12_hours_format"
+    android:format24Hour="@string/keyguard_widget_24_hours_format"
+    android:elegantTextHeight="false"
+/>
diff --git a/packages/SystemUI/res/layout/global_actions_wrapped.xml b/packages/SystemUI/res/layout/global_actions_wrapped.xml
index 7f4e0d2..f932303 100644
--- a/packages/SystemUI/res/layout/global_actions_wrapped.xml
+++ b/packages/SystemUI/res/layout/global_actions_wrapped.xml
@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <com.android.systemui.HardwareUiLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@id/global_actions_view"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:layout_gravity="top|right"
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 476089a..98f0cbe 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -106,7 +106,7 @@
 
     <!-- The default tiles to display in QuickSettings -->
     <string name="quick_settings_tiles_default" translatable="false">
-        wifi,bt,dnd,flashlight,rotation,battery,cell,airplane,cast
+        wifi,bt,dnd,flashlight,rotation,battery,cell,airplane,cast,sensorprivacy
     </string>
 
     <!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 633f868..bd34bea 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -114,5 +114,8 @@
     <item type="id" name="aod_mask_transition_progress_tag" />
     <item type="id" name="aod_mask_transition_progress_end_tag" />
     <item type="id" name="aod_mask_transition_progress_start_tag" />
+
+    <!-- Global Actions Menu -->
+    <item type="id" name="global_actions_view" />
 </resources>
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index a8094d20..e9ce1a6 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -248,10 +248,6 @@
         mClockView.setShowCurrentUserTime(showCurrentUserTime);
     }
 
-    public void setElegantTextHeight(boolean elegant) {
-        mClockView.setElegantTextHeight(elegant);
-    }
-
     public void setTextSize(int unit, float size) {
         mClockView.setTextSize(unit, size);
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index f0cdc89..7ae4c41 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -202,10 +202,6 @@
         updateOwnerInfo();
         updateLogoutView();
         updateDark();
-
-        // Disable elegant text height because our fancy colon makes the ymin value huge for no
-        // reason.
-        mClockView.setElegantTextHeight(false);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
index 16e869e..e28aa9d 100644
--- a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
@@ -37,23 +37,25 @@
 import com.android.systemui.tuner.TunerService.Tunable;
 import com.android.systemui.util.leak.RotationUtils;
 
-public class HardwareUiLayout extends LinearLayout implements Tunable {
+/**
+ * Layout for placing two containers at a specific physical position on the device, relative to the
+ * device's hardware, regardless of screen rotation.
+ */
+public class HardwareUiLayout extends MultiListLayout implements Tunable {
 
     private static final String EDGE_BLEED = "sysui_hwui_edge_bleed";
     private static final String ROUNDED_DIVIDER = "sysui_hwui_rounded_divider";
     private final int[] mTmp2 = new int[2];
-    private View mList;
-    private View mSeparatedView;
+    private ViewGroup mList;
+    private ViewGroup mSeparatedView;
     private int mOldHeight;
     private boolean mAnimating;
     private AnimatorSet mAnimation;
     private View mDivision;
-    private boolean mHasOutsideTouch;
     private HardwareBgDrawable mListBackground;
     private HardwareBgDrawable mSeparatedViewBackground;
     private Animator mAnimator;
     private boolean mCollapse;
-    private boolean mHasSeparatedButton;
     private int mEndPoint;
     private boolean mEdgeBleed;
     private boolean mRoundedDivider;
@@ -67,6 +69,35 @@
     }
 
     @Override
+    protected ViewGroup getSeparatedView() {
+        return findViewById(com.android.systemui.R.id.separated_button);
+    }
+
+    @Override
+    protected ViewGroup getListView() {
+        return findViewById(android.R.id.list);
+    }
+
+    @Override
+    public void removeAllItems() {
+        if (mList != null) {
+            mList.removeAllViews();
+        }
+        if (mSeparatedView != null) {
+            mSeparatedView.removeAllViews();
+        }
+    }
+
+    @Override
+    public ViewGroup getParentView(boolean separated, int index) {
+        if (separated) {
+            return getSeparatedView();
+        } else {
+            return getListView();
+        }
+    }
+
+    @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         updateSettings();
@@ -137,9 +168,9 @@
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
         if (mList == null) {
             if (getChildCount() != 0) {
-                mList = getChildAt(0);
+                mList = getListView();
                 mList.setBackground(mListBackground);
-                mSeparatedView = getChildAt(1);
+                mSeparatedView = getSeparatedView();
                 mSeparatedView.setBackground(mSeparatedViewBackground);
                 updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding());
                 mOldHeight = mList.getMeasuredHeight();
@@ -187,7 +218,7 @@
         } else {
             rotateLeft();
         }
-        if (mHasSeparatedButton) {
+        if (mHasSeparatedView) {
             if (from == ROTATION_SEASCAPE || to == ROTATION_SEASCAPE) {
                 // Separated view has top margin, so seascape separated view need special rotation,
                 // not a full left or right rotation.
@@ -408,8 +439,8 @@
         if (mList == null) return;
         // If got separated button, setRotatedBackground to false,
         // all items won't get white background.
-        mListBackground.setRotatedBackground(mHasSeparatedButton);
-        mSeparatedViewBackground.setRotatedBackground(mHasSeparatedButton);
+        mListBackground.setRotatedBackground(mHasSeparatedView);
+        mSeparatedViewBackground.setRotatedBackground(mHasSeparatedView);
         if (mDivision != null && mDivision.getVisibility() == VISIBLE) {
             int index = mRotatedBackground ? 0 : 1;
             mDivision.getLocationOnScreen(mTmp2);
@@ -460,21 +491,21 @@
             case RotationUtils.ROTATION_LANDSCAPE:
                 defaultTopPadding = getPaddingLeft();
                 viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth();
-                separatedViewTopMargin = mHasSeparatedButton ? params.leftMargin : 0;
+                separatedViewTopMargin = mHasSeparatedView ? params.leftMargin : 0;
                 screenHeight = getMeasuredWidth();
                 targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.TOP;
                 break;
             case RotationUtils.ROTATION_SEASCAPE:
                 defaultTopPadding = getPaddingRight();
                 viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth();
-                separatedViewTopMargin = mHasSeparatedButton ? params.leftMargin : 0;
+                separatedViewTopMargin = mHasSeparatedView ? params.leftMargin : 0;
                 screenHeight = getMeasuredWidth();
                 targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.BOTTOM;
                 break;
             default: // Portrait
                 defaultTopPadding = getPaddingTop();
                 viewsTotalHeight = mList.getMeasuredHeight() + mSeparatedView.getMeasuredHeight();
-                separatedViewTopMargin = mHasSeparatedButton ? params.topMargin : 0;
+                separatedViewTopMargin = mHasSeparatedView ? params.topMargin : 0;
                 screenHeight = getMeasuredHeight();
                 targetGravity = Gravity.CENTER_VERTICAL|Gravity.RIGHT;
                 break;
@@ -491,30 +522,10 @@
         return super.getOutlineProvider();
     }
 
-    public void setOutsideTouchListener(OnClickListener onClickListener) {
-        mHasOutsideTouch = true;
-        requestLayout();
-        setOnClickListener(onClickListener);
-        setClickable(true);
-        setFocusable(true);
-    }
-
     public void setCollapse() {
         mCollapse = true;
     }
 
-    public void setHasSeparatedButton(boolean hasSeparatedButton) {
-        mHasSeparatedButton = hasSeparatedButton;
-    }
-
-    public static HardwareUiLayout get(View v) {
-        if (v instanceof HardwareUiLayout) return (HardwareUiLayout) v;
-        if (v.getParent() instanceof View) {
-            return get((View) v.getParent());
-        }
-        return null;
-    }
-
     private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsListener = inoutInfo -> {
         if (mHasOutsideTouch || (mList == null)) {
             inoutInfo.setTouchableInsets(
diff --git a/packages/SystemUI/src/com/android/systemui/MultiListLayout.java b/packages/SystemUI/src/com/android/systemui/MultiListLayout.java
new file mode 100644
index 0000000..0c7a9a9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/MultiListLayout.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+
+/**
+ * Layout class representing the Global Actions menu which appears when the power button is held.
+ */
+public abstract class MultiListLayout extends LinearLayout {
+    boolean mHasOutsideTouch;
+    boolean mHasSeparatedView;
+
+    int mExpectedSeparatedItemCount;
+    int mExpectedListItemCount;
+
+    public MultiListLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    protected abstract ViewGroup getSeparatedView();
+
+    protected abstract ViewGroup getListView();
+
+    /**
+     * Removes all child items from the separated and list views, if they exist.
+     */
+    public abstract void removeAllItems();
+
+    /**
+     * Get the parent view which will be used to contain the item at the specified index.
+     * @param separated Whether or not this index refers to a position in the separated or list
+     *                  container.
+     * @param index The index of the item within the container.
+     * @return The parent ViewGroup which will be used to contain the specified item
+     * after it has been added to the layout.
+     */
+    public abstract ViewGroup getParentView(boolean separated, int index);
+
+    /**
+     * Sets the divided view, which may have a differently-colored background.
+     */
+    public abstract void setDivisionView(View v);
+
+    /**
+     * Set the view accessibility delegate for the list view container.
+     */
+    public void setListViewAccessibilityDelegate(View.AccessibilityDelegate delegate) {
+        getListView().setAccessibilityDelegate(delegate);
+    }
+
+    protected void setSeparatedViewVisibility(boolean visible) {
+        getSeparatedView().setVisibility(visible ? View.VISIBLE : View.GONE);
+    }
+
+    /**
+     * Sets the number of items expected to be rendered in the separated container. This allows the
+     * layout to correctly determine which parent containers will be used for items before they have
+     * beenadded to the layout.
+     * @param count The number of items expected.
+     */
+    public void setExpectedSeparatedItemCount(int count) {
+        mExpectedSeparatedItemCount = count;
+    }
+
+    /**
+     * Sets the number of items expected to be rendered in the list container. This allows the
+     * layout to correctly determine which parent containers will be used for items before they have
+     * beenadded to the layout.
+     * @param count The number of items expected.
+     */
+    public void setExpectedListItemCount(int count) {
+        mExpectedListItemCount = count;
+    }
+
+    /**
+     * Sets whether the separated view should be shown, and handles updating visibility on
+     * that view.
+     */
+    public void setHasSeparatedView(boolean hasSeparatedView) {
+        mHasSeparatedView = hasSeparatedView;
+        setSeparatedViewVisibility(hasSeparatedView);
+    }
+
+    /**
+     * Sets this layout to respond to an outside touch listener.
+     */
+    public void setOutsideTouchListener(OnClickListener onClickListener) {
+        mHasOutsideTouch = true;
+        requestLayout();
+        setOnClickListener(onClickListener);
+        setClickable(true);
+        setFocusable(true);
+    }
+
+    /**
+     * Retrieve the MultiListLayout associated with the given view.
+     */
+    public static MultiListLayout get(View v) {
+        if (v instanceof MultiListLayout) return (MultiListLayout) v;
+        if (v.getParent() instanceof View) {
+            return get((View) v.getParent());
+        }
+        return null;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 268245b..7b18fad 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -67,10 +67,8 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.AdapterView.OnItemLongClickListener;
 import android.widget.BaseAdapter;
-import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.ImageView.ScaleType;
-import android.widget.LinearLayout;
 import android.widget.TextView;
 
 import com.android.internal.R;
@@ -86,8 +84,8 @@
 import com.android.internal.util.ScreenshotHelper;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.systemui.Dependency;
-import com.android.systemui.HardwareUiLayout;
 import com.android.systemui.Interpolators;
+import com.android.systemui.MultiListLayout;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
 import com.android.systemui.statusbar.phone.ScrimController;
@@ -490,6 +488,11 @@
         public boolean showBeforeProvisioning() {
             return true;
         }
+
+        @Override
+        public boolean shouldBeSeparated() {
+            return true;
+        }
     }
 
     private final class RestartAction extends SinglePressAction implements LongPressAction {
@@ -926,6 +929,34 @@
             return getItem(position).isEnabled();
         }
 
+        public ArrayList<Action> getSeparatedActions(boolean shouldUseSeparatedView) {
+            ArrayList<Action> separatedActions = new ArrayList<Action>();
+            if (!shouldUseSeparatedView) {
+                return separatedActions;
+            }
+            for (int i = 0; i < mItems.size(); i++) {
+                final Action action = mItems.get(i);
+                if (action.shouldBeSeparated()) {
+                    separatedActions.add(action);
+                }
+            }
+            return separatedActions;
+        }
+
+        public ArrayList<Action> getListActions(boolean shouldUseSeparatedView) {
+            if (!shouldUseSeparatedView) {
+                return new ArrayList<Action>(mItems);
+            }
+            ArrayList<Action> listActions = new ArrayList<Action>();
+            for (int i = 0; i < mItems.size(); i++) {
+                final Action action = mItems.get(i);
+                if (!action.shouldBeSeparated()) {
+                    listActions.add(action);
+                }
+            }
+            return listActions;
+        }
+
         @Override
         public boolean areAllItemsEnabled() {
             return false;
@@ -965,7 +996,7 @@
             View view = action.create(mContext, convertView, parent, LayoutInflater.from(mContext));
             // Everything but screenshot, the last item, gets white background.
             if (position == getCount() - 1) {
-                HardwareUiLayout.get(parent).setDivisionView(view);
+                MultiListLayout.get(parent).setDivisionView(view);
             }
             return view;
         }
@@ -1004,6 +1035,10 @@
         boolean showBeforeProvisioning();
 
         boolean isEnabled();
+
+        default boolean shouldBeSeparated() {
+            return false;
+        }
     }
 
     /**
@@ -1423,9 +1458,7 @@
 
         private final Context mContext;
         private final MyAdapter mAdapter;
-        private final LinearLayout mListView;
-        private final FrameLayout mSeparatedView;
-        private final HardwareUiLayout mHardwareLayout;
+        private final MultiListLayout mGlobalActionsLayout;
         private final OnClickListener mClickListener;
         private final OnItemLongClickListener mLongClickListener;
         private final GradientDrawable mGradientDrawable;
@@ -1466,16 +1499,11 @@
             window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
 
             setContentView(com.android.systemui.R.layout.global_actions_wrapped);
-            mListView = findViewById(android.R.id.list);
-            mSeparatedView = findViewById(com.android.systemui.R.id.separated_button);
-            if (!mShouldDisplaySeparatedButton) {
-                mSeparatedView.setVisibility(View.GONE);
-            }
-            mHardwareLayout = HardwareUiLayout.get(mListView);
-            mHardwareLayout.setOutsideTouchListener(view -> dismiss());
-            mHardwareLayout.setHasSeparatedButton(mShouldDisplaySeparatedButton);
-            setTitle(R.string.global_actions);
-            mListView.setAccessibilityDelegate(new View.AccessibilityDelegate() {
+            mGlobalActionsLayout = (MultiListLayout)
+                    findViewById(com.android.systemui.R.id.global_actions_view);
+            mGlobalActionsLayout.setOutsideTouchListener(view -> dismiss());
+            mGlobalActionsLayout.setHasSeparatedView(mShouldDisplaySeparatedButton);
+            mGlobalActionsLayout.setListViewAccessibilityDelegate(new View.AccessibilityDelegate() {
                 @Override
                 public boolean dispatchPopulateAccessibilityEvent(
                         View host, AccessibilityEvent event) {
@@ -1484,20 +1512,33 @@
                     return true;
                 }
             });
+            setTitle(R.string.global_actions);
         }
 
         private void updateList() {
-            mListView.removeAllViews();
-            mSeparatedView.removeAllViews();
+            mGlobalActionsLayout.removeAllItems();
+            ArrayList<Action> separatedActions =
+                    mAdapter.getSeparatedActions(mShouldDisplaySeparatedButton);
+            ArrayList<Action> listActions = mAdapter.getListActions(mShouldDisplaySeparatedButton);
+            mGlobalActionsLayout.setExpectedListItemCount(listActions.size());
+            mGlobalActionsLayout.setExpectedSeparatedItemCount(separatedActions.size());
+
             for (int i = 0; i < mAdapter.getCount(); i++) {
-                ViewGroup parentView = mShouldDisplaySeparatedButton && i == mAdapter.getCount() - 1
-                        ? mSeparatedView : mListView;
-                View v = mAdapter.getView(i, null, parentView);
+                Action action = mAdapter.getItem(i);
+                int separatedIndex = separatedActions.indexOf(action);
+                ViewGroup parent;
+                if (separatedIndex != -1) {
+                    parent = mGlobalActionsLayout.getParentView(true, separatedIndex);
+                } else {
+                    int listIndex = listActions.indexOf(action);
+                    parent = mGlobalActionsLayout.getParentView(false, listIndex);
+                }
+                View v = mAdapter.getView(i, null, parent);
                 final int pos = i;
                 v.setOnClickListener(view -> mClickListener.onClick(this, pos));
                 v.setOnLongClickListener(view ->
                         mLongClickListener.onItemLongClick(null, v, pos, 0));
-                parentView.addView(v);
+                parent.addView(v);
             }
         }
 
@@ -1543,9 +1584,9 @@
             super.show();
             mShowing = true;
             mGradientDrawable.setAlpha(0);
-            mHardwareLayout.setTranslationX(getAnimTranslation());
-            mHardwareLayout.setAlpha(0);
-            mHardwareLayout.animate()
+            mGlobalActionsLayout.setTranslationX(getAnimTranslation());
+            mGlobalActionsLayout.setAlpha(0);
+            mGlobalActionsLayout.animate()
                     .alpha(1)
                     .translationX(0)
                     .setDuration(300)
@@ -1564,9 +1605,9 @@
                 return;
             }
             mShowing = false;
-            mHardwareLayout.setTranslationX(0);
-            mHardwareLayout.setAlpha(1);
-            mHardwareLayout.animate()
+            mGlobalActionsLayout.setTranslationX(0);
+            mGlobalActionsLayout.setAlpha(1);
+            mGlobalActionsLayout.animate()
                     .alpha(0)
                     .translationX(getAnimTranslation())
                     .setDuration(300)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyTile.java
index 5230cea..7ee37d5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyTile.java
@@ -84,7 +84,7 @@
 
     @Override
     public Intent getLongClickIntent() {
-        return null;
+        return new Intent();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
index eea4490..839b06c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
@@ -33,6 +33,13 @@
     default void onPendingEntryAdded(NotificationEntry entry) {
     }
 
+    // TODO: Combine this with onPreEntryUpdated into "onBeforeEntryFiltered" or similar
+    /**
+     * Called when a new entry is created but before it has been filtered or displayed to the user.
+     */
+    default void onBeforeNotificationAdded(NotificationEntry entry) {
+    }
+
     /**
      * Called when a new entry is created.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 45db002..989e781 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -18,11 +18,9 @@
 import android.annotation.Nullable;
 import android.app.Notification;
 import android.content.Context;
-import android.os.UserHandle;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.StatusBarNotification;
 import android.util.ArrayMap;
-import android.util.ArraySet;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -41,7 +39,6 @@
 import com.android.systemui.statusbar.notification.row.NotificationInflater;
 import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.util.leak.LeakDetector;
 
@@ -68,8 +65,6 @@
     @VisibleForTesting
     protected final HashMap<String, NotificationEntry> mPendingNotifications = new HashMap<>();
 
-    private final DeviceProvisionedController mDeviceProvisionedController =
-            Dependency.get(DeviceProvisionedController.class);
     private final ForegroundServiceController mForegroundServiceController =
             Dependency.get(ForegroundServiceController.class);
 
@@ -81,25 +76,12 @@
     private NotificationListenerService.RankingMap mLatestRankingMap;
     @VisibleForTesting
     protected NotificationData mNotificationData;
-    private NotificationListContainer mListContainer;
+
     @VisibleForTesting
     final ArrayList<NotificationLifetimeExtender> mNotificationLifetimeExtenders
             = new ArrayList<>();
     private final List<NotificationEntryListener> mNotificationEntryListeners = new ArrayList<>();
 
-    private final DeviceProvisionedController.DeviceProvisionedListener
-            mDeviceProvisionedListener =
-            new DeviceProvisionedController.DeviceProvisionedListener() {
-                @Override
-                public void onDeviceProvisionedChanged() {
-                    updateNotifications();
-                }
-            };
-
-    public void destroy() {
-        mDeviceProvisionedController.removeCallback(mDeviceProvisionedListener);
-    }
-
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("NotificationEntryManager state:");
@@ -151,9 +133,6 @@
             HeadsUpManager headsUpManager) {
         mPresenter = presenter;
         mNotificationData.setHeadsUpManager(headsUpManager);
-        mListContainer = listContainer;
-
-        mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);
     }
 
     /** Adds multiple {@link NotificationLifetimeExtender}s. */
@@ -227,7 +206,9 @@
                     listener.onEntryInflated(entry, inflatedFlags);
                 }
                 mNotificationData.add(entry);
-                tagForeground(entry.notification);
+                for (NotificationEntryListener listener : mNotificationEntryListeners) {
+                    listener.onBeforeNotificationAdded(entry);
+                }
                 updateNotifications();
                 for (NotificationEntryListener listener : mNotificationEntryListeners) {
                     listener.onNotificationAdded(entry);
@@ -283,7 +264,6 @@
 
                 if (entry.rowExists()) {
                     entry.removeRow();
-                    mListContainer.cleanUpViewStateForEntry(entry);
                 }
 
                 // Let's remove the children if this was a summary
@@ -368,19 +348,6 @@
         }
     }
 
-    @VisibleForTesting
-    void tagForeground(StatusBarNotification notification) {
-        ArraySet<Integer> activeOps = mForegroundServiceController.getAppOps(
-                notification.getUserId(), notification.getPackageName());
-        if (activeOps != null) {
-            int N = activeOps.size();
-            for (int i = 0; i < N; i++) {
-                updateNotificationsForAppOp(activeOps.valueAt(i), notification.getUid(),
-                        notification.getPackageName(), true);
-            }
-        }
-    }
-
     @Override
     public void addNotification(StatusBarNotification notification,
             NotificationListenerService.RankingMap ranking) {
@@ -391,15 +358,6 @@
         }
     }
 
-    public void updateNotificationsForAppOp(int appOp, int uid, String pkg, boolean showIcon) {
-        String foregroundKey = mForegroundServiceController.getStandardLayoutKey(
-                UserHandle.getUserId(uid), pkg);
-        if (foregroundKey != null) {
-            mNotificationData.updateAppOp(appOp, uid, pkg, foregroundKey, showIcon);
-            updateNotifications();
-        }
-    }
-
     private void updateNotificationInternal(StatusBarNotification notification,
             NotificationListenerService.RankingMap ranking) throws InflationException {
         if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
@@ -452,8 +410,9 @@
 
     public void updateNotifications() {
         mNotificationData.filterAndSort();
-
-        mPresenter.updateNotificationViews();
+        if (mPresenter != null) {
+            mPresenter.updateNotificationViews();
+        }
     }
 
     public void updateNotificationRanking(NotificationListenerService.RankingMap rankingMap) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
new file mode 100644
index 0000000..88f4ca2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.os.UserHandle;
+import android.service.notification.StatusBarNotification;
+import android.util.ArraySet;
+
+import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.ForegroundServiceController;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
+
+/**
+ * Root controller for the list of notifications in the shade.
+ *
+ * TODO: Much of the code in NotificationPresenter should eventually move in here. It will proxy
+ * domain-specific behavior (ARC, etc) to subcontrollers.
+ */
+public class NotificationListController {
+    private final NotificationEntryManager mEntryManager;
+    private final NotificationListContainer mListContainer;
+    private final ForegroundServiceController mForegroundServiceController;
+    private final DeviceProvisionedController mDeviceProvisionedController;
+
+    public NotificationListController(
+            NotificationEntryManager entryManager,
+            NotificationListContainer listContainer,
+            ForegroundServiceController foregroundServiceController,
+            DeviceProvisionedController deviceProvisionedController) {
+        mEntryManager = checkNotNull(entryManager);
+        mListContainer = checkNotNull(listContainer);
+        mForegroundServiceController = checkNotNull(foregroundServiceController);
+        mDeviceProvisionedController = checkNotNull(deviceProvisionedController);
+    }
+
+    /**
+     * Causes the controller to register listeners on its dependencies. This method must be called
+     * before the controller is ready to perform its duties.
+     */
+    public void bind() {
+        mEntryManager.addNotificationEntryListener(mEntryListener);
+        mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);
+    }
+
+    /** Should be called when the list controller is being destroyed. */
+    public void destroy() {
+        mDeviceProvisionedController.removeCallback(mDeviceProvisionedListener);
+    }
+
+    @SuppressWarnings("FieldCanBeLocal")
+    private final NotificationEntryListener mEntryListener = new NotificationEntryListener() {
+        @Override
+        public void onEntryRemoved(
+                NotificationEntry entry,
+                NotificationVisibility visibility,
+                boolean removedByUser) {
+            mListContainer.cleanUpViewStateForEntry(entry);
+        }
+
+        @Override
+        public void onBeforeNotificationAdded(NotificationEntry entry) {
+            tagForeground(entry.notification);
+        }
+    };
+
+    private final DeviceProvisionedListener mDeviceProvisionedListener =
+            new DeviceProvisionedListener() {
+                @Override
+                public void onDeviceProvisionedChanged() {
+                    mEntryManager.updateNotifications();
+                }
+            };
+
+    // TODO: This method is horrifically inefficient
+    private void tagForeground(StatusBarNotification notification) {
+        ArraySet<Integer> activeOps =
+                mForegroundServiceController.getAppOps(
+                        notification.getUserId(), notification.getPackageName());
+        if (activeOps != null) {
+            int len = activeOps.size();
+            for (int i = 0; i < len; i++) {
+                updateNotificationsForAppOp(activeOps.valueAt(i), notification.getUid(),
+                        notification.getPackageName(), true);
+            }
+        }
+    }
+
+    /** When an app op changes, propagate that change to notifications. */
+    public void updateNotificationsForAppOp(int appOp, int uid, String pkg, boolean showIcon) {
+        String foregroundKey =
+                mForegroundServiceController.getStandardLayoutKey(UserHandle.getUserId(uid), pkg);
+        if (foregroundKey != null) {
+            mEntryManager
+                    .getNotificationData().updateAppOp(appOp, uid, pkg, foregroundKey, showIcon);
+            mEntryManager.updateNotifications();
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 853d7ab..3568f28 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -612,9 +612,11 @@
         anim.setStartDelay(mAnimationDelay);
         anim.setDuration(mAnimationDuration);
         anim.addListener(new AnimatorListenerAdapter() {
+            private Callback lastCallback = mCallback;
+
             @Override
             public void onAnimationEnd(Animator animation) {
-                onFinished();
+                onFinished(lastCallback);
 
                 scrim.setTag(TAG_KEY_ANIM, null);
                 dispatchScrimsVisible();
@@ -672,14 +674,23 @@
     }
 
     private void onFinished() {
+        onFinished(mCallback);
+    }
+
+    private void onFinished(Callback callback) {
         if (mWakeLockHeld) {
             mWakeLock.release();
             mWakeLockHeld = false;
         }
-        if (mCallback != null) {
-            mCallback.onFinished();
-            mCallback = null;
+
+        if (callback != null) {
+            callback.onFinished();
+
+            if (callback == mCallback) {
+                mCallback = null;
+            }
         }
+
         // When unlocking with fingerprint, we'll fade the scrims from black to transparent.
         // At the end of the animation we need to remove the tint.
         if (mState == ScrimState.UNLOCKED) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 7569a50..ed71598 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -196,6 +196,7 @@
 import com.android.systemui.statusbar.notification.NotificationClicker;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
+import com.android.systemui.statusbar.notification.NotificationListController;
 import com.android.systemui.statusbar.notification.NotificationRowBinder;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -387,6 +388,7 @@
     private NotificationGutsManager mGutsManager;
     protected NotificationLogger mNotificationLogger;
     protected NotificationEntryManager mEntryManager;
+    private NotificationListController mNotificationListController;
     private NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
     private NotificationRowBinder mNotificationRowBinder;
     protected NotificationViewHierarchyManager mViewHierarchyManager;
@@ -593,7 +595,7 @@
     public void onActiveStateChanged(int code, int uid, String packageName, boolean active) {
         mForegroundServiceController.onAppOpChanged(code, uid, packageName, active);
         Dependency.get(Dependency.MAIN_HANDLER).post(() -> {
-            mEntryManager.updateNotificationsForAppOp(code, uid, packageName, active);
+            mNotificationListController.updateNotificationsForAppOp(code, uid, packageName, active);
         });
     }
 
@@ -1044,6 +1046,13 @@
                 mScrimController, mActivityLaunchAnimator, mStatusBarKeyguardViewManager,
                 mNotificationAlertingManager);
 
+        mNotificationListController =
+                new NotificationListController(
+                        mEntryManager,
+                        (NotificationListContainer) mStackScroller,
+                        mForegroundServiceController,
+                        mDeviceProvisionedController);
+
         mAppOpsController.addCallback(APP_OPS, this);
         mNotificationListener.setUpWithPresenter(mPresenter);
         mNotificationShelf.setOnActivatedListener(mPresenter);
@@ -1056,6 +1065,7 @@
                 this, Dependency.get(BubbleController.class), mNotificationActivityStarter));
 
         mGroupAlertTransferHelper.bind(mEntryManager, mGroupManager);
+        mNotificationListController.bind();
     }
 
     /**
@@ -2831,7 +2841,7 @@
         } catch (RemoteException e) {
             // Ignore.
         }
-        mEntryManager.destroy();
+        mNotificationListController.destroy();
         // End old BaseStatusBar.destroy().
         if (mStatusBarWindow != null) {
             mWindowManager.removeViewImmediate(mStatusBarWindow);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index d937f93..9ce6ae1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -22,19 +22,15 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.app.ActivityManager;
-import android.app.AppOpsManager;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -49,7 +45,6 @@
 import android.support.test.filters.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
-import android.util.ArraySet;
 import android.widget.FrameLayout;
 
 import com.android.internal.logging.MetricsLogger;
@@ -79,8 +74,6 @@
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
-import junit.framework.Assert;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -346,7 +339,6 @@
 
         verify(mEntryListener, never()).onInflationError(any(), any());
 
-        verify(mListContainer).cleanUpViewStateForEntry(mEntry);
         verify(mPresenter).updateNotificationViews();
         verify(mEntryListener).onEntryRemoved(
                 mEntry, null, false /* removedByUser */);
@@ -401,90 +393,6 @@
     }
 
     @Test
-    public void testUpdateAppOps_foregroundNoti() {
-        com.android.systemui.util.Assert.isNotMainThread();
-
-        when(mForegroundServiceController.getStandardLayoutKey(anyInt(), anyString()))
-                .thenReturn(mEntry.key);
-        mEntry.setRow(mRow);
-        mEntryManager.getNotificationData().add(mEntry);
-
-        mEntryManager.updateNotificationsForAppOp(
-                AppOpsManager.OP_CAMERA, mEntry.notification.getUid(),
-                mEntry.notification.getPackageName(), true);
-
-        verify(mPresenter, times(1)).updateNotificationViews();
-        assertTrue(mEntryManager.getNotificationData().get(mEntry.key).mActiveAppOps.contains(
-                AppOpsManager.OP_CAMERA));
-    }
-
-    @Test
-    public void testUpdateAppOps_otherNoti() {
-        com.android.systemui.util.Assert.isNotMainThread();
-
-        when(mForegroundServiceController.getStandardLayoutKey(anyInt(), anyString()))
-                .thenReturn(null);
-        mEntryManager.updateNotificationsForAppOp(AppOpsManager.OP_CAMERA, 1000, "pkg", true);
-
-        verify(mPresenter, never()).updateNotificationViews();
-    }
-
-    @Test
-    public void testAddNotificationExistingAppOps() {
-        mEntry.setRow(mRow);
-        mEntryManager.getNotificationData().add(mEntry);
-        ArraySet<Integer> expected = new ArraySet<>();
-        expected.add(3);
-        expected.add(235);
-        expected.add(1);
-
-        when(mForegroundServiceController.getAppOps(mEntry.notification.getUserId(),
-                mEntry.notification.getPackageName())).thenReturn(expected);
-        when(mForegroundServiceController.getStandardLayoutKey(
-                mEntry.notification.getUserId(),
-                mEntry.notification.getPackageName())).thenReturn(mEntry.key);
-
-        mEntryManager.tagForeground(mEntry.notification);
-
-        Assert.assertEquals(expected.size(), mEntry.mActiveAppOps.size());
-        for (int op : expected) {
-            assertTrue("Entry missing op " + op, mEntry.mActiveAppOps.contains(op));
-        }
-    }
-
-    @Test
-    public void testAdd_noExistingAppOps() {
-        mEntry.setRow(mRow);
-        mEntryManager.getNotificationData().add(mEntry);
-        when(mForegroundServiceController.getStandardLayoutKey(
-                mEntry.notification.getUserId(),
-                mEntry.notification.getPackageName())).thenReturn(mEntry.key);
-        when(mForegroundServiceController.getAppOps(mEntry.notification.getUserId(),
-                mEntry.notification.getPackageName())).thenReturn(null);
-
-        mEntryManager.tagForeground(mEntry.notification);
-        Assert.assertEquals(0, mEntry.mActiveAppOps.size());
-    }
-
-    @Test
-    public void testAdd_existingAppOpsNotForegroundNoti() {
-        mEntry.setRow(mRow);
-        mEntryManager.getNotificationData().add(mEntry);
-        ArraySet<Integer> ops = new ArraySet<>();
-        ops.add(3);
-        ops.add(235);
-        ops.add(1);
-        when(mForegroundServiceController.getAppOps(mEntry.notification.getUserId(),
-                mEntry.notification.getPackageName())).thenReturn(ops);
-        when(mForegroundServiceController.getStandardLayoutKey(
-                mEntry.notification.getUserId(),
-                mEntry.notification.getPackageName())).thenReturn("something else");
-
-        mEntryManager.tagForeground(mEntry.notification);
-        Assert.assertEquals(0, mEntry.mActiveAppOps.size());
-    }
-
-    @Test
     public void testUpdateNotificationRanking() {
         when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
         when(mEnvironment.isDeviceProvisioned()).thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
new file mode 100644
index 0000000..4b5037b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.app.Notification;
+import android.os.UserHandle;
+import android.service.notification.StatusBarNotification;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.util.ArraySet;
+
+import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.ForegroundServiceController;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class NotificationListControllerTest extends SysuiTestCase {
+    private NotificationListController mController;
+
+    @Mock private NotificationEntryManager mEntryManager;
+    @Mock private NotificationListContainer mListContainer;
+    @Mock private ForegroundServiceController mForegroundServiceController;
+    @Mock private DeviceProvisionedController mDeviceProvisionedController;
+
+    @Captor private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor;
+    @Captor private ArgumentCaptor<DeviceProvisionedListener> mProvisionedCaptor;
+
+    private NotificationEntryListener mEntryListener;
+    private DeviceProvisionedListener mProvisionedListener;
+
+    // TODO: Remove this once EntryManager no longer needs to be mocked
+    private NotificationData mNotificationData = new NotificationData();
+
+    private int mNextNotifId = 0;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
+
+        mController = new NotificationListController(
+                mEntryManager,
+                mListContainer,
+                mForegroundServiceController,
+                mDeviceProvisionedController);
+        mController.bind();
+
+        // Capture callbacks passed to mocks
+        verify(mEntryManager).addNotificationEntryListener(mEntryListenerCaptor.capture());
+        mEntryListener = mEntryListenerCaptor.getValue();
+        verify(mDeviceProvisionedController).addCallback(mProvisionedCaptor.capture());
+        mProvisionedListener = mProvisionedCaptor.getValue();
+    }
+
+    @Test
+    public void testCleanUpViewStateOnEntryRemoved() {
+        final NotificationEntry entry = buildEntry();
+        mEntryListener.onEntryRemoved(
+                entry,
+                NotificationVisibility.obtain(entry.key, 0, 0, true),
+                false);
+        verify(mListContainer).cleanUpViewStateForEntry(entry);
+    }
+
+    @Test
+    public void testCallUpdateNotificationsOnDeviceProvisionedChange() {
+        mProvisionedListener.onDeviceProvisionedChanged();
+        verify(mEntryManager).updateNotifications();
+    }
+
+    @Test
+    public void testAppOps_appOpAddedToForegroundNotif() {
+        // GIVEN a notification associated with a foreground service
+        final NotificationEntry entry = buildEntry();
+        mNotificationData.add(entry);
+        when(mForegroundServiceController.getStandardLayoutKey(anyInt(), anyString()))
+                .thenReturn(entry.key);
+
+        // WHEN we are notified of a new app op
+        mController.updateNotificationsForAppOp(
+                AppOpsManager.OP_CAMERA,
+                entry.notification.getUid(),
+                entry.notification.getPackageName(),
+                true);
+
+        // THEN the app op is added to the entry
+        assertTrue(entry.mActiveAppOps.contains(AppOpsManager.OP_CAMERA));
+        // THEN updateNotifications() is called
+        verify(mEntryManager, times(1)).updateNotifications();
+    }
+
+    @Test
+    public void testAppOps_appOpAddedToUnrelatedNotif() {
+        // GIVEN No current foreground notifs
+        when(mForegroundServiceController.getStandardLayoutKey(anyInt(), anyString()))
+                .thenReturn(null);
+
+        // WHEN An unrelated notification gets a new app op
+        mController.updateNotificationsForAppOp(AppOpsManager.OP_CAMERA, 1000, "pkg", true);
+
+        // THEN We never call updateNotifications()
+        verify(mEntryManager, never()).updateNotifications();
+    }
+
+    @Test
+    public void testAppOps_addNotificationWithExistingAppOps() {
+        // GIVEN a notification with three associated app ops that is associated with a foreground
+        // service
+        final NotificationEntry entry = buildEntry();
+        mNotificationData.add(entry);
+        ArraySet<Integer> expected = new ArraySet<>();
+        expected.add(3);
+        expected.add(235);
+        expected.add(1);
+        when(mForegroundServiceController.getStandardLayoutKey(
+                entry.notification.getUserId(),
+                entry.notification.getPackageName())).thenReturn(entry.key);
+        when(mForegroundServiceController.getAppOps(entry.notification.getUserId(),
+                entry.notification.getPackageName())).thenReturn(expected);
+
+        // WHEN the notification is added
+        mEntryListener.onBeforeNotificationAdded(entry);
+
+        // THEN the entry is tagged with all three app ops
+        assertEquals(expected.size(), entry.mActiveAppOps.size());
+        for (int op : expected) {
+            assertTrue("Entry missing op " + op, entry.mActiveAppOps.contains(op));
+        }
+    }
+
+    @Test
+    public void testAdd_addNotificationWithNoExistingAppOps() {
+        // GIVEN a notification with NO associated app ops
+        final NotificationEntry entry = buildEntry();
+
+        mNotificationData.add(entry);
+        when(mForegroundServiceController.getStandardLayoutKey(
+                entry.notification.getUserId(),
+                entry.notification.getPackageName())).thenReturn(entry.key);
+        when(mForegroundServiceController.getAppOps(entry.notification.getUserId(),
+                entry.notification.getPackageName())).thenReturn(null);
+
+        // WHEN the notification is added
+        mEntryListener.onBeforeNotificationAdded(entry);
+
+        // THEN the entry doesn't have any app ops associated with it
+        assertEquals(0, entry.mActiveAppOps.size());
+    }
+
+    @Test
+    public void testAdd_addNonForegroundNotificationWithExistingAppOps() {
+        // GIVEN a notification with app ops that isn't associated with a foreground service
+        final NotificationEntry entry = buildEntry();
+        mNotificationData.add(entry);
+        ArraySet<Integer> ops = new ArraySet<>();
+        ops.add(3);
+        ops.add(235);
+        ops.add(1);
+        when(mForegroundServiceController.getAppOps(entry.notification.getUserId(),
+                entry.notification.getPackageName())).thenReturn(ops);
+        when(mForegroundServiceController.getStandardLayoutKey(
+                entry.notification.getUserId(),
+                entry.notification.getPackageName())).thenReturn("something else");
+
+        // WHEN the notification is added
+        mEntryListener.onBeforeNotificationAdded(entry);
+
+        // THEN the entry doesn't have any app ops associated with it
+        assertEquals(0, entry.mActiveAppOps.size());
+    }
+
+    private NotificationEntry buildEntry() {
+        mNextNotifId++;
+
+        Notification.Builder n = new Notification.Builder(mContext, "")
+                .setSmallIcon(R.drawable.ic_person)
+                .setContentTitle("Title")
+                .setContentText("Text");
+
+        StatusBarNotification notification =
+                new StatusBarNotification(
+                        TEST_PACKAGE_NAME,
+                        TEST_PACKAGE_NAME,
+                        mNextNotifId,
+                        null,
+                        TEST_UID,
+                        0,
+                        n.build(),
+                        new UserHandle(ActivityManager.getCurrentUser()),
+                        null,
+                        0);
+        return new NotificationEntry(notification);
+    }
+
+    private static final String TEST_PACKAGE_NAME = "test";
+    private static final int TEST_UID = 0;
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index cf9f233..8ffadde 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -462,7 +462,7 @@
             return false;
         }
 
-        endGestureDetection();
+        endGestureDetection(true);
 
         mAms.onGesture(gestureId);
 
@@ -472,7 +472,7 @@
     @Override
     public boolean onGestureCancelled(MotionEvent event, int policyFlags) {
         if (mCurrentState == STATE_GESTURE_DETECTING) {
-            endGestureDetection();
+            endGestureDetection(event.getActionMasked() == MotionEvent.ACTION_UP);
             return true;
         } else if (mCurrentState == STATE_TOUCH_EXPLORING) {
             // If the finger is still moving, pass the event on.
@@ -804,13 +804,19 @@
         }
     }
 
-    private void endGestureDetection() {
+    private void endGestureDetection(boolean interactionEnd) {
         mAms.onTouchInteractionEnd();
 
         // Announce the end of the gesture recognition.
         sendAccessibilityEvent(AccessibilityEvent.TYPE_GESTURE_DETECTION_END);
-        // Announce the end of a the touch interaction.
-        sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
+        if (interactionEnd) {
+            // Announce the end of a the touch interaction.
+            sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
+        } else {
+            // If gesture detection is end, but user doesn't release the finger, announce the
+            // transition to exploration state.
+            sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
+        }
 
         mExitGestureDetectionModeDelayed.cancel();
         mCurrentState = STATE_TOUCH_EXPLORING;
@@ -889,7 +895,6 @@
         MotionEvent event = mInjectedPointerTracker.getLastInjectedHoverEvent();
         if (event != null && event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT) {
             final int pointerIdBits = event.getPointerIdBits();
-            sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
             sendMotionEvent(event, MotionEvent.ACTION_HOVER_ENTER, pointerIdBits, policyFlags);
         }
     }
@@ -1148,8 +1153,8 @@
             sendAccessibilityEvent(AccessibilityEvent.TYPE_GESTURE_DETECTION_END);
             // Clearing puts is in touch exploration state with a finger already
             // down, so announce the transition to exploration state.
-            sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
             clear();
+            sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
         }
     }
 
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index ec6d20d..c992da4 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -252,9 +252,8 @@
     @Override // from AbstractMasterSystemService
     protected AutofillManagerServiceImpl newServiceLocked(@UserIdInt int resolvedUserId,
             boolean disabled) {
-        return new AutofillManagerServiceImpl(this, mLock, mRequestsHistory,
-                mUiLatencyHistory, mWtfHistory, resolvedUserId, mUi, mAutofillCompatState,
-                disabled);
+        return new AutofillManagerServiceImpl(this, mLock, mUiLatencyHistory,
+                mWtfHistory, resolvedUserId, mUi, mAutofillCompatState, disabled);
     }
 
     @Override // AbstractMasterSystemService
@@ -291,6 +290,13 @@
         return mSupportedSmartSuggestionModes;
     }
 
+    /**
+     * Logs a request so it's dumped later...
+     */
+    void logRequestLocked(@NonNull String historyItem) {
+        mRequestsHistory.log(historyItem);
+    }
+
     // Called by AutofillManagerServiceImpl, doesn't need to check permission
     boolean isInstantServiceAllowed() {
         return mAllowInstantService;
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index d037b08..954b67e 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -108,7 +108,6 @@
 
     private static final Random sRandom = new Random();
 
-    private final LocalLog mRequestsHistory;
     private final LocalLog mUiLatencyHistory;
     private final LocalLog mWtfHistory;
     private final FieldClassificationStrategy mFieldClassificationStrategy;
@@ -166,12 +165,12 @@
     @Nullable
     private RemoteAugmentedAutofillService mRemoteAugmentedAutofillService;
 
-    AutofillManagerServiceImpl(AutofillManagerService master, Object lock, LocalLog requestsHistory,
+    AutofillManagerServiceImpl(AutofillManagerService master, Object lock,
             LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui,
-            AutofillCompatState autofillCompatState, boolean disabled) {
+            AutofillCompatState autofillCompatState,
+            boolean disabled) {
         super(master, lock, userId);
 
-        mRequestsHistory = requestsHistory;
         mUiLatencyHistory = uiLatencyHistory;
         mWtfHistory = wtfHistory;
         mUi = ui;
@@ -310,7 +309,7 @@
                 + " s=" + mInfo.getServiceInfo().packageName
                 + " u=" + mUserId + " i=" + autofillId + " b=" + virtualBounds
                 + " hc=" + hasCallback + " f=" + flags;
-        mRequestsHistory.log(historyItem);
+        mMaster.logRequestLocked(historyItem);
 
         newSession.updateLocked(autofillId, virtualBounds, value, ACTION_START_SESSION, flags);
 
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index a5ef21a..7dfd8fe 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -2610,6 +2610,13 @@
                     + " when server returned null for session " + this.id);
         }
 
+        final String historyItem =
+                "aug:id=" + id + " u=" + uid + " m=" + mode
+                + " a=" + ComponentName.flattenToShortString(mComponentName)
+                + " f=" + mCurrentViewId
+                + " s=" + remoteService.getComponentName();
+        mService.getMaster().logRequestLocked(historyItem);
+
         final AutofillValue currentValue = mViewStates.get(mCurrentViewId).getCurrentValue();
 
         // TODO(b/111330312): we might need to add a new state in the AutofillManager to optimize
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index dc0f602..e4bbcd6 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -32,6 +32,7 @@
 import android.os.ShellCallback;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.util.LocalLog;
 import android.util.Slog;
 import android.view.contentcapture.IContentCaptureManager;
 
@@ -69,6 +70,8 @@
 
     private final LocalService mLocalService = new LocalService();
 
+    private final LocalLog mRequestsHistory = new LocalLog(20);
+
     public ContentCaptureManagerService(@NonNull Context context) {
         super(context, new FrameworkResourcesServiceNameResolver(context,
                 com.android.internal.R.string.config_defaultContentCaptureService),
@@ -154,6 +157,13 @@
         }
     }
 
+    /**
+     * Logs a request so it's dumped later...
+     */
+    void logRequestLocked(@NonNull String historyItem) {
+        mRequestsHistory.log(historyItem);
+    }
+
     private ActivityManagerInternal getAmInternal() {
         synchronized (mLock) {
             if (mAm == null) {
@@ -217,9 +227,29 @@
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
 
+            boolean showHistory = true;
+            if (args != null) {
+                for (String arg : args) {
+                    switch(arg) {
+                        case "--no-history":
+                            showHistory = false;
+                            break;
+                        case "--help":
+                            pw.println("Usage: dumpsys content_capture [--no-history]");
+                            return;
+                        default:
+                            Slog.w(TAG, "Ignoring invalid dump arg: " + arg);
+                    }
+                }
+            }
+
             synchronized (mLock) {
                 dumpLocked("", pw);
             }
+            if (showHistory) {
+                pw.println(); pw.println("Requests history:"); pw.println();
+                mRequestsHistory.reverseDump(fd, pw, args);
+            }
         }
 
         @Override
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index 1dae2ce..8d2c79b 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -85,7 +85,6 @@
     ContentCapturePerUserService(@NonNull ContentCaptureManagerService master,
             @NonNull Object lock, boolean disabled, @UserIdInt int userId) {
         super(master, lock, userId);
-
         updateRemoteServiceLocked(disabled);
     }
 
@@ -170,14 +169,24 @@
             @NonNull ComponentName componentName, int taskId, int displayId,
             @NonNull String sessionId, int uid, int flags,
             @NonNull IResultReceiver clientReceiver) {
-        if (!isEnabledLocked()) {
+
+        final ComponentName serviceComponentName = getServiceComponentName();
+        final boolean enabled = isEnabledLocked();
+        final String historyItem =
+                "id=" + sessionId + " uid=" + uid
+                + " a=" + ComponentName.flattenToShortString(componentName)
+                + " t=" + taskId + " d=" + displayId
+                + " s=" + ComponentName.flattenToShortString(serviceComponentName)
+                + " u=" + mUserId + " f=" + flags + (enabled ? "" : " (disabled)");
+        mMaster.logRequestLocked(historyItem);
+
+        if (!enabled) {
             // TODO: it would be better to split in differet reasons, like
             // STATE_DISABLED_NO_SERVICE and STATE_DISABLED_BY_DEVICE_POLICY
             setClientState(clientReceiver, STATE_DISABLED | STATE_NO_SERVICE,
                     /* binder= */ null);
             return;
         }
-        final ComponentName serviceComponentName = getServiceComponentName();
         if (serviceComponentName == null) {
             // TODO(b/111276913): this happens when the system service is starting, we should
             // probably handle it in a more elegant way (like waiting for boot_complete or
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
index ebe0083..3c52e17 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
@@ -83,6 +83,8 @@
      */
     @GuardedBy("mLock")
     public void sendActivitySnapshotLocked(@NonNull SnapshotData snapshotData) {
+        mService.getMaster().logRequestLocked("snapshot: id=" + mId);
+
         mRemoteService.onActivitySnapshotRequest(mId, snapshotData);
     }
 
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index 3ea9810..9789688 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -282,6 +282,7 @@
     private void setCurrentProxyScript(String script) {
         if (mProxyService == null) {
             Log.e(TAG, "setCurrentProxyScript: no proxy service");
+            return;
         }
         try {
             mProxyService.setPacFile(script);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6baf12c..36d1af2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1342,6 +1342,7 @@
     final @Nullable String mSystemTextClassifierPackage;
     final @Nullable String mWellbeingPackage;
     final @Nullable String mDocumenterPackage;
+    final @Nullable String mConfiguratorPackage;
     final @NonNull String mServicesSystemSharedLibraryPackageName;
     final @NonNull String mSharedSystemSharedLibraryPackageName;
 
@@ -2865,6 +2866,8 @@
 
             mWellbeingPackage = getWellbeingPackageName();
             mDocumenterPackage = getDocumenterPackageName();
+            mConfiguratorPackage =
+                    mContext.getString(R.string.config_deviceConfiguratorPackageName);
 
             // Now that we know all of the shared libraries, update all clients to have
             // the correct library paths.
@@ -19135,7 +19138,7 @@
         // writer
         synchronized (mPackages) {
             PackageParser.Package pkg = mPackages.get(packageName);
-            if (pkg == null || pkg.applicationInfo.uid != callingUid) {
+            if (pkg == null || !isCallerSameApp(packageName, callingUid)) {
                 if (mContext.checkCallingOrSelfPermission(
                         android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
                         != PackageManager.PERMISSION_GRANTED) {
@@ -23122,6 +23125,8 @@
                     return mWellbeingPackage;
                 case PackageManagerInternal.PACKAGE_DOCUMENTER:
                     return mDocumenterPackage;
+                case PackageManagerInternal.PACKAGE_CONFIGURATOR:
+                    return mConfiguratorPackage;
             }
             return null;
         }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 95da209..b0f2326 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -2790,13 +2790,13 @@
                 // dataPath   - path to package's data path
                 // seinfo     - seinfo label for the app (assigned at install time)
                 // gids       - supplementary gids this app launches with
+                // profileableFromShellFlag  - 0 or 1 if the package is profileable from shell.
                 //
                 // NOTE: We prefer not to expose all ApplicationInfo flags for now.
                 //
                 // DO NOT MODIFY THIS FORMAT UNLESS YOU CAN ALSO MODIFY ITS USERS
                 // FROM NATIVE CODE. AT THE MOMENT, LOOK AT THE FOLLOWING SOURCES:
-                //   frameworks/base/libs/packagelistparser
-                //   system/core/run-as/run-as.c
+                //   system/core/libpackagelistparser
                 //
                 sb.setLength(0);
                 sb.append(ai.packageName);
@@ -2816,6 +2816,8 @@
                 } else {
                     sb.append("none");
                 }
+                sb.append(" ");
+                sb.append(ai.isProfileableByShell() ? "1" : "0");
                 sb.append("\n");
                 writer.append(sb);
             }
diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
index 3a49412..17f8347 100644
--- a/services/core/java/com/android/server/pm/permission/BasePermission.java
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -247,6 +247,10 @@
     public boolean isDocumenter() {
         return (protectionLevel & PermissionInfo.PROTECTION_FLAG_DOCUMENTER) != 0;
     }
+    public boolean isConfigurator() {
+        return (protectionLevel & PermissionInfo.PROTECTION_FLAG_CONFIGURATOR)
+            != 0;
+    }
 
     public void transfer(@NonNull String origPackageName, @NonNull String newPackageName) {
         if (!origPackageName.equals(sourcePackageName)) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 93964cb..30b5e49 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -1640,6 +1640,13 @@
                 // Special permissions for the system default text classifier.
                 allowed = true;
             }
+            if (!allowed && bp.isConfigurator()
+                    && pkg.packageName.equals(mPackageManagerInt.getKnownPackageName(
+                    PackageManagerInternal.PACKAGE_CONFIGURATOR,
+                    UserHandle.USER_SYSTEM))) {
+                // Special permissions for the device configurator.
+                allowed = true;
+            }
             if (!allowed && bp.isWellbeing()
                     && pkg.packageName.equals(mPackageManagerInt.getKnownPackageName(
                     PackageManagerInternal.PACKAGE_WELLBEING, UserHandle.USER_SYSTEM))) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 4bc2416..6b111a0 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -480,6 +480,7 @@
     int mShortPressOnSleepBehavior;
     int mShortPressOnWindowBehavior;
     boolean mHasSoftInput = false;
+    boolean mHapticTextHandleEnabled;
     boolean mUseTvRouting;
     int mVeryLongPressTimeout;
     boolean mAllowStartActivityForLongPressOnPowerDuringSetup;
@@ -567,6 +568,10 @@
     private boolean mScreenshotChordPowerKeyTriggered;
     private long mScreenshotChordPowerKeyTime;
 
+    private static final long MOVING_DISPLAY_TO_TOP_DURATION_MILLIS = 10;
+    private volatile boolean mMovingDisplayToTopKeyTriggered;
+    private volatile long mMovingDisplayToTopKeyTime;
+
     // Ringer toggle should reuse timing and triggering from screenshot power and a11y vol up
     private int mRingerToggleChord = VOLUME_HUSH_OFF;
 
@@ -606,7 +611,7 @@
     private boolean mAodShowing;
 
     private boolean mPerDisplayFocusEnabled = false;
-    private int mTopFocusedDisplayId = INVALID_DISPLAY;
+    private volatile int mTopFocusedDisplayId = INVALID_DISPLAY;
 
     private static final int MSG_ENABLE_POINTER_LOCATION = 1;
     private static final int MSG_DISABLE_POINTER_LOCATION = 2;
@@ -634,6 +639,7 @@
     private static final int MSG_POWER_VERY_LONG_PRESS = 25;
     private static final int MSG_NOTIFY_USER_ACTIVITY = 26;
     private static final int MSG_RINGER_TOGGLE_CHORD = 27;
+    private static final int MSG_MOVE_DISPLAY_TO_TOP = 28;
 
     private class PolicyHandler extends Handler {
         @Override
@@ -729,6 +735,10 @@
                 case MSG_RINGER_TOGGLE_CHORD:
                     handleRingerChordGesture();
                     break;
+                case MSG_MOVE_DISPLAY_TO_TOP:
+                    mWindowManagerFuncs.moveDisplayToTop(msg.arg1);
+                    mMovingDisplayToTopKeyTriggered = false;
+                    break;
             }
         }
     }
@@ -1827,6 +1837,9 @@
         mAllowStartActivityForLongPressOnPowerDuringSetup = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_allowStartActivityForLongPressOnPowerInSetup);
 
+        mHapticTextHandleEnabled = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_enableHapticTextHandle);
+
         mUseTvRouting = AudioSystem.getPlatformType(mContext) == AudioSystem.PLATFORM_TELEVISION;
 
         mHandleVolumeKeysInWM = mContext.getResources().getBoolean(
@@ -2570,12 +2583,25 @@
         final int eventDisplayId = event.getDisplayId();
         if (result == 0 && !mPerDisplayFocusEnabled
                 && eventDisplayId != INVALID_DISPLAY && eventDisplayId != mTopFocusedDisplayId) {
-            // Someone tries to send a key event to a display which doesn't have a focused window.
-            // We drop the event here, or it will cause ANR.
-            // TODO (b/121057974): The user may be confused about why the key doesn't work, so we
-            // may need to deal with this problem.
-            Slog.i(TAG, "Dropping this event targeting display #" + eventDisplayId
-                    + " because the focus is on display #" + mTopFocusedDisplayId);
+            // An event is targeting a non-focused display. Try to move the display to top so that
+            // it can become the focused display to interact with the user.
+            final long eventDownTime = event.getDownTime();
+            if (mMovingDisplayToTopKeyTime < eventDownTime) {
+                // We have not handled this event yet. Move the display to top, and then tell
+                // dispatcher to try again later.
+                mMovingDisplayToTopKeyTime = eventDownTime;
+                mMovingDisplayToTopKeyTriggered = true;
+                mHandler.sendMessage(
+                        mHandler.obtainMessage(MSG_MOVE_DISPLAY_TO_TOP, eventDisplayId, 0));
+                return MOVING_DISPLAY_TO_TOP_DURATION_MILLIS;
+            } else if (mMovingDisplayToTopKeyTriggered) {
+                // The message has not been handled yet. Tell dispatcher to try again later.
+                return MOVING_DISPLAY_TO_TOP_DURATION_MILLIS;
+            }
+            // The target display is still not the top focused display. Drop the event because the
+            // display may not contain any window which can receive keys.
+            Slog.w(TAG, "Dropping key targeting non-focused display #" + eventDisplayId
+                    + " keyCode=" + KeyEvent.keyCodeToString(event.getKeyCode()));
             return -1;
         }
         return result;
@@ -5179,8 +5205,11 @@
             case HapticFeedbackConstants.CLOCK_TICK:
             case HapticFeedbackConstants.CONTEXT_CLICK:
                 return VibrationEffect.get(VibrationEffect.EFFECT_TICK);
-            case HapticFeedbackConstants.KEYBOARD_RELEASE:
             case HapticFeedbackConstants.TEXT_HANDLE_MOVE:
+                if (!mHapticTextHandleEnabled) {
+                    return null;
+                }
+            case HapticFeedbackConstants.KEYBOARD_RELEASE:
             case HapticFeedbackConstants.VIRTUAL_KEY_RELEASE:
             case HapticFeedbackConstants.ENTRY_BUMP:
             case HapticFeedbackConstants.DRAG_CROSSING:
@@ -5345,11 +5374,13 @@
                 pw.println(mAllowStartActivityForLongPressOnPowerDuringSetup);
         pw.print(prefix);
                 pw.print("mHasSoftInput="); pw.print(mHasSoftInput);
-                pw.print(" mDismissImeOnBackKeyPressed="); pw.println(mDismissImeOnBackKeyPressed);
+                pw.print(" mHapticTextHandleEnabled="); pw.println(mHapticTextHandleEnabled);
         pw.print(prefix);
-                pw.print("mIncallPowerBehavior=");
-                pw.print(incallPowerBehaviorToString(mIncallPowerBehavior));
-                pw.print(" mIncallBackBehavior=");
+                pw.print("mDismissImeOnBackKeyPressed="); pw.print(mDismissImeOnBackKeyPressed);
+                pw.print(" mIncallPowerBehavior=");
+                pw.println(incallPowerBehaviorToString(mIncallPowerBehavior));
+        pw.print(prefix);
+                pw.print("mIncallBackBehavior=");
                 pw.print(incallBackBehaviorToString(mIncallBackBehavior));
                 pw.print(" mEndcallBehavior=");
                 pw.println(endcallBehaviorToString(mEndcallBehavior));
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 3da325c..c37254b 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -634,6 +634,12 @@
          * Notifies window manager that user is switched.
          */
         void onUserSwitched();
+
+        /**
+         * Hint to window manager that the user is interacting with a display that should be treated
+         * as the top display.
+         */
+        void moveDisplayToTop(int displayId);
     }
 
     /**
diff --git a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
index 45c975b..055c941 100644
--- a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
+++ b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
@@ -62,6 +62,8 @@
                         mContext.getContentResolver(),
                         Settings.Secure.SMS_DEFAULT_APPLICATION, userId);
 
+                // TODO: STOPSHIP: Remove the following code once we remove default_sms_application
+                // and use the new config_defaultRoleHolders.
                 if (result == null) {
                     Collection<SmsApplication.SmsApplicationData> applications =
                             SmsApplication.getApplicationCollectionAsUser(mContext, userId);
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index c0ec367..5516b23 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -229,9 +229,12 @@
         // Any role for which we have a record are already migrated
         RoleUserState userState = getOrCreateUserState(userId);
         if (!userState.isRoleAvailable(role)) {
-            userState.addRoleName(role);
             List<String> roleHolders = mLegacyRoleResolver.getRoleHolders(role, userId);
+            if (roleHolders.isEmpty()) {
+                return;
+            }
             Slog.i(LOG_TAG, "Migrating " + role + ", legacy holders: " + roleHolders);
+            userState.addRoleName(role);
             int size = roleHolders.size();
             for (int i = 0; i < size; i++) {
                 userState.addRoleHolder(role, roleHolders.get(i));
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index 0616846..65d66f4 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -625,6 +625,10 @@
             return;
         }
 
+        // Collect the stacks that are necessary to be removed instead of performing the removal
+        // by looping mStacks, so that we don't miss any stacks after the stack size changed or
+        // stacks reordered.
+        final ArrayList<ActivityStack> stacks = new ArrayList<>();
         for (int j = windowingModes.length - 1 ; j >= 0; --j) {
             final int windowingMode = windowingModes[j];
             for (int i = mStacks.size() - 1; i >= 0; --i) {
@@ -635,9 +639,13 @@
                 if (stack.getWindowingMode() != windowingMode) {
                     continue;
                 }
-                mRootActivityContainer.mStackSupervisor.removeStack(stack);
+                stacks.add(stack);
             }
         }
+
+        for (int i = stacks.size() - 1; i >= 0; --i) {
+            mRootActivityContainer.mStackSupervisor.removeStack(stacks.get(i));
+        }
     }
 
     void removeStacksWithActivityTypes(int... activityTypes) {
@@ -645,15 +653,23 @@
             return;
         }
 
+        // Collect the stacks that are necessary to be removed instead of performing the removal
+        // by looping mStacks, so that we don't miss any stacks after the stack size changed or
+        // stacks reordered.
+        final ArrayList<ActivityStack> stacks = new ArrayList<>();
         for (int j = activityTypes.length - 1 ; j >= 0; --j) {
             final int activityType = activityTypes[j];
             for (int i = mStacks.size() - 1; i >= 0; --i) {
                 final ActivityStack stack = mStacks.get(i);
                 if (stack.getActivityType() == activityType) {
-                    mRootActivityContainer.mStackSupervisor.removeStack(stack);
+                    stacks.add(stack);
                 }
             }
         }
+
+        for (int i = stacks.size() - 1; i >= 0; --i) {
+            mRootActivityContainer.mStackSupervisor.removeStack(stacks.get(i));
+        }
     }
 
     void onStackWindowingModeChanged(ActivityStack stack) {
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index a4cda5a..3a288ca 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -2641,6 +2641,9 @@
                 try {
                     mService.moveTaskToFrontLocked(task.taskId, 0, options,
                             true /* fromRecents */);
+                    // Apply options to prevent pendingOptions be taken by client to make sure
+                    // the override pending app transition will be applied immediately.
+                    targetActivity.applyOptionsLocked();
                 } finally {
                     mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT,
                             targetActivity);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index b735115..6527ca0 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -328,14 +328,6 @@
     private int mLastOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
 
     /**
-     * Flag indicating that the application is receiving an orientation that has different metrics
-     * than it expected. E.g. Portrait instead of Landscape.
-     *
-     * @see #updateRotationUnchecked()
-     */
-    private boolean mAltOrientation = false;
-
-    /**
      * Orientation forced by some window. If there is no visible window that specifies orientation
      * it is set to {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED}.
      *
@@ -1085,10 +1077,6 @@
         return mLastOrientation;
     }
 
-    boolean getAltOrientation() {
-        return mAltOrientation;
-    }
-
     int getLastWindowForcedOrientation() {
         return mLastWindowForcedOrientation;
     }
@@ -1130,15 +1118,9 @@
     boolean rotationNeedsUpdate() {
         final int lastOrientation = getLastOrientation();
         final int oldRotation = getRotation();
-        final boolean oldAltOrientation = getAltOrientation();
 
         final int rotation = mDisplayRotation.rotationForOrientation(lastOrientation, oldRotation);
-        final boolean altOrientation = !mDisplayRotation.rotationHasCompatibleMetrics(
-                lastOrientation, rotation);
-        if (oldRotation == rotation && oldAltOrientation == altOrientation) {
-            return false;
-        }
-        return true;
+        return oldRotation != rotation;
     }
 
     /**
@@ -1336,7 +1318,6 @@
 
         final int oldRotation = mRotation;
         final int lastOrientation = mLastOrientation;
-        final boolean oldAltOrientation = mAltOrientation;
         final int rotation = mDisplayRotation.rotationForOrientation(lastOrientation, oldRotation);
         if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Computed rotation=" + rotation + " for display id="
                 + mDisplayId + " based on lastOrientation=" + lastOrientation
@@ -1368,35 +1349,26 @@
         }
         final boolean rotateSeamlessly = mayRotateSeamlessly;
 
-        // TODO: Implement forced rotation changes.
-        //       Set mAltOrientation to indicate that the application is receiving
-        //       an orientation that has different metrics than it expected.
-        //       eg. Portrait instead of Landscape.
-
-        final boolean altOrientation = !mDisplayRotation.rotationHasCompatibleMetrics(
-                lastOrientation, rotation);
-
         if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + mDisplayId
                 + " selected orientation " + lastOrientation
                 + ", got rotation " + rotation + " which has "
-                + (altOrientation ? "incompatible" : "compatible") + " metrics");
+                + " metrics");
 
-        if (oldRotation == rotation && oldAltOrientation == altOrientation) {
+        if (oldRotation == rotation) {
             // No change.
             return false;
         }
 
         if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + mDisplayId
                 + " rotation changed to " + rotation
-                + (altOrientation ? " (alt)" : "") + " from " + oldRotation
-                + (oldAltOrientation ? " (alt)" : "") + ", lastOrientation=" + lastOrientation);
+                + " from " + oldRotation
+                + ", lastOrientation=" + lastOrientation);
 
         if (DisplayContent.deltaRotation(rotation, oldRotation) != 2) {
             mWaitingForConfig = true;
         }
 
         mRotation = rotation;
-        mAltOrientation = altOrientation;
 
         mWmService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
         mWmService.mH.sendNewMessageDelayed(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT,
@@ -1538,26 +1510,8 @@
     private DisplayInfo updateDisplayAndOrientation(int uiMode) {
         // Use the effective "visual" dimensions based on current rotation
         final boolean rotated = (mRotation == ROTATION_90 || mRotation == ROTATION_270);
-        final int realdw = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
-        final int realdh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
-        int dw = realdw;
-        int dh = realdh;
-
-        if (mAltOrientation) {
-            if (realdw > realdh) {
-                // Turn landscape into portrait.
-                int maxw = (int)(realdh/1.3f);
-                if (maxw < realdw) {
-                    dw = maxw;
-                }
-            } else {
-                // Turn portrait into landscape.
-                int maxh = (int)(realdw/1.3f);
-                if (maxh < realdh) {
-                    dh = maxh;
-                }
-            }
-        }
+        final int dw = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
+        final int dh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
 
         // Update application display metrics.
         final WmDisplayCutout wmDisplayCutout = calculateDisplayCutoutForRotation(mRotation);
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 7aabc15..bc165dc 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -676,36 +676,6 @@
         return rotation == mPortraitRotation || rotation == mUpsideDownRotation;
     }
 
-    /**
-     * Given an orientation constant and a rotation, returns true if the rotation
-     * has compatible metrics to the requested orientation.  For example, if
-     * the application requested landscape and got seascape, then the rotation
-     * has compatible metrics; if the application requested portrait and got landscape,
-     * then the rotation has incompatible metrics; if the application did not specify
-     * a preference, then anything goes.
-     *
-     * @param orientation An orientation constant, such as
-     * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}.
-     * @param rotation The rotation to check.
-     * @return True if the rotation is compatible with the requested orientation.
-     */
-    boolean rotationHasCompatibleMetrics(int orientation, int rotation) {
-        switch (orientation) {
-            case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
-            case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT:
-            case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT:
-                return isAnyPortrait(rotation);
-
-            case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
-            case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
-            case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
-                return isLandscapeOrSeascape(rotation);
-
-            default:
-                return true;
-        }
-    }
-
     private boolean isValidRotationChoice(final int preferredRotation) {
         // Determine if the given app orientation is compatible with the provided rotation choice.
         switch (mCurrentAppOrientation) {
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index 55554a7..9b72141 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -234,7 +234,7 @@
         mWindowManager = wm;
         setWindowContainer(mWindowManager.mRoot);
         mDisplayManager = mService.mContext.getSystemService(DisplayManager.class);
-        mDisplayManager.registerDisplayListener(this, mService.mH);
+        mDisplayManager.registerDisplayListener(this, mService.mUiHandler);
         mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
 
         final Display[] displays = mDisplayManager.getDisplays();
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 937c9d9..58cf73a 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -47,10 +47,9 @@
 import android.view.IWindowSession;
 import android.view.IWindowSessionCallback;
 import android.view.InputChannel;
-import android.view.Surface;
+import android.view.InsetsState;
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
-import android.view.InsetsState;
 import android.view.WindowManager;
 
 import com.android.internal.os.logging.MetricsLoggerWrapper;
@@ -432,7 +431,7 @@
 
     @Override
     public void insetsModified(IWindow window, InsetsState state) {
-        synchronized (mService.mWindowMap) {
+        synchronized (mService.mGlobalLock) {
             final WindowState windowState = mService.windowForClientLocked(this, window,
                     false /* throwOnError */);
             if (windowState != null) {
diff --git a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
index b219419..9057870 100644
--- a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
+++ b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
@@ -67,7 +67,7 @@
                     return;
                 }
                 WindowContainer parent = mDisplayContent.getParent();
-                if (parent != null) {
+                if (parent != null && parent.getTopChild() != mDisplayContent) {
                     parent.positionChildAt(WindowContainer.POSITION_TOP, mDisplayContent,
                             true /* includingParents */);
                 }
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 25e61f8..1905877 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -437,6 +437,7 @@
                 if (mChildren.peekLast() != child) {
                     mChildren.remove(child);
                     mChildren.add(child);
+                    onChildPositionChanged();
                 }
                 if (includingParents && getParent() != null) {
                     getParent().positionChildAt(POSITION_TOP, this /* child */,
@@ -447,6 +448,7 @@
                 if (mChildren.peekFirst() != child) {
                     mChildren.remove(child);
                     mChildren.addFirst(child);
+                    onChildPositionChanged();
                 }
                 if (includingParents && getParent() != null) {
                     getParent().positionChildAt(POSITION_BOTTOM, this /* child */,
@@ -460,8 +462,8 @@
                 //       doing this adjustment here and remove any adjustments in the callers.
                 mChildren.remove(child);
                 mChildren.add(position, child);
+                onChildPositionChanged();
         }
-        onChildPositionChanged();
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 90506e7..fda7a85 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -723,7 +723,7 @@
 
         void updateSystemUiSettings() {
             boolean changed;
-            synchronized (mWindowMap) {
+            synchronized (mGlobalLock) {
                 changed = ImmersiveModeConfirmation.loadSetting(mCurrentUserId, mContext)
                         || PolicyControl.reloadFromSetting(mContext);
             }
@@ -2629,12 +2629,23 @@
     @Override
     public void onUserSwitched() {
         mSettingsObserver.updateSystemUiSettings();
-        synchronized (mWindowMap) {
+        synchronized (mGlobalLock) {
             // force a re-application of focused window sysui visibility on each display.
             mRoot.forAllDisplayPolicies(DisplayPolicy::resetSystemUiVisibilityLw);
         }
     }
 
+    @Override
+    public void moveDisplayToTop(int displayId) {
+        synchronized (mGlobalLock) {
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+            if (displayContent != null && mRoot.getTopChild() != displayContent) {
+                mRoot.positionChildAt(WindowContainer.POSITION_TOP, displayContent,
+                        true /* includingParents */);
+            }
+        }
+    }
+
     /**
      * Starts deferring layout passes. Useful when doing multiple changes but to optimize
      * performance, only one layout pass should be done. This can be called multiple times, and
@@ -5932,8 +5943,6 @@
                     pw.print(" apps="); pw.print(mAppsFreezingScreen);
             final DisplayContent defaultDisplayContent = getDefaultDisplayContentLocked();
             pw.print("  mRotation="); pw.print(defaultDisplayContent.getRotation());
-                    pw.print(" mAltOrientation=");
-                            pw.println(defaultDisplayContent.getAltOrientation());
             pw.print("  mLastWindowForcedOrientation=");
                     pw.print(defaultDisplayContent.getLastWindowForcedOrientation());
                     pw.print(" mLastOrientation=");
@@ -6379,7 +6388,7 @@
     }
 
     void setForceDesktopModeOnExternalDisplays(boolean forceDesktopModeOnExternalDisplays) {
-        synchronized (mWindowMap) {
+        synchronized (mGlobalLock) {
             mForceDesktopModeOnExternalDisplays = forceDesktopModeOnExternalDisplays;
         }
     }
diff --git a/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java b/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java
new file mode 100644
index 0000000..5b77f54
--- /dev/null
+++ b/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2019 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.net.shared;
+
+import static android.net.shared.ParcelableUtil.fromParcelableArray;
+import static android.net.shared.ParcelableUtil.toParcelableArray;
+
+import android.annotation.Nullable;
+import android.net.InetAddresses;
+import android.net.IpPrefix;
+import android.net.IpPrefixParcelable;
+import android.net.LinkAddress;
+import android.net.LinkAddressParcelable;
+import android.net.LinkProperties;
+import android.net.LinkPropertiesParcelable;
+import android.net.ProxyInfo;
+import android.net.ProxyInfoParcelable;
+import android.net.RouteInfo;
+import android.net.RouteInfoParcelable;
+import android.net.Uri;
+
+import java.net.InetAddress;
+import java.util.Arrays;
+
+/**
+ * Collection of utility methods to convert to and from stable AIDL parcelables for LinkProperties
+ * and its attributes.
+ * @hide
+ */
+public final class LinkPropertiesParcelableUtil {
+
+    /**
+     * Convert a ProxyInfo to a ProxyInfoParcelable
+     */
+    public static ProxyInfoParcelable toStableParcelable(@Nullable ProxyInfo proxyInfo) {
+        if (proxyInfo == null) {
+            return null;
+        }
+        final ProxyInfoParcelable parcel = new ProxyInfoParcelable();
+        parcel.host = proxyInfo.getHost();
+        parcel.port = proxyInfo.getPort();
+        parcel.exclusionList = proxyInfo.getExclusionList();
+        parcel.pacFileUrl = proxyInfo.getPacFileUrl().toString();
+        return parcel;
+    }
+
+    /**
+     * Convert a ProxyInfoParcelable to a ProxyInfo
+     */
+    public static ProxyInfo fromStableParcelable(@Nullable ProxyInfoParcelable parcel) {
+        if (parcel == null) {
+            return null;
+        }
+        if (Uri.EMPTY.toString().equals(parcel.pacFileUrl)) {
+            return ProxyInfo.buildDirectProxy(
+                    parcel.host, parcel.port, Arrays.asList(parcel.exclusionList));
+        } else {
+            return ProxyInfo.buildPacProxy(Uri.parse(parcel.pacFileUrl));
+        }
+    }
+
+    /**
+     * Convert an IpPrefixParcelable to an IpPrefix
+     */
+    public static IpPrefixParcelable toStableParcelable(@Nullable IpPrefix ipPrefix) {
+        if (ipPrefix == null) {
+            return null;
+        }
+        final IpPrefixParcelable parcel = new IpPrefixParcelable();
+        parcel.address = ipPrefix.getAddress().getHostAddress();
+        parcel.prefixLength = ipPrefix.getPrefixLength();
+        return parcel;
+    }
+
+    /**
+     * Convert an IpPrefix to an IpPrefixParcelable
+     */
+    public static IpPrefix fromStableParcelable(@Nullable IpPrefixParcelable parcel) {
+        if (parcel == null) {
+            return null;
+        }
+        return new IpPrefix(InetAddresses.parseNumericAddress(parcel.address), parcel.prefixLength);
+    }
+
+    /**
+     * Convert a RouteInfoParcelable to a RouteInfo
+     */
+    public static RouteInfoParcelable toStableParcelable(@Nullable RouteInfo routeInfo) {
+        if (routeInfo == null) {
+            return null;
+        }
+        final RouteInfoParcelable parcel = new RouteInfoParcelable();
+        parcel.destination = toStableParcelable(routeInfo.getDestination());
+        parcel.gatewayAddr = routeInfo.getGateway().getHostAddress();
+        parcel.ifaceName = routeInfo.getInterface();
+        parcel.type = routeInfo.getType();
+        return parcel;
+    }
+
+    /**
+     * Convert a RouteInfo to a RouteInfoParcelable
+     */
+    public static RouteInfo fromStableParcelable(@Nullable RouteInfoParcelable parcel) {
+        if (parcel == null) {
+            return null;
+        }
+        final IpPrefix destination = fromStableParcelable(parcel.destination);
+        return new RouteInfo(
+                destination, InetAddresses.parseNumericAddress(parcel.gatewayAddr),
+                parcel.ifaceName, parcel.type);
+    }
+
+    /**
+     * Convert a LinkAddressParcelable to a LinkAddress
+     */
+    public static LinkAddressParcelable toStableParcelable(@Nullable LinkAddress la) {
+        if (la == null) {
+            return null;
+        }
+        final LinkAddressParcelable parcel = new LinkAddressParcelable();
+        parcel.address = la.getAddress().getHostAddress();
+        parcel.prefixLength = la.getPrefixLength();
+        parcel.flags = la.getFlags();
+        parcel.scope = la.getScope();
+        return parcel;
+    }
+
+    /**
+     * Convert a LinkAddress to a LinkAddressParcelable
+     */
+    public static LinkAddress fromStableParcelable(@Nullable LinkAddressParcelable parcel) {
+        if (parcel == null) {
+            return null;
+        }
+        return new LinkAddress(
+                InetAddresses.parseNumericAddress(parcel.address),
+                parcel.prefixLength,
+                parcel.flags,
+                parcel.scope);
+    }
+
+    /**
+     * Convert a LinkProperties to a LinkPropertiesParcelable
+     */
+    public static LinkPropertiesParcelable toStableParcelable(@Nullable LinkProperties lp) {
+        if (lp == null) {
+            return null;
+        }
+        final LinkPropertiesParcelable parcel = new LinkPropertiesParcelable();
+        parcel.ifaceName = lp.getInterfaceName();
+        parcel.linkAddresses = toParcelableArray(
+                lp.getLinkAddresses(),
+                LinkPropertiesParcelableUtil::toStableParcelable,
+                LinkAddressParcelable.class);
+        parcel.dnses = toParcelableArray(
+                lp.getDnsServers(), InetAddress::getHostAddress, String.class);
+        parcel.pcscfs = toParcelableArray(
+                lp.getPcscfServers(), InetAddress::getHostAddress, String.class);
+        parcel.validatedPrivateDnses = toParcelableArray(
+                lp.getValidatedPrivateDnsServers(), InetAddress::getHostAddress, String.class);
+        parcel.usePrivateDns = lp.isPrivateDnsActive();
+        parcel.privateDnsServerName = lp.getPrivateDnsServerName();
+        parcel.domains = lp.getDomains();
+        parcel.routes = toParcelableArray(
+                lp.getRoutes(), LinkPropertiesParcelableUtil::toStableParcelable,
+                RouteInfoParcelable.class);
+        parcel.httpProxy = toStableParcelable(lp.getHttpProxy());
+        parcel.mtu = lp.getMtu();
+        parcel.tcpBufferSizes = lp.getTcpBufferSizes();
+        parcel.nat64Prefix = toStableParcelable(lp.getNat64Prefix());
+        parcel.stackedLinks = toParcelableArray(
+                lp.getStackedLinks(), LinkPropertiesParcelableUtil::toStableParcelable,
+                LinkPropertiesParcelable.class);
+        return parcel;
+    }
+
+    /**
+     * Convert a LinkPropertiesParcelable to a LinkProperties
+     */
+    public static LinkProperties fromStableParcelable(@Nullable LinkPropertiesParcelable parcel) {
+        if (parcel == null) {
+            return null;
+        }
+        final LinkProperties lp = new LinkProperties();
+        lp.setInterfaceName(parcel.ifaceName);
+        lp.setLinkAddresses(fromParcelableArray(parcel.linkAddresses,
+                LinkPropertiesParcelableUtil::fromStableParcelable));
+        lp.setDnsServers(fromParcelableArray(parcel.dnses, InetAddresses::parseNumericAddress));
+        lp.setPcscfServers(fromParcelableArray(parcel.pcscfs, InetAddresses::parseNumericAddress));
+        lp.setValidatedPrivateDnsServers(
+                fromParcelableArray(parcel.validatedPrivateDnses,
+                InetAddresses::parseNumericAddress));
+        lp.setUsePrivateDns(parcel.usePrivateDns);
+        lp.setPrivateDnsServerName(parcel.privateDnsServerName);
+        lp.setDomains(parcel.domains);
+        for (RouteInfoParcelable route : parcel.routes) {
+            lp.addRoute(fromStableParcelable(route));
+        }
+        lp.setHttpProxy(fromStableParcelable(parcel.httpProxy));
+        lp.setMtu(parcel.mtu);
+        lp.setTcpBufferSizes(parcel.tcpBufferSizes);
+        lp.setNat64Prefix(fromStableParcelable(parcel.nat64Prefix));
+        for (LinkPropertiesParcelable stackedLink : parcel.stackedLinks) {
+            lp.addStackedLink(fromStableParcelable(stackedLink));
+        }
+        return lp;
+    }
+}
diff --git a/services/net/java/android/net/shared/ParcelableUtil.java b/services/net/java/android/net/shared/ParcelableUtil.java
new file mode 100644
index 0000000..a18976c
--- /dev/null
+++ b/services/net/java/android/net/shared/ParcelableUtil.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2019 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.net.shared;
+
+import android.annotation.NonNull;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Function;
+
+/**
+ * Utility methods to help convert to/from stable parcelables.
+ * @hide
+ */
+public final class ParcelableUtil {
+    // Below methods could be implemented easily with streams, but streams are frowned upon in
+    // frameworks code.
+
+    /**
+     * Convert a list of BaseType items to an array of ParcelableType items using the specified
+     * converter function.
+     */
+    public static <ParcelableType, BaseType> ParcelableType[] toParcelableArray(
+            @NonNull List<BaseType> base,
+            @NonNull Function<BaseType, ParcelableType> conv,
+            @NonNull Class<ParcelableType> parcelClass) {
+        final ParcelableType[] out = (ParcelableType[]) Array.newInstance(parcelClass, base.size());
+        int i = 0;
+        for (BaseType b : base) {
+            out[i] = conv.apply(b);
+            i++;
+        }
+        return out;
+    }
+
+    /**
+     * Convert an array of ParcelableType items to a list of BaseType items using the specified
+     * converter function.
+     */
+    public static <ParcelableType, BaseType> ArrayList<BaseType> fromParcelableArray(
+            @NonNull ParcelableType[] parceled, @NonNull Function<ParcelableType, BaseType> conv) {
+        final ArrayList<BaseType> out = new ArrayList<>(parceled.length);
+        for (ParcelableType t : parceled) {
+            out.add(conv.apply(t));
+        }
+        return out;
+    }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
index 5bf3d2d..56f4a85 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
@@ -36,6 +36,9 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
 
 import android.platform.test.annotations.Presubmit;
 
@@ -54,11 +57,6 @@
 @Presubmit
 public class ActivityDisplayTests extends ActivityTestsBase {
 
-    @Before
-    public void setUp() throws Exception {
-        setupActivityTaskManagerService();
-    }
-
     @Test
     public void testLastFocusedStackIsUpdatedWhenMovingStack() {
         // Create a stack at bottom.
@@ -277,4 +275,60 @@
         assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop());
         assertEquals(anotherAlwaysOnTopStack, display.getChildAt(topPosition - 1));
     }
+
+    @Test
+    public void testRemoveStackInWindowingModes() {
+        removeStackTests(() -> mRootActivityContainer.removeStacksInWindowingModes(
+                WINDOWING_MODE_FULLSCREEN));
+    }
+
+    @Test
+    public void testRemoveStackWithActivityTypes() {
+        removeStackTests(
+                () -> mRootActivityContainer.removeStacksWithActivityTypes(ACTIVITY_TYPE_STANDARD));
+    }
+
+    private void removeStackTests(Runnable runnable) {
+        final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+        final ActivityStack stack1 = display.createStack(WINDOWING_MODE_FULLSCREEN,
+                ACTIVITY_TYPE_STANDARD, ON_TOP);
+        final ActivityStack stack2 = display.createStack(WINDOWING_MODE_FULLSCREEN,
+                ACTIVITY_TYPE_STANDARD, ON_TOP);
+        final ActivityStack stack3 = display.createStack(WINDOWING_MODE_FULLSCREEN,
+                ACTIVITY_TYPE_STANDARD, ON_TOP);
+        final ActivityStack stack4 = display.createStack(WINDOWING_MODE_FULLSCREEN,
+                ACTIVITY_TYPE_STANDARD, ON_TOP);
+        final TaskRecord task1 = new TaskBuilder(mService.mStackSupervisor).setStack(
+                stack1).setTaskId(1).build();
+        final TaskRecord task2 = new TaskBuilder(mService.mStackSupervisor).setStack(
+                stack2).setTaskId(2).build();
+        final TaskRecord task3 = new TaskBuilder(mService.mStackSupervisor).setStack(
+                stack3).setTaskId(3).build();
+        final TaskRecord task4 = new TaskBuilder(mService.mStackSupervisor).setStack(
+                stack4).setTaskId(4).build();
+
+        // Reordering stacks while removing stacks.
+        doAnswer(invocation -> {
+            display.positionChildAtTop(stack3, false);
+            return true;
+        }).when(mSupervisor).removeTaskByIdLocked(eq(task4.taskId), anyBoolean(), anyBoolean(),
+                any());
+
+        // Removing stacks from the display while removing stacks.
+        doAnswer(invocation -> {
+            display.removeChild(stack2);
+            return true;
+        }).when(mSupervisor).removeTaskByIdLocked(eq(task2.taskId), anyBoolean(), anyBoolean(),
+                any());
+
+        runnable.run();
+        verify(mSupervisor).removeTaskByIdLocked(eq(task4.taskId), anyBoolean(), anyBoolean(),
+                any());
+        verify(mSupervisor).removeTaskByIdLocked(eq(task3.taskId), anyBoolean(), anyBoolean(),
+                any());
+        verify(mSupervisor).removeTaskByIdLocked(eq(task2.taskId), anyBoolean(), anyBoolean(),
+                any());
+        verify(mSupervisor).removeTaskByIdLocked(eq(task1.taskId), anyBoolean(), anyBoolean(),
+                any());
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index cac9cf6..ee22861 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -70,8 +70,6 @@
 
     @Before
     public void setUpAMLO() throws Exception {
-        setupActivityTaskManagerService();
-
         mLaunchObserver = mock(ActivityMetricsLaunchObserver.class);
 
         // ActivityStackSupervisor always creates its own instance of ActivityMetricsLogger.
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index fcb5893..8be63fc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -72,7 +72,6 @@
 
     @Before
     public void setUp() throws Exception {
-        setupActivityTaskManagerService();
         mStack = (TestActivityStack) new StackBuilder(mRootActivityContainer).build();
         mTask = mStack.getChildAt(0);
         mActivity = mTask.getTopActivity();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
index f7b5d26..59e71c4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
@@ -64,7 +64,6 @@
 
     @Before
     public void setUp() throws Exception {
-        setupActivityTaskManagerService();
         mFullscreenStack = mRootActivityContainer.getDefaultDisplay().createStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index fda23e9..35c1ede 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -75,7 +75,6 @@
 
     @Before
     public void setUp() throws Exception {
-        setupActivityTaskManagerService();
         mDefaultDisplay = mRootActivityContainer.getDefaultDisplay();
         mStack = spy(mDefaultDisplay.createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD,
                 true /* onTop */));
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java
index 2ba2fdb..96db38b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java
@@ -56,7 +56,6 @@
 
     @Before
     public void setUp() throws Exception {
-        mService = createActivityTaskManagerService();
         mFactory = mock(Factory.class);
         mController = new ActivityStartController(mService, mService.mStackSupervisor, mFactory);
         mStarter = spy(new ActivityStarter(mController, mService,
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 898d107..a381023 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -117,7 +117,6 @@
 
     @Before
     public void setUp() throws Exception {
-        setupActivityTaskManagerService();
         mController = mock(ActivityStartController.class);
         mActivityMetricsLogger = mock(ActivityMetricsLogger.class);
         clearInvocations(mActivityMetricsLogger);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index d462e69..68df87e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -111,6 +111,10 @@
     @Before
     public void setUpBase() {
         mTestInjector.setUp();
+
+        mService = new TestActivityTaskManagerService(mContext);
+        mSupervisor = mService.mStackSupervisor;
+        mRootActivityContainer = mService.mRootActivityContainer;
     }
 
     @After
@@ -122,17 +126,6 @@
         }
     }
 
-    ActivityTaskManagerService createActivityTaskManagerService() {
-        mService = new TestActivityTaskManagerService(mContext);
-        mSupervisor = mService.mStackSupervisor;
-        mRootActivityContainer = mService.mRootActivityContainer;
-        return mService;
-    }
-
-    void setupActivityTaskManagerService() {
-        createActivityTaskManagerService();
-    }
-
     /** Creates a {@link TestActivityDisplay}. */
     TestActivityDisplay createNewActivityDisplay() {
         return TestActivityDisplay.create(mSupervisor, sNextDisplayId++);
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index 0c6e632..123de2d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -60,7 +60,7 @@
 
     @BeforeClass
     public static void setUpRootWindowContainerMock() {
-        final WindowManagerService wm = WmServiceUtils.getWindowManagerService();
+        final WindowManagerService wm = TestSystemServices.getWindowManagerService();
         // For unit test, we don't need to test performSurfacePlacement to prevent some abnormal
         // interaction with surfaceflinger native side.
         sOriginalRootWindowContainer = wm.mRoot;
@@ -74,7 +74,7 @@
 
     @AfterClass
     public static void tearDownRootWindowContainerMock() {
-        final WindowManagerService wm = WmServiceUtils.getWindowManagerService();
+        final WindowManagerService wm = TestSystemServices.getWindowManagerService();
         wm.mRoot = sOriginalRootWindowContainer;
         sOriginalRootWindowContainer = null;
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
index 8c3dec7..b28ae40 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
@@ -71,7 +71,6 @@
 
     @Before
     public void setUp() throws Exception {
-        mService = createActivityTaskManagerService();
         mPersister = new TestLaunchParamsPersister();
         mController = new LaunchParamsController(mService, mPersister);
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
index 8635364..aeda473 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
@@ -102,8 +102,6 @@
         mFolder = new File(cacheFolder, "launch_params_tests");
         deleteRecursively(mFolder);
 
-        setupActivityTaskManagerService();
-
         mDisplayUniqueId = "test:" + Integer.toString(sNextUniqueId++);
         final DisplayInfo info = new DisplayInfo();
         info.uniqueId = mDisplayUniqueId;
diff --git a/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java
index efd7d25..beaac8e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java
@@ -52,7 +52,6 @@
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mService = createActivityTaskManagerService();
         mService.mH.runWithScissors(() -> {
             mHandler = new TestHandler(null, mClock);
         }, 0);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index a3f535a..e3bacf9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -82,7 +82,6 @@
 
     @Before
     public void setUp() throws Exception {
-        setupActivityTaskManagerService();
         mFullscreenStack = mRootActivityContainer.getDefaultDisplay().createStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
index a8b6dc3..dc96480 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
@@ -49,7 +49,6 @@
 
     @Before
     public void setUp() throws Exception {
-        setupActivityTaskManagerService();
         mRunningTasks = new RunningTasks();
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index 53e99fa..ace179a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -75,10 +75,6 @@
 
     @Before
     public void setUp() throws Exception {
-        setupActivityTaskManagerService();
-        mService.mSupportsFreeformWindowManagement = true;
-        when(mSupervisor.canUseActivityOptionsLaunchBounds(any())).thenCallRealMethod();
-
         mActivity = new ActivityBuilder(mService).build();
         mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1;
         mActivity.info.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index 99be50b..e182c45 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -90,7 +90,6 @@
     @Before
     public void setUp() throws Exception {
         TaskRecord.setTaskRecordFactory(null);
-        setupActivityTaskManagerService();
         mParentBounds = new Rect(10 /*left*/, 30 /*top*/, 80 /*right*/, 60 /*bottom*/);
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WmServiceUtils.java b/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java
similarity index 97%
rename from services/tests/wmtests/src/com/android/server/wm/WmServiceUtils.java
rename to services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java
index 05ac8c1..b151fb7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WmServiceUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java
@@ -66,7 +66,7 @@
 /**
  * A Test utility class to create a mock {@link WindowManagerService} instance for tests.
  */
-class WmServiceUtils {
+class TestSystemServices {
     private static StaticMockitoSession sMockitoSession;
     private static WindowManagerService sService;
     private static TestWindowManagerPolicy sPolicy;
@@ -78,7 +78,7 @@
                 .strictness(Strictness.LENIENT)
                 .startMocking();
 
-        runWithDexmakerShareClassLoader(WmServiceUtils::setUpTestWindowService);
+        runWithDexmakerShareClassLoader(TestSystemServices::setUpTestWindowService);
     }
 
     static void tearDownWindowManagerService() {
@@ -147,7 +147,7 @@
         final WindowManagerGlobalLock wmLock = new WindowManagerGlobalLock();
         doReturn(wmLock).when(atms).getGlobalLock();
 
-        sPolicy = new TestWindowManagerPolicy(WmServiceUtils::getWindowManagerService);
+        sPolicy = new TestWindowManagerPolicy(TestSystemServices::getWindowManagerService);
         sService = WindowManagerService.main(context, ims, false, false, sPolicy, atms);
 
         sService.onInitReady();
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 89c1551..e38118e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -101,14 +101,14 @@
     public static void setUpOnceBase() {
         AttributeCache.init(getInstrumentation().getTargetContext());
 
-        WmServiceUtils.setUpWindowManagerService();
+        TestSystemServices.setUpWindowManagerService();
 
         sPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class);
     }
 
     @AfterClass
     public static void tearDonwOnceBase() {
-        WmServiceUtils.tearDownWindowManagerService();
+        TestSystemServices.tearDownWindowManagerService();
     }
 
     @Before
@@ -120,7 +120,7 @@
 
             final Context context = getInstrumentation().getTargetContext();
 
-            mWm = WmServiceUtils.getWindowManagerService();
+            mWm = TestSystemServices.getWindowManagerService();
             beforeCreateDisplay();
 
             context.getDisplay().getDisplayInfo(mDisplayInfo);
@@ -198,7 +198,7 @@
             }
 
             // Cleaned up everything in Handler.
-            WmServiceUtils.cleanupWindowManagerHandlers();
+            TestSystemServices.cleanupWindowManagerHandlers();
         } catch (Exception e) {
             Log.e(TAG, "Failed to tear down test", e);
             throw e;
@@ -219,7 +219,7 @@
      * Waits until the main handler for WM has processed all messages.
      */
     void waitUntilHandlersIdle() {
-        WmServiceUtils.waitUntilWindowManagerHandlersIdle();
+        TestSystemServices.waitUntilWindowManagerHandlersIdle();
     }
 
     private WindowToken createWindowToken(
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index 3408291..17516bc2 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -66,7 +66,8 @@
     public static final int EVENT_DATA_CONNECTION_DETACHED = BASE + 9;
     public static final int EVENT_ROAMING_ON = BASE + 11;
     public static final int EVENT_ROAMING_OFF = BASE + 12;
-    public static final int EVENT_ENABLE_NEW_APN = BASE + 13;
+    public static final int EVENT_ENABLE_APN = BASE + 13;
+    public static final int EVENT_DISABLE_APN = BASE + 14;
     public static final int EVENT_DISCONNECT_DONE = BASE + 15;
     public static final int EVENT_DATA_CONNECTION_ATTACHED = BASE + 16;
     public static final int EVENT_DATA_STALL_ALARM = BASE + 17;
diff --git a/tests/net/java/android/net/shared/LinkPropertiesParcelableUtilTest.java b/tests/net/java/android/net/shared/LinkPropertiesParcelableUtilTest.java
new file mode 100644
index 0000000..4cabfc9
--- /dev/null
+++ b/tests/net/java/android/net/shared/LinkPropertiesParcelableUtilTest.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2019 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.net.shared;
+
+import static android.net.shared.LinkPropertiesParcelableUtil.fromStableParcelable;
+import static android.net.shared.LinkPropertiesParcelableUtil.toStableParcelable;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.InetAddresses;
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.ProxyInfo;
+import android.net.RouteInfo;
+import android.net.Uri;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.Collections;
+
+/**
+ * Tests for {@link LinkPropertiesParcelableUtil}
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class LinkPropertiesParcelableUtilTest {
+    private LinkProperties mLinkProperties;
+
+    private static final String TEST_LINKPROPS_IFACE = "TEST_IFACE";
+    private static final String TEST_STACKED_LINK_1_IFACE = "TEST_STACKED_IFACE_1";
+    private static final String TEST_STACKED_LINK_2_IFACE = "TEST_STACKED_IFACE_2";
+
+    @Before
+    public void setUp() {
+        mLinkProperties = makeLinkProperties(TEST_LINKPROPS_IFACE);
+        mLinkProperties.addStackedLink(makeLinkProperties(TEST_STACKED_LINK_1_IFACE));
+        mLinkProperties.addStackedLink(makeLinkProperties(TEST_STACKED_LINK_2_IFACE));
+    }
+
+    private static LinkProperties makeLinkProperties(String iface) {
+        final LinkProperties lp = new LinkProperties();
+        lp.setInterfaceName(iface);
+        lp.setLinkAddresses(Arrays.asList(
+                new LinkAddress(InetAddresses.parseNumericAddress("192.168.0.42"), 16),
+                new LinkAddress(InetAddresses.parseNumericAddress("2001:db8::7"), 42)));
+        lp.setDnsServers(Arrays.asList(
+                InetAddresses.parseNumericAddress("2001:db8::42"),
+                InetAddresses.parseNumericAddress("192.168.1.1")
+        ));
+        lp.setValidatedPrivateDnsServers(Arrays.asList(
+                InetAddresses.parseNumericAddress("2001:db8::43"),
+                InetAddresses.parseNumericAddress("192.168.42.43")
+        ));
+        lp.setPcscfServers(Arrays.asList(
+                InetAddresses.parseNumericAddress("2001:db8::47"),
+                InetAddresses.parseNumericAddress("192.168.42.47")
+        ));
+        lp.setUsePrivateDns(true);
+        lp.setPrivateDnsServerName("test.example.com");
+        lp.setDomains("test1.example.com,test2.example.com");
+        lp.addRoute(new RouteInfo(
+                new IpPrefix(InetAddresses.parseNumericAddress("2001:db8::44"), 45),
+                InetAddresses.parseNumericAddress("2001:db8::45"),
+                iface,
+                RouteInfo.RTN_UNICAST
+        ));
+        lp.addRoute(new RouteInfo(
+                new IpPrefix(InetAddresses.parseNumericAddress("192.168.44.45"), 16),
+                InetAddresses.parseNumericAddress("192.168.45.1"),
+                iface,
+                RouteInfo.RTN_THROW
+        ));
+        lp.setHttpProxy(new ProxyInfo("test3.example.com", 8000,
+                "excl1.example.com,excl2.example.com"));
+        lp.setMtu(5000);
+        lp.setTcpBufferSizes("1,2,3,4,5,6");
+        lp.setNat64Prefix(new IpPrefix(InetAddresses.parseNumericAddress("2001:db8::48"), 96));
+
+        // Verify that this test does not miss any new field added later.
+        // If any added field is not included in LinkProperties#equals, assertLinkPropertiesEquals
+        // must also be updated.
+        assertEquals(14, Arrays.stream(LinkProperties.class.getDeclaredFields())
+                .filter(f -> !Modifier.isStatic(f.getModifiers())).count());
+
+        return lp;
+    }
+
+    @Test
+    public void testParcelUnparcel() {
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_NullInterface() {
+        mLinkProperties.setInterfaceName(null);
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_NullPrivateDnsServer() {
+        mLinkProperties.setPrivateDnsServerName(null);
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_NullDomains() {
+        mLinkProperties.setDomains(null);
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_NullProxy() {
+        mLinkProperties.setHttpProxy(null);
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_NullTcpBufferSizes() {
+        mLinkProperties.setTcpBufferSizes(null);
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_EmptyLinkAddresses() {
+        mLinkProperties.setLinkAddresses(Collections.emptyList());
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_EmptyDnses() {
+        mLinkProperties.setDnsServers(Collections.emptyList());
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_EmptyValidatedPrivateDnses() {
+        mLinkProperties.setValidatedPrivateDnsServers(Collections.emptyList());
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_EmptyRoutes() {
+        for (RouteInfo r : mLinkProperties.getAllRoutes()) {
+            mLinkProperties.removeRoute(r);
+        }
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_PacFileProxyInfo() {
+        mLinkProperties.setHttpProxy(new ProxyInfo(Uri.parse("http://pacfile.example.com")));
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_NullNat64Prefix() {
+        mLinkProperties.setNat64Prefix(null);
+        doParcelUnparcelTest();
+    }
+
+    private void doParcelUnparcelTest() {
+        final LinkProperties unparceled = fromStableParcelable(toStableParcelable(mLinkProperties));
+        assertLinkPropertiesEquals(mLinkProperties, unparceled);
+    }
+
+    private static void assertLinkPropertiesEquals(LinkProperties expected, LinkProperties actual) {
+        assertEquals(expected, actual);
+
+        // LinkProperties equals() does not include stacked links
+        assertEquals(expected.getStackedLinks(), actual.getStackedLinks());
+    }
+}