Merge "Add log when acquiring and releasing wakelock."
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 4d1ac0e..9abb308 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -8,6 +8,7 @@
                cmds/input/
                core/jni/
                libs/input/
+               services/core/jni/
 
 [Hook Scripts]
 checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java
index 20661c6..eb414b0 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java
@@ -27,6 +27,11 @@
 
     public static final int CURRENT_XML_VERSION = 1;
 
+    private static final String ROOT_DIR_NAME = "blobstore";
+    private static final String BLOBS_DIR_NAME = "blobs";
+    private static final String SESSIONS_INDEX_FILE_NAME = "sessions_index.xml";
+    private static final String BLOBS_INDEX_FILE_NAME = "blobs_index.xml";
+
     @Nullable
     public static File prepareBlobFile(long sessionId) {
         final File blobsDir = prepareBlobsDir();
@@ -60,7 +65,7 @@
 
     @NonNull
     private static File getBlobsDir(File blobsRootDir) {
-        return new File(blobsRootDir, "blobs");
+        return new File(blobsRootDir, BLOBS_DIR_NAME);
     }
 
     @Nullable
@@ -69,7 +74,7 @@
         if (blobStoreRootDir == null) {
             return null;
         }
-        return new File(blobStoreRootDir, "sessions_index.xml");
+        return new File(blobStoreRootDir, SESSIONS_INDEX_FILE_NAME);
     }
 
     @Nullable
@@ -78,7 +83,7 @@
         if (blobsStoreRootDir == null) {
             return null;
         }
-        return new File(blobsStoreRootDir, "blobs_index.xml");
+        return new File(blobsStoreRootDir, BLOBS_INDEX_FILE_NAME);
     }
 
     @Nullable
@@ -93,6 +98,6 @@
 
     @NonNull
     public static File getBlobStoreRootDir() {
-        return new File(Environment.getDataSystemDirectory(), "blobstore");
+        return new File(Environment.getDataSystemDirectory(), ROOT_DIR_NAME);
     }
 }
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
index a0e83da..bb94275 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
@@ -144,14 +144,18 @@
     public void startTrackingRestrictedJobLocked(JobStatus jobStatus) {
         // Don't need to start tracking the job. If the job needed network, it would already be
         // tracked.
-        updateConstraintsSatisfied(jobStatus);
+        if (jobStatus.hasConnectivityConstraint()) {
+            updateConstraintsSatisfied(jobStatus);
+        }
     }
 
     @Override
     public void stopTrackingRestrictedJobLocked(JobStatus jobStatus) {
         // Shouldn't stop tracking the job here. If the job was tracked, it still needs network,
         // even after being unrestricted.
-        updateConstraintsSatisfied(jobStatus);
+        if (jobStatus.hasConnectivityConstraint()) {
+            updateConstraintsSatisfied(jobStatus);
+        }
     }
 
     /**
diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java
index ac66d1b..d59270c 100644
--- a/apex/media/framework/java/android/media/MediaParser.java
+++ b/apex/media/framework/java/android/media/MediaParser.java
@@ -223,7 +223,7 @@
     public static final class SeekPoint {
 
         /** A {@link SeekPoint} whose time and byte offset are both set to 0. */
-        public static final @NonNull SeekPoint START = new SeekPoint(0, 0);
+        @NonNull public static final SeekPoint START = new SeekPoint(0, 0);
 
         /** The time of the seek point, in microseconds. */
         public final long timeUs;
@@ -241,7 +241,8 @@
         }
 
         @Override
-        public @NonNull String toString() {
+        @NonNull
+        public String toString() {
             return "[timeUs=" + timeUs + ", position=" + position + "]";
         }
 
@@ -414,7 +415,8 @@
      * @return A new instance.
      * @throws IllegalArgumentException If an invalid name is provided.
      */
-    public static @NonNull MediaParser createByName(
+    @NonNull
+    public static MediaParser createByName(
             @NonNull String name, @NonNull OutputConsumer outputConsumer) {
         String[] nameAsArray = new String[] {name};
         assertValidNames(nameAsArray);
@@ -431,7 +433,8 @@
      *     default array of names is used.
      * @return A new instance.
      */
-    public static @NonNull MediaParser create(
+    @NonNull
+    public static MediaParser create(
             @NonNull OutputConsumer outputConsumer, @NonNull String... extractorNames) {
         assertValidNames(extractorNames);
         if (extractorNames.length == 0) {
@@ -448,7 +451,8 @@
      *
      * <p>TODO: List which properties are taken into account. E.g. MimeType.
      */
-    public static @NonNull List<String> getExtractorNames(@NonNull MediaFormat mediaFormat) {
+    @NonNull
+    public static List<String> getExtractorNames(@NonNull MediaFormat mediaFormat) {
         throw new UnsupportedOperationException();
     }
 
@@ -479,7 +483,8 @@
      * @return The name of the backing extractor implementation, or null if the backing extractor
      *     implementation has not yet been selected.
      */
-    public @Nullable String getExtractorName() {
+    @Nullable
+    public String getExtractorName() {
         return mExtractorName;
     }
 
diff --git a/apex/sdkextensions/framework/Android.bp b/apex/sdkextensions/framework/Android.bp
index dd17473..245a96b 100644
--- a/apex/sdkextensions/framework/Android.bp
+++ b/apex/sdkextensions/framework/Android.bp
@@ -32,6 +32,7 @@
     libs: [ "framework-annotations-lib" ],
     permitted_packages: [ "android.os.ext" ],
     installable: true,
+    plugins: ["java_api_finder"],
     visibility: [
         "//frameworks/base/apex/sdkextensions",
         "//frameworks/base/apex/sdkextensions/testing",
diff --git a/api/current.txt b/api/current.txt
index 2e99edd..e614f17 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2873,6 +2873,8 @@
     method public final boolean performGlobalAction(int);
     method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo);
     method public boolean takeScreenshot(int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.graphics.Bitmap>);
+    field public static final int GESTURE_DOUBLE_TAP = 17; // 0x11
+    field public static final int GESTURE_DOUBLE_TAP_AND_HOLD = 18; // 0x12
     field public static final int GESTURE_SWIPE_DOWN = 2; // 0x2
     field public static final int GESTURE_SWIPE_DOWN_AND_LEFT = 15; // 0xf
     field public static final int GESTURE_SWIPE_DOWN_AND_RIGHT = 16; // 0x10
@@ -2986,9 +2988,11 @@
     field @Deprecated public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
     field public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 32; // 0x20
     field public static final int FLAG_REQUEST_FINGERPRINT_GESTURES = 512; // 0x200
+    field public static final int FLAG_REQUEST_MULTI_FINGER_GESTURES = 4096; // 0x1000
     field public static final int FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK = 1024; // 0x400
     field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4
     field public static final int FLAG_RETRIEVE_INTERACTIVE_WINDOWS = 64; // 0x40
+    field public static final int FLAG_SERVICE_HANDLES_DOUBLE_TAP = 2048; // 0x800
     field public int eventTypes;
     field public int feedbackType;
     field public int flags;
@@ -10169,6 +10173,7 @@
     field public static final String STORAGE_STATS_SERVICE = "storagestats";
     field public static final String SYSTEM_HEALTH_SERVICE = "systemhealth";
     field public static final String TELECOM_SERVICE = "telecom";
+    field public static final String TELEPHONY_IMS_SERVICE = "telephony_ims";
     field public static final String TELEPHONY_SERVICE = "phone";
     field public static final String TELEPHONY_SUBSCRIPTION_SERVICE = "telephony_subscription_service";
     field public static final String TEXT_CLASSIFICATION_SERVICE = "textclassification";
@@ -12012,6 +12017,7 @@
     field public static final String FEATURE_CAMERA_CAPABILITY_MANUAL_POST_PROCESSING = "android.hardware.camera.capability.manual_post_processing";
     field public static final String FEATURE_CAMERA_CAPABILITY_MANUAL_SENSOR = "android.hardware.camera.capability.manual_sensor";
     field public static final String FEATURE_CAMERA_CAPABILITY_RAW = "android.hardware.camera.capability.raw";
+    field public static final String FEATURE_CAMERA_CONCURRENT = "android.hardware.camera.concurrent";
     field public static final String FEATURE_CAMERA_EXTERNAL = "android.hardware.camera.external";
     field public static final String FEATURE_CAMERA_FLASH = "android.hardware.camera.flash";
     field public static final String FEATURE_CAMERA_FRONT = "android.hardware.camera.front";
@@ -12069,6 +12075,7 @@
     field public static final String FEATURE_SENSOR_GYROSCOPE = "android.hardware.sensor.gyroscope";
     field public static final String FEATURE_SENSOR_HEART_RATE = "android.hardware.sensor.heartrate";
     field public static final String FEATURE_SENSOR_HEART_RATE_ECG = "android.hardware.sensor.heartrate.ecg";
+    field public static final String FEATURE_SENSOR_HINGE_ANGLE = "android.hardware.sensor.hinge_angle";
     field public static final String FEATURE_SENSOR_LIGHT = "android.hardware.sensor.light";
     field public static final String FEATURE_SENSOR_PROXIMITY = "android.hardware.sensor.proximity";
     field public static final String FEATURE_SENSOR_RELATIVE_HUMIDITY = "android.hardware.sensor.relative_humidity";
@@ -17168,6 +17175,7 @@
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Float> SCALER_AVAILABLE_MAX_DIGITAL_ZOOM;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> SCALER_AVAILABLE_ROTATE_AND_CROP_MODES;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SCALER_CROPPING_TYPE;
+    field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_CONCURRENT_STREAM_COMBINATIONS;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_STREAM_COMBINATIONS;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.StreamConfigurationMap> SCALER_STREAM_CONFIGURATION_MAP;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> SENSOR_AVAILABLE_TEST_PATTERN_MODES;
@@ -17257,6 +17265,8 @@
   public final class CameraManager {
     method @NonNull public android.hardware.camera2.CameraCharacteristics getCameraCharacteristics(@NonNull String) throws android.hardware.camera2.CameraAccessException;
     method @NonNull public String[] getCameraIdList() throws android.hardware.camera2.CameraAccessException;
+    method @NonNull public java.util.Set<java.util.Set<java.lang.String>> getConcurrentStreamingCameraIds() throws android.hardware.camera2.CameraAccessException;
+    method @RequiresPermission(android.Manifest.permission.CAMERA) public boolean isConcurrentSessionConfigurationSupported(@NonNull java.util.Map<java.lang.String,android.hardware.camera2.params.SessionConfiguration>) throws android.hardware.camera2.CameraAccessException;
     method @RequiresPermission(android.Manifest.permission.CAMERA) public void openCamera(@NonNull String, @NonNull android.hardware.camera2.CameraDevice.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     method @RequiresPermission(android.Manifest.permission.CAMERA) public void openCamera(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraDevice.StateCallback) throws android.hardware.camera2.CameraAccessException;
     method public void registerAvailabilityCallback(@NonNull android.hardware.camera2.CameraManager.AvailabilityCallback, @Nullable android.os.Handler);
@@ -45207,6 +45217,7 @@
     method public void registerCallback(android.telecom.Call.Callback);
     method public void registerCallback(android.telecom.Call.Callback, android.os.Handler);
     method public void reject(boolean, String);
+    method public void reject(int);
     method public void removeExtras(java.util.List<java.lang.String>);
     method public void removeExtras(java.lang.String...);
     method public void respondToRttRequest(int, boolean);
@@ -45222,6 +45233,8 @@
     field public static final String EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS = "android.telecom.extra.LAST_EMERGENCY_CALLBACK_TIME_MILLIS";
     field public static final String EXTRA_SILENT_RINGING_REQUESTED = "android.telecom.extra.SILENT_RINGING_REQUESTED";
     field public static final String EXTRA_SUGGESTED_PHONE_ACCOUNTS = "android.telecom.extra.SUGGESTED_PHONE_ACCOUNTS";
+    field public static final int REJECT_REASON_DECLINED = 1; // 0x1
+    field public static final int REJECT_REASON_UNWANTED = 2; // 0x2
     field public static final int STATE_ACTIVE = 4; // 0x4
     field public static final int STATE_AUDIO_PROCESSING = 12; // 0xc
     field public static final int STATE_CONNECTING = 9; // 0x9
@@ -45489,6 +45502,7 @@
     method public void onPostDialContinue(boolean);
     method public void onPullExternalCall();
     method public void onReject();
+    method public void onReject(int);
     method public void onReject(String);
     method public void onSeparate();
     method public void onShowIncomingCallUi();
@@ -48248,13 +48262,20 @@
 
   public final class ImsException extends java.lang.Exception {
     method public int getCode();
+    field public static final int CODE_ERROR_INVALID_SUBSCRIPTION = 3; // 0x3
     field public static final int CODE_ERROR_SERVICE_UNAVAILABLE = 1; // 0x1
     field public static final int CODE_ERROR_UNSPECIFIED = 0; // 0x0
     field public static final int CODE_ERROR_UNSUPPORTED_OPERATION = 2; // 0x2
   }
 
+  public class ImsManager {
+    method @NonNull public android.telephony.ims.ImsMmTelManager getImsMmTelManager(int);
+    field public static final String ACTION_WFC_IMS_REGISTRATION_ERROR = "android.telephony.ims.action.WFC_IMS_REGISTRATION_ERROR";
+    field public static final String EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_MESSAGE";
+    field public static final String EXTRA_WFC_REGISTRATION_FAILURE_TITLE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_TITLE";
+  }
+
   public class ImsMmTelManager implements android.telephony.ims.RegistrationManager {
-    method @NonNull @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int);
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public int getVoWiFiModeSetting();
diff --git a/api/system-current.txt b/api/system-current.txt
index b8df8f2..095f343 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1780,6 +1780,7 @@
     field public static final String BUGREPORT_SERVICE = "bugreport";
     field public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions";
     field public static final String CONTEXTHUB_SERVICE = "contexthub";
+    field public static final String ETHERNET_SERVICE = "ethernet";
     field public static final String EUICC_CARD_SERVICE = "euicc_card";
     field public static final String HDMI_CONTROL_SERVICE = "hdmi_control";
     field public static final String NETD_SERVICE = "netd";
@@ -1795,7 +1796,6 @@
     field public static final String STATUS_BAR_SERVICE = "statusbar";
     field public static final String SYSTEM_CONFIG_SERVICE = "system_config";
     field public static final String SYSTEM_UPDATE_SERVICE = "system_update";
-    field public static final String TELEPHONY_IMS_SERVICE = "telephony_ims";
     field public static final String TELEPHONY_REGISTRY_SERVICE = "telephony_registry";
     field public static final String TETHERING_SERVICE = "tethering";
     field public static final String VR_SERVICE = "vrmanager";
@@ -2519,7 +2519,7 @@
     method @Nullable public android.hardware.display.BrightnessCorrection getCorrectionByPackageName(@NonNull String);
     method public android.util.Pair<float[],float[]> getCurve();
     method public float getShortTermModelLowerLuxMultiplier();
-    method public long getShortTermModelTimeout();
+    method public long getShortTermModelTimeoutMillis();
     method public float getShortTermModelUpperLuxMultiplier();
     method public boolean shouldCollectColorSamples();
     method public void writeToParcel(android.os.Parcel, int);
@@ -2536,7 +2536,7 @@
     method public int getMaxCorrectionsByPackageName();
     method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setDescription(@Nullable String);
     method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelLowerLuxMultiplier(@FloatRange(from=0.0f) float);
-    method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelTimeout(long);
+    method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelTimeoutMillis(long);
     method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelUpperLuxMultiplier(@FloatRange(from=0.0f) float);
     method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShouldCollectColorSamples(boolean);
   }
@@ -6078,6 +6078,19 @@
     method @Deprecated public void onUpstreamChanged(@Nullable android.net.Network);
   }
 
+  public class EthernetManager {
+    method @NonNull public android.net.EthernetManager.TetheredInterfaceRequest requestTetheredInterface(@NonNull android.net.EthernetManager.TetheredInterfaceCallback);
+  }
+
+  public static interface EthernetManager.TetheredInterfaceCallback {
+    method public void onAvailable(@NonNull String);
+    method public void onUnavailable();
+  }
+
+  public static class EthernetManager.TetheredInterfaceRequest {
+    method public void release();
+  }
+
   public class InvalidPacketException extends java.lang.Exception {
     ctor public InvalidPacketException(int);
     field public static final int ERROR_INVALID_IP_ADDRESS = -21; // 0xffffffeb
@@ -6507,6 +6520,7 @@
     field public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
     field public static final String EXTRA_ERRORED_TETHER = "erroredArray";
     field public static final int TETHERING_BLUETOOTH = 2; // 0x2
+    field public static final int TETHERING_ETHERNET = 5; // 0x5
     field public static final int TETHERING_INVALID = -1; // 0xffffffff
     field public static final int TETHERING_NCM = 4; // 0x4
     field public static final int TETHERING_USB = 1; // 0x1
@@ -7557,12 +7571,12 @@
   }
 
   public class WifiInfo implements android.os.Parcelable {
-    method @Nullable public String getAppPackageName();
-    method public double getRxSuccessRate();
+    method public double getLostTxPacketsPerSecond();
+    method @Nullable public String getRequestingPackageName();
+    method public double getRetriedTxPacketsPerSecond();
     method public int getScore();
-    method public double getTxBadRate();
-    method public double getTxRetriesRate();
-    method public double getTxSuccessRate();
+    method public double getSuccessfulRxPacketsPerSecond();
+    method public double getSuccessfulTxPacketsPerSecond();
     method public boolean isEphemeral();
     method public boolean isOsuAp();
     method public boolean isPasspointAp();
@@ -7590,7 +7604,6 @@
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void connect(int, @Nullable android.net.wifi.WifiManager.ActionListener);
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void disable(int, @Nullable android.net.wifi.WifiManager.ActionListener);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK}) public void disableEphemeralNetwork(@NonNull String);
-    method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void enableVerboseLogging(int);
     method @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) public void factoryReset();
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void forget(int, @Nullable android.net.wifi.WifiManager.ActionListener);
     method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.util.Pair<android.net.wifi.WifiConfiguration,java.util.Map<java.lang.Integer,java.util.List<android.net.wifi.ScanResult>>>> getAllMatchingWifiConfigs(@NonNull java.util.List<android.net.wifi.ScanResult>);
@@ -7602,7 +7615,6 @@
     method @NonNull @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE}) public java.util.Map<android.net.wifi.WifiNetworkSuggestion,java.util.List<android.net.wifi.ScanResult>> getMatchingScanResults(@NonNull java.util.List<android.net.wifi.WifiNetworkSuggestion>, @Nullable java.util.List<android.net.wifi.ScanResult>);
     method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE, android.Manifest.permission.READ_WIFI_CREDENTIAL}) public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks();
     method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public android.net.wifi.SoftApConfiguration getSoftApConfiguration();
-    method public int getVerboseLoggingLevel();
     method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public void getWifiActivityEnergyInfoAsync(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiActivityEnergyInfoListener);
     method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public android.net.wifi.WifiConfiguration getWifiApConfiguration();
     method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public int getWifiApState();
@@ -7612,6 +7624,7 @@
     method @Deprecated public boolean isDeviceToDeviceRttSupported();
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public boolean isDualModeSupported();
     method public boolean isPortableHotspotSupported();
+    method public boolean isVerboseLoggingEnabled();
     method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean isWifiApEnabled();
     method public boolean isWifiScannerSupported();
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerNetworkRequestMatchCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.NetworkRequestMatchCallback);
@@ -7628,6 +7641,7 @@
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setMacRandomizationSettingPasspointEnabled(@NonNull String, boolean);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setMeteredOverridePasspoint(@NonNull String, int);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public boolean setSoftApConfiguration(@NonNull android.net.wifi.SoftApConfiguration);
+    method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setVerboseLoggingEnabled(boolean);
     method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
     method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public boolean setWifiConnectedNetworkScorer(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.WifiConnectedNetworkScorer);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsConfiguratorInitiator(@NonNull String, int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
@@ -8592,9 +8606,6 @@
     field public static final int STATUS_SUCCESS = 0; // 0x0
   }
 
-  @IntDef(prefix={"STATUS_"}, value={android.os.HwParcel.STATUS_SUCCESS}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface HwParcel.Status {
-  }
-
   public interface IHwBinder {
     method public boolean linkToDeath(android.os.IHwBinder.DeathRecipient, long);
     method public android.os.IHwInterface queryLocalInterface(String);
@@ -9031,23 +9042,15 @@
   }
 
   public final class WifiActivityEnergyInfo implements android.os.Parcelable {
-    ctor public WifiActivityEnergyInfo(long, int, long, long, long, long);
+    ctor public WifiActivityEnergyInfo(long, int, @IntRange(from=0) long, @IntRange(from=0) long, @IntRange(from=0) long, @IntRange(from=0) long);
     method public int describeContents();
-    method public long getControllerEnergyUsedMicroJoules();
-    method public long getControllerIdleDurationMillis();
-    method public long getControllerRxDurationMillis();
-    method public long getControllerScanDurationMillis();
-    method public long getControllerTxDurationMillis();
+    method @IntRange(from=0) public long getControllerEnergyUsedMicroJoules();
+    method @IntRange(from=0) public long getControllerIdleDurationMillis();
+    method @IntRange(from=0) public long getControllerRxDurationMillis();
+    method @IntRange(from=0) public long getControllerScanDurationMillis();
+    method @IntRange(from=0) public long getControllerTxDurationMillis();
     method public int getStackState();
     method public long getTimeSinceBootMillis();
-    method public boolean isValid();
-    method public void setControllerEnergyUsedMicroJoules(long);
-    method public void setControllerIdleDurationMillis(long);
-    method public void setControllerRxDurationMillis(long);
-    method public void setControllerScanDurationMillis(long);
-    method public void setControllerTxDurationMillis(long);
-    method public void setStackState(int);
-    method public void setTimeSinceBootMillis(long);
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.os.connectivity.WifiActivityEnergyInfo> CREATOR;
     field public static final int STACK_STATE_INVALID = 0; // 0x0
@@ -9665,6 +9668,7 @@
 
   public static final class Telephony.Carriers implements android.provider.BaseColumns {
     field public static final String APN_SET_ID = "apn_set_id";
+    field @Deprecated public static final String BEARER_BITMASK = "bearer_bitmask";
     field public static final int CARRIER_EDITED = 4; // 0x4
     field @NonNull public static final android.net.Uri DPC_URI;
     field public static final String EDITED_STATUS = "edited";
@@ -9673,6 +9677,11 @@
     field public static final String MODEM_PERSIST = "modem_cognitive";
     field public static final String MTU = "mtu";
     field public static final int NO_APN_SET_ID = 0; // 0x0
+    field public static final String PROFILE_ID = "profile_id";
+    field public static final String SKIP_464XLAT = "skip_464xlat";
+    field public static final int SKIP_464XLAT_DEFAULT = -1; // 0xffffffff
+    field public static final int SKIP_464XLAT_DISABLE = 0; // 0x0
+    field public static final int SKIP_464XLAT_ENABLE = 1; // 0x1
     field public static final String TIME_LIMIT_FOR_MAX_CONNECTIONS = "max_conns_time";
     field public static final int UNEDITED = 0; // 0x0
     field public static final int USER_DELETED = 2; // 0x2
@@ -11027,6 +11036,27 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CallAttributes> CREATOR;
   }
 
+  public final class CallForwardingInfo implements android.os.Parcelable {
+    ctor public CallForwardingInfo(int, int, @Nullable String, int);
+    method public int describeContents();
+    method @Nullable public String getNumber();
+    method public int getReason();
+    method public int getStatus();
+    method public int getTimeoutSeconds();
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CallForwardingInfo> CREATOR;
+    field public static final int REASON_ALL = 4; // 0x4
+    field public static final int REASON_ALL_CONDITIONAL = 5; // 0x5
+    field public static final int REASON_BUSY = 1; // 0x1
+    field public static final int REASON_NOT_REACHABLE = 3; // 0x3
+    field public static final int REASON_NO_REPLY = 2; // 0x2
+    field public static final int REASON_UNCONDITIONAL = 0; // 0x0
+    field public static final int STATUS_ACTIVE = 1; // 0x1
+    field public static final int STATUS_FDN_CHECK_FAILURE = 2; // 0x2
+    field public static final int STATUS_INACTIVE = 0; // 0x0
+    field public static final int STATUS_NOT_SUPPORTED = 4; // 0x4
+    field public static final int STATUS_UNKNOWN_ERROR = 3; // 0x3
+  }
+
   public final class CallQuality implements android.os.Parcelable {
     ctor public CallQuality(int, int, int, int, int, int, int, int, int, int, int);
     ctor public CallQuality(int, int, int, int, int, int, int, int, int, int, int, boolean, boolean, boolean);
@@ -11137,7 +11167,7 @@
   }
 
   public class CellBroadcastIntents {
-    method public static void sendOrderedBroadcastForBackgroundReceivers(@NonNull android.content.Context, @Nullable android.os.UserHandle, @NonNull android.content.Intent, @Nullable String, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
+    method public static void sendSmsCbReceivedBroadcast(@NonNull android.content.Context, @Nullable android.os.UserHandle, @NonNull android.telephony.SmsCbMessage, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, int);
   }
 
   public abstract class CellBroadcastService extends android.app.Service {
@@ -12157,6 +12187,8 @@
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getAidForAppType(int);
     method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getAllowedNetworkTypes();
+    method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CallForwardingInfo getCallForwarding(int);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCallWaitingStatus();
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int);
     method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
     method public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int);
@@ -12247,6 +12279,8 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setAllowedNetworkTypes(long);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setAlwaysAllowMmsData(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAlwaysReportSignalStrength(boolean);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setCallForwarding(@NonNull android.telephony.CallForwardingInfo);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setCallWaitingStatus(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCarrierDataEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setCarrierRestrictionRules(@NonNull android.telephony.CarrierRestrictionRules);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setCdmaRoamingMode(int);
@@ -12297,6 +12331,10 @@
     field public static final String ACTION_SIM_APPLICATION_STATE_CHANGED = "android.telephony.action.SIM_APPLICATION_STATE_CHANGED";
     field public static final String ACTION_SIM_CARD_STATE_CHANGED = "android.telephony.action.SIM_CARD_STATE_CHANGED";
     field public static final String ACTION_SIM_SLOT_STATUS_CHANGED = "android.telephony.action.SIM_SLOT_STATUS_CHANGED";
+    field public static final int CALL_WAITING_STATUS_ACTIVE = 1; // 0x1
+    field public static final int CALL_WAITING_STATUS_INACTIVE = 2; // 0x2
+    field public static final int CALL_WAITING_STATUS_NOT_SUPPORTED = 4; // 0x4
+    field public static final int CALL_WAITING_STATUS_UNKNOWN_ERROR = 3; // 0x3
     field public static final int CARD_POWER_DOWN = 0; // 0x0
     field public static final int CARD_POWER_UP = 1; // 0x1
     field public static final int CARD_POWER_UP_PASS_THROUGH = 2; // 0x2
@@ -13001,21 +13039,18 @@
   }
 
   public class ImsManager {
-    method @NonNull public android.telephony.ims.ImsMmTelManager getImsMmTelManager(int);
     method @NonNull public android.telephony.ims.ImsRcsManager getImsRcsManager(int);
     field public static final String ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION = "com.android.internal.intent.action.ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION";
-    field public static final String ACTION_WFC_IMS_REGISTRATION_ERROR = "android.telephony.ims.action.WFC_IMS_REGISTRATION_ERROR";
-    field public static final String EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_MESSAGE";
-    field public static final String EXTRA_WFC_REGISTRATION_FAILURE_TITLE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_TITLE";
   }
 
   public class ImsMmTelManager implements android.telephony.ims.RegistrationManager {
+    method @Deprecated @NonNull @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws android.telephony.ims.ImsException;
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoWiFiRoamingModeSetting();
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAvailable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isCapable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void isSupported(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>) throws android.telephony.ims.ImsException;
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAvailable(int, int);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isCapable(int, int);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void isSupported(int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>) throws android.telephony.ims.ImsException;
     method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback) throws android.telephony.ims.ImsException;
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAdvancedCallingSettingEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setRttCapabilitySetting(boolean);
@@ -13279,13 +13314,13 @@
   public class ProvisioningManager {
     method @NonNull public static android.telephony.ims.ProvisioningManager createForSubscriptionId(int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public int getProvisioningIntValue(int);
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean getProvisioningStatusForCapability(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean getProvisioningStatusForCapability(int, int);
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public String getProvisioningStringValue(int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean getRcsProvisioningStatusForCapability(int);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyRcsAutoConfigurationReceived(@NonNull byte[], boolean);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerProvisioningChangedCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.Callback) throws android.telephony.ims.ImsException;
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningIntValue(int, int);
-    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setProvisioningStatusForCapability(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int, boolean);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setProvisioningStatusForCapability(int, int, boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningStringValue(int, @NonNull String);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setRcsProvisioningStatusForCapability(int, boolean);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.Callback);
@@ -13377,8 +13412,8 @@
     method public int describeContents();
     method @NonNull public java.util.List<java.lang.String> getCapableExtensionTags();
     method @NonNull public android.net.Uri getContactUri();
-    method @Nullable public android.net.Uri getServiceUri(int);
-    method public boolean isCapable(int);
+    method @Nullable public android.net.Uri getServiceUri(long);
+    method public boolean isCapable(long);
     method public boolean isCapable(@NonNull String);
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field public static final int CAPABILITY_CALL_COMPOSER = 4194304; // 0x400000
@@ -13400,6 +13435,7 @@
     field public static final int CAPABILITY_IMAGE_SHARE = 256; // 0x100
     field public static final int CAPABILITY_IP_VIDEO_CALL = 16384; // 0x4000
     field public static final int CAPABILITY_IP_VOICE_CALL = 8192; // 0x2000
+    field public static final int CAPABILITY_MMTEL_CALL_COMPOSER = 1073741824; // 0x40000000
     field public static final int CAPABILITY_PLUG_IN = 268435456; // 0x10000000
     field public static final int CAPABILITY_POST_CALL = 8388608; // 0x800000
     field public static final int CAPABILITY_RCS_VIDEO_CALL = 1048576; // 0x100000
@@ -13408,6 +13444,7 @@
     field public static final int CAPABILITY_SHARED_MAP = 16777216; // 0x1000000
     field public static final int CAPABILITY_SHARED_SKETCH = 33554432; // 0x2000000
     field public static final int CAPABILITY_SOCIAL_PRESENCE = 2048; // 0x800
+    field public static final int CAPABILITY_STANDALONE_CHAT_BOT = 536870912; // 0x20000000
     field public static final int CAPABILITY_VIDEO_SHARE = 1024; // 0x400
     field public static final int CAPABILITY_VIDEO_SHARE_DURING_CS_CALL = 512; // 0x200
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RcsContactUceCapability> CREATOR;
@@ -13415,14 +13452,16 @@
 
   public static class RcsContactUceCapability.Builder {
     ctor public RcsContactUceCapability.Builder(@NonNull android.net.Uri);
-    method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(int, @NonNull android.net.Uri);
-    method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(int);
+    method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(long, @NonNull android.net.Uri);
+    method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(long);
     method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(@NonNull String);
     method @NonNull public android.telephony.ims.RcsContactUceCapability build();
   }
 
   public class RcsUceAdapter {
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getUcePublishState() throws android.telephony.ims.ImsException;
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isUceSettingEnabled() throws android.telephony.ims.ImsException;
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void requestCapabilities(@NonNull java.util.concurrent.Executor, @NonNull java.util.List<android.net.Uri>, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException;
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUceSettingEnabled(boolean) throws android.telephony.ims.ImsException;
     field public static final int ERROR_ALREADY_IN_QUEUE = 13; // 0xd
     field public static final int ERROR_FORBIDDEN = 6; // 0x6
@@ -13444,13 +13483,19 @@
     field public static final int PUBLISH_STATE_VOLTE_PROVISION_ERROR = 3; // 0x3
   }
 
+  public static class RcsUceAdapter.CapabilitiesCallback {
+    ctor public RcsUceAdapter.CapabilitiesCallback();
+    method public void onCapabilitiesReceived(@NonNull java.util.List<android.telephony.ims.RcsContactUceCapability>);
+    method public void onError(int);
+  }
+
 }
 
 package android.telephony.ims.feature {
 
   public final class CapabilityChangeRequest implements android.os.Parcelable {
-    method public void addCapabilitiesToDisableForTech(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
-    method public void addCapabilitiesToEnableForTech(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
+    method public void addCapabilitiesToDisableForTech(int, int);
+    method public void addCapabilitiesToEnableForTech(int, int);
     method public int describeContents();
     method public java.util.List<android.telephony.ims.feature.CapabilityChangeRequest.CapabilityPair> getCapabilitiesToDisable();
     method public java.util.List<android.telephony.ims.feature.CapabilityChangeRequest.CapabilityPair> getCapabilitiesToEnable();
@@ -13459,8 +13504,8 @@
   }
 
   public static class CapabilityChangeRequest.CapabilityPair {
-    ctor public CapabilityChangeRequest.CapabilityPair(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
-    method @android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability public int getCapability();
+    ctor public CapabilityChangeRequest.CapabilityPair(int, int);
+    method public int getCapability();
     method public int getRadioTech();
   }
 
@@ -13505,10 +13550,10 @@
     method public final void notifyVoiceMessageCountUpdate(int);
     method public void onFeatureReady();
     method public void onFeatureRemoved();
-    method public boolean queryCapabilityConfiguration(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
+    method public boolean queryCapabilityConfiguration(int, int);
     method @NonNull public final android.telephony.ims.feature.MmTelFeature.MmTelCapabilities queryCapabilityStatus();
     method public void setUiTtyMode(int, @Nullable android.os.Message);
-    method @android.telephony.ims.feature.MmTelFeature.ProcessCallResult public int shouldProcessCall(@NonNull String[]);
+    method public int shouldProcessCall(@NonNull String[]);
     field public static final String EXTRA_IS_UNKNOWN_CALL = "android.telephony.ims.feature.extra.IS_UNKNOWN_CALL";
     field public static final String EXTRA_IS_USSD = "android.telephony.ims.feature.extra.IS_USSD";
     field public static final int PROCESS_CALL_CSFB = 1; // 0x1
@@ -13518,21 +13563,17 @@
   public static class MmTelFeature.MmTelCapabilities extends android.telephony.ims.feature.ImsFeature.Capabilities {
     ctor public MmTelFeature.MmTelCapabilities();
     ctor @Deprecated public MmTelFeature.MmTelCapabilities(android.telephony.ims.feature.ImsFeature.Capabilities);
-    ctor public MmTelFeature.MmTelCapabilities(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int);
-    method public final void addCapabilities(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int);
-    method public final boolean isCapable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int);
-    method public final void removeCapabilities(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int);
-  }
-
-  @IntDef(flag=true, value={android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO, android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT, android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_SMS}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface MmTelFeature.MmTelCapabilities.MmTelCapability {
-  }
-
-  @IntDef(flag=true, value={android.telephony.ims.feature.MmTelFeature.PROCESS_CALL_IMS, android.telephony.ims.feature.MmTelFeature.PROCESS_CALL_CSFB}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface MmTelFeature.ProcessCallResult {
+    ctor public MmTelFeature.MmTelCapabilities(int);
+    method public final void addCapabilities(int);
+    method public final boolean isCapable(int);
+    method public final void removeCapabilities(int);
   }
 
   public class RcsFeature extends android.telephony.ims.feature.ImsFeature {
     ctor public RcsFeature();
     method public void changeEnabledCapabilities(@NonNull android.telephony.ims.feature.CapabilityChangeRequest, @NonNull android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy);
+    method @NonNull public android.telephony.ims.stub.RcsSipOptionsImplBase getOptionsExchangeImpl();
+    method @NonNull public android.telephony.ims.stub.RcsPresenceExchangeImplBase getPresenceExchangeImpl();
     method public final void notifyCapabilitiesStatusChanged(@NonNull android.telephony.ims.feature.RcsFeature.RcsImsCapabilities);
     method public void onFeatureReady();
     method public void onFeatureRemoved();
@@ -13725,6 +13766,71 @@
     field public static final int INVALID_RESULT = -1; // 0xffffffff
   }
 
+  public class RcsCapabilityExchange {
+    ctor public RcsCapabilityExchange();
+    method public final void onCommandUpdate(int, int) throws android.telephony.ims.ImsException;
+    field public static final int COMMAND_CODE_FETCH_ERROR = 4; // 0x4
+    field public static final int COMMAND_CODE_GENERIC_FAILURE = 2; // 0x2
+    field public static final int COMMAND_CODE_INSUFFICIENT_MEMORY = 6; // 0x6
+    field public static final int COMMAND_CODE_INVALID_PARAM = 3; // 0x3
+    field public static final int COMMAND_CODE_LOST_NETWORK_CONNECTION = 7; // 0x7
+    field public static final int COMMAND_CODE_NOT_FOUND = 9; // 0x9
+    field public static final int COMMAND_CODE_NOT_SUPPORTED = 8; // 0x8
+    field public static final int COMMAND_CODE_NO_CHANGE_IN_CAP = 11; // 0xb
+    field public static final int COMMAND_CODE_REQUEST_TIMEOUT = 5; // 0x5
+    field public static final int COMMAND_CODE_SERVICE_UNAVAILABLE = 10; // 0xa
+    field public static final int COMMAND_CODE_SERVICE_UNKNOWN = 0; // 0x0
+    field public static final int COMMAND_CODE_SUCCESS = 1; // 0x1
+  }
+
+  public class RcsPresenceExchangeImplBase extends android.telephony.ims.stub.RcsCapabilityExchange {
+    ctor public RcsPresenceExchangeImplBase();
+    method public final void onCapabilityRequestResponse(@NonNull java.util.List<android.telephony.ims.RcsContactUceCapability>, int) throws android.telephony.ims.ImsException;
+    method public final void onNetworkResponse(int, @NonNull String, int) throws android.telephony.ims.ImsException;
+    method public final void onNotifyUpdateCapabilites(int) throws android.telephony.ims.ImsException;
+    method public final void onUnpublish() throws android.telephony.ims.ImsException;
+    method public void requestCapabilities(@NonNull java.util.List<android.net.Uri>, int);
+    method public void updateCapabilities(@NonNull android.telephony.ims.RcsContactUceCapability, int);
+    field public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 0; // 0x0
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G = 6; // 0x6
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G = 5; // 0x5
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD = 3; // 0x3
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_HSPAPLUS = 4; // 0x4
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_IWLAN = 8; // 0x8
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED = 1; // 0x1
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED = 2; // 0x2
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_DISABLED = 10; // 0xa
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED = 11; // 0xb
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN = 7; // 0x7
+    field public static final int CAPABILITY_UPDATE_TRIGGER_UNKNOWN = 9; // 0x9
+    field public static final int RESPONSE_FORBIDDEN = 3; // 0x3
+    field public static final int RESPONSE_NOT_AUTHORIZED_FOR_PRESENCE = 2; // 0x2
+    field public static final int RESPONSE_NOT_FOUND = 4; // 0x4
+    field public static final int RESPONSE_NOT_REGISTERED = 1; // 0x1
+    field public static final int RESPONSE_SIP_INTERVAL_TOO_SHORT = 7; // 0x7
+    field public static final int RESPONSE_SIP_REQUEST_TIMEOUT = 5; // 0x5
+    field public static final int RESPONSE_SIP_SERVICE_UNAVAILABLE = 8; // 0x8
+    field public static final int RESPONSE_SUBSCRIBE_GENERIC_FAILURE = -1; // 0xffffffff
+    field public static final int RESPONSE_SUBSCRIBE_TOO_LARGE = 6; // 0x6
+    field public static final int RESPONSE_SUCCESS = 0; // 0x0
+  }
+
+  public class RcsSipOptionsImplBase extends android.telephony.ims.stub.RcsCapabilityExchange {
+    ctor public RcsSipOptionsImplBase();
+    method public final void onCapabilityRequestResponse(int, @NonNull String, @Nullable android.telephony.ims.RcsContactUceCapability, int) throws android.telephony.ims.ImsException;
+    method public final void onRemoteCapabilityRequest(@NonNull android.net.Uri, @NonNull android.telephony.ims.RcsContactUceCapability, int) throws android.telephony.ims.ImsException;
+    method public void respondToCapabilityRequest(@NonNull String, @NonNull android.telephony.ims.RcsContactUceCapability, int);
+    method public void respondToCapabilityRequestWithError(@NonNull android.net.Uri, int, @NonNull String, int);
+    method public void sendCapabilityRequest(@NonNull android.net.Uri, @NonNull android.telephony.ims.RcsContactUceCapability, int);
+    field public static final int RESPONSE_BAD_REQUEST = 5; // 0x5
+    field public static final int RESPONSE_DOES_NOT_EXIST_ANYWHERE = 4; // 0x4
+    field public static final int RESPONSE_GENERIC_FAILURE = -1; // 0xffffffff
+    field public static final int RESPONSE_NOT_FOUND = 3; // 0x3
+    field public static final int RESPONSE_REQUEST_TIMEOUT = 2; // 0x2
+    field public static final int RESPONSE_SUCCESS = 0; // 0x0
+    field public static final int RESPONSE_TEMPORARILY_UNAVAILABLE = 1; // 0x1
+  }
+
 }
 
 package android.telephony.mbms {
diff --git a/api/test-current.txt b/api/test-current.txt
index e7a0cf6..d0ac723 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -771,12 +771,12 @@
     field public static final String BUGREPORT_SERVICE = "bugreport";
     field public static final String CONTENT_CAPTURE_MANAGER_SERVICE = "content_capture";
     field public static final String DEVICE_IDLE_CONTROLLER = "deviceidle";
+    field public static final String ETHERNET_SERVICE = "ethernet";
     field public static final String NETWORK_STACK_SERVICE = "network_stack";
     field public static final String PERMISSION_SERVICE = "permission";
     field public static final String POWER_WHITELIST_MANAGER = "power_whitelist";
     field public static final String ROLLBACK_SERVICE = "rollback";
     field public static final String STATUS_BAR_SERVICE = "statusbar";
-    field public static final String TELEPHONY_IMS_SERVICE = "telephony_ims";
     field public static final String TEST_NETWORK_SERVICE = "test_network";
   }
 
@@ -1091,7 +1091,7 @@
     method @Nullable public android.hardware.display.BrightnessCorrection getCorrectionByPackageName(@NonNull String);
     method public android.util.Pair<float[],float[]> getCurve();
     method public float getShortTermModelLowerLuxMultiplier();
-    method public long getShortTermModelTimeout();
+    method public long getShortTermModelTimeoutMillis();
     method public float getShortTermModelUpperLuxMultiplier();
     method public boolean shouldCollectColorSamples();
     method public void writeToParcel(android.os.Parcel, int);
@@ -1108,7 +1108,7 @@
     method public int getMaxCorrectionsByPackageName();
     method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setDescription(@Nullable String);
     method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelLowerLuxMultiplier(@FloatRange(from=0.0f) float);
-    method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelTimeout(long);
+    method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelTimeoutMillis(long);
     method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelUpperLuxMultiplier(@FloatRange(from=0.0f) float);
     method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShouldCollectColorSamples(boolean);
   }
@@ -1612,6 +1612,19 @@
     field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
   }
 
+  public class EthernetManager {
+    method @NonNull public android.net.EthernetManager.TetheredInterfaceRequest requestTetheredInterface(@NonNull android.net.EthernetManager.TetheredInterfaceCallback);
+  }
+
+  public static interface EthernetManager.TetheredInterfaceCallback {
+    method public void onAvailable(@NonNull String);
+    method public void onUnavailable();
+  }
+
+  public static class EthernetManager.TetheredInterfaceRequest {
+    method public void release();
+  }
+
   public final class IpPrefix implements android.os.Parcelable {
     ctor public IpPrefix(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
     ctor public IpPrefix(@NonNull String);
@@ -1760,6 +1773,7 @@
     field public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
     field public static final String EXTRA_ERRORED_TETHER = "erroredArray";
     field public static final int TETHERING_BLUETOOTH = 2; // 0x2
+    field public static final int TETHERING_ETHERNET = 5; // 0x5
     field public static final int TETHERING_INVALID = -1; // 0xffffffff
     field public static final int TETHERING_NCM = 4; // 0x4
     field public static final int TETHERING_USB = 1; // 0x1
@@ -2204,9 +2218,6 @@
     field public static final int STATUS_SUCCESS = 0; // 0x0
   }
 
-  @IntDef(prefix={"STATUS_"}, value={android.os.HwParcel.STATUS_SUCCESS}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface HwParcel.Status {
-  }
-
   public interface IHwBinder {
     method public boolean linkToDeath(android.os.IHwBinder.DeathRecipient, long);
     method public android.os.IHwInterface queryLocalInterface(String);
@@ -3793,21 +3804,18 @@
   }
 
   public class ImsManager {
-    method @NonNull public android.telephony.ims.ImsMmTelManager getImsMmTelManager(int);
     method @NonNull public android.telephony.ims.ImsRcsManager getImsRcsManager(int);
     field public static final String ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION = "com.android.internal.intent.action.ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION";
-    field public static final String ACTION_WFC_IMS_REGISTRATION_ERROR = "android.telephony.ims.action.WFC_IMS_REGISTRATION_ERROR";
-    field public static final String EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_MESSAGE";
-    field public static final String EXTRA_WFC_REGISTRATION_FAILURE_TITLE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_TITLE";
   }
 
   public class ImsMmTelManager implements android.telephony.ims.RegistrationManager {
+    method @Deprecated @NonNull @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int);
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws android.telephony.ims.ImsException;
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getVoWiFiRoamingModeSetting();
-    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isAvailable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
-    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isCapable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
-    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void isSupported(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>) throws android.telephony.ims.ImsException;
+    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isAvailable(int, int);
+    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isCapable(int, int);
+    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void isSupported(int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>) throws android.telephony.ims.ImsException;
     method @Deprecated @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback) throws android.telephony.ims.ImsException;
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAdvancedCallingSettingEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setRttCapabilitySetting(boolean);
@@ -4067,13 +4075,13 @@
   public class ProvisioningManager {
     method @NonNull public static android.telephony.ims.ProvisioningManager createForSubscriptionId(int);
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") @WorkerThread public int getProvisioningIntValue(int);
-    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") @WorkerThread public boolean getProvisioningStatusForCapability(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
+    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") @WorkerThread public boolean getProvisioningStatusForCapability(int, int);
     method @Nullable @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") @WorkerThread public String getProvisioningStringValue(int);
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") @WorkerThread public boolean getRcsProvisioningStatusForCapability(int);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyRcsAutoConfigurationReceived(@NonNull byte[], boolean);
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void registerProvisioningChangedCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.Callback) throws android.telephony.ims.ImsException;
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningIntValue(int, int);
-    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setProvisioningStatusForCapability(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int, boolean);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setProvisioningStatusForCapability(int, int, boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningStringValue(int, @NonNull String);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setRcsProvisioningStatusForCapability(int, boolean);
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void unregisterProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.Callback);
@@ -4161,8 +4169,60 @@
     method public void onProvisioningStringChanged(int, @NonNull String);
   }
 
+  public final class RcsContactUceCapability implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public java.util.List<java.lang.String> getCapableExtensionTags();
+    method @NonNull public android.net.Uri getContactUri();
+    method @Nullable public android.net.Uri getServiceUri(long);
+    method public boolean isCapable(long);
+    method public boolean isCapable(@NonNull String);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int CAPABILITY_CALL_COMPOSER = 4194304; // 0x400000
+    field public static final int CAPABILITY_CHAT_BOT = 67108864; // 0x4000000
+    field public static final int CAPABILITY_CHAT_BOT_ROLE = 134217728; // 0x8000000
+    field public static final int CAPABILITY_CHAT_SESSION = 2; // 0x2
+    field public static final int CAPABILITY_CHAT_SESSION_STORE_FORWARD = 4; // 0x4
+    field public static final int CAPABILITY_CHAT_STANDALONE = 1; // 0x1
+    field public static final int CAPABILITY_DISCOVERY_VIA_PRESENCE = 4096; // 0x1000
+    field public static final int CAPABILITY_FILE_TRANSFER = 8; // 0x8
+    field public static final int CAPABILITY_FILE_TRANSFER_HTTP = 64; // 0x40
+    field public static final int CAPABILITY_FILE_TRANSFER_SMS = 128; // 0x80
+    field public static final int CAPABILITY_FILE_TRANSFER_STORE_FORWARD = 32; // 0x20
+    field public static final int CAPABILITY_FILE_TRANSFER_THUMBNAIL = 16; // 0x10
+    field public static final int CAPABILITY_GEOLOCATION_PULL = 131072; // 0x20000
+    field public static final int CAPABILITY_GEOLOCATION_PULL_FILE_TRANSFER = 262144; // 0x40000
+    field public static final int CAPABILITY_GEOLOCATION_PUSH = 32768; // 0x8000
+    field public static final int CAPABILITY_GEOLOCATION_PUSH_SMS = 65536; // 0x10000
+    field public static final int CAPABILITY_IMAGE_SHARE = 256; // 0x100
+    field public static final int CAPABILITY_IP_VIDEO_CALL = 16384; // 0x4000
+    field public static final int CAPABILITY_IP_VOICE_CALL = 8192; // 0x2000
+    field public static final int CAPABILITY_MMTEL_CALL_COMPOSER = 1073741824; // 0x40000000
+    field public static final int CAPABILITY_PLUG_IN = 268435456; // 0x10000000
+    field public static final int CAPABILITY_POST_CALL = 8388608; // 0x800000
+    field public static final int CAPABILITY_RCS_VIDEO_CALL = 1048576; // 0x100000
+    field public static final int CAPABILITY_RCS_VIDEO_ONLY_CALL = 2097152; // 0x200000
+    field public static final int CAPABILITY_RCS_VOICE_CALL = 524288; // 0x80000
+    field public static final int CAPABILITY_SHARED_MAP = 16777216; // 0x1000000
+    field public static final int CAPABILITY_SHARED_SKETCH = 33554432; // 0x2000000
+    field public static final int CAPABILITY_SOCIAL_PRESENCE = 2048; // 0x800
+    field public static final int CAPABILITY_STANDALONE_CHAT_BOT = 536870912; // 0x20000000
+    field public static final int CAPABILITY_VIDEO_SHARE = 1024; // 0x400
+    field public static final int CAPABILITY_VIDEO_SHARE_DURING_CS_CALL = 512; // 0x200
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RcsContactUceCapability> CREATOR;
+  }
+
+  public static class RcsContactUceCapability.Builder {
+    ctor public RcsContactUceCapability.Builder(@NonNull android.net.Uri);
+    method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(long, @NonNull android.net.Uri);
+    method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(long);
+    method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(@NonNull String);
+    method @NonNull public android.telephony.ims.RcsContactUceCapability build();
+  }
+
   public class RcsUceAdapter {
+    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getUcePublishState() throws android.telephony.ims.ImsException;
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isUceSettingEnabled() throws android.telephony.ims.ImsException;
+    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void requestCapabilities(@NonNull java.util.concurrent.Executor, @NonNull java.util.List<android.net.Uri>, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException;
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUceSettingEnabled(boolean) throws android.telephony.ims.ImsException;
     field public static final int ERROR_ALREADY_IN_QUEUE = 13; // 0xd
     field public static final int ERROR_FORBIDDEN = 6; // 0x6
@@ -4184,13 +4244,19 @@
     field public static final int PUBLISH_STATE_VOLTE_PROVISION_ERROR = 3; // 0x3
   }
 
+  public static class RcsUceAdapter.CapabilitiesCallback {
+    ctor public RcsUceAdapter.CapabilitiesCallback();
+    method public void onCapabilitiesReceived(@NonNull java.util.List<android.telephony.ims.RcsContactUceCapability>);
+    method public void onError(int);
+  }
+
 }
 
 package android.telephony.ims.feature {
 
   public final class CapabilityChangeRequest implements android.os.Parcelable {
-    method public void addCapabilitiesToDisableForTech(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
-    method public void addCapabilitiesToEnableForTech(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
+    method public void addCapabilitiesToDisableForTech(int, int);
+    method public void addCapabilitiesToEnableForTech(int, int);
     method public int describeContents();
     method public java.util.List<android.telephony.ims.feature.CapabilityChangeRequest.CapabilityPair> getCapabilitiesToDisable();
     method public java.util.List<android.telephony.ims.feature.CapabilityChangeRequest.CapabilityPair> getCapabilitiesToEnable();
@@ -4199,8 +4265,8 @@
   }
 
   public static class CapabilityChangeRequest.CapabilityPair {
-    ctor public CapabilityChangeRequest.CapabilityPair(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
-    method @android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability public int getCapability();
+    ctor public CapabilityChangeRequest.CapabilityPair(int, int);
+    method public int getCapability();
     method public int getRadioTech();
   }
 
@@ -4245,10 +4311,10 @@
     method public final void notifyVoiceMessageCountUpdate(int);
     method public void onFeatureReady();
     method public void onFeatureRemoved();
-    method public boolean queryCapabilityConfiguration(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
+    method public boolean queryCapabilityConfiguration(int, int);
     method @NonNull public final android.telephony.ims.feature.MmTelFeature.MmTelCapabilities queryCapabilityStatus();
     method public void setUiTtyMode(int, @Nullable android.os.Message);
-    method @android.telephony.ims.feature.MmTelFeature.ProcessCallResult public int shouldProcessCall(@NonNull String[]);
+    method public int shouldProcessCall(@NonNull String[]);
     field public static final String EXTRA_IS_UNKNOWN_CALL = "android.telephony.ims.feature.extra.IS_UNKNOWN_CALL";
     field public static final String EXTRA_IS_USSD = "android.telephony.ims.feature.extra.IS_USSD";
     field public static final int PROCESS_CALL_CSFB = 1; // 0x1
@@ -4258,21 +4324,17 @@
   public static class MmTelFeature.MmTelCapabilities extends android.telephony.ims.feature.ImsFeature.Capabilities {
     ctor public MmTelFeature.MmTelCapabilities();
     ctor @Deprecated public MmTelFeature.MmTelCapabilities(android.telephony.ims.feature.ImsFeature.Capabilities);
-    ctor public MmTelFeature.MmTelCapabilities(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int);
-    method public final void addCapabilities(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int);
-    method public final boolean isCapable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int);
-    method public final void removeCapabilities(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int);
-  }
-
-  @IntDef(flag=true, value={android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO, android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT, android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_SMS}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface MmTelFeature.MmTelCapabilities.MmTelCapability {
-  }
-
-  @IntDef(flag=true, value={android.telephony.ims.feature.MmTelFeature.PROCESS_CALL_IMS, android.telephony.ims.feature.MmTelFeature.PROCESS_CALL_CSFB}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface MmTelFeature.ProcessCallResult {
+    ctor public MmTelFeature.MmTelCapabilities(int);
+    method public final void addCapabilities(int);
+    method public final boolean isCapable(int);
+    method public final void removeCapabilities(int);
   }
 
   public class RcsFeature extends android.telephony.ims.feature.ImsFeature {
     ctor public RcsFeature();
     method public void changeEnabledCapabilities(@NonNull android.telephony.ims.feature.CapabilityChangeRequest, @NonNull android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy);
+    method @NonNull public android.telephony.ims.stub.RcsSipOptionsImplBase getOptionsExchangeImpl();
+    method @NonNull public android.telephony.ims.stub.RcsPresenceExchangeImplBase getPresenceExchangeImpl();
     method public final void notifyCapabilitiesStatusChanged(@NonNull android.telephony.ims.feature.RcsFeature.RcsImsCapabilities);
     method public void onFeatureReady();
     method public void onFeatureRemoved();
@@ -4465,6 +4527,71 @@
     field public static final int INVALID_RESULT = -1; // 0xffffffff
   }
 
+  public class RcsCapabilityExchange {
+    ctor public RcsCapabilityExchange();
+    method public final void onCommandUpdate(int, int) throws android.telephony.ims.ImsException;
+    field public static final int COMMAND_CODE_FETCH_ERROR = 4; // 0x4
+    field public static final int COMMAND_CODE_GENERIC_FAILURE = 2; // 0x2
+    field public static final int COMMAND_CODE_INSUFFICIENT_MEMORY = 6; // 0x6
+    field public static final int COMMAND_CODE_INVALID_PARAM = 3; // 0x3
+    field public static final int COMMAND_CODE_LOST_NETWORK_CONNECTION = 7; // 0x7
+    field public static final int COMMAND_CODE_NOT_FOUND = 9; // 0x9
+    field public static final int COMMAND_CODE_NOT_SUPPORTED = 8; // 0x8
+    field public static final int COMMAND_CODE_NO_CHANGE_IN_CAP = 11; // 0xb
+    field public static final int COMMAND_CODE_REQUEST_TIMEOUT = 5; // 0x5
+    field public static final int COMMAND_CODE_SERVICE_UNAVAILABLE = 10; // 0xa
+    field public static final int COMMAND_CODE_SERVICE_UNKNOWN = 0; // 0x0
+    field public static final int COMMAND_CODE_SUCCESS = 1; // 0x1
+  }
+
+  public class RcsPresenceExchangeImplBase extends android.telephony.ims.stub.RcsCapabilityExchange {
+    ctor public RcsPresenceExchangeImplBase();
+    method public final void onCapabilityRequestResponse(@NonNull java.util.List<android.telephony.ims.RcsContactUceCapability>, int) throws android.telephony.ims.ImsException;
+    method public final void onNetworkResponse(int, @NonNull String, int) throws android.telephony.ims.ImsException;
+    method public final void onNotifyUpdateCapabilites(int) throws android.telephony.ims.ImsException;
+    method public final void onUnpublish() throws android.telephony.ims.ImsException;
+    method public void requestCapabilities(@NonNull java.util.List<android.net.Uri>, int);
+    method public void updateCapabilities(@NonNull android.telephony.ims.RcsContactUceCapability, int);
+    field public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 0; // 0x0
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G = 6; // 0x6
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G = 5; // 0x5
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD = 3; // 0x3
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_HSPAPLUS = 4; // 0x4
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_IWLAN = 8; // 0x8
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED = 1; // 0x1
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED = 2; // 0x2
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_DISABLED = 10; // 0xa
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED = 11; // 0xb
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN = 7; // 0x7
+    field public static final int CAPABILITY_UPDATE_TRIGGER_UNKNOWN = 9; // 0x9
+    field public static final int RESPONSE_FORBIDDEN = 3; // 0x3
+    field public static final int RESPONSE_NOT_AUTHORIZED_FOR_PRESENCE = 2; // 0x2
+    field public static final int RESPONSE_NOT_FOUND = 4; // 0x4
+    field public static final int RESPONSE_NOT_REGISTERED = 1; // 0x1
+    field public static final int RESPONSE_SIP_INTERVAL_TOO_SHORT = 7; // 0x7
+    field public static final int RESPONSE_SIP_REQUEST_TIMEOUT = 5; // 0x5
+    field public static final int RESPONSE_SIP_SERVICE_UNAVAILABLE = 8; // 0x8
+    field public static final int RESPONSE_SUBSCRIBE_GENERIC_FAILURE = -1; // 0xffffffff
+    field public static final int RESPONSE_SUBSCRIBE_TOO_LARGE = 6; // 0x6
+    field public static final int RESPONSE_SUCCESS = 0; // 0x0
+  }
+
+  public class RcsSipOptionsImplBase extends android.telephony.ims.stub.RcsCapabilityExchange {
+    ctor public RcsSipOptionsImplBase();
+    method public final void onCapabilityRequestResponse(int, @NonNull String, @Nullable android.telephony.ims.RcsContactUceCapability, int) throws android.telephony.ims.ImsException;
+    method public final void onRemoteCapabilityRequest(@NonNull android.net.Uri, @NonNull android.telephony.ims.RcsContactUceCapability, int) throws android.telephony.ims.ImsException;
+    method public void respondToCapabilityRequest(@NonNull String, @NonNull android.telephony.ims.RcsContactUceCapability, int);
+    method public void respondToCapabilityRequestWithError(@NonNull android.net.Uri, int, @NonNull String, int);
+    method public void sendCapabilityRequest(@NonNull android.net.Uri, @NonNull android.telephony.ims.RcsContactUceCapability, int);
+    field public static final int RESPONSE_BAD_REQUEST = 5; // 0x5
+    field public static final int RESPONSE_DOES_NOT_EXIST_ANYWHERE = 4; // 0x4
+    field public static final int RESPONSE_GENERIC_FAILURE = -1; // 0xffffffff
+    field public static final int RESPONSE_NOT_FOUND = 3; // 0x3
+    field public static final int RESPONSE_REQUEST_TIMEOUT = 2; // 0x2
+    field public static final int RESPONSE_SUCCESS = 0; // 0x0
+    field public static final int RESPONSE_TEMPORARILY_UNAVAILABLE = 1; // 0x1
+  }
+
 }
 
 package android.telephony.mbms {
diff --git a/api/test-lint-baseline.txt b/api/test-lint-baseline.txt
index a9c1836..94db346 100644
--- a/api/test-lint-baseline.txt
+++ b/api/test-lint-baseline.txt
@@ -2451,14 +2451,6 @@
     
 
 
-PublicTypedef: android.os.HwParcel.Status:
-    
-PublicTypedef: android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability:
-    
-PublicTypedef: android.telephony.ims.feature.MmTelFeature.ProcessCallResult:
-    
-
-
 RawAidl: android.telephony.mbms.vendor.MbmsDownloadServiceBase:
     
 RawAidl: android.telephony.mbms.vendor.MbmsStreamingServiceBase:
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index d9d5be6..7011724 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -137,7 +137,7 @@
         DaveyOccurred davey_occurred = 58 [(allow_from_any_uid) = true];
         OverlayStateChanged overlay_state_changed = 59;
         ForegroundServiceStateChanged foreground_service_state_changed = 60;
-        CallStateChanged call_state_changed = 61;
+        CallStateChanged call_state_changed = 61 [(module) = "telecom"];
         KeyguardStateChanged keyguard_state_changed = 62 [(module) = "sysui"];
         KeyguardBouncerStateChanged keyguard_bouncer_state_changed = 63 [(module) = "sysui"];
         KeyguardBouncerPasswordEntered keyguard_bouncer_password_entered = 64 [(module) = "sysui"];
@@ -288,8 +288,8 @@
         MediametricsNuPlayerReported mediametrics_nuplayer_reported = 199;
         MediametricsRecorderReported mediametrics_recorder_reported = 200;
         MediametricsDrmManagerReported mediametrics_drmmanager_reported = 201;
-        CarPowerStateChanged car_power_state_changed = 203;
-        GarageModeInfo garage_mode_info = 204;
+        CarPowerStateChanged car_power_state_changed = 203 [(module) = "car"];
+        GarageModeInfo garage_mode_info = 204 [(module) = "car"];
         TestAtomReported test_atom_reported = 205 [(module) = "cts"];
         ContentCaptureCallerMismatchReported content_capture_caller_mismatch_reported = 206;
         ContentCaptureServiceEvents content_capture_service_events = 207;
@@ -324,7 +324,8 @@
         AppCompatibilityChangeReported app_compatibility_change_reported =
             228 [(allow_from_any_uid) = true];
         PerfettoUploaded perfetto_uploaded = 229 [(module) = "perfetto"];
-        VmsClientConnectionStateChanged vms_client_connection_state_changed = 230;
+        VmsClientConnectionStateChanged vms_client_connection_state_changed =
+                230 [(module) = "car"];
         MediaProviderScanEvent media_provider_scan_event = 233 [(module) = "mediaprovider"];
         MediaProviderDeletionEvent media_provider_deletion_event = 234 [(module) = "mediaprovider"];
         MediaProviderPermissionEvent media_provider_permission_event =
@@ -343,6 +344,10 @@
         NotificationChannelModified notification_panel_modified = 246;
         IntegrityCheckResultReported integrity_check_result_reported = 247;
         IntegrityRulesPushed integrity_rules_pushed = 248;
+        CellBroadcastMessageReported cb_message_reported =
+            249 [(module) = "cellbroadcast"];
+        CellBroadcastMessageError cb_message_error =
+            250 [(module) = "cellbroadcast"];
     }
 
     // Pulled events will start at field 10000.
@@ -412,7 +417,7 @@
         SurfaceflingerStatsGlobalInfo surfaceflinger_stats_global_info = 10062;
         SurfaceflingerStatsLayerInfo surfaceflinger_stats_layer_info = 10063;
         ProcessMemorySnapshot process_memory_snapshot = 10064;
-        VmsClientStats vms_client_stats = 10065;
+        VmsClientStats vms_client_stats = 10065 [(module) = "car"];
         NotificationRemoteViews notification_remote_views = 10066;
         DangerousPermissionStateSampled dangerous_permission_state_sampled = 10067;
         GraphicsStats graphics_stats = 10068;
@@ -8112,3 +8117,55 @@
     // identify the rules.
     optional string rule_version = 3;
 }
+
+/**
+ * Logs when a cell broadcast message is received on the device.
+ *
+ * Logged from CellBroadcastService module:
+ *   packages/modules/CellBroadcastService/src/com/android/cellbroadcastservice/
+ */
+message CellBroadcastMessageReported {
+    // The type of Cell Broadcast message
+    enum CbType {
+        UNKNOWN_TYPE = 0;
+        GSM = 1;
+        CDMA = 2;
+        CDMA_SPC = 3;
+    }
+
+    // GSM, CDMA, CDMA-SCP
+    optional CbType type = 1;
+}
+
+/**
+ * Logs when an error occurs while handling a cell broadcast message;
+ *
+ * Logged from CellBroadcastService module:
+ *   packages/modules/CellBroadcastService/src/com/android/cellbroadcastservice/
+ */
+message CellBroadcastMessageError {
+    // The type of error raised when trying to handle a cell broadcast message
+    enum ErrorType {
+        UNKNOWN_TYPE = 0;
+        CDMA_DECODING_ERROR = 1;
+        CDMA_SCP_EMPTY = 2;
+        CDMA_SCP_HANDLING_ERROR = 3;
+        GSM_INVALID_HEADER_LENGTH = 4;
+        GSM_UNSUPPORTED_HEADER_MESSAGE_TYPE = 5;
+        GSM_UNSUPPORTED_HEADER_DATA_CODING_SCHEME = 6;
+        GSM_INVALID_PDU = 7;
+        GSM_INVALID_GEO_FENCING_DATA = 8;
+        GSM_UMTS_INVALID_WAC = 9;
+        FAILED_TO_INSERT_TO_DB = 10;
+        UNEXPECTED_GEOMETRY_FROM_FWK = 11;
+        UNEXPECTED_GSM_MESSAGE_TYPE_FROM_FWK = 12;
+        UNEXPECTED_CDMA_MESSAGE_TYPE_FROM_FWK = 13;
+        UNEXPECTED_CDMA_SCP_MESSAGE_TYPE_FROM_FWK = 14;
+    }
+
+    // What kind of error occurred
+    optional ErrorType type = 1;
+
+    // Exception message (or log message) associated with the error (max 1000 chars)
+    optional string exception_message = 2;
+}
diff --git a/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
index 1987440..9707405 100644
--- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java
+++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
@@ -366,12 +366,8 @@
     }
 
     private void runGetMaxPhones() throws RemoteException {
-        // This assumes the max number of SIMs is 2, which it currently is
-        if (TelephonyManager.MULTISIM_ALLOWED == mTelephonyManager.isMultiSimSupported()) {
-            System.out.println("2");
-        } else {
-            System.out.println("1");
-        }
+        // how many logical modems can be potentially active simultaneously
+        System.out.println(mTelephonyManager.getSupportedModemCount());
     }
 
     private void runSetEmergencyPhoneAccountPackageFilter() throws RemoteException {
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index ee6ccc2..7722dc3 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -310,13 +310,11 @@
 
     /**
      * The user has performed a double tap gesture on the touch screen.
-     * @hide
      */
     public static final int GESTURE_DOUBLE_TAP = 17;
 
     /**
      * The user has performed a double tap and hold gesture on the touch screen.
-     * @hide
      */
     public static final int GESTURE_DOUBLE_TAP_AND_HOLD = 18;
 
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 12f2c3b..82c7635 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -341,6 +341,26 @@
      */
     public static final int FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK = 0x00000400;
 
+    /**
+     * This flag requests that when {@link #FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is enabled,
+     * double tap and double tap and hold gestures are dispatched to the service rather than being
+     * handled by the framework. If {@link #FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is disabled this
+     * flag has no effect.
+     *
+     * @see #FLAG_REQUEST_TOUCH_EXPLORATION_MODE
+     */
+    public static final int FLAG_SERVICE_HANDLES_DOUBLE_TAP = 0x0000800;
+
+    /**
+     * This flag requests that when when {@link #FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is enabled,
+     * multi-finger gestures are also enabled. As a consequence, two-finger bypass gestures will be
+     * disabled. If {@link #FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is disabled this flag has no
+     * effect.
+     *
+     * @see #FLAG_REQUEST_TOUCH_EXPLORATION_MODE
+     */
+    public static final int FLAG_REQUEST_MULTI_FINGER_GESTURES = 0x0001000;
+
     /** {@hide} */
     public static final int FLAG_FORCE_DIRECT_BOOT_AWARE = 0x00010000;
 
@@ -1221,6 +1241,10 @@
                 return "FLAG_INCLUDE_NOT_IMPORTANT_VIEWS";
             case FLAG_REQUEST_TOUCH_EXPLORATION_MODE:
                 return "FLAG_REQUEST_TOUCH_EXPLORATION_MODE";
+            case FLAG_SERVICE_HANDLES_DOUBLE_TAP:
+                return "FLAG_SERVICE_HANDLES_DOUBLE_TAP";
+            case FLAG_REQUEST_MULTI_FINGER_GESTURES:
+                return "FLAG_REQUEST_MULTI_FINGER_GESTURES";
             case FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY:
                 return "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
             case FLAG_REPORT_VIEW_IDS:
diff --git a/core/java/android/annotation/SystemApi.java b/core/java/android/annotation/SystemApi.java
index 2cb93e4..1a8b78f 100644
--- a/core/java/android/annotation/SystemApi.java
+++ b/core/java/android/annotation/SystemApi.java
@@ -44,35 +44,43 @@
     enum Client {
         /**
          * Specifies that the intended clients of a SystemApi are privileged apps.
-         * This is the default value for {@link #client}. This implies
-         * MODULE_APPS and MODULE_LIBRARIES as well, which means that APIs will also
-         * be available to module apps and jars.
+         * This is the default value for {@link #client}.
+         * TODO Update the javadoc according to the final spec
          */
         PRIVILEGED_APPS,
 
         /**
-         * Specifies that the intended clients of a SystemApi are modules implemented
-         * as apps, like the NetworkStack app. This implies MODULE_LIBRARIES as well,
-         * which means that APIs will also be available to module jars.
+         * DO NOT USE. Use PRIVILEGED_APPS instead.
+         * (This would provide no further protection over PRIVILEGED_APPS; do not rely on it)
+         * @deprecated Use #PRIVILEGED_APPS instead
          */
+        @Deprecated
         MODULE_APPS,
 
         /**
          * Specifies that the intended clients of a SystemApi are modules implemented
          * as libraries, like the conscrypt.jar in the conscrypt APEX.
+         * TODO Update the javadoc according to the final spec
          */
-        MODULE_LIBRARIES
+        MODULE_LIBRARIES,
+
+        /**
+         * Specifies that the system API is available only in the system server process.
+         * Use this to expose APIs from code loaded by the system server process <em>but</em>
+         * not in <pre>BOOTCLASSPATH</pre>.
+         * TODO(b/148177503) Update "services-stubs" and actually use it.
+         */
+        SYSTEM_SERVER
     }
 
+    /** @deprecated do not use */
+    @Deprecated
     enum Process {
-        /**
-         * Specifies that the SystemAPI is available in every Java processes.
-         * This is the default value for {@link #process}.
-         */
+        /** @deprecated do not use */
         ALL,
 
         /**
-         * Specifies that the SystemAPI is available only in the system server process.
+         * @deprecated use Client#SYSTEM_SERVER instead
          */
         SYSTEM_SERVER
     }
@@ -83,7 +91,8 @@
     Client client() default android.annotation.SystemApi.Client.PRIVILEGED_APPS;
 
     /**
-     * The process(es) that this SystemAPI is available
+     * @deprecated use Client#SYSTEM_SERVER instead for system_server APIs
      */
+    @Deprecated
     Process process() default android.annotation.SystemApi.Process.ALL;
 }
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 5a4d620..c09aa1f 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -632,22 +632,22 @@
     private static final int SYS_FEATURE_CACHE_SIZE = 256;
     private static final String CACHE_KEY_SYS_FEATURE_PROPERTY = "cache_key.has_system_feature";
 
-    private class HasSystemFeatureQuery {
+    private class SystemFeatureQuery {
         public final String name;
         public final int version;
-        public HasSystemFeatureQuery(String n, int v) {
+        public SystemFeatureQuery(String n, int v) {
             name = n;
             version = v;
         }
         @Override
         public String toString() {
-            return String.format("HasSystemFeatureQuery(name=\"%s\", version=%d)",
+            return String.format("SystemFeatureQuery(name=\"%s\", version=%d)",
                     name, version);
         }
         @Override
         public boolean equals(Object o) {
-            if (o instanceof HasSystemFeatureQuery) {
-                HasSystemFeatureQuery r = (HasSystemFeatureQuery) o;
+            if (o instanceof SystemFeatureQuery) {
+                SystemFeatureQuery r = (SystemFeatureQuery) o;
                 return Objects.equals(name, r.name) &&  version == r.version;
             } else {
                 return false;
@@ -655,32 +655,32 @@
         }
         @Override
         public int hashCode() {
-            return Objects.hashCode(name) * 13 + version;
+            return Objects.hashCode(name) + version;
         }
     }
 
-    private final PropertyInvalidatedCache<HasSystemFeatureQuery, Boolean> mHasSystemFeatureCache =
-            new PropertyInvalidatedCache<>(
+    private final PropertyInvalidatedCache<SystemFeatureQuery, Boolean> mSysFeatureCache =
+            new PropertyInvalidatedCache<SystemFeatureQuery, Boolean>(
                 SYS_FEATURE_CACHE_SIZE,
                 CACHE_KEY_SYS_FEATURE_PROPERTY) {
                 @Override
-                protected Boolean recompute(HasSystemFeatureQuery query) {
+                protected Boolean recompute(SystemFeatureQuery query) {
                     return hasSystemFeatureUncached(query.name, query.version);
                 }
             };
 
     @Override
     public boolean hasSystemFeature(String name, int version) {
-        return mHasSystemFeatureCache.query(new HasSystemFeatureQuery(name, version));
+        return mSysFeatureCache.query(new SystemFeatureQuery(name, version)).booleanValue();
     }
 
     /** @hide */
-    public void disableHasSystemFeatureCache() {
-        mHasSystemFeatureCache.disableLocal();
+    public void disableSysFeatureCache() {
+        mSysFeatureCache.disableLocal();
     }
 
     /** @hide */
-    public static void invalidateHasSystemFeatureCache() {
+    public static void invalidateSysFeatureCache() {
         PropertyInvalidatedCache.invalidateCache(CACHE_KEY_SYS_FEATURE_PROPERTY);
     }
 
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index d665f33..4b1ba02 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -18,6 +18,7 @@
 package android.app;
 
 import android.app.ITransientNotification;
+import android.app.ITransientNotificationCallback;
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationChannelGroup;
@@ -45,8 +46,7 @@
     void cancelAllNotifications(String pkg, int userId);
 
     void clearData(String pkg, int uid, boolean fromApp);
-    // TODO: Replace parameter (ITransientNotification callback) with (CharSequence text)
-    void enqueueTextToast(String pkg, IBinder token, ITransientNotification callback, int duration, int displayId);
+    void enqueueTextToast(String pkg, IBinder token, CharSequence text, int duration, int displayId, @nullable ITransientNotificationCallback callback);
     void enqueueToast(String pkg, IBinder token, ITransientNotification callback, int duration, int displayId);
     void cancelToast(String pkg, IBinder token);
     void finishToken(String pkg, IBinder token);
diff --git a/core/java/android/app/ITransientNotificationCallback.aidl b/core/java/android/app/ITransientNotificationCallback.aidl
new file mode 100644
index 0000000..abe254f
--- /dev/null
+++ b/core/java/android/app/ITransientNotificationCallback.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+/**
+ * Callback object to be called when the associated toast is shown or hidden.
+ *
+ * @hide
+ */
+oneway interface ITransientNotificationCallback {
+    void onToastShown();
+    void onToastHidden();
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 58a0ea5..a0d5c10 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4139,16 +4139,16 @@
     public static final String LOWPAN_SERVICE = "lowpan";
 
     /**
-     * Use with {@link #getSystemService(String)} to retrieve a {@link
-     * android.net.EthernetManager} for handling management of
-     * Ethernet access.
+     * Use with {@link #getSystemService(String)} to retrieve a {@link android.net.EthernetManager}
+     * for handling management of Ethernet access.
      *
      * @see #getSystemService(String)
      * @see android.net.EthernetManager
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
+    @TestApi
     public static final String ETHERNET_SERVICE = "ethernet";
 
     /**
@@ -5032,10 +5032,7 @@
     /**
      * Use with {@link #getSystemService(String)} to retrieve an
      * {@link android.telephony.ims.ImsManager}.
-     * @hide
      */
-    @SystemApi
-    @TestApi
     public static final String TELEPHONY_IMS_SERVICE = "telephony_ims";
 
     /**
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 66a2b7a..b64c001 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1960,6 +1960,15 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device's main front and back cameras can stream
+     * concurrently as described in  {@link
+     * android.hardware.camera2.CameraManager#getConcurrentStreamingCameraIds()}
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_CAMERA_CONCURRENT = "android.hardware.camera.concurrent";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device is capable of communicating with
      * consumer IR devices.
      */
@@ -2326,6 +2335,13 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device includes a hinge angle sensor.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_SENSOR_HINGE_ANGLE = "android.hardware.sensor.hinge_angle";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device supports high fidelity sensor processing
      * capabilities.
      */
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index 008cfa5..f150664 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -362,6 +362,10 @@
             // Don't support switching to an ephemeral user with removal in progress.
             return false;
         }
+        if (preCreated) {
+            // Don't support switching to pre-created users until they become "real" users.
+            return false;
+        }
         return !isProfile();
     }
 
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index dfc4f0f..b3a1ee2 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -2875,7 +2875,28 @@
     @NonNull
     public static final Key<int[]> SCALER_AVAILABLE_ROTATE_AND_CROP_MODES =
             new Key<int[]>("android.scaler.availableRotateAndCropModes", int[].class);
-
+    /**
+     * <p>An array of mandatory concurrent stream combinations.
+     * This is an app-readable conversion of the concurrent mandatory stream combination
+     * {@link android.hardware.camera2.CameraDevice#createCaptureSession tables}.</p>
+     * <p>The array of
+     * {@link android.hardware.camera2.params.MandatoryStreamCombination combinations} is
+     * generated according to the documented
+     * {@link android.hardware.camera2.CameraDevice#createCaptureSession guideline} for each device
+     * which has its Id present in the set returned by
+     * {@link android.hardware.camera2.CameraManager#getConcurrentStreamingCameraIds}.
+     * Clients can use the array as a quick reference to find an appropriate camera stream
+     * combination.
+     * The mandatory stream combination array will be {@code null} in case the device is not a part
+     * of at least one set of combinations returned by
+     * {@link android.hardware.camera2.CameraManager#getConcurrentStreamingCameraIds}.</p>
+     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+     */
+    @PublicKey
+    @NonNull
+    @SyntheticKey
+    public static final Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_CONCURRENT_STREAM_COMBINATIONS =
+            new Key<android.hardware.camera2.params.MandatoryStreamCombination[]>("android.scaler.mandatoryConcurrentStreamCombinations", android.hardware.camera2.params.MandatoryStreamCombination[].class);
     /**
      * <p>The area of the image sensor which corresponds to active pixels after any geometric
      * distortion correction has been applied.</p>
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index cc06681..24d9311 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -680,6 +680,25 @@
      * </table><br>
      * </p>
      *
+     *<p>Devices capable of streaming concurrently with other devices as described by
+     * {@link android.hardware.camera2.CameraManager#getConcurrentStreamingCameraIds} have the
+     * following guaranteed streams (when streaming concurrently with other devices)</p>
+     *
+     * <table>
+     * <tr><th colspan="5">Concurrent stream guaranteed configurations</th></tr>
+     * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th rowspan="2">Sample use case(s)</th> </tr>
+     * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr>
+     * <tr> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td>  <td colspan="2" id="rb"></td> <td>In-app video / image processing.</td> </tr>
+     * <tr> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td>  <td colspan="2" id="rb"></td> <td>In-app viewfinder analysis.</td> </tr>
+     * <tr> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code YUV }</td><td id="rb">{@code MAXIMUM}</td> <td>In-app video / processing with preview.</td> </tr>
+     * <tr> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV }</td><td id="rb">{@code MAXIMUM}</td> <td>In-app video / processing with preview.</td> </tr>
+     * <tr> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV }</td><td id="rb">{@code MAXIMUM}</td> <td>Standard Recording.</td> </tr>
+     * </table><br>
+     * </p>
+     *
+     * <p> For guaranteed concurrent stream configurations, MAXIMUM refers to the camera device's
+     * resolution for that format from {@link StreamConfigurationMap#getOutputSizes} or
+     * 720p(1280X720) whichever is lower. </p>
      * <p>MONOCHROME-capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES}
      * includes {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME MONOCHROME}) devices
      * supporting {@link android.graphics.ImageFormat#Y8 Y8} support substituting {@code YUV}
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 55025f0..9ee56a9 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -31,6 +31,9 @@
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.legacy.CameraDeviceUserShim;
 import android.hardware.camera2.legacy.LegacyMetadataMapper;
+import android.hardware.camera2.params.SessionConfiguration;
+import android.hardware.camera2.utils.CameraIdAndSessionConfiguration;
+import android.hardware.camera2.utils.ConcurrentCameraIdCombination;
 import android.os.Binder;
 import android.os.DeadObjectException;
 import android.os.Handler;
@@ -40,6 +43,7 @@
 import android.os.ServiceSpecificException;
 import android.os.SystemProperties;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Log;
 import android.util.Size;
 import android.view.Display;
@@ -48,6 +52,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
@@ -126,6 +131,66 @@
     }
 
     /**
+     * Return the list of combinations of currently connected camera devices identifiers, which
+     * support configuring camera device sessions concurrently.
+     *
+     * <p>The set of combinations may include camera devices that may be in use by other camera API
+     * clients.</p>
+     *
+     * <p>The set of combinations doesn't contain physical cameras that can only be used as
+     * part of a logical multi-camera device.</p>
+     *
+     * @return The set of combinations of currently connected camera devices, that may have
+     *         sessions configured concurrently. The set of combinations will be empty if no such
+     *         combinations are supported by the camera subsystem.
+     *
+     * @throws CameraAccessException if the camera device has been disconnected.
+     */
+    @NonNull
+    public Set<Set<String>> getConcurrentStreamingCameraIds() throws CameraAccessException {
+        return CameraManagerGlobal.get().getConcurrentStreamingCameraIds();
+    }
+
+    /**
+     * Checks whether the provided set of camera devices and their corresponding
+     * {@link SessionConfiguration} can be configured concurrently.
+     *
+     * <p>This method performs a runtime check of the given {@link SessionConfiguration} and camera
+     * id combinations. The result confirms whether or not the passed session configurations can be
+     * successfully used to create camera capture sessions concurrently, on the given camera
+     * devices using {@link CameraDevice#createCaptureSession(SessionConfiguration)}.
+     * </p>
+     *
+     * <p>The method can be called at any point before, during and after active capture sessions.
+     * It will not impact normal camera behavior in any way and must complete significantly
+     * faster than creating a regular or constrained capture session.</p>
+     *
+     * <p>Although this method is faster than creating a new capture session, it is not intended
+     * to be used for exploring the entire space of supported concurrent stream combinations. The
+     * available mandatory concurrent stream combinations may be obtained by querying
+     * {@link #getCameraCharacteristics} for the key
+     * SCALER_MANDATORY_CONCURRENT_STREAM_COMBINATIONS. </p>
+     *
+     * <p>Note that session parameters will be ignored and calls to
+     * {@link SessionConfiguration#setSessionParameters} are not required.</p>
+     *
+     * @return {@code true} if the given combination of session configurations and corresponding
+     *                      camera ids are concurrently supported by the camera sub-system,
+     *         {@code false} otherwise.
+     *
+     * @throws IllegalArgumentException if the set of camera devices provided is not a subset of
+     *                                  those returned by getConcurrentStreamingCameraIds()
+     * @throws CameraAccessException if one of the camera devices queried is no longer connected.
+     */
+    @RequiresPermission(android.Manifest.permission.CAMERA)
+    public boolean isConcurrentSessionConfigurationSupported(
+            @NonNull Map<String, SessionConfiguration> cameraIdAndSessionConfig)
+            throws CameraAccessException {
+        return CameraManagerGlobal.get().isConcurrentSessionConfigurationSupported(
+                cameraIdAndSessionConfig);
+    }
+
+    /**
      * Register a callback to be notified about camera device availability.
      *
      * <p>Registering the same callback again will replace the handler with the
@@ -336,8 +401,10 @@
                     } catch (NumberFormatException e) {
                         Log.e(TAG, "Failed to parse camera Id " + cameraId + " to integer");
                     }
+                    boolean hasConcurrentStreams =
+                            CameraManagerGlobal.get().cameraIdHasConcurrentStreamsLocked(cameraId);
+                    info.setHasMandatoryConcurrentStreams(hasConcurrentStreams);
                     info.setDisplaySize(displaySize);
-
                     characteristics = new CameraCharacteristics(info);
                 }
             } catch (ServiceSpecificException e) {
@@ -964,6 +1031,9 @@
         private final ArrayMap<String, ArrayList<String>> mUnavailablePhysicalDevices =
                 new ArrayMap<String, ArrayList<String>>();
 
+        private final Set<Set<String>> mConcurrentCameraIdCombinations =
+                new ArraySet<Set<String>>();
+
         // Registered availablility callbacks and their executors
         private final ArrayMap<AvailabilityCallback, Executor> mCallbackMap =
             new ArrayMap<AvailabilityCallback, Executor>();
@@ -1068,7 +1138,22 @@
             } catch (RemoteException e) {
                 // Camera service is now down, leave mCameraService as null
             }
+
+            try {
+                ConcurrentCameraIdCombination[] cameraIdCombinations =
+                        cameraService.getConcurrentStreamingCameraIds();
+                for (ConcurrentCameraIdCombination comb : cameraIdCombinations) {
+                    mConcurrentCameraIdCombinations.add(comb.getConcurrentCameraIdCombination());
+                }
+            } catch (ServiceSpecificException e) {
+                // Unexpected failure
+                throw new IllegalStateException("Failed to get concurrent camera id combinations",
+                        e);
+            } catch (RemoteException e) {
+                // Camera service died in all probability
+            }
         }
+
         private String[] extractCameraIdListLocked() {
             String[] cameraIds = null;
             int idCount = 0;
@@ -1089,6 +1174,31 @@
             }
             return cameraIds;
         }
+
+        private Set<Set<String>> extractConcurrentCameraIdListLocked() {
+            Set<Set<String>> concurrentCameraIds = new ArraySet<Set<String>>();
+            for (Set<String> cameraIds : mConcurrentCameraIdCombinations) {
+                Set<String> extractedCameraIds = new ArraySet<String>();
+                for (String cameraId : cameraIds) {
+                    // if the camera id status is NOT_PRESENT or ENUMERATING; skip the device.
+                    // TODO: Would a device status NOT_PRESENT ever be in the map ? it gets removed
+                    // in the callback anyway.
+                    Integer status = mDeviceStatus.get(cameraId);
+                    if (status == null) {
+                        // camera id not present
+                        continue;
+                    }
+                    if (status == ICameraServiceListener.STATUS_ENUMERATING
+                            || status == ICameraServiceListener.STATUS_NOT_PRESENT) {
+                        continue;
+                    }
+                    extractedCameraIds.add(cameraId);
+                }
+                concurrentCameraIds.add(extractedCameraIds);
+            }
+            return concurrentCameraIds;
+        }
+
         private static void sortCameraIds(String[] cameraIds) {
             // The sort logic must match the logic in
             // libcameraservice/common/CameraProviderManager.cpp::getAPI1CompatibleCameraDeviceIds
@@ -1214,6 +1324,88 @@
             return cameraIds;
         }
 
+        public @NonNull Set<Set<String>> getConcurrentStreamingCameraIds() {
+            Set<Set<String>> concurrentStreamingCameraIds = null;
+            synchronized (mLock) {
+                // Try to make sure we have an up-to-date list of concurrent camera devices.
+                connectCameraServiceLocked();
+                concurrentStreamingCameraIds = extractConcurrentCameraIdListLocked();
+            }
+            // TODO: Some sort of sorting  ?
+            return concurrentStreamingCameraIds;
+        }
+
+        public boolean isConcurrentSessionConfigurationSupported(
+                @NonNull Map<String, SessionConfiguration> cameraIdsAndSessionConfigurations)
+                throws CameraAccessException {
+
+            if (cameraIdsAndSessionConfigurations == null) {
+                throw new IllegalArgumentException("cameraIdsAndSessionConfigurations was null");
+            }
+
+            int size = cameraIdsAndSessionConfigurations.size();
+            if (size == 0) {
+                throw new IllegalArgumentException("camera id and session combination is empty");
+            }
+
+            synchronized (mLock) {
+                // Go through all the elements and check if the camera ids are valid at least /
+                // belong to one of the combinations returned by getConcurrentStreamingCameraIds()
+                boolean subsetFound = false;
+                for (Set<String> combination : mConcurrentCameraIdCombinations) {
+                    if (combination.containsAll(cameraIdsAndSessionConfigurations.keySet())) {
+                        subsetFound = true;
+                    }
+                }
+                if (!subsetFound) {
+                    throw new IllegalArgumentException(
+                            "The set of camera ids provided is not a subset of"
+                            + "getConcurrentStreamingCameraIds");
+                }
+                CameraIdAndSessionConfiguration [] cameraIdsAndConfigs =
+                        new CameraIdAndSessionConfiguration[size];
+                int i = 0;
+                for (Map.Entry<String, SessionConfiguration> pair :
+                        cameraIdsAndSessionConfigurations.entrySet()) {
+                    cameraIdsAndConfigs[i] =
+                            new CameraIdAndSessionConfiguration(pair.getKey(), pair.getValue());
+                    i++;
+                }
+                try {
+                    return mCameraService.isConcurrentSessionConfigurationSupported(
+                            cameraIdsAndConfigs);
+                } catch (ServiceSpecificException e) {
+                   throwAsPublicException(e);
+                } catch (RemoteException e) {
+                  // Camera service died - act as if the camera was disconnected
+                  throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
+                          "Camera service is currently unavailable", e);
+                }
+            }
+
+            return false;
+        }
+
+      /**
+        * Helper function to find out if a camera id is in the set of combinations returned by
+        * getConcurrentStreamingCameraIds()
+        * @param cameraId the unique identifier of the camera device to query
+        * @return Whether the camera device was found in the set of combinations returned by
+        *         getConcurrentStreamingCameraIds
+        */
+        public boolean cameraIdHasConcurrentStreamsLocked(String cameraId) {
+            if (!mDeviceStatus.containsKey(cameraId)) {
+                Log.e(TAG, "cameraIdHasConcurrentStreamsLocked called on non existing camera id");
+                return false;
+            }
+            for (Set<String> comb : mConcurrentCameraIdCombinations) {
+                if (comb.contains(cameraId)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
         public void setTorchMode(String cameraId, boolean enabled) throws CameraAccessException {
             synchronized(mLock) {
 
@@ -1698,6 +1890,8 @@
                             cameraId);
                 }
 
+                mConcurrentCameraIdCombinations.clear();
+
                 scheduleCameraServiceReconnectionLocked();
             }
         }
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 3ae3d78..aefe66f 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -621,6 +621,16 @@
                     }
                 });
         sGetCommandMap.put(
+                CameraCharacteristics.SCALER_MANDATORY_CONCURRENT_STREAM_COMBINATIONS.getNativeKey(),
+                        new GetCommand() {
+                    @Override
+                    @SuppressWarnings("unchecked")
+                    public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
+                        return (T) metadata.getMandatoryConcurrentStreamCombinations();
+                    }
+                });
+
+        sGetCommandMap.put(
                 CameraCharacteristics.CONTROL_MAX_REGIONS_AE.getNativeKey(), new GetCommand() {
                     @Override
                     @SuppressWarnings("unchecked")
@@ -1247,7 +1257,8 @@
         return ret;
     }
 
-    private MandatoryStreamCombination[] getMandatoryStreamCombinations() {
+    private MandatoryStreamCombination[] getMandatoryStreamCombinationsHelper(
+            boolean getConcurrent) {
         int[] capabilities = getBase(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
         ArrayList<Integer> caps = new ArrayList<Integer>();
         caps.ensureCapacity(capabilities.length);
@@ -1257,7 +1268,13 @@
         int hwLevel = getBase(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
         MandatoryStreamCombination.Builder build = new MandatoryStreamCombination.Builder(
                 mCameraId, hwLevel, mDisplaySize, caps, getStreamConfigurationMap());
-        List<MandatoryStreamCombination> combs = build.getAvailableMandatoryStreamCombinations();
+
+        List<MandatoryStreamCombination> combs = null;
+        if (getConcurrent) {
+            combs = build.getAvailableMandatoryConcurrentStreamCombinations();
+        } else {
+            combs = build.getAvailableMandatoryStreamCombinations();
+        }
         if ((combs != null) && (!combs.isEmpty())) {
             MandatoryStreamCombination[] combArray = new MandatoryStreamCombination[combs.size()];
             combArray = combs.toArray(combArray);
@@ -1267,6 +1284,17 @@
         return null;
     }
 
+    private MandatoryStreamCombination[] getMandatoryConcurrentStreamCombinations() {
+        if (!mHasMandatoryConcurrentStreams) {
+            return null;
+        }
+        return getMandatoryStreamCombinationsHelper(true);
+    }
+
+    private MandatoryStreamCombination[] getMandatoryStreamCombinations() {
+        return getMandatoryStreamCombinationsHelper(false);
+    }
+
     private StreamConfigurationMap getStreamConfigurationMap() {
         StreamConfiguration[] configurations = getBase(
                 CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
@@ -1614,6 +1642,7 @@
     }
 
     private int mCameraId = -1;
+    private boolean mHasMandatoryConcurrentStreams = false;
     private Size mDisplaySize = new Size(0, 0);
 
     /**
@@ -1628,6 +1657,18 @@
     }
 
     /**
+     * Set the current camera Id.
+     *
+     * @param hasMandatoryConcurrentStreams whether the metadata advertises mandatory concurrent
+     *        streams.
+     *
+     * @hide
+     */
+    public void setHasMandatoryConcurrentStreams(boolean hasMandatoryConcurrentStreams) {
+        mHasMandatoryConcurrentStreams = hasMandatoryConcurrentStreams;
+    }
+
+    /**
      * Set the current display size.
      *
      * @param displaySize The current display size.
@@ -1682,6 +1723,7 @@
     public void swap(CameraMetadataNative other) {
         nativeSwap(other);
         mCameraId = other.mCameraId;
+        mHasMandatoryConcurrentStreams = other.mHasMandatoryConcurrentStreams;
         mDisplaySize = other.mDisplaySize;
     }
 
diff --git a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
index 23f18a8..41e1443 100644
--- a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
+++ b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
@@ -16,30 +16,27 @@
 
 package android.hardware.camera2.params;
 
-import static com.android.internal.util.Preconditions.*;
 import static android.hardware.camera2.params.StreamConfigurationMap.checkArgumentFormat;
 
-import android.annotation.IntRange;
+import static com.android.internal.util.Preconditions.*;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.Context;
 import android.graphics.ImageFormat;
 import android.graphics.ImageFormat.Format;
 import android.hardware.camera2.CameraCharacteristics;
-import android.hardware.camera2.CameraCharacteristics.Key;
 import android.hardware.camera2.CameraDevice;
 import android.hardware.camera2.CameraManager;
 import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.params.StreamConfigurationMap;
 import android.hardware.camera2.utils.HashCodeHelpers;
-import android.graphics.PixelFormat;
 import android.media.CamcorderProfile;
-import android.util.Size;
 import android.util.Log;
 import android.util.Pair;
+import android.util.Size;
 
-import java.util.Arrays;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
@@ -200,7 +197,6 @@
         mDescription = description;
         mIsReprocessable = isReprocessable;
     }
-
     /**
      * Get the mandatory stream combination description.
      *
@@ -271,7 +267,7 @@
                 mStreamsInformation.hashCode());
     }
 
-    private static enum SizeThreshold { VGA, PREVIEW, RECORD, MAXIMUM }
+    private static enum SizeThreshold { VGA, PREVIEW, RECORD, MAXIMUM, s720p }
     private static enum ReprocessType { NONE, PRIVATE, YUV }
     private static final class StreamTemplate {
         public int mFormat;
@@ -653,6 +649,27 @@
                 /*reprocessType*/ ReprocessType.YUV),
     };
 
+    private static StreamCombinationTemplate sConcurrentStreamCombinations[] = {
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s720p) },
+                "In-app video / image processing"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s720p) },
+                "preview / preview to GPU"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s720p),
+                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s720p)},
+                "In-app video / image processing with preview"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s720p),
+                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s720p)},
+                "In-app video / image processing with preview"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s720p),
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s720p)},
+                "Standard Recording"),
+    };
+
     /**
      * Helper builder class to generate a list of available mandatory stream combinations.
      * @hide
@@ -687,6 +704,64 @@
         }
 
         /**
+          * Retrieve a list of all available mandatory concurrent stream combinations.
+          * This method should only be called for devices which are listed in combinations returned
+          * by CameraManager.getConcurrentStreamingCameraIds.
+          *
+          * @return a non-modifiable list of supported mandatory concurrent stream combinations.
+          */
+        public @NonNull List<MandatoryStreamCombination>
+                getAvailableMandatoryConcurrentStreamCombinations() {
+            // Since concurrent streaming support is optional, we mandate these stream
+            // combinations regardless of camera device capabilities.
+            if (!isColorOutputSupported()) {
+                Log.v(TAG, "Device is not backward compatible!");
+                throw new IllegalArgumentException("Camera device which is not BACKWARD_COMPATIBLE"
+                         + " cannot have mandatory concurrent streams");
+            }
+            Size size720p = new Size(1280, 720);
+
+            ArrayList<MandatoryStreamCombination> availableConcurrentStreamCombinations =
+                    new ArrayList<MandatoryStreamCombination>();
+            availableConcurrentStreamCombinations.ensureCapacity(
+                    sConcurrentStreamCombinations.length);
+            for (StreamCombinationTemplate combTemplate : sConcurrentStreamCombinations) {
+                ArrayList<MandatoryStreamInformation> streamsInfo =
+                        new ArrayList<MandatoryStreamInformation>();
+                streamsInfo.ensureCapacity(combTemplate.mStreamTemplates.length);
+                for (StreamTemplate template : combTemplate.mStreamTemplates) {
+                    MandatoryStreamInformation streamInfo;
+                    List<Size> sizes = new ArrayList<Size>();
+                    Size sizeChosen =
+                            getMinSize(size720p,
+                                    getMaxSize(mStreamConfigMap.getOutputSizes(template.mFormat)));
+                    sizes.add(sizeChosen);
+                    try {
+                        streamInfo = new MandatoryStreamInformation(sizes, template.mFormat);
+                    } catch (IllegalArgumentException e) {
+                        String cause = "No available sizes found for format: " + template.mFormat
+                                + " size threshold: " + template.mSizeThreshold + " combination: "
+                                + combTemplate.mDescription;
+                        throw new RuntimeException(cause, e);
+                    }
+                    streamsInfo.add(streamInfo);
+                }
+
+                MandatoryStreamCombination streamCombination;
+                try {
+                    streamCombination = new MandatoryStreamCombination(streamsInfo,
+                            combTemplate.mDescription, /*isReprocess*/false);
+                } catch (IllegalArgumentException e) {
+                    String cause =  "No stream information for mandatory combination: "
+                            + combTemplate.mDescription;
+                    throw new RuntimeException(cause, e);
+                }
+                availableConcurrentStreamCombinations.add(streamCombination);
+            }
+            return Collections.unmodifiableList(availableConcurrentStreamCombinations);
+        }
+
+        /**
          * Retrieve a list of all available mandatory stream combinations.
          *
          * @return a non-modifiable list of supported mandatory stream combinations or
@@ -965,6 +1040,18 @@
         }
 
         /**
+         * Return the lower size
+         */
+        public static @Nullable Size getMinSize(Size a, Size b) {
+            if (a == null || b == null) {
+                throw new IllegalArgumentException("sizes was empty");
+            }
+            if (a.getWidth() * a.getHeight() < b.getHeight() * b.getWidth()) {
+                return a;
+            }
+            return b;
+        }
+        /**
          * Get the largest size by area.
          *
          * @param sizes an array of sizes, must have at least 1 element
diff --git a/core/java/android/hardware/camera2/utils/CameraIdAndSessionConfiguration.java b/core/java/android/hardware/camera2/utils/CameraIdAndSessionConfiguration.java
new file mode 100644
index 0000000..cdc037c
--- /dev/null
+++ b/core/java/android/hardware/camera2/utils/CameraIdAndSessionConfiguration.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2020 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.hardware.camera2.utils;
+
+import android.annotation.NonNull;
+import android.hardware.camera2.params.SessionConfiguration;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * CameraIdAndSessionConfiguration
+ *
+ * Includes the pair of a cameraId and its corresponding SessionConfiguration, to be used with
+ * ICameraService.isConcurrentSessionConfigurationSupported.
+ * @hide
+ */
+public class CameraIdAndSessionConfiguration implements Parcelable {
+
+    private String mCameraId;
+    private SessionConfiguration mSessionConfiguration;
+
+    public CameraIdAndSessionConfiguration(@NonNull String cameraId,
+            @NonNull SessionConfiguration sessionConfiguration) {
+        mCameraId = cameraId;
+        mSessionConfiguration = sessionConfiguration;
+    }
+
+    public static final @NonNull
+            Parcelable.Creator<CameraIdAndSessionConfiguration> CREATOR =
+            new Parcelable.Creator<CameraIdAndSessionConfiguration>() {
+        @Override
+        public CameraIdAndSessionConfiguration createFromParcel(Parcel in) {
+            return new CameraIdAndSessionConfiguration(in);
+        }
+
+        @Override
+        public CameraIdAndSessionConfiguration[] newArray(int size) {
+            return new CameraIdAndSessionConfiguration[size];
+        }
+    };
+
+    private CameraIdAndSessionConfiguration(Parcel in) {
+        readFromParcel(in);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mCameraId);
+        mSessionConfiguration.writeToParcel(dest, flags);
+    }
+
+    /**
+     * helper for CREATOR
+     */
+    public void readFromParcel(Parcel in) {
+        mCameraId = in.readString();
+        mSessionConfiguration = SessionConfiguration.CREATOR.createFromParcel(in);
+    }
+
+    public @NonNull String getCameraId() {
+        return mCameraId;
+    }
+
+    public @NonNull SessionConfiguration getSessionConfiguration() {
+        return mSessionConfiguration;
+    }
+}
diff --git a/core/java/android/hardware/camera2/utils/ConcurrentCameraIdCombination.java b/core/java/android/hardware/camera2/utils/ConcurrentCameraIdCombination.java
new file mode 100644
index 0000000..8f4d636
--- /dev/null
+++ b/core/java/android/hardware/camera2/utils/ConcurrentCameraIdCombination.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 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.hardware.camera2.utils;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * ConcurrentCameraIdCombination
+ *
+ * Includes a list of camera ids that may have sessions configured concurrently.
+ * @hide
+ */
+public class ConcurrentCameraIdCombination implements Parcelable {
+
+    private Set<String> mConcurrentCameraIds = new HashSet<>();
+
+    public static final @NonNull
+            Parcelable.Creator<ConcurrentCameraIdCombination> CREATOR =
+            new Parcelable.Creator<ConcurrentCameraIdCombination>() {
+        @Override
+        public ConcurrentCameraIdCombination createFromParcel(Parcel in) {
+            return new ConcurrentCameraIdCombination(in);
+        }
+
+        @Override
+        public ConcurrentCameraIdCombination[] newArray(int size) {
+            return new ConcurrentCameraIdCombination[size];
+        }
+    };
+
+    private ConcurrentCameraIdCombination(Parcel in) {
+        readFromParcel(in);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mConcurrentCameraIds.size());
+        for (String cameraId : mConcurrentCameraIds) {
+            dest.writeString(cameraId);
+        }
+    }
+
+    /**
+     * helper for CREATOR
+     */
+    public void readFromParcel(Parcel in) {
+        mConcurrentCameraIds.clear();
+        int cameraCombinationSize = in.readInt();
+        if (cameraCombinationSize < 0) {
+            throw new RuntimeException("cameraCombinationSize " + cameraCombinationSize
+                    + " should not be negative");
+        }
+        for (int i = 0; i < cameraCombinationSize; i++) {
+            String cameraId = in.readString();
+            if (cameraId == null) {
+                throw new RuntimeException("Failed to read camera id from Parcel");
+            }
+            mConcurrentCameraIds.add(cameraId);
+        }
+    }
+
+    /**
+     * Get this concurrent camera id combination.
+     */
+    public Set<String> getConcurrentCameraIdCombination() {
+        return mConcurrentCameraIds;
+    }
+}
diff --git a/core/java/android/hardware/display/BrightnessConfiguration.java b/core/java/android/hardware/display/BrightnessConfiguration.java
index 13122d2..6412a0c 100644
--- a/core/java/android/hardware/display/BrightnessConfiguration.java
+++ b/core/java/android/hardware/display/BrightnessConfiguration.java
@@ -61,7 +61,7 @@
     private static final String ATTR_MODEL_LOWER_BOUND = "model-lower-bound";
     private static final String ATTR_MODEL_UPPER_BOUND = "model-upper-bound";
     /**
-     * Returned from {@link #getShortTermModelTimeout()} if no timeout has been set.
+     * Returned from {@link #getShortTermModelTimeoutMillis()} if no timeout has been set.
      * In this case the device will use the default timeout available in the
      * {@link BrightnessConfiguration} returned from
      * {@link DisplayManager#getDefaultBrightnessConfiguration()}.
@@ -160,7 +160,7 @@
      * {@link #getShortTermModelUpperLuxMultiplier()} to decide whether to keep any adjustment
      * the user has made to adaptive brightness.
      */
-    public long getShortTermModelTimeout() {
+    public long getShortTermModelTimeoutMillis() {
         return mShortTermModelTimeout;
     }
 
@@ -326,7 +326,7 @@
             builder.setDescription(description);
             final boolean shouldCollectColorSamples = in.readBoolean();
             builder.setShouldCollectColorSamples(shouldCollectColorSamples);
-            builder.setShortTermModelTimeout(in.readLong());
+            builder.setShortTermModelTimeoutMillis(in.readLong());
             builder.setShortTermModelLowerLuxMultiplier(in.readFloat());
             builder.setShortTermModelUpperLuxMultiplier(in.readFloat());
             return builder.build();
@@ -487,7 +487,7 @@
             builder.addCorrectionByCategory(category, correction);
         }
         builder.setShouldCollectColorSamples(shouldCollectColorSamples);
-        builder.setShortTermModelTimeout(shortTermModelTimeout);
+        builder.setShortTermModelTimeoutMillis(shortTermModelTimeout);
         builder.setShortTermModelLowerLuxMultiplier(shortTermModelLowerLuxMultiplier);
         builder.setShortTermModelUpperLuxMultiplier(shortTermModelUpperLuxMultiplier);
         return builder.build();
@@ -673,8 +673,8 @@
          * adjustment the user has made to adaptive brightness.
          */
         @NonNull
-        public Builder setShortTermModelTimeout(long shortTermModelTimeout) {
-            mShortTermModelTimeout = shortTermModelTimeout;
+        public Builder setShortTermModelTimeoutMillis(long shortTermModelTimeoutMillis) {
+            mShortTermModelTimeout = shortTermModelTimeoutMillis;
             return this;
         }
 
diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java
index fd015b4..a3899b7 100644
--- a/core/java/android/net/EthernetManager.java
+++ b/core/java/android/net/EthernetManager.java
@@ -16,7 +16,10 @@
 
 package android.net;
 
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.annotation.SystemService;
+import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Handler;
@@ -24,12 +27,15 @@
 import android.os.RemoteException;
 
 import java.util.ArrayList;
+import java.util.Objects;
 
 /**
  * A class representing the IP configuration of the Ethernet network.
  *
  * @hide
  */
+@SystemApi
+@TestApi
 @SystemService(Context.ETHERNET_SERVICE)
 public class EthernetManager {
     private static final String TAG = "EthernetManager";
@@ -37,7 +43,7 @@
 
     private final Context mContext;
     private final IEthernetManager mService;
-    private final Handler mHandler = new Handler() {
+    private final Handler mHandler = new Handler(ConnectivityThread.getInstanceLooper()) {
         @Override
         public void handleMessage(Message msg) {
             if (msg.what == MSG_AVAILABILITY_CHANGED) {
@@ -60,12 +66,14 @@
 
     /**
      * A listener interface to receive notification on changes in Ethernet.
+     * @hide
      */
     public interface Listener {
         /**
          * Called when Ethernet port's availability is changed.
          * @param iface Ethernet interface name
          * @param isAvailable {@code true} if Ethernet port exists.
+         * @hide
          */
         @UnsupportedAppUsage
         void onAvailabilityChanged(String iface, boolean isAvailable);
@@ -76,6 +84,7 @@
      * Applications will almost always want to use
      * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
      * the standard {@link android.content.Context#ETHERNET_SERVICE Context.ETHERNET_SERVICE}.
+     * @hide
      */
     public EthernetManager(Context context, IEthernetManager service) {
         mContext = context;
@@ -85,6 +94,7 @@
     /**
      * Get Ethernet configuration.
      * @return the Ethernet Configuration, contained in {@link IpConfiguration}.
+     * @hide
      */
     @UnsupportedAppUsage
     public IpConfiguration getConfiguration(String iface) {
@@ -97,6 +107,7 @@
 
     /**
      * Set Ethernet configuration.
+     * @hide
      */
     @UnsupportedAppUsage
     public void setConfiguration(String iface, IpConfiguration config) {
@@ -109,6 +120,7 @@
 
     /**
      * Indicates whether the system currently has one or more Ethernet interfaces.
+     * @hide
      */
     @UnsupportedAppUsage
     public boolean isAvailable() {
@@ -119,6 +131,7 @@
      * Indicates whether the system has given interface.
      *
      * @param iface Ethernet interface name
+     * @hide
      */
     @UnsupportedAppUsage
     public boolean isAvailable(String iface) {
@@ -133,6 +146,7 @@
      * Adds a listener.
      * @param listener A {@link Listener} to add.
      * @throws IllegalArgumentException If the listener is null.
+     * @hide
      */
     @UnsupportedAppUsage
     public void addListener(Listener listener) {
@@ -151,6 +165,7 @@
 
     /**
      * Returns an array of available Ethernet interface names.
+     * @hide
      */
     @UnsupportedAppUsage
     public String[] getAvailableInterfaces() {
@@ -165,6 +180,7 @@
      * Removes a listener.
      * @param listener A {@link Listener} to remove.
      * @throws IllegalArgumentException If the listener is null.
+     * @hide
      */
     @UnsupportedAppUsage
     public void removeListener(Listener listener) {
@@ -180,4 +196,78 @@
             }
         }
     }
+
+    /**
+     * A request for a tethered interface.
+     */
+    public static class TetheredInterfaceRequest {
+        private final IEthernetManager mService;
+        private final ITetheredInterfaceCallback mCb;
+
+        private TetheredInterfaceRequest(@NonNull IEthernetManager service,
+                @NonNull ITetheredInterfaceCallback cb) {
+            this.mService = service;
+            this.mCb = cb;
+        }
+
+        /**
+         * Release the request, causing the interface to revert back from tethering mode if there
+         * is no other requestor.
+         */
+        public void release() {
+            try {
+                mService.releaseTetheredInterface(mCb);
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
+     * Callback for {@link #requestTetheredInterface(TetheredInterfaceCallback)}.
+     */
+    public interface TetheredInterfaceCallback {
+        /**
+         * Called when the tethered interface is available.
+         * @param iface The name of the interface.
+         */
+        void onAvailable(@NonNull String iface);
+
+        /**
+         * Called when the tethered interface is now unavailable.
+         */
+        void onUnavailable();
+    }
+
+    /**
+     * Request a tethered interface in tethering mode.
+     *
+     * <p>When this method is called and there is at least one ethernet interface available, the
+     * system will designate one to act as a tethered interface. If there is already a tethered
+     * interface, the existing interface will be used.
+     * @param callback A callback to be called once the request has been fulfilled.
+     */
+    @NonNull
+    public TetheredInterfaceRequest requestTetheredInterface(
+            @NonNull TetheredInterfaceCallback callback) {
+        Objects.requireNonNull(callback, "Callback must be non-null");
+        final ITetheredInterfaceCallback cbInternal = new ITetheredInterfaceCallback.Stub() {
+            @Override
+            public void onAvailable(String iface) {
+                callback.onAvailable(iface);
+            }
+
+            @Override
+            public void onUnavailable() {
+                callback.onUnavailable();
+            }
+        };
+
+        try {
+            mService.requestTetheredInterface(cbInternal);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+        return new TetheredInterfaceRequest(mService, cbInternal);
+    }
 }
diff --git a/core/java/android/net/IEthernetManager.aidl b/core/java/android/net/IEthernetManager.aidl
index 94960b5..ccc6e35 100644
--- a/core/java/android/net/IEthernetManager.aidl
+++ b/core/java/android/net/IEthernetManager.aidl
@@ -18,6 +18,7 @@
 
 import android.net.IpConfiguration;
 import android.net.IEthernetServiceListener;
+import android.net.ITetheredInterfaceCallback;
 
 /**
  * Interface that answers queries about, and allows changing
@@ -32,4 +33,6 @@
     boolean isAvailable(String iface);
     void addListener(in IEthernetServiceListener listener);
     void removeListener(in IEthernetServiceListener listener);
+    void requestTetheredInterface(in ITetheredInterfaceCallback callback);
+    void releaseTetheredInterface(in ITetheredInterfaceCallback callback);
 }
diff --git a/core/java/android/net/ITetheredInterfaceCallback.aidl b/core/java/android/net/ITetheredInterfaceCallback.aidl
new file mode 100644
index 0000000..e3d0759
--- /dev/null
+++ b/core/java/android/net/ITetheredInterfaceCallback.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2020 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;
+
+/** @hide */
+interface ITetheredInterfaceCallback {
+    void onAvailable(in String iface);
+    void onUnavailable();
+}
\ No newline at end of file
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index 8d9f0d0..a9d7f17 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -102,9 +102,9 @@
 
     /**
      * The time, as reported by {@link SystemClock#elapsedRealtime}, when this LinkAddress will be
-     * or was deprecated. {@link #LIFETIME_UNKNOWN} indicates this information is not available. At
-     * the time existing connections can still use this address until it expires, but new
-     * connections should use the new address. {@link #LIFETIME_PERMANENT} indicates this
+     * or was deprecated. At the time existing connections can still use this address until it
+     * expires, but new connections should use the new address. {@link #LIFETIME_UNKNOWN} indicates
+     * this information is not available. {@link #LIFETIME_PERMANENT} indicates this
      * {@link LinkAddress} will never be deprecated.
      */
     private long deprecationTime;
@@ -261,10 +261,10 @@
      * @param scope An integer defining the scope in which the address is unique (e.g.,
      *              {@link OsConstants#RT_SCOPE_LINK} or {@link OsConstants#RT_SCOPE_SITE}).
      * @param deprecationTime The time, as reported by {@link SystemClock#elapsedRealtime}, when
-     *                        this {@link LinkAddress} will be or was deprecated.
-     *                        {@link #LIFETIME_UNKNOWN} indicates this information is not available.
-     *                        At the time existing connections can still use this address until it
-     *                        expires, but new connections should use the new address.
+     *                        this {@link LinkAddress} will be or was deprecated. At the time
+     *                        existing connections can still use this address until it expires, but
+     *                        new connections should use the new address. {@link #LIFETIME_UNKNOWN}
+     *                        indicates this information is not available.
      *                        {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress} will
      *                        never be deprecated.
      * @param expirationTime The time, as reported by {@link SystemClock#elapsedRealtime}, when this
@@ -441,7 +441,7 @@
         if (expirationTime == LIFETIME_PERMANENT) {
             flags |= IFA_F_PERMANENT;
         } else if (expirationTime != LIFETIME_UNKNOWN) {
-            // If we know this address expired or will expire in the future or, then this address
+            // If we know this address expired or will expire in the future, then this address
             // should not be permanent.
             flags &= ~IFA_F_PERMANENT;
         }
@@ -458,10 +458,13 @@
     }
 
     /**
-     * @return The time that this address will be deprecated. At the time the existing connection
-     * can still use this address until it expires, but the new connection should use the new
-     * address. This is the EPOCH time in milliseconds. 0 indicates this information is not
-     * available.
+     * Get the deprecation time, as reported by {@link SystemClock#elapsedRealtime}, when this
+     * {@link LinkAddress} will be or was deprecated. At the time existing connections can still use
+     * this address until it expires, but new connections should use the new address.
+     *
+     * @return The deprecation time in milliseconds. {@link #LIFETIME_UNKNOWN} indicates this
+     * information is not available. {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress}
+     * will never be deprecated.
      *
      * @hide
      */
@@ -472,8 +475,12 @@
     }
 
     /**
-     * @return The time that this address will expire and will be no longer valid. This is the EPOCH
-     * time in milliseconds. 0 indicates this information is not available.
+     * Get the expiration time, as reported by {@link SystemClock#elapsedRealtime}, when this
+     * {@link LinkAddress} will expire and be removed from the interface.
+     *
+     * @return The expiration time in milliseconds. {@link #LIFETIME_UNKNOWN} indicates this
+     * information is not available. {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress}
+     * will never expire.
      *
      * @hide
      */
diff --git a/core/java/android/net/NetworkKey.java b/core/java/android/net/NetworkKey.java
index 4469d7d..5cd4eb5 100644
--- a/core/java/android/net/NetworkKey.java
+++ b/core/java/android/net/NetworkKey.java
@@ -75,13 +75,11 @@
      *
      * @return A new {@link NetworkKey} instance or <code>null</code> if the given
      *         {@link ScanResult} instance is malformed.
-     * @throws IllegalArgumentException
+     * @throws NullPointerException
      */
     @Nullable
     public static NetworkKey createFromScanResult(@NonNull ScanResult result) {
-        if (result == null) {
-            throw new IllegalArgumentException("ScanResult cannot be null");
-        }
+        Objects.requireNonNull(result);
         final String ssid = result.SSID;
         if (TextUtils.isEmpty(ssid) || ssid.equals(WifiManager.UNKNOWN_SSID)) {
             return null;
diff --git a/core/java/android/os/HwParcel.java b/core/java/android/os/HwParcel.java
index fb36e6f..228548a 100644
--- a/core/java/android/os/HwParcel.java
+++ b/core/java/android/os/HwParcel.java
@@ -38,6 +38,7 @@
 public class HwParcel {
     private static final String TAG = "HwParcel";
 
+    /** @hide */
     @IntDef(prefix = { "STATUS_" }, value = {
         STATUS_SUCCESS,
     })
diff --git a/core/java/android/os/connectivity/WifiActivityEnergyInfo.java b/core/java/android/os/connectivity/WifiActivityEnergyInfo.java
index 664b6c8..016cc2f 100644
--- a/core/java/android/os/connectivity/WifiActivityEnergyInfo.java
+++ b/core/java/android/os/connectivity/WifiActivityEnergyInfo.java
@@ -16,7 +16,9 @@
 
 package android.os.connectivity;
 
+import android.annotation.ElapsedRealtimeLong;
 import android.annotation.IntDef;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.app.ActivityThread;
@@ -37,14 +39,20 @@
  */
 @SystemApi
 public final class WifiActivityEnergyInfo implements Parcelable {
-    private long mTimeSinceBootMillis;
+    @ElapsedRealtimeLong
+    private final long mTimeSinceBootMillis;
     @StackState
-    private int mStackState;
-    private long mControllerTxDurationMillis;
-    private long mControllerRxDurationMillis;
-    private long mControllerScanDurationMillis;
-    private long mControllerIdleDurationMillis;
-    private long mControllerEnergyUsedMicroJoules;
+    private final int mStackState;
+    @IntRange(from = 0)
+    private final long mControllerTxDurationMillis;
+    @IntRange(from = 0)
+    private final long mControllerRxDurationMillis;
+    @IntRange(from = 0)
+    private final long mControllerScanDurationMillis;
+    @IntRange(from = 0)
+    private final long mControllerIdleDurationMillis;
+    @IntRange(from = 0)
+    private final long mControllerEnergyUsedMicroJoules;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
@@ -67,7 +75,7 @@
     /**
      * Constructor.
      *
-     * @param timeSinceBootMillis the time since boot, in milliseconds.
+     * @param timeSinceBootMillis the elapsed real time since boot, in milliseconds.
      * @param stackState The current state of the Wifi Stack. One of {@link #STACK_STATE_INVALID},
      *                   {@link #STACK_STATE_STATE_ACTIVE}, {@link #STACK_STATE_STATE_SCANNING},
      *                   or {@link #STACK_STATE_STATE_IDLE}.
@@ -78,23 +86,27 @@
      *                       receiving.
      */
     public WifiActivityEnergyInfo(
-            long timeSinceBootMillis,
+            @ElapsedRealtimeLong long timeSinceBootMillis,
             @StackState int stackState,
-            long txDurationMillis,
-            long rxDurationMillis,
-            long scanDurationMillis,
-            long idleDurationMillis) {
-        mTimeSinceBootMillis = timeSinceBootMillis;
-        mStackState = stackState;
-        mControllerTxDurationMillis = txDurationMillis;
-        mControllerRxDurationMillis = rxDurationMillis;
-        mControllerScanDurationMillis = scanDurationMillis;
-        mControllerIdleDurationMillis = idleDurationMillis;
+            @IntRange(from = 0) long txDurationMillis,
+            @IntRange(from = 0) long rxDurationMillis,
+            @IntRange(from = 0) long scanDurationMillis,
+            @IntRange(from = 0) long idleDurationMillis) {
 
+        this(timeSinceBootMillis,
+                stackState,
+                txDurationMillis,
+                rxDurationMillis,
+                scanDurationMillis,
+                idleDurationMillis,
+                calculateEnergyMicroJoules(txDurationMillis, rxDurationMillis, idleDurationMillis));
+    }
+
+    private static long calculateEnergyMicroJoules(
+            long txDurationMillis, long rxDurationMillis, long idleDurationMillis) {
         final Context context = ActivityThread.currentActivityThread().getSystemContext();
         if (context == null) {
-            mControllerEnergyUsedMicroJoules = 0L;
-            return;
+            return 0L;
         }
         // Calculate energy used using PowerProfile.
         PowerProfile powerProfile = new PowerProfile(context);
@@ -106,10 +118,28 @@
                 PowerProfile.POWER_WIFI_CONTROLLER_TX);
         final double voltage = powerProfile.getAveragePower(
                 PowerProfile.POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE) / 1000.0;
-        final long energyUsedMicroJoules = (long) ((mControllerTxDurationMillis * txCurrent
-                + mControllerRxDurationMillis * rxCurrent
-                + mControllerIdleDurationMillis * rxIdleCurrent)
+
+        return (long) ((txDurationMillis * txCurrent
+                + rxDurationMillis * rxCurrent
+                + idleDurationMillis * rxIdleCurrent)
                 * voltage);
+    }
+
+    /** @hide */
+    public WifiActivityEnergyInfo(
+            @ElapsedRealtimeLong long timeSinceBootMillis,
+            @StackState int stackState,
+            @IntRange(from = 0) long txDurationMillis,
+            @IntRange(from = 0) long rxDurationMillis,
+            @IntRange(from = 0) long scanDurationMillis,
+            @IntRange(from = 0) long idleDurationMillis,
+            @IntRange(from = 0) long energyUsedMicroJoules) {
+        mTimeSinceBootMillis = timeSinceBootMillis;
+        mStackState = stackState;
+        mControllerTxDurationMillis = txDurationMillis;
+        mControllerRxDurationMillis = rxDurationMillis;
+        mControllerScanDurationMillis = scanDurationMillis;
+        mControllerIdleDurationMillis = idleDurationMillis;
         mControllerEnergyUsedMicroJoules = energyUsedMicroJoules;
     }
 
@@ -158,16 +188,12 @@
         return 0;
     }
 
-    /** Get the timestamp (milliseconds since boot) of record creation. */
+    /** Get the timestamp (elapsed real time milliseconds since boot) of record creation. */
+    @ElapsedRealtimeLong
     public long getTimeSinceBootMillis() {
         return mTimeSinceBootMillis;
     }
 
-    /** Set the timestamp (milliseconds since boot) of record creation. */
-    public void setTimeSinceBootMillis(long timeSinceBootMillis) {
-        mTimeSinceBootMillis = timeSinceBootMillis;
-    }
-
     /**
      * Get the Wifi stack reported state. One of {@link #STACK_STATE_INVALID},
      * {@link #STACK_STATE_STATE_ACTIVE}, {@link #STACK_STATE_STATE_SCANNING},
@@ -178,66 +204,40 @@
         return mStackState;
     }
 
-    /**
-     * Set the Wifi stack reported state. One of {@link #STACK_STATE_INVALID},
-     * {@link #STACK_STATE_STATE_ACTIVE}, {@link #STACK_STATE_STATE_SCANNING},
-     * {@link #STACK_STATE_STATE_IDLE}.
-     */
-    public void setStackState(@StackState int stackState) {
-        mStackState = stackState;
-    }
-
     /** Get the Wifi transmission duration, in milliseconds. */
+    @IntRange(from = 0)
     public long getControllerTxDurationMillis() {
         return mControllerTxDurationMillis;
     }
 
-    /** Set the Wifi transmission duration, in milliseconds. */
-    public void setControllerTxDurationMillis(long controllerTxDurationMillis) {
-        mControllerTxDurationMillis = controllerTxDurationMillis;
-    }
-
     /** Get the Wifi receive duration, in milliseconds. */
+    @IntRange(from = 0)
     public long getControllerRxDurationMillis() {
         return mControllerRxDurationMillis;
     }
 
-    /** Set the Wifi receive duration, in milliseconds. */
-    public void setControllerRxDurationMillis(long controllerRxDurationMillis) {
-        mControllerRxDurationMillis = controllerRxDurationMillis;
-    }
-
     /** Get the Wifi scan duration, in milliseconds. */
+    @IntRange(from = 0)
     public long getControllerScanDurationMillis() {
         return mControllerScanDurationMillis;
     }
 
-    /** Set the Wifi scan duration, in milliseconds. */
-    public void setControllerScanDurationMillis(long controllerScanDurationMillis) {
-        mControllerScanDurationMillis = controllerScanDurationMillis;
-    }
-
     /** Get the Wifi idle duration, in milliseconds. */
+    @IntRange(from = 0)
     public long getControllerIdleDurationMillis() {
         return mControllerIdleDurationMillis;
     }
 
-    /** Set the Wifi idle duration, in milliseconds. */
-    public void setControllerIdleDurationMillis(long controllerIdleDurationMillis) {
-        mControllerIdleDurationMillis = controllerIdleDurationMillis;
-    }
-
     /** Get the energy consumed by Wifi, in microjoules. */
+    @IntRange(from = 0)
     public long getControllerEnergyUsedMicroJoules() {
         return mControllerEnergyUsedMicroJoules;
     }
 
-    /** Set the energy consumed by Wifi, in microjoules. */
-    public void setControllerEnergyUsedMicroJoules(long controllerEnergyUsedMicroJoules) {
-        mControllerEnergyUsedMicroJoules = controllerEnergyUsedMicroJoules;
-    }
-
-    /** Returns true if the record is valid, false otherwise. */
+    /**
+     * Returns true if the record is valid, false otherwise.
+     * @hide
+     */
     public boolean isValid() {
         return mControllerTxDurationMillis >= 0
                 && mControllerRxDurationMillis >= 0
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index f25cdf1..9da584e 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -3745,6 +3745,7 @@
          * @deprecated this column is no longer supported, use {@link #NETWORK_TYPE_BITMASK} instead
          */
         @Deprecated
+        @SystemApi
         public static final String BEARER_BITMASK = "bearer_bitmask";
 
         /**
@@ -3794,6 +3795,7 @@
          * <p>Type: INTEGER</p>
          *@hide
          */
+        @SystemApi
         public static final String PROFILE_ID = "profile_id";
 
         /**
@@ -3994,6 +3996,7 @@
          *
          * @hide
          */
+        @SystemApi
         public static final String SKIP_464XLAT = "skip_464xlat";
 
         /**
@@ -4002,6 +4005,7 @@
          *
          * @hide
          */
+        @SystemApi
         public static final int SKIP_464XLAT_DEFAULT = -1;
 
         /**
@@ -4010,6 +4014,7 @@
          *
          * @hide
          */
+        @SystemApi
         public static final int SKIP_464XLAT_DISABLE = 0;
 
         /**
@@ -4018,6 +4023,7 @@
          *
          * @hide
          */
+        @SystemApi
         public static final int SKIP_464XLAT_ENABLE = 1;
 
 
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index 36e2d1f..ac2532d 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -544,11 +544,14 @@
                 Preconditions.checkNotNull(adapter);
                 Preconditions.checkNotNull(executor);
 
-                DataShareReadAdapterDelegate delegate =
-                        new DataShareReadAdapterDelegate(executor, adapter);
+                ICancellationSignal cancellationSignalTransport =
+                        CancellationSignal.createTransport();
+
+                DataShareReadAdapterDelegate delegate = new DataShareReadAdapterDelegate(
+                        executor, cancellationSignalTransport, adapter);
 
                 try {
-                    callback.accept(delegate);
+                    callback.accept(cancellationSignalTransport, delegate);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Failed to accept data sharing", e);
                 }
@@ -655,12 +658,16 @@
         private final Object mLock = new Object();
         private final WeakReference<DataShareReadAdapter> mAdapterReference;
         private final WeakReference<Executor> mExecutorReference;
+        private final WeakReference<ICancellationSignal> mCancellationSignalReference;
 
-        DataShareReadAdapterDelegate(Executor executor, DataShareReadAdapter adapter) {
+        DataShareReadAdapterDelegate(Executor executor,
+                ICancellationSignal cancellationSignalTransport, DataShareReadAdapter adapter) {
             Preconditions.checkNotNull(executor);
+            Preconditions.checkNotNull(cancellationSignalTransport);
             Preconditions.checkNotNull(adapter);
 
             mExecutorReference = new WeakReference<>(executor);
+            mCancellationSignalReference = new WeakReference<>(cancellationSignalTransport);
             mAdapterReference = new WeakReference<>(adapter);
         }
 
@@ -668,7 +675,17 @@
         public void start(ParcelFileDescriptor fd, ICancellationSignal remoteCancellationSignal)
                 throws RemoteException {
             synchronized (mLock) {
-                CancellationSignal cancellationSignal = new CancellationSignal();
+                ICancellationSignal serverControlledCancellationSignal =
+                        mCancellationSignalReference.get();
+
+                if (serverControlledCancellationSignal == null) {
+                    Slog.w(TAG, "Can't execute onStart(), reference to cancellation signal has "
+                            + "been GC'ed");
+                    return;
+                }
+
+                CancellationSignal cancellationSignal =
+                        CancellationSignal.fromTransport(serverControlledCancellationSignal);
                 cancellationSignal.setRemote(remoteCancellationSignal);
 
                 executeAdapterMethodLocked(
diff --git a/core/java/android/service/contentcapture/DataShareReadAdapter.java b/core/java/android/service/contentcapture/DataShareReadAdapter.java
index d9350ba..ca68201 100644
--- a/core/java/android/service/contentcapture/DataShareReadAdapter.java
+++ b/core/java/android/service/contentcapture/DataShareReadAdapter.java
@@ -40,8 +40,7 @@
     void onStart(@NonNull ParcelFileDescriptor fd, @NonNull CancellationSignal cancellationSignal);
 
     /**
-     * Signals that the session failed to start or terminated unsuccessfully (e.g. due to a
-     * timeout).
+     * Signals that the session failed to start or terminated unsuccessfully.
      **/
     void onError(int errorCode);
 }
diff --git a/core/java/android/service/contentcapture/IDataShareCallback.aidl b/core/java/android/service/contentcapture/IDataShareCallback.aidl
index c1aa1bb..d972ada 100644
--- a/core/java/android/service/contentcapture/IDataShareCallback.aidl
+++ b/core/java/android/service/contentcapture/IDataShareCallback.aidl
@@ -16,10 +16,11 @@
 
 package android.service.contentcapture;
 
+import android.os.ICancellationSignal;
 import android.service.contentcapture.IDataShareReadAdapter;
 
 /** @hide */
 oneway interface IDataShareCallback {
-    void accept(in IDataShareReadAdapter adapter);
+    void accept(in ICancellationSignal cancellationSignal, in IDataShareReadAdapter adapter);
     void reject();
 }
diff --git a/core/java/android/service/controls/TokenProvider.aidl b/core/java/android/service/controls/TokenProvider.aidl
new file mode 100644
index 0000000..8f4b795
--- /dev/null
+++ b/core/java/android/service/controls/TokenProvider.aidl
@@ -0,0 +1,7 @@
+package android.service.controls;
+
+/** @hide */
+interface TokenProvider {
+    void setAuthToken(String token);
+    String getAccountName();
+}
\ No newline at end of file
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 7815864..26c8314 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -1259,6 +1259,7 @@
     @Override
     public IBinder onBind(Intent intent) {
         if (TextToSpeech.Engine.INTENT_ACTION_TTS_SERVICE.equals(intent.getAction())) {
+            Binder.allowBlocking(mBinder.asBinder());
             return mBinder;
         }
         return null;
diff --git a/core/java/android/telephony/CellBroadcastIntents.java b/core/java/android/telephony/CellBroadcastIntents.java
index 8446253..2e08108 100644
--- a/core/java/android/telephony/CellBroadcastIntents.java
+++ b/core/java/android/telephony/CellBroadcastIntents.java
@@ -16,22 +16,23 @@
 
 package android.telephony;
 
+import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.app.AppOpsManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.os.Bundle;
 import android.os.Handler;
 import android.os.UserHandle;
+import android.provider.Telephony;
 
 /**
  * A static helper class used to send Intents with prepopulated flags.
  * <p>
- * This is intended to be used by the CellBroadcastService and will throw a security exception if
- * used from a UID besides the network stack UID.
+ * This is intended to be used by the CellBroadcastService and does nothing if the caller does not
+ * have permission to broadcast {@link Telephony.Sms.Intents.SMS_CB_RECEIVED_ACTION}.
  *
  * @hide
  */
@@ -39,6 +40,8 @@
 public class CellBroadcastIntents {
     private static final String LOG_TAG = "CellBroadcastIntents";
 
+    private static final String EXTRA_MESSAGE = "message";
+
     /**
      * @hide
      */
@@ -46,50 +49,71 @@
     }
 
     /**
-     * Returns an intent which can be received by background BroadcastReceivers. This is only
-     * intended to be used by the CellBroadcastService and will throw a security exception if called
-     * from another UID.
+     * Broadcasts an SMS_CB_RECEIVED_ACTION intent which can be received by background
+     * BroadcastReceivers. This is only intended to be used by the CellBroadcastService and will
+     * do nothing if the caller does not have permission to broadcast
+     * {@link Telephony.Sms.Intents.SMS_CB_RECEIVED_ACTION}.
      *
      * @param context            The context from which to send the broadcast
      * @param user               The user from which to send the broadcast
-     * @param intent             The Intent to broadcast; all receivers matching this Intent will
-     *                           receive the broadcast.
-     * @param receiverPermission String naming a permissions that a receiver must hold in order to
-     *                           receive your broadcast. If null, no permission is required.
-     * @param receiverAppOp      The app op associated with the broadcast. If null, no appOp is
-     *                           required. If both receiverAppOp and receiverPermission are
-     *                           non-null, a receiver must have both of them to receive the
-     *                           broadcast
+     * @param smsCbMessage       The SmsCbMessage to include with the intent
      * @param resultReceiver     Your own BroadcastReceiver to treat as the final receiver of the
      *                           broadcast.
      * @param scheduler          A custom Handler with which to schedule the resultReceiver
      *                           callback; if null it will be scheduled in the Context's main
      *                           thread.
      * @param initialCode        An initial value for the result code.  Often Activity.RESULT_OK.
-     * @param initialData        An initial value for the result data.  Often null.
-     * @param initialExtras      An initial value for the result extras.  Often null.
+     * @param slotIndex          The slot index to include in the intent
      */
-    public static void sendOrderedBroadcastForBackgroundReceivers(@NonNull Context context,
-            @Nullable UserHandle user, @NonNull Intent intent, @Nullable String receiverPermission,
-            @Nullable String receiverAppOp, @Nullable BroadcastReceiver resultReceiver,
-            @Nullable Handler scheduler, int initialCode, @Nullable String initialData,
-            @Nullable Bundle initialExtras) {
-        int status = context.checkCallingOrSelfPermission(
-                "android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS");
-        if (status == PackageManager.PERMISSION_DENIED) {
-            throw new SecurityException(
-                    "Caller does not have permission to send broadcast for background receivers");
-        }
-        Intent backgroundIntent = new Intent(intent);
+    public static void sendSmsCbReceivedBroadcast(@NonNull Context context,
+            @Nullable UserHandle user, @NonNull SmsCbMessage smsCbMessage,
+            @Nullable BroadcastReceiver resultReceiver, @Nullable Handler scheduler,
+            int initialCode, int slotIndex) {
+        Intent backgroundIntent = new Intent(Telephony.Sms.Intents.SMS_CB_RECEIVED_ACTION);
+        backgroundIntent.putExtra(EXTRA_MESSAGE, smsCbMessage);
         backgroundIntent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+        putPhoneIdAndSubIdExtra(context, backgroundIntent, slotIndex);
+
+        String receiverPermission = Manifest.permission.RECEIVE_SMS;
+        String receiverAppOp = AppOpsManager.OPSTR_RECEIVE_SMS;
         if (user != null) {
             context.createContextAsUser(user, 0).sendOrderedBroadcast(backgroundIntent,
                     receiverPermission, receiverAppOp, resultReceiver, scheduler, initialCode,
-                    initialData, initialExtras);
+                    null, null);
         } else {
             context.sendOrderedBroadcast(backgroundIntent, receiverPermission,
-                    receiverAppOp, resultReceiver, scheduler, initialCode, initialData,
-                    initialExtras);
+                    receiverAppOp, resultReceiver, scheduler, initialCode, null, null);
+        }
+    }
+
+    /**
+     * Put the phone ID and sub ID into an intent as extras.
+     */
+    private static void putPhoneIdAndSubIdExtra(Context context, Intent intent, int phoneId) {
+        int subId = getSubIdForPhone(context, phoneId);
+        if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+            intent.putExtra("subscription", subId);
+            intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);
+        }
+        intent.putExtra("phone", phoneId);
+        intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, phoneId);
+    }
+
+    /**
+     * Get the subscription ID for a phone ID, or INVALID_SUBSCRIPTION_ID if the phone does not
+     * have an active sub
+     * @param phoneId the phoneId to use
+     * @return the associated sub id
+     */
+    private static int getSubIdForPhone(Context context, int phoneId) {
+        SubscriptionManager subMan =
+                (SubscriptionManager) context.getSystemService(
+                        Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+        int[] subIds = subMan.getSubscriptionIds(phoneId);
+        if (subIds != null) {
+            return subIds[0];
+        } else {
+            return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
         }
     }
 }
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 14390f1..e1f1581 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -558,12 +558,6 @@
     boolean isWindowTraceEnabled();
 
     /**
-     * Requests that the WindowManager sends
-     * WindowManagerPolicyConstants#ACTION_USER_ACTIVITY_NOTIFICATION on the next user activity.
-     */
-    void requestUserActivityNotification();
-
-    /**
      * Notify WindowManager that it should not override the info in DisplayManager for the specified
      * display. This can disable letter- or pillar-boxing applied in DisplayManager when the metrics
      * of the logical display reported from WindowManager do not correspond to the metrics of the
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 55c298e..a6450a1 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -2459,6 +2459,7 @@
          * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED}
          * will be used.
          */
+        @ActivityInfo.ScreenOrientation
         public int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 
         /**
diff --git a/core/java/android/view/WindowManagerPolicyConstants.java b/core/java/android/view/WindowManagerPolicyConstants.java
index a22f5a5..492ab6f 100644
--- a/core/java/android/view/WindowManagerPolicyConstants.java
+++ b/core/java/android/view/WindowManagerPolicyConstants.java
@@ -66,12 +66,6 @@
     String NAV_BAR_MODE_GESTURAL_OVERLAY = "com.android.internal.systemui.navbar.gestural";
 
     /**
-     * Broadcast sent when a user activity is detected.
-     */
-    String ACTION_USER_ACTIVITY_NOTIFICATION =
-            "android.intent.action.USER_ACTIVITY_NOTIFICATION";
-
-    /**
      * Sticky broadcast of the current HDMI plugged state.
      */
     String ACTION_HDMI_PLUGGED = "android.intent.action.HDMI_PLUGGED";
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 9cbba87..02b098b 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -102,6 +102,12 @@
     public static final int STATE_FLAG_HIGH_TEXT_CONTRAST_ENABLED = 0x00000004;
 
     /** @hide */
+    public static final int STATE_FLAG_DISPATCH_DOUBLE_TAP = 0x00000008;
+
+    /** @hide */
+    public static final int STATE_FLAG_REQUEST_MULTI_FINGER_GESTURES = 0x00000010;
+
+    /** @hide */
     public static final int DALTONIZER_DISABLED = -1;
 
     /** @hide */
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 81c8383..cede3b5 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -35,6 +35,7 @@
 import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.ICancellationSignal;
 import android.os.Looper;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
@@ -655,9 +656,12 @@
         Preconditions.checkNotNull(dataShareWriteAdapter);
         Preconditions.checkNotNull(executor);
 
+        ICancellationSignal cancellationSignalTransport = CancellationSignal.createTransport();
+
         try {
-            mService.shareData(request,
-                    new DataShareAdapterDelegate(executor, dataShareWriteAdapter));
+            mService.shareData(request, cancellationSignalTransport,
+                    new DataShareAdapterDelegate(executor,
+                            cancellationSignalTransport, dataShareWriteAdapter));
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
         }
@@ -715,20 +719,30 @@
 
         private final WeakReference<DataShareWriteAdapter> mAdapterReference;
         private final WeakReference<Executor> mExecutorReference;
+        private final WeakReference<ICancellationSignal> mCancellationSignal;
 
-        private DataShareAdapterDelegate(Executor executor, DataShareWriteAdapter adapter) {
+        private DataShareAdapterDelegate(Executor executor,
+                ICancellationSignal cancellationSignalTransport, DataShareWriteAdapter adapter) {
             Preconditions.checkNotNull(executor);
+            Preconditions.checkNotNull(cancellationSignalTransport);
             Preconditions.checkNotNull(adapter);
 
             mExecutorReference = new WeakReference<>(executor);
             mAdapterReference = new WeakReference<>(adapter);
+            mCancellationSignal = new WeakReference<>(cancellationSignalTransport);
         }
 
         @Override
         public void write(ParcelFileDescriptor destination)
                 throws RemoteException {
-            // TODO(b/148264965): implement this.
-            CancellationSignal cancellationSignal = new CancellationSignal();
+            ICancellationSignal cancellationSignalTransport = mCancellationSignal.get();
+            if (cancellationSignalTransport == null) {
+                Slog.w(TAG, "Can't execute write(), reference to cancellation signal has been "
+                        + "GC'ed");
+            }
+            CancellationSignal cancellationSignal =
+                    CancellationSignal.fromTransport(cancellationSignalTransport);
+
             executeAdapterMethodLocked(adapter -> adapter.onWrite(destination, cancellationSignal),
                     "onWrite");
         }
diff --git a/core/java/android/view/contentcapture/IContentCaptureManager.aidl b/core/java/android/view/contentcapture/IContentCaptureManager.aidl
index e8d85ac..5217e68 100644
--- a/core/java/android/view/contentcapture/IContentCaptureManager.aidl
+++ b/core/java/android/view/contentcapture/IContentCaptureManager.aidl
@@ -23,6 +23,7 @@
 import android.view.contentcapture.DataShareRequest;
 import android.view.contentcapture.IDataShareWriteAdapter;
 import android.os.IBinder;
+import android.os.ICancellationSignal;
 
 import com.android.internal.os.IResultReceiver;
 
@@ -68,7 +69,8 @@
     /**
     * Requests sharing of a binary data with the content capture service.
     */
-    void shareData(in DataShareRequest request, in IDataShareWriteAdapter adapter);
+    void shareData(in DataShareRequest request, in ICancellationSignal cancellationSignal,
+                   in IDataShareWriteAdapter adapter);
 
     /**
      * Returns whether the content capture feature is enabled for the calling user.
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 42d7892..c8a7c07 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -17,6 +17,7 @@
 package android.widget;
 
 import static com.android.internal.util.Preconditions.checkNotNull;
+import static com.android.internal.util.Preconditions.checkState;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -24,6 +25,9 @@
 import android.annotation.StringRes;
 import android.app.INotificationManager;
 import android.app.ITransientNotification;
+import android.app.ITransientNotificationCallback;
+import android.compat.Compatibility;
+import android.compat.annotation.ChangeId;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -105,15 +109,45 @@
      */
     public static final int LENGTH_LONG = 1;
 
+    /**
+     * Text toasts will be rendered by SystemUI instead of in-app, so apps can't circumvent
+     * background custom toast restrictions.
+     *
+     * TODO(b/144152069): Add @EnabledAfter(Q) to target R+ after assessing impact on dogfood
+     */
+    @ChangeId
+    // @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
+    private static final long CHANGE_TEXT_TOASTS_IN_THE_SYSTEM = 147798919L;
+
+
     private final Binder mToken;
     private final Context mContext;
+    private final Handler mHandler;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     final TN mTN;
     @UnsupportedAppUsage
     int mDuration;
-    View mNextView;
-    // TODO(b/128611929): Remove this and check for null view when toast creation is in the system
-    boolean mIsCustomToast = false;
+
+    /**
+     * This is also passed to {@link TN} object, where it's also accessed with itself as its own
+     * lock.
+     */
+    @GuardedBy("mCallbacks")
+    private final List<Callback> mCallbacks;
+
+    /**
+     * View to be displayed, in case this is a custom toast (e.g. not created with {@link
+     * #makeText(Context, int, int)} or its variants).
+     */
+    @Nullable
+    private View mNextView;
+
+    /**
+     * Text to be shown, in case this is NOT a custom toast (e.g. created with {@link
+     * #makeText(Context, int, int)} or its variants).
+     */
+    @Nullable
+    private CharSequence mText;
 
     /**
      * Construct an empty Toast object.  You must call {@link #setView} before you
@@ -133,19 +167,34 @@
     public Toast(@NonNull Context context, @Nullable Looper looper) {
         mContext = context;
         mToken = new Binder();
-        mTN = new TN(context.getPackageName(), mToken, looper);
+        looper = getLooper(looper);
+        mHandler = new Handler(looper);
+        mCallbacks = new ArrayList<>();
+        mTN = new TN(context.getPackageName(), mToken, mCallbacks, looper);
         mTN.mY = context.getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.toast_y_offset);
         mTN.mGravity = context.getResources().getInteger(
                 com.android.internal.R.integer.config_toastDefaultGravity);
     }
 
+    private Looper getLooper(@Nullable Looper looper) {
+        if (looper != null) {
+            return looper;
+        }
+        return checkNotNull(Looper.myLooper(),
+                "Can't toast on a thread that has not called Looper.prepare()");
+    }
+
     /**
      * Show the view for the specified duration.
      */
     public void show() {
-        if (mNextView == null) {
-            throw new RuntimeException("setView must have been called");
+        if (Compatibility.isChangeEnabled(CHANGE_TEXT_TOASTS_IN_THE_SYSTEM)) {
+            checkState(mNextView != null || mText != null, "You must either set a text or a view");
+        } else {
+            if (mNextView == null) {
+                throw new RuntimeException("setView must have been called");
+            }
         }
 
         INotificationManager service = getService();
@@ -155,10 +204,18 @@
         final int displayId = mContext.getDisplayId();
 
         try {
-            if (mIsCustomToast) {
-                service.enqueueToast(pkg, mToken, tn, mDuration, displayId);
+            if (Compatibility.isChangeEnabled(CHANGE_TEXT_TOASTS_IN_THE_SYSTEM)) {
+                if (mNextView != null) {
+                    // It's a custom toast
+                    service.enqueueToast(pkg, mToken, tn, mDuration, displayId);
+                } else {
+                    // It's a text toast
+                    ITransientNotificationCallback callback =
+                            new CallbackBinder(mCallbacks, mHandler);
+                    service.enqueueTextToast(pkg, mToken, mText, mDuration, displayId, callback);
+                }
             } else {
-                service.enqueueTextToast(pkg, mToken, tn, mDuration, displayId);
+                service.enqueueToast(pkg, mToken, tn, mDuration, displayId);
             }
         } catch (RemoteException e) {
             // Empty
@@ -171,7 +228,16 @@
      * after the appropriate duration.
      */
     public void cancel() {
-        mTN.cancel();
+        if (Compatibility.isChangeEnabled(CHANGE_TEXT_TOASTS_IN_THE_SYSTEM)
+                && mNextView == null) {
+            try {
+                getService().cancelToast(mContext.getOpPackageName(), mToken);
+            } catch (RemoteException e) {
+                // Empty
+            }
+        } else {
+            mTN.cancel();
+        }
     }
 
     /**
@@ -187,7 +253,6 @@
      */
     @Deprecated
     public void setView(View view) {
-        mIsCustomToast = true;
         mNextView = view;
     }
 
@@ -203,7 +268,6 @@
      *      will not have custom toast views displayed.
      */
     public View getView() {
-        mIsCustomToast = true;
         return mNextView;
     }
 
@@ -298,8 +362,8 @@
      */
     public void addCallback(@NonNull Callback callback) {
         checkNotNull(callback);
-        synchronized (mTN.mCallbacks) {
-            mTN.mCallbacks.add(callback);
+        synchronized (mCallbacks) {
+            mCallbacks.add(callback);
         }
     }
 
@@ -307,8 +371,8 @@
      * Removes a callback previously added with {@link #addCallback(Callback)}.
      */
     public void removeCallback(@NonNull Callback callback) {
-        synchronized (mTN.mCallbacks) {
-            mTN.mCallbacks.remove(callback);
+        synchronized (mCallbacks) {
+            mCallbacks.remove(callback);
         }
     }
 
@@ -338,22 +402,30 @@
     /**
      * Make a standard toast to display using the specified looper.
      * If looper is null, Looper.myLooper() is used.
+     *
      * @hide
      */
     public static Toast makeText(@NonNull Context context, @Nullable Looper looper,
             @NonNull CharSequence text, @Duration int duration) {
-        Toast result = new Toast(context, looper);
+        if (Compatibility.isChangeEnabled(CHANGE_TEXT_TOASTS_IN_THE_SYSTEM)) {
+            Toast result = new Toast(context, looper);
+            result.mText = text;
+            result.mDuration = duration;
+            return result;
+        } else {
+            Toast result = new Toast(context, looper);
 
-        LayoutInflater inflate = (LayoutInflater)
-                context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        View v = inflate.inflate(com.android.internal.R.layout.transient_notification, null);
-        TextView tv = (TextView)v.findViewById(com.android.internal.R.id.message);
-        tv.setText(text);
+            LayoutInflater inflate = (LayoutInflater)
+                    context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+            View v = inflate.inflate(com.android.internal.R.layout.transient_notification, null);
+            TextView tv = (TextView) v.findViewById(com.android.internal.R.id.message);
+            tv.setText(text);
 
-        result.mNextView = v;
-        result.mDuration = duration;
+            result.mNextView = v;
+            result.mDuration = duration;
 
-        return result;
+            return result;
+        }
     }
 
     /**
@@ -385,14 +457,23 @@
      * @param s The new text for the Toast.
      */
     public void setText(CharSequence s) {
-        if (mNextView == null) {
-            throw new RuntimeException("This Toast was not created with Toast.makeText()");
+        if (Compatibility.isChangeEnabled(CHANGE_TEXT_TOASTS_IN_THE_SYSTEM)) {
+            if (mNextView != null) {
+                throw new IllegalStateException(
+                        "Text provided for custom toast, remove previous setView() calls if you "
+                                + "want a text toast instead.");
+            }
+            mText = s;
+        } else {
+            if (mNextView == null) {
+                throw new RuntimeException("This Toast was not created with Toast.makeText()");
+            }
+            TextView tv = mNextView.findViewById(com.android.internal.R.id.message);
+            if (tv == null) {
+                throw new RuntimeException("This Toast was not created with Toast.makeText()");
+            }
+            tv.setText(s);
         }
-        TextView tv = mNextView.findViewById(com.android.internal.R.id.message);
-        if (tv == null) {
-            throw new RuntimeException("This Toast was not created with Toast.makeText()");
-        }
-        tv.setText(s);
     }
 
     // =======================================================================================
@@ -442,12 +523,18 @@
         final Binder mToken;
 
         @GuardedBy("mCallbacks")
-        private final List<Callback> mCallbacks = new ArrayList<>();
+        private final List<Callback> mCallbacks;
 
         static final long SHORT_DURATION_TIMEOUT = 4000;
         static final long LONG_DURATION_TIMEOUT = 7000;
 
-        TN(String packageName, Binder token, @Nullable Looper looper) {
+        /**
+         * Creates a {@link ITransientNotification} object.
+         *
+         * The parameter {@code callbacks} is not copied and is accessed with itself as its own
+         * lock.
+         */
+        TN(String packageName, Binder token, List<Callback> callbacks, @Nullable Looper looper) {
             // XXX This should be changed to use a Dialog, with a Theme.Toast
             // defined that sets up the layout params appropriately.
             final WindowManager.LayoutParams params = mParams;
@@ -464,15 +551,8 @@
 
             mPackageName = packageName;
             mToken = token;
+            mCallbacks = callbacks;
 
-            if (looper == null) {
-                // Use Looper.myLooper() if looper is not specified.
-                looper = Looper.myLooper();
-                if (looper == null) {
-                    throw new RuntimeException(
-                            "Can't toast on a thread that has not called Looper.prepare()");
-                }
-            }
             mHandler = new Handler(looper, null) {
                 @Override
                 public void handleMessage(Message msg) {
@@ -655,4 +735,46 @@
          */
         public void onToastHidden() {}
     }
+
+    private static class CallbackBinder extends ITransientNotificationCallback.Stub {
+        private final Handler mHandler;
+
+        @GuardedBy("mCallbacks")
+        private final List<Callback> mCallbacks;
+
+        /**
+         * Creates a {@link ITransientNotificationCallback} object.
+         *
+         * The parameter {@code callbacks} is not copied and is accessed with itself as its own
+         * lock.
+         */
+        private CallbackBinder(List<Callback> callbacks, Handler handler) {
+            mCallbacks = callbacks;
+            mHandler = handler;
+        }
+
+        @Override
+        public void onToastShown() {
+            mHandler.post(() -> {
+                for (Callback callback : getCallbacks()) {
+                    callback.onToastShown();
+                }
+            });
+        }
+
+        @Override
+        public void onToastHidden() {
+            mHandler.post(() -> {
+                for (Callback callback : getCallbacks()) {
+                    callback.onToastHidden();
+                }
+            });
+        }
+
+        private List<Callback> getCallbacks() {
+            synchronized (mCallbacks) {
+                return new ArrayList<>(mCallbacks);
+            }
+        }
+    }
 }
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index de64573..b232efc 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -364,6 +364,12 @@
      */
     public static final String NAV_BAR_HANDLE_FORCE_OPAQUE = "nav_bar_handle_force_opaque";
 
+    /**
+     * (boolean) Whether to force the Nav Bar handle to remain visible over the lockscreen.
+     */
+    public static final String NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN =
+            "nav_bar_handle_show_over_lockscreen";
+
     private SystemUiDeviceConfigFlags() {
     }
 }
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index aa0ac37..a273633 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -16,6 +16,7 @@
 
 package com.android.internal.statusbar;
 
+import android.app.ITransientNotificationCallback;
 import android.content.ComponentName;
 import android.graphics.Rect;
 import android.hardware.biometrics.IBiometricServiceReceiverInternal;
@@ -198,4 +199,15 @@
      * Dismiss the warning that the device is about to go to sleep due to user inactivity.
      */
     void dismissInattentiveSleepWarning(boolean animated);
+
+    /**
+     * Displays a text toast.
+     */
+    void showToast(String packageName, IBinder token, CharSequence text, IBinder windowToken,
+            int duration, @nullable ITransientNotificationCallback callback);
+
+    /**
+     * Cancels toast with token {@code token} in {@code packageName}.
+     */
+    void hideToast(String packageName, IBinder token);
 }
diff --git a/core/java/com/android/internal/util/ConnectivityUtil.java b/core/java/com/android/internal/util/LocationPermissionChecker.java
similarity index 71%
rename from core/java/com/android/internal/util/ConnectivityUtil.java
rename to core/java/com/android/internal/util/LocationPermissionChecker.java
index 799352b..2db0e99 100644
--- a/core/java/com/android/internal/util/ConnectivityUtil.java
+++ b/core/java/com/android/internal/util/LocationPermissionChecker.java
@@ -33,28 +33,59 @@
 
 
 /**
- * Utility methods for common functionality using by different networks.
+ * The methods used for location permission and location mode checking.
  *
  * @hide
  */
-public class ConnectivityUtil {
+public class LocationPermissionChecker {
 
-    private static final String TAG = "ConnectivityUtil";
+    private static final String TAG = "LocationPermissionChecker";
 
     private final Context mContext;
-    private final AppOpsManager mAppOps;
+    private final AppOpsManager mAppOpsManager;
     private final UserManager mUserManager;
+    private final LocationManager mLocationManager;
 
-    public ConnectivityUtil(Context context) {
+    public LocationPermissionChecker(Context context) {
         mContext = context;
-        mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+        mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        mLocationManager =
+            (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
     }
 
     /**
-     * API to determine if the caller has fine/coarse location permission (depending on
-     * config/targetSDK level) and the location mode is enabled for the user. SecurityException is
-     * thrown if the caller has no permission or the location mode is disabled.
+     * Check location permission granted by the caller.
+     *
+     * This API check if the location mode enabled for the caller and the caller has
+     * ACCESS_COARSE_LOCATION permission is targetSDK<29, otherwise, has ACCESS_FINE_LOCATION.
+     *
+     * @param pkgName package name of the application requesting access
+     * @param featureId The feature in the package
+     * @param uid The uid of the package
+     * @param message A message describing why the permission was checked. Only needed if this is
+     *                not inside of a two-way binder call from the data receiver
+     *
+     * @return {@code true} returns if the caller has location permission and the location mode is
+     *         enabled.
+     */
+    public boolean checkLocationPermission(String pkgName, @Nullable String featureId,
+            int uid, @Nullable String message) {
+        try {
+            enforceLocationPermission(pkgName, featureId, uid, message);
+            return true;
+        } catch (SecurityException e) {
+            return false;
+        }
+    }
+
+    /**
+     * Enforce the caller has location permission.
+     *
+     * This API determines if the location mode enabled for the caller and the caller has
+     * ACCESS_COARSE_LOCATION permission is targetSDK<29, otherwise, has ACCESS_FINE_LOCATION.
+     * SecurityException is thrown if the caller has no permission or the location mode is disabled.
+     *
      * @param pkgName package name of the application requesting access
      * @param featureId The feature in the package
      * @param uid The uid of the package
@@ -62,31 +93,21 @@
      *                not inside of a two-way binder call from the data receiver
      */
     public void enforceLocationPermission(String pkgName, @Nullable String featureId, int uid,
-            @Nullable String message)
-            throws SecurityException {
+            @Nullable String message) throws SecurityException {
+
         checkPackage(uid, pkgName);
 
         // Location mode must be enabled
         if (!isLocationModeEnabled()) {
-            // Location mode is disabled, scan results cannot be returned
             throw new SecurityException("Location mode is disabled for the device");
         }
 
         // LocationAccess by App: caller must have Coarse/Fine Location permission to have access to
         // location information.
-        boolean canAppPackageUseLocation = checkCallersLocationPermission(pkgName, featureId,
-                uid, /* coarseForTargetSdkLessThanQ */ true, message);
-
-        // If neither caller or app has location access, there is no need to check
-        // any other permissions. Deny access to scan results.
-        if (!canAppPackageUseLocation) {
+        if (!checkCallersLocationPermission(pkgName, featureId,
+                uid, /* coarseForTargetSdkLessThanQ */ true, message)) {
             throw new SecurityException("UID " + uid + " has no location permission");
         }
-        // If the User or profile is current, permission is granted
-        // Otherwise, uid must have INTERACT_ACROSS_USERS_FULL permission.
-        if (!isCurrentProfile(uid) && !checkInteractAcrossUsersFull(uid)) {
-            throw new SecurityException("UID " + uid + " profile not permitted");
-        }
     }
 
     /**
@@ -104,6 +125,7 @@
      */
     public boolean checkCallersLocationPermission(String pkgName, @Nullable String featureId,
             int uid, boolean coarseForTargetSdkLessThanQ, @Nullable String message) {
+
         boolean isTargetSdkLessThanQ = isTargetSdkLessThan(pkgName, Build.VERSION_CODES.Q, uid);
 
         String permissionType = Manifest.permission.ACCESS_FINE_LOCATION;
@@ -111,8 +133,7 @@
             // Having FINE permission implies having COARSE permission (but not the reverse)
             permissionType = Manifest.permission.ACCESS_COARSE_LOCATION;
         }
-        if (getUidPermission(permissionType, uid)
-                == PackageManager.PERMISSION_DENIED) {
+        if (getUidPermission(permissionType, uid) == PackageManager.PERMISSION_DENIED) {
             return false;
         }
 
@@ -134,10 +155,8 @@
      * Retrieves a handle to LocationManager (if not already done) and check if location is enabled.
      */
     public boolean isLocationModeEnabled() {
-        LocationManager locationManager =
-                (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
         try {
-            return locationManager.isLocationEnabledForUser(UserHandle.of(
+            return mLocationManager.isLocationEnabledForUser(UserHandle.of(
                     getCurrentUser()));
         } catch (Exception e) {
             Log.e(TAG, "Failure to get location mode via API, falling back to settings", e);
@@ -166,27 +185,16 @@
 
     private boolean noteAppOpAllowed(String op, String pkgName, @Nullable String featureId,
             int uid, @Nullable String message) {
-        return mAppOps.noteOp(op, uid, pkgName, featureId, message) == AppOpsManager.MODE_ALLOWED;
+        return mAppOpsManager.noteOp(op, uid, pkgName, featureId, message)
+                == AppOpsManager.MODE_ALLOWED;
     }
 
-    private void checkPackage(int uid, String pkgName) throws SecurityException {
+    private void checkPackage(int uid, String pkgName)
+            throws SecurityException {
         if (pkgName == null) {
             throw new SecurityException("Checking UID " + uid + " but Package Name is Null");
         }
-        mAppOps.checkPackage(uid, pkgName);
-    }
-
-    private boolean isCurrentProfile(int uid) {
-        UserHandle currentUser = UserHandle.of(getCurrentUser());
-        UserHandle callingUser = UserHandle.getUserHandleForUid(uid);
-        return currentUser.equals(callingUser)
-                || mUserManager.isSameProfileGroup(currentUser, callingUser);
-    }
-
-    private boolean checkInteractAcrossUsersFull(int uid) {
-        return getUidPermission(
-                android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, uid)
-                == PackageManager.PERMISSION_GRANTED;
+        mAppOpsManager.checkPackage(uid, pkgName);
     }
 
     @VisibleForTesting
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index eb7d432..30e914d 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -34,7 +34,6 @@
 #include <string>
 
 #define DEBUG_PARCEL 0
-#define ASHMEM_BITMAP_MIN_SIZE (128 * (1 << 10))
 
 static jclass   gBitmap_class;
 static jfieldID gBitmap_nativePtr;
@@ -587,7 +586,6 @@
 
     android::Parcel* p = android::parcelForJavaObject(env, parcel);
 
-    const bool        isMutable = p->readInt32() != 0;
     const SkColorType colorType = (SkColorType)p->readInt32();
     const SkAlphaType alphaType = (SkAlphaType)p->readInt32();
     const uint32_t    colorSpaceSize = p->readUint32();
@@ -636,11 +634,10 @@
 
     // Map the bitmap in place from the ashmem region if possible otherwise copy.
     sk_sp<Bitmap> nativeBitmap;
-    if (blob.fd() >= 0 && (blob.isMutable() || !isMutable) && (size >= ASHMEM_BITMAP_MIN_SIZE)) {
+    if (blob.fd() >= 0 && !blob.isMutable()) {
 #if DEBUG_PARCEL
-        ALOGD("Bitmap.createFromParcel: mapped contents of %s bitmap from %s blob "
+        ALOGD("Bitmap.createFromParcel: mapped contents of bitmap from %s blob "
                 "(fds %s)",
-                isMutable ? "mutable" : "immutable",
                 blob.isMutable() ? "mutable" : "immutable",
                 p->allowFds() ? "allowed" : "forbidden");
 #endif
@@ -657,7 +654,7 @@
         // Map the pixels in place and take ownership of the ashmem region. We must also respect the
         // rowBytes value already set on the bitmap instead of attempting to compute our own.
         nativeBitmap = Bitmap::createFrom(bitmap->info(), bitmap->rowBytes(), dupFd,
-                                          const_cast<void*>(blob.data()), size, !isMutable);
+                                          const_cast<void*>(blob.data()), size, true);
         if (!nativeBitmap) {
             close(dupFd);
             blob.release();
@@ -695,7 +692,7 @@
     }
 
     return createBitmap(env, nativeBitmap.release(),
-            getPremulBitmapCreateFlags(isMutable), NULL, NULL, density);
+            getPremulBitmapCreateFlags(false), NULL, NULL, density);
 #else
     doThrowRE(env, "Cannot use parcels outside of Android");
     return NULL;
@@ -703,9 +700,7 @@
 }
 
 static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
-                                     jlong bitmapHandle,
-                                     jboolean isMutable, jint density,
-                                     jobject parcel) {
+                                     jlong bitmapHandle, jint density, jobject parcel) {
 #ifdef __ANDROID__ // Layoutlib does not support parcel
     if (parcel == NULL) {
         SkDebugf("------- writeToParcel null parcel\n");
@@ -718,7 +713,6 @@
     auto bitmapWrapper = reinterpret_cast<BitmapWrapper*>(bitmapHandle);
     bitmapWrapper->getSkBitmap(&bitmap);
 
-    p->writeInt32(isMutable);
     p->writeInt32(bitmap.colorType());
     p->writeInt32(bitmap.alphaType());
     SkColorSpace* colorSpace = bitmap.colorSpace();
@@ -745,7 +739,7 @@
     // Transfer the underlying ashmem region if we have one and it's immutable.
     android::status_t status;
     int fd = bitmapWrapper->bitmap().getAshmemFd();
-    if (fd >= 0 && !isMutable && p->allowFds()) {
+    if (fd >= 0 && p->allowFds()) {
 #if DEBUG_PARCEL
         ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as "
                 "immutable blob (fds %s)",
@@ -761,17 +755,14 @@
     }
 
     // Copy the bitmap to a new blob.
-    bool mutableCopy = isMutable;
 #if DEBUG_PARCEL
-    ALOGD("Bitmap.writeToParcel: copying %s bitmap into new %s blob (fds %s)",
-            isMutable ? "mutable" : "immutable",
-            mutableCopy ? "mutable" : "immutable",
+    ALOGD("Bitmap.writeToParcel: copying bitmap into new blob (fds %s)",
             p->allowFds() ? "allowed" : "forbidden");
 #endif
 
     size_t size = bitmap.computeByteSize();
     android::Parcel::WritableBlob blob;
-    status = p->writeBlob(size, mutableCopy, &blob);
+    status = p->writeBlob(size, false, &blob);
     if (status) {
         doThrowRE(env, "Could not copy bitmap to parcel blob.");
         return JNI_FALSE;
@@ -1109,7 +1100,7 @@
     {   "nativeCreateFromParcel",
         "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
         (void*)Bitmap_createFromParcel },
-    {   "nativeWriteToParcel",      "(JZILandroid/os/Parcel;)Z",
+    {   "nativeWriteToParcel",      "(JILandroid/os/Parcel;)Z",
         (void*)Bitmap_writeToParcel },
     {   "nativeExtractAlpha",       "(JJ[I)Landroid/graphics/Bitmap;",
         (void*)Bitmap_extractAlpha },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index fdfac97..020a835 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -94,7 +94,6 @@
     <protected-broadcast android:name="android.intent.action.OVERLAY_CHANGED" />
     <protected-broadcast android:name="android.intent.action.OVERLAY_REMOVED" />
     <protected-broadcast android:name="android.intent.action.OVERLAY_PRIORITY_CHANGED" />
-    <protected-broadcast android:name="android.intent.action.USER_ACTIVITY_NOTIFICATION" />
     <protected-broadcast android:name="android.intent.action.MY_PACKAGE_SUSPENDED" />
     <protected-broadcast android:name="android.intent.action.MY_PACKAGE_UNSUSPENDED" />
 
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index c9c47b9..20901e0 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3714,6 +3714,10 @@
             <flag name="flagRequestFingerprintGestures" value="0x00000200" />
             <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK}. -->
             <flag name="flagRequestShortcutWarningDialogSpokenFeedback" value="0x00000400" />
+            <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_SERVICE_HANDLES_DOUBLE_TAP}. -->
+            <flag name="flagServiceHandlesDoubleTap" value="0x00000800" />
+            <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_MULTI_FINGER_GESTURES}. -->
+            <flag name="flagRequestMultiFingerGestures" value="0x00001000" />
         </attr>
         <!-- Component name of an activity that allows the user to modify
              the settings for this service. This setting cannot be changed at runtime. -->
diff --git a/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java b/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java
index 895b22c..4370462 100644
--- a/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java
+++ b/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java
@@ -132,7 +132,7 @@
         BrightnessConfiguration.Builder builder =
                 new BrightnessConfiguration.Builder(LUX_LEVELS, NITS_LEVELS);
         builder.setShouldCollectColorSamples(true);
-        builder.setShortTermModelTimeout(1234L);
+        builder.setShortTermModelTimeoutMillis(1234L);
         builder.setShortTermModelLowerLuxMultiplier(0.9f);
         builder.setShortTermModelUpperLuxMultiplier(0.2f);
         builder.addCorrectionByCategory(3,
@@ -153,7 +153,7 @@
         BrightnessConfiguration.Builder builder =
                 new BrightnessConfiguration.Builder(LUX_LEVELS, NITS_LEVELS);
         builder.setShouldCollectColorSamples(true);
-        builder.setShortTermModelTimeout(123L);
+        builder.setShortTermModelTimeoutMillis(123L);
         builder.setShortTermModelLowerLuxMultiplier(0.4f);
         builder.setShortTermModelUpperLuxMultiplier(0.8f);
         builder.addCorrectionByCategory(3,
@@ -236,7 +236,7 @@
         assertNotEquals(baseConfig, colorCollectionDiffers);
 
         builder = new BrightnessConfiguration.Builder(LUX_LEVELS, NITS_LEVELS);
-        builder.setShortTermModelTimeout(300L);
+        builder.setShortTermModelTimeoutMillis(300L);
         BrightnessConfiguration timeoutDiffers = builder.build();
         assertNotEquals(baseConfig, timeoutDiffers);
 
diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestRunner.java b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestRunner.java
index 70c266a..ac63853 100644
--- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestRunner.java
+++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestRunner.java
@@ -58,7 +58,7 @@
         }
         // enable verbose wifi logging
         ((WifiManager)getContext().getSystemService(Context.WIFI_SERVICE))
-            .enableVerboseLogging(1);
+                .setVerboseLoggingEnabled(true);
         super.onCreate(icicle);
     }
 
diff --git a/core/tests/utiltests/src/com/android/internal/util/ConnectivityUtilTest.java b/core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java
similarity index 84%
rename from core/tests/utiltests/src/com/android/internal/util/ConnectivityUtilTest.java
rename to core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java
index 0809f69..6010f39 100644
--- a/core/tests/utiltests/src/com/android/internal/util/ConnectivityUtilTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java
@@ -28,6 +28,7 @@
 import static org.mockito.Mockito.when;
 
 import android.Manifest;
+import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -48,8 +49,8 @@
 
 import java.util.HashMap;
 
-/** Unit tests for {@link ConnectivityUtil}. */
-public class ConnectivityUtilTest {
+/** Unit tests for {@link LocationPermissionChecker}. */
+public class LocationPermissionCheckerTest {
 
     public static final String TAG = "ConnectivityUtilTest";
 
@@ -85,18 +86,7 @@
     private boolean mThrowSecurityException;
     private Answer<Integer> mReturnPermission;
     private HashMap<String, Integer> mPermissionsList = new HashMap<String, Integer>();
-
-    private class TestConnectivityUtil extends ConnectivityUtil {
-
-        TestConnectivityUtil(Context context) {
-            super(context);
-        }
-
-        @Override
-        protected int getCurrentUser() {
-            return mCurrentUser;
-        }
-    }
+    private LocationPermissionChecker mChecker;
 
     @Before
     public void setUp() {
@@ -141,11 +131,12 @@
         mThrowSecurityException = true;
         mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.M;
         mIsLocationEnabled = false;
-        mCurrentUser = UserHandle.USER_SYSTEM;
+        mCurrentUser = ActivityManager.getCurrentUser();
         mCoarseLocationPermission = PackageManager.PERMISSION_DENIED;
         mFineLocationPermission = PackageManager.PERMISSION_DENIED;
         mAllowCoarseLocationApps = AppOpsManager.MODE_ERRORED;
         mAllowFineLocationApps = AppOpsManager.MODE_ERRORED;
+        mChecker = new LocationPermissionChecker(mMockContext);
     }
 
     private void setupMockInterface() {
@@ -189,8 +180,7 @@
         mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
         mUid = mCurrentUser;
         setupTestCase();
-        new TestConnectivityUtil(mMockContext)
-                .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null);
+        mChecker.enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null);
     }
 
     @Test
@@ -203,8 +193,7 @@
         mAllowFineLocationApps = AppOpsManager.MODE_ALLOWED;
         mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
         setupTestCase();
-        new TestConnectivityUtil(mMockContext)
-                .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null);
+        mChecker.enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null);
     }
 
     @Test
@@ -217,22 +206,8 @@
         setupTestCase();
 
         assertThrows(SecurityException.class,
-                () -> new TestConnectivityUtil(mMockContext)
-                        .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
-    }
-
-    @Test
-    public void testenforceCanAccessScanResults_UserOrProfileNotCurrent() throws Exception {
-        mIsLocationEnabled = true;
-        mThrowSecurityException = false;
-        mCoarseLocationPermission = PackageManager.PERMISSION_GRANTED;
-        mAllowCoarseLocationApps = AppOpsManager.MODE_ALLOWED;
-        mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
-        setupTestCase();
-
-        assertThrows(SecurityException.class,
-                () -> new TestConnectivityUtil(mMockContext)
-                        .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
+                () -> mChecker.enforceLocationPermission(
+                        TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
     }
 
     @Test
@@ -241,8 +216,8 @@
         mIsLocationEnabled = true;
         setupTestCase();
         assertThrows(SecurityException.class,
-                () -> new TestConnectivityUtil(mMockContext)
-                        .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
+                () -> mChecker.enforceLocationPermission(
+                        TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
     }
 
     @Test
@@ -256,8 +231,8 @@
         setupTestCase();
 
         assertThrows(SecurityException.class,
-                () -> new TestConnectivityUtil(mMockContext)
-                        .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
+                () -> mChecker.enforceLocationPermission(
+                        TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
         verify(mMockAppOps, never()).noteOp(anyInt(), anyInt(), anyString());
     }
 
@@ -272,8 +247,8 @@
         setupTestCase();
 
         assertThrows(SecurityException.class,
-                () -> new TestConnectivityUtil(mMockContext)
-                        .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
+                () -> mChecker.enforceLocationPermission(
+                        TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
     }
 
     private static void assertThrows(Class<? extends Exception> exceptionClass, Runnable r) {
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 1e98e3a..79589bf 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -697,12 +697,6 @@
       "group": "WM_DEBUG_REMOTE_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
     },
-    "-650040763": {
-      "message": "rotationForOrientation(orient=%d, last=%d); user=%d %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
     "-635082269": {
       "message": "******** booted=%b msg=%b haveBoot=%b haveApp=%b haveWall=%b wallEnabled=%b haveKeyguard=%b",
       "level": "INFO",
@@ -901,6 +895,12 @@
       "group": "WM_DEBUG_WINDOW_MOVEMENT",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-177040661": {
+      "message": "Start rotation animation. customAnim=%s, mCurRotation=%s, mOriginalRotation=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
+    },
     "-167822951": {
       "message": "Attempted to add starting window to token with already existing starting window",
       "level": "WARN",
@@ -1105,6 +1105,12 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
     },
+    "202263690": {
+      "message": "rotationForOrientation(orient=%s (%d), last=%s (%d)); user=%s (%d) %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
     "221540118": {
       "message": "mUserActivityTimeout set to %d",
       "level": "DEBUG",
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index ac094ba..9c2e95f 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -2132,7 +2132,7 @@
     public void writeToParcel(Parcel p, int flags) {
         checkRecycled("Can't parcel a recycled bitmap");
         noteHardwareBitmapSlowCall();
-        if (!nativeWriteToParcel(mNativePtr, isMutable(), mDensity, p)) {
+        if (!nativeWriteToParcel(mNativePtr, mDensity, p)) {
             throw new RuntimeException("native writeToParcel failed");
         }
     }
@@ -2285,7 +2285,6 @@
     private static native Bitmap nativeCreateFromParcel(Parcel p);
     // returns true on success
     private static native boolean nativeWriteToParcel(long nativeBitmap,
-                                                      boolean isMutable,
                                                       int density,
                                                       Parcel p);
     // returns a new bitmap built from the native bitmap's alpha, and the paint
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index f61d55e..57405d7 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -52,6 +52,7 @@
  * <tr><td>{@link #KEY_PIXEL_ASPECT_RATIO_WIDTH}</td><td>Integer</td><td>optional, the pixel aspect ratio width</td></tr>
  * <tr><td>{@link #KEY_PIXEL_ASPECT_RATIO_HEIGHT}</td><td>Integer</td><td>optional, the pixel aspect ratio height</td></tr>
  * <tr><td>{@link #KEY_BIT_RATE}</td><td>Integer</td><td><b>encoder-only</b>, desired bitrate in bits/second</td></tr>
+ * <tr><td>{@link #KEY_DURATION}</td><td>long</td><td>the duration of the content (in microseconds)</td></tr>
  * </table>
  *
  * Video formats have the following keys:
diff --git a/native/graphics/jni/imagedecoder.cpp b/native/graphics/jni/imagedecoder.cpp
index 79bcc15..c1143ce 100644
--- a/native/graphics/jni/imagedecoder.cpp
+++ b/native/graphics/jni/imagedecoder.cpp
@@ -325,11 +325,9 @@
 
     ImageDecoder* imageDecoder = toDecoder(decoder);
 
-    const int height = imageDecoder->getOutputInfo().height();
-    const size_t minStride = AImageDecoder_getMinimumStride(decoder);
-    // If this calculation were to overflow, it would have been caught in
-    // setTargetSize.
-    if (stride < minStride || size < stride * (height - 1) + minStride) {
+    SkImageInfo info = imageDecoder->getOutputInfo();
+    size_t minSize = info.computeByteSize(stride);
+    if (SkImageInfo::ByteSizeOverflowed(minSize) || size < minSize || !info.validRowBytes(stride)) {
         return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
     }
 
diff --git a/packages/CarSystemUI/res/values/config.xml b/packages/CarSystemUI/res/values/config.xml
index 981c129..e2297e4 100644
--- a/packages/CarSystemUI/res/values/config.xml
+++ b/packages/CarSystemUI/res/values/config.xml
@@ -80,5 +80,6 @@
         <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>
         <item>com.android.systemui.theme.ThemeOverlayController</item>
         <item>com.android.systemui.navigationbar.car.CarNavigationBar</item>
+        <item>com.android.systemui.toast.ToastUI</item>
     </string-array>
 </resources>
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
index 0bd2e06..07b7b22 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
@@ -32,6 +32,7 @@
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.tv.TvStatusBar;
 import com.android.systemui.theme.ThemeOverlayController;
+import com.android.systemui.toast.ToastUI;
 import com.android.systemui.util.leak.GarbageMonitor;
 import com.android.systemui.volume.VolumeUI;
 
@@ -163,4 +164,10 @@
     @IntoMap
     @ClassKey(VolumeUI.class)
     public abstract SystemUI bindVolumeUI(VolumeUI sysui);
+
+    /** Inject into ToastUI. */
+    @Binds
+    @IntoMap
+    @ClassKey(ToastUI.class)
+    public abstract SystemUI bindToastUI(ToastUI service);
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 9d4c24e..84dde05 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -1141,7 +1141,7 @@
         } else if (isActive()) {
             summary.append(getSummary(mContext, /* ssid */ null, getDetailedState(),
                     mInfo != null && mInfo.isEphemeral(),
-                    mInfo != null ? mInfo.getAppPackageName() : null));
+                    mInfo != null ? mInfo.getRequestingPackageName() : null));
         } else { // not active
             if (mConfig != null && mConfig.hasNoInternetAccess()) {
                 int messageID = mConfig.getNetworkSelectionStatus().isNetworkPermanentlyDisabled()
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index ed4ff08..26abf71 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -226,7 +226,7 @@
         mConnectivityManager = connectivityManager;
 
         // check if verbose logging developer option has been turned on or off
-        sVerboseLogging = mWifiManager != null && (mWifiManager.getVerboseLoggingLevel() > 0);
+        sVerboseLogging = mWifiManager != null && mWifiManager.isVerboseLoggingEnabled();
 
         mFilter = filter;
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
index b93b000..78ccba0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
@@ -102,10 +102,10 @@
             if (accessPoint.getSpeed() != AccessPoint.Speed.NONE) {
                 visibility.append(" speed=").append(accessPoint.getSpeedLabel());
             }
-            visibility.append(String.format(" tx=%.1f,", info.getTxSuccessRate()));
-            visibility.append(String.format("%.1f,", info.getTxRetriesRate()));
-            visibility.append(String.format("%.1f ", info.getTxBadRate()));
-            visibility.append(String.format("rx=%.1f", info.getRxSuccessRate()));
+            visibility.append(String.format(" tx=%.1f,", info.getSuccessfulTxPacketsPerSecond()));
+            visibility.append(String.format("%.1f,", info.getRetriedTxPacketsPerSecond()));
+            visibility.append(String.format("%.1f ", info.getLostTxPacketsPerSecond()));
+            visibility.append(String.format("rx=%.1f", info.getSuccessfulRxPacketsPerSecond()));
         }
 
         int maxRssi5 = INVALID_RSSI;
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index 03201ae..42f3cbb 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -507,7 +507,7 @@
         WifiInfo wifiInfo = new WifiInfo();
         wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(TEST_SSID));
         wifiInfo.setEphemeral(true);
-        wifiInfo.setAppPackageName(appPackageName);
+        wifiInfo.setRequestingPackageName(appPackageName);
         wifiInfo.setRssi(rssi);
 
         Context context = mock(Context.class);
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 30ad9c5..48d405a 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -156,7 +156,6 @@
     static final String EXTRA_BUGREPORT_TYPE = "android.intent.extra.BUGREPORT_TYPE";
     static final String EXTRA_SCREENSHOT = "android.intent.extra.SCREENSHOT";
     static final String EXTRA_ID = "android.intent.extra.ID";
-    static final String EXTRA_MAX = "android.intent.extra.MAX";
     static final String EXTRA_NAME = "android.intent.extra.NAME";
     static final String EXTRA_TITLE = "android.intent.extra.TITLE";
     static final String EXTRA_DESCRIPTION = "android.intent.extra.DESCRIPTION";
@@ -173,7 +172,6 @@
 
     // Maximum progress displayed in %.
     private static final int CAPPED_PROGRESS = 99;
-    private static final int CAPPED_MAX = 100;
 
     /** Show the progress log every this percent. */
     private static final int LOG_PROGRESS_STEP = 10;
@@ -528,12 +526,10 @@
             }
             final String action = intent.getAction();
             final int id = intent.getIntExtra(EXTRA_ID, 0);
-            final int max = intent.getIntExtra(EXTRA_MAX, -1);
             final String name = intent.getStringExtra(EXTRA_NAME);
 
             if (DEBUG)
-                Log.v(TAG, "action: " + action + ", name: " + name + ", id: " + id
-                        + ", max: " + max);
+                Log.v(TAG, "action: " + action + ", name: " + name + ", id: " + id);
             switch (action) {
                 case INTENT_BUGREPORT_REQUESTED:
                     startBugreportAPI(intent);
@@ -608,7 +604,7 @@
         String name = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date());
 
         BugreportInfo info = new BugreportInfo(mContext, baseName, name,
-                100 /* max progress*/, shareTitle, shareDescription, bugreportType);
+                shareTitle, shareDescription, bugreportType);
 
         ParcelFileDescriptor bugreportFd = info.createBugreportFd();
         if (bugreportFd == null) {
@@ -662,8 +658,8 @@
      * Updates the system notification for a given bugreport.
      */
     private void updateProgress(BugreportInfo info) {
-        if (info.max <= 0 || info.progress < 0) {
-            Log.e(TAG, "Invalid progress values for " + info);
+        if (info.progress < 0) {
+            Log.e(TAG, "Invalid progress value for " + info);
             return;
         }
 
@@ -676,7 +672,7 @@
         final NumberFormat nf = NumberFormat.getPercentInstance();
         nf.setMinimumFractionDigits(2);
         nf.setMaximumFractionDigits(2);
-        final String percentageText = nf.format((double) info.progress / info.max);
+        final String percentageText = nf.format((double) info.progress / 100);
 
         String title = mContext.getString(R.string.bugreport_in_progress_title, info.id);
 
@@ -684,7 +680,7 @@
         if (mIsWatch) {
             nf.setMinimumFractionDigits(0);
             nf.setMaximumFractionDigits(0);
-            final String watchPercentageText = nf.format((double) info.progress / info.max);
+            final String watchPercentageText = nf.format((double) info.progress / 100);
             title = title + "\n" + watchPercentageText;
         }
 
@@ -695,7 +691,7 @@
                 .setContentTitle(title)
                 .setTicker(title)
                 .setContentText(name)
-                .setProgress(info.max, info.progress, false)
+                .setProgress(100 /* max value of progress percentage */, info.progress, false)
                 .setOngoing(true);
 
         // Wear and ATV bugreport doesn't need the bug info dialog, screenshot and cancel action.
@@ -724,7 +720,7 @@
                 .setActions(infoAction, screenshotAction, cancelAction);
         }
         // Show a debug log, every LOG_PROGRESS_STEP percent.
-        final int progress = (info.progress * 100) / info.max;
+        final int progress = info.progress;
 
         if ((info.progress == 0) || (info.progress >= 100) ||
                 ((progress / LOG_PROGRESS_STEP) != (mLastProgressPercent / LOG_PROGRESS_STEP))) {
@@ -1457,7 +1453,6 @@
         }
         final StringBuilder buffer = new StringBuilder(action).append(" extras: ");
         addExtra(buffer, intent, EXTRA_ID);
-        addExtra(buffer, intent, EXTRA_MAX);
         addExtra(buffer, intent, EXTRA_NAME);
         addExtra(buffer, intent, EXTRA_DESCRIPTION);
         addExtra(buffer, intent, EXTRA_BUGREPORT);
@@ -1761,26 +1756,11 @@
         String description;
 
         /**
-         * Maximum progress of the bugreport generation as displayed by the UI.
-         */
-        int max;
-
-        /**
-         * Current progress of the bugreport generation as displayed by the UI.
+         * Current progress (in percentage) of the bugreport generation as displayed by the UI.
          */
         int progress;
 
         /**
-         * Maximum progress of the bugreport generation as reported by dumpstate.
-         */
-        int realMax;
-
-        /**
-         * Current progress of the bugreport generation as reported by dumpstate.
-         */
-        int realProgress;
-
-        /**
          * Time of the last progress update.
          */
         long lastUpdate = System.currentTimeMillis();
@@ -1831,12 +1811,11 @@
         /**
          * Constructor for tracked bugreports - typically called upon receiving BUGREPORT_REQUESTED.
          */
-        BugreportInfo(Context context, String baseName, String name, int max,
+        BugreportInfo(Context context, String baseName, String name,
                 @Nullable String shareTitle, @Nullable String shareDescription,
                 @BugreportParams.BugreportMode int type) {
             this.context = context;
             this.name = this.initialName = name;
-            this.max = this.realMax = max;
             this.shareTitle = shareTitle == null ? "" : shareTitle;
             this.shareDescription = shareDescription == null ? "" : shareDescription;
             this.type = type;
@@ -1930,8 +1909,6 @@
 
         @Override
         public String toString() {
-            final float percent = ((float) progress * 100 / max);
-            final float realPercent = ((float) realProgress * 100 / realMax);
 
             final StringBuilder builder = new StringBuilder()
                     .append("\tid: ").append(id)
@@ -1953,10 +1930,7 @@
             return builder
                 .append("\n\tfile: ").append(bugreportFile)
                 .append("\n\tscreenshots: ").append(screenshotFiles)
-                .append("\n\tprogress: ").append(progress).append("/").append(max)
-                .append(" (").append(percent).append(")")
-                .append("\n\treal progress: ").append(realProgress).append("/").append(realMax)
-                .append(" (").append(realPercent).append(")")
+                .append("\n\tprogress: ").append(progress)
                 .append("\n\tlast_update: ").append(getFormattedLastUpdate())
                 .append("\n\taddingDetailsToZip: ").append(addingDetailsToZip)
                 .append(" addedDetailsToZip: ").append(addedDetailsToZip)
@@ -1974,10 +1948,7 @@
             initialName = in.readString();
             title = in.readString();
             description = in.readString();
-            max = in.readInt();
             progress = in.readInt();
-            realMax = in.readInt();
-            realProgress = in.readInt();
             lastUpdate = in.readLong();
             formattedLastUpdate = in.readString();
             bugreportFile = readFile(in);
@@ -2001,10 +1972,7 @@
             dest.writeString(initialName);
             dest.writeString(title);
             dest.writeString(description);
-            dest.writeInt(max);
             dest.writeInt(progress);
-            dest.writeInt(realMax);
-            dest.writeInt(realProgress);
             dest.writeLong(lastUpdate);
             dest.writeString(getFormattedLastUpdate());
             writeFile(dest, bugreportFile);
@@ -2055,22 +2023,13 @@
         if (progress > CAPPED_PROGRESS) {
             progress = CAPPED_PROGRESS;
         }
-        updateProgressInfo(info, progress, CAPPED_MAX);
-    }
-
-    private void updateProgressInfo(BugreportInfo info, int progress, int max) {
         if (DEBUG) {
             if (progress != info.progress) {
                 Log.v(TAG, "Updating progress for name " + info.name + "(id: " + info.id
                         + ") from " + info.progress + " to " + progress);
             }
-            if (max != info.max) {
-                Log.v(TAG, "Updating max progress for name " + info.name + "(id: " + info.id
-                        + ") from " + info.max + " to " + max);
-            }
         }
         info.progress = progress;
-        info.max = max;
         info.lastUpdate = System.currentTimeMillis();
 
         updateProgress(info);
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index bb298e9..b95092a 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -27,7 +27,6 @@
 import static com.android.shell.BugreportPrefs.setWarningState;
 import static com.android.shell.BugreportProgressService.EXTRA_BUGREPORT;
 import static com.android.shell.BugreportProgressService.EXTRA_ID;
-import static com.android.shell.BugreportProgressService.EXTRA_MAX;
 import static com.android.shell.BugreportProgressService.EXTRA_NAME;
 import static com.android.shell.BugreportProgressService.EXTRA_SCREENSHOT;
 import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_FINISHED;
@@ -144,6 +143,7 @@
     private static final String DESCRIPTION = "One's description...";
     private static final String DESCRIPTION2 = "...is another's treasure.";
     // TODO(b/143130523): Fix (update) tests and add to presubmit
+    private static final String EXTRA_MAX = "android.intent.extra.MAX";
     private static final String EXTRA_PID = "android.intent.extra.PID";
     private static final String INTENT_BUGREPORT_STARTED =
             "com.android.internal.intent.action.BUGREPORT_STARTED";
diff --git a/packages/SystemUI/res/color/light_background.xml b/packages/SystemUI/res/color/light_background.xml
new file mode 100644
index 0000000..2effd99
--- /dev/null
+++ b/packages/SystemUI/res/color/light_background.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+  <item android:state_enabled="false"
+        android:color="@color/control_default_background" />
+  <item android:color="@color/GM2_yellow_50" />
+</selector>
diff --git a/packages/SystemUI/res/color/light_foreground.xml b/packages/SystemUI/res/color/light_foreground.xml
new file mode 100644
index 0000000..8143028
--- /dev/null
+++ b/packages/SystemUI/res/color/light_foreground.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+  <item android:state_enabled="false"
+        android:color="@color/control_default_foreground" />
+  <item android:color="@color/GM2_orange_900" />
+</selector>
diff --git a/packages/SystemUI/res/color/lock_background.xml b/packages/SystemUI/res/color/lock_background.xml
new file mode 100644
index 0000000..646fe5d
--- /dev/null
+++ b/packages/SystemUI/res/color/lock_background.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+  <item android:state_enabled="false"
+        android:color="@color/control_default_background" />
+  <item android:color="@color/GM2_blue_50" />
+</selector>
diff --git a/packages/SystemUI/res/color/lock_foreground.xml b/packages/SystemUI/res/color/lock_foreground.xml
new file mode 100644
index 0000000..3e05653
--- /dev/null
+++ b/packages/SystemUI/res/color/lock_foreground.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+  <item android:state_enabled="false"
+        android:color="@color/control_default_foreground" />
+  <item android:color="@color/GM2_blue_700" />
+</selector>
diff --git a/packages/SystemUI/res/color/unknown_foreground.xml b/packages/SystemUI/res/color/unknown_foreground.xml
new file mode 100644
index 0000000..bf028f1
--- /dev/null
+++ b/packages/SystemUI/res/color/unknown_foreground.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+   <item android:state_enabled="false"
+         android:color="@color/control_default_foreground" />
+   <item android:color="@color/GM2_blue_700" />
+ </selector>
diff --git a/packages/SystemUI/res/drawable/control_background.xml b/packages/SystemUI/res/drawable/control_background.xml
new file mode 100644
index 0000000..b246ea0
--- /dev/null
+++ b/packages/SystemUI/res/drawable/control_background.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright 2020, 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.
+*/
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+  <item>
+    <shape>
+      <solid android:color="?android:attr/colorBackgroundFloating"/>
+      <corners android:radius="@dimen/control_corner_radius" />
+    </shape>
+  </item>
+  <item
+      android:id="@+id/clip_layer">
+    <clip
+        android:clipOrientation="horizontal"
+        android:drawable="@drawable/control_layer"/>
+  </item>
+</layer-list>
diff --git a/packages/SystemUI/res/drawable/control_layer.xml b/packages/SystemUI/res/drawable/control_layer.xml
new file mode 100644
index 0000000..fe8c4a4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/control_layer.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright 2020, The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+  <solid android:color="@android:color/transparent"/>
+  <corners android:radius="@dimen/control_corner_radius" />
+</shape>
diff --git a/packages/SystemUI/res/drawable/control_no_favorites_background.xml b/packages/SystemUI/res/drawable/control_no_favorites_background.xml
new file mode 100644
index 0000000..1e282ad
--- /dev/null
+++ b/packages/SystemUI/res/drawable/control_no_favorites_background.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright 2020, The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+  <stroke android:width="1dp" android:color="?android:attr/colorBackgroundFloating"/>
+  <corners android:radius="@dimen/control_corner_radius" />
+</shape>
diff --git a/packages/SystemUI/res/drawable/ic_device_thermostat_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_device_thermostat_gm2_24px.xml
new file mode 100644
index 0000000..45a658f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_device_thermostat_gm2_24px.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M18,9h-5v2h5m3,-6h-8v2h8m-9,11.97c0.62,-0.83 1,-1.85 1,-2.97 0,-1.63 -0.79,-3.09 -2,-4V6c0,-1.66 -1.34,-3 -3,-3S5,4.34 5,6v6c-1.21,0.91 -2,2.37 -2,4 0,1.12 0.38,2.14 1,2.97V19h0.02c0.91,1.21 2.35,2 3.98,2s3.06,-0.79 3.98,-2H12v-0.03zM6.2,13.6L7,13V6c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v7l0.8,0.6c0.75,0.57 1.2,1.46 1.2,2.4H5c0,-0.94 0.45,-1.84 1.2,-2.4z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_light_off_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_light_off_gm2_24px.xml
new file mode 100644
index 0000000..78c3cc5
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_light_off_gm2_24px.xml
@@ -0,0 +1,19 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M9,21v-1h6v1c0,0.55 -0.45,1 -1,1h-4c-0.55,0 -1,-0.45 -1,-1z"/>
+  <group>
+    <clip-path android:pathData="M0,0h24v24H0z M 0,0"/>
+  </group>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M12,2c-1.89,0 -3.6,0.75 -4.86,1.97l1.41,1.41C9.45,4.53 10.67,4 12,4c2.76,0 5,2.24 5,5 0,1.28 -0.5,2.5 -1.36,3.42l-0.02,0.02 1.41,1.41C18.25,12.6 19,10.89 19,9c0,-3.86 -3.14,-7 -7,-7z"
+      android:fillType="evenOdd"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M2.92,2.29L1.65,3.57l3.59,3.59C5.09,7.75 5,8.36 5,9c0,2.38 1.19,4.47 3,5.74V17c0,0.55 0.45,1 1,1h6c0.3,0 0.57,-0.13 0.75,-0.34L20.09,22l1.27,-1.27L2.92,2.29zM10,16v-2.3l-0.85,-0.6C7.8,12.16 7,10.63 7,9v-0.08L14.09,16H10z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_lock_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_lock_gm2_24px.xml
new file mode 100644
index 0000000..f4299e6
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_lock_gm2_24px.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM9,6c0,-1.66 1.34,-3 3,-3s3,1.34 3,3v2L9,8L9,6zM18,20L6,20L6,10h12v10zM12,17c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_lock_open_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_lock_open_gm2_24px.xml
new file mode 100644
index 0000000..59fe0a9
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_lock_open_gm2_24px.xml
@@ -0,0 +1,12 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6h2c0,-1.66 1.34,-3 3,-3s3,1.34 3,3v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM18,20L6,20L6,10h12v10z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M12,15m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_more_vert.xml b/packages/SystemUI/res/drawable/ic_more_vert.xml
new file mode 100644
index 0000000..1309fa8
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_more_vert.xml
@@ -0,0 +1,24 @@
+<!--
+    Copyright (C) 2020 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_power_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_power_gm2_24px.xml
new file mode 100644
index 0000000..cd95719
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_power_gm2_24px.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M16,9v4.66l-3.5,3.51V19h-1v-1.83L8,13.65V9h8m0,-6h-2v4h-4V3H8v4h-0.01C6.9,6.99 6,7.89 6,8.98v5.52L9.5,18v3h5v-3l3.5,-3.51V9c0,-1.1 -0.9,-2 -2,-2V3z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_power_off_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_power_off_gm2_24px.xml
new file mode 100644
index 0000000..3eb7dd6
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_power_off_gm2_24px.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M21.19,21.19L2.81,2.81 1.39,4.22l4.63,4.63L6,14.5 9.5,18v3h5v-3l0.34,-0.34 4.94,4.94 1.41,-1.41zM12.5,17.17L12.5,19h-1v-1.83L8,13.65v-2.83l5.42,5.42 -0.92,0.93zM11.83,9L8,5.17L8,3h2v4h4L14,3h2v4c1.1,0 2,0.9 2,2v5.49l-0.34,0.34L16,13.17L16,9h-4.17z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_power_settings_new_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_power_settings_new_gm2_24px.xml
new file mode 100644
index 0000000..f4edd87
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_power_settings_new_gm2_24px.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M11,2h2v10h-2zM18.37,5.64l-1.41,1.41c2.73,2.73 2.72,7.16 -0.01,9.89 -2.73,2.73 -7.17,2.73 -9.89,0.01 -2.73,-2.73 -2.74,-7.18 -0.01,-9.91l-1.41,-1.4c-3.51,3.51 -3.51,9.21 0.01,12.73 3.51,3.51 9.21,3.51 12.72,-0.01 3.51,-3.51 3.51,-9.2 0,-12.72z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_switches_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_switches_gm2_24px.xml
new file mode 100644
index 0000000..bb535ce
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_switches_gm2_24px.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M19,9h-8.02C10.06,7.79 8.63,7 7,7c-2.76,0 -5,2.24 -5,5s2.24,5 5,5c1.63,0 3.06,-0.79 3.98,-2H19c1.66,0 3,-1.34 3,-3S20.66,9 19,9zM19,13h-7.1c0.07,-0.32 0.1,-0.66 0.1,-1s-0.04,-0.68 -0.1,-1H19c0.55,0 1,0.45 1,1S19.55,13 19,13z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_vacuum_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_vacuum_gm2_24px.xml
new file mode 100644
index 0000000..86b9591
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_vacuum_gm2_24px.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M4,16c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3zM4,20c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM23,20v2h-7v-2h2.49L12.01,4.59C11.6,3.63 10.66,3 9.61,3 8.17,3 7,4.17 7,5.61L7,9h2c2.21,0 4,1.79 4,4v9L7.99,22c0.44,-0.58 0.76,-1.26 0.91,-2L11,20v-7c0,-1.1 -0.9,-2 -2,-2L4,11v3c-0.71,0 -1.39,0.15 -2,0.42L2,9h3L5,5.61C5,3.07 7.07,1 9.61,1c1.86,0 3.53,1.11 4.25,2.82L20.66,20L23,20z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_videocam_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_videocam_gm2_24px.xml
new file mode 100644
index 0000000..687c9c4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_videocam_gm2_24px.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M18,10.48L18,6c0,-1.1 -0.9,-2 -2,-2L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2v-4.48l4,3.98v-11l-4,3.98zM16,9.69L16,18L4,18L4,6h12v3.69z"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/controls_base_item.xml b/packages/SystemUI/res/layout/controls_base_item.xml
new file mode 100644
index 0000000..3c4c61e
--- /dev/null
+++ b/packages/SystemUI/res/layout/controls_base_item.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2020 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.
+-->
+<androidx.constraintlayout.widget.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="0dp"
+    android:layout_weight="1"
+    android:layout_height="@dimen/control_height"
+    android:padding="@dimen/control_padding"
+    android:clickable="true"
+    android:focusable="true"
+    android:layout_marginLeft="3dp"
+    android:layout_marginRight="3dp"
+    android:background="@drawable/control_background">
+
+    <ImageView
+        android:id="@+id/icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <TextView
+        android:id="@+id/status"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textSize="@dimen/control_status_normal"
+        android:textColor="?android:attr/textColorPrimary"
+        android:fontFamily="@*android:string/config_bodyFontFamily"
+        android:paddingLeft="3dp"
+        app:layout_constraintBottom_toBottomOf="@+id/icon"
+        app:layout_constraintStart_toEndOf="@+id/icon" />
+
+    <TextView
+        android:id="@+id/status_extra"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textSize="@dimen/control_status_normal"
+        android:textColor="?android:attr/textColorPrimary"
+        android:fontFamily="@*android:string/config_bodyFontFamily"
+        android:paddingLeft="3dp"
+        app:layout_constraintBottom_toBottomOf="@+id/icon"
+        app:layout_constraintStart_toEndOf="@+id/status" />
+
+    <TextView
+        android:id="@+id/title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textSize="18sp"
+        android:textColor="?android:attr/textColorPrimary"
+        android:fontFamily="@*android:string/config_headlineFontFamily"
+        app:layout_constraintBottom_toTopOf="@+id/subtitle"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/icon" />
+
+    <TextView
+        android:id="@+id/subtitle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textSize="16sp"
+        android:textColor="?android:attr/textColorSecondary"
+        android:fontFamily="@*android:string/config_headlineFontFamily"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toStartOf="parent" />
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/packages/SystemUI/res/layout/controls_no_favorites.xml b/packages/SystemUI/res/layout/controls_no_favorites.xml
new file mode 100644
index 0000000..79672ca
--- /dev/null
+++ b/packages/SystemUI/res/layout/controls_no_favorites.xml
@@ -0,0 +1,18 @@
+<merge
+    xmlns:android="http://schemas.android.com/apk/res/android">
+  <TextView
+      android:id="@+id/controls_title"
+      android:text="@string/quick_controls_title"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+      android:singleLine="true"
+      android:gravity="center"
+      android:textSize="25dp"
+      android:paddingTop="40dp"
+      android:paddingBottom="40dp"
+      android:layout_marginLeft="10dp"
+      android:layout_marginRight="10dp"
+      android:textColor="?android:attr/textColorPrimary"
+      android:fontFamily="@*android:string/config_headlineFontFamily"
+      android:background="@drawable/control_no_favorites_background"/>
+</merge>
diff --git a/packages/SystemUI/res/layout/controls_row.xml b/packages/SystemUI/res/layout/controls_row.xml
new file mode 100644
index 0000000..13a6b36
--- /dev/null
+++ b/packages/SystemUI/res/layout/controls_row.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2020 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.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    orientation="horizontal"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_marginBottom="@dimen/control_spacing" />
diff --git a/packages/SystemUI/res/layout/controls_with_favorites.xml b/packages/SystemUI/res/layout/controls_with_favorites.xml
new file mode 100644
index 0000000..7804fe6
--- /dev/null
+++ b/packages/SystemUI/res/layout/controls_with_favorites.xml
@@ -0,0 +1,35 @@
+<merge
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+
+  <androidx.constraintlayout.widget.ConstraintLayout
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content">
+
+    <TextView
+        android:text="@string/quick_controls_title"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:singleLine="true"
+        android:gravity="center"
+        android:textSize="25dp"
+        android:textColor="?android:attr/textColorPrimary"
+        android:fontFamily="@*android:string/config_headlineFontFamily"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"/>
+    <ImageView
+        android:id="@+id/controls_more"
+        android:src="@drawable/ic_more_vert"
+        android:layout_width="34dp"
+        android:layout_height="24dp" 
+        android:layout_marginEnd="10dp"
+        app:layout_constraintEnd_toEndOf="parent"/>
+
+  </androidx.constraintlayout.widget.ConstraintLayout>
+
+  <LinearLayout
+      android:id="@+id/global_actions_controls_list"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+      android:orientation="vertical" />
+</merge>
diff --git a/packages/SystemUI/res/layout/global_actions_grid_v2.xml b/packages/SystemUI/res/layout/global_actions_grid_v2.xml
index 4cfb47e..6741484 100644
--- a/packages/SystemUI/res/layout/global_actions_grid_v2.xml
+++ b/packages/SystemUI/res/layout/global_actions_grid_v2.xml
@@ -111,20 +111,7 @@
         app:layout_constraintLeft_toLeftOf="parent"
         app:layout_constraintRight_toRightOf="parent"
         app:layout_constraintTop_toBottomOf="@id/global_actions_panel">
-      <TextView
-          android:text="Home"
-          android:layout_width="match_parent"
-          android:layout_height="wrap_content"
-          android:singleLine="true"
-          android:gravity="center"
-          android:textSize="25dp"
-          android:textColor="?android:attr/textColorPrimary"
-          android:fontFamily="@*android:string/config_headlineFontFamily" />
-    <LinearLayout
-        android:id="@+id/global_actions_controls_list"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical" />
+
     </LinearLayout>
   </androidx.constraintlayout.widget.ConstraintLayout>
 </ScrollView>
diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml
index 4cc5a67..dd4c321 100644
--- a/packages/SystemUI/res/values-television/config.xml
+++ b/packages/SystemUI/res/values-television/config.xml
@@ -36,5 +36,6 @@
         <item>com.android.systemui.SliceBroadcastRelayHandler</item>
         <item>com.android.systemui.SizeCompatModeActivityController</item>
         <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>
+        <item>com.android.systemui.toast.ToastUI</item>
     </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 8dd2a8b..09058f2 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -200,18 +200,28 @@
     <color name="GM2_grey_800">#3C4043</color>
     <color name="GM2_grey_900">#202124</color>
 
+    <color name="GM2_red_50">#FCE8E6</color>
     <color name="GM2_red_300">#F28B82</color>
     <color name="GM2_red_500">#B71C1C</color>
     <color name="GM2_red_700">#C5221F</color>
 
+    <color name="GM2_blue_50">#E8F0FE</color>
     <color name="GM2_blue_200">#AECBFA</color>
     <color name="GM2_blue_300">#8AB4F8</color>
+    <color name="GM2_blue_500">#FF4285F4</color>
     <color name="GM2_blue_600">#1A73E8</color>
     <color name="GM2_blue_700">#1967D2</color>
 
+    <color name="GM2_yellow_50">#FEF7E0</color>
     <color name="GM2_yellow_500">#FFFBBC04</color>
+
     <color name="GM2_green_500">#FF34A853</color>
-    <color name="GM2_blue_500">#FF4285F4</color>
+
+    <color name="GM2_orange_900">#B06000</color>
 
     <color name="magnification_border_color">#FF9900</color>
+
+    <!-- controls -->
+    <color name="control_default_foreground">?android:attr/textColorPrimary</color>
+    <color name="control_default_background">?android:attr/colorBackgroundFloating</color>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index edcd801..2aa6d95 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -297,6 +297,7 @@
         <item>com.android.systemui.theme.ThemeOverlayController</item>
         <item>com.android.systemui.accessibility.WindowMagnification</item>
         <item>com.android.systemui.accessibility.SystemActions</item>
+        <item>com.android.systemui.toast.ToastUI</item>
     </string-array>
 
     <!-- SystemUI vender service, used in config_systemUIServiceComponents. -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index b40c5c0..cc58b20 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1181,5 +1181,12 @@
     <dimen name="magnifier_up_down_controls_width">45dp</dimen>
     <dimen name="magnifier_up_down_controls_height">40dp</dimen>
 
+    <!-- Home Controls -->
+    <dimen name="control_spacing">5dp</dimen>
+    <dimen name="control_corner_radius">15dp</dimen>
+    <dimen name="control_height">100dp</dimen>
+    <dimen name="control_padding">15dp</dimen>
+    <dimen name="control_status_normal">12dp</dimen>
+    <dimen name="control_status_expanded">18dp</dimen>
     <dimen name="app_icon_size">32dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 44a7fda..1f13f8d 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2546,4 +2546,7 @@
     <string name="magnification_window_title">Magnification Window</string>
     <!-- Title for Magnification Controls Window [CHAR LIMIT=NONE] -->
     <string name="magnification_controls_title">Magnification Window Controls</string>
+
+    <!-- Quick Controls strings [CHAR LIMIT=30] -->
+    <string name="quick_controls_title">Quick Controls</string>
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
new file mode 100644
index 0000000..81b5f36
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 2020 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.controls.ui
+
+import android.content.Context
+import android.graphics.drawable.ClipDrawable
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.GradientDrawable
+import android.graphics.drawable.Icon
+import android.graphics.drawable.LayerDrawable
+import android.service.controls.Control
+import android.service.controls.DeviceTypes
+import android.service.controls.actions.BooleanAction
+import android.service.controls.actions.ControlAction
+import android.service.controls.actions.FloatAction
+import android.service.controls.templates.ControlTemplate
+import android.service.controls.templates.RangeTemplate
+import android.service.controls.templates.ToggleRangeTemplate
+import android.service.controls.templates.ToggleTemplate
+import android.util.TypedValue
+import android.view.MotionEvent
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+
+import com.android.systemui.controls.controller.ControlsController
+import com.android.systemui.R
+
+private const val MIN_LEVEL = 0
+private const val MAX_LEVEL = 10000
+
+class ControlViewHolder(
+    val layout: ViewGroup,
+    val controlsController: ControlsController
+) {
+    val icon: ImageView = layout.requireViewById(R.id.icon)
+    val status: TextView = layout.requireViewById(R.id.status)
+    val statusExtra: TextView = layout.requireViewById(R.id.status_extra)
+    val title: TextView = layout.requireViewById(R.id.title)
+    val subtitle: TextView = layout.requireViewById(R.id.subtitle)
+    val context: Context = layout.getContext()
+    val clipLayer: ClipDrawable
+    val gd: GradientDrawable
+    lateinit var cws: ControlWithState
+
+    init {
+        val ld = layout.getBackground() as LayerDrawable
+        ld.mutate()
+        clipLayer = ld.findDrawableByLayerId(R.id.clip_layer) as ClipDrawable
+        gd = clipLayer.getDrawable() as GradientDrawable
+    }
+
+    fun bindData(cws: ControlWithState) {
+        this.cws = cws
+
+        val (status, template) = cws.control?.let {
+            title.setText(it.getTitle())
+            subtitle.setText(it.getSubtitle())
+            Pair(it.getStatus(), it.getControlTemplate())
+        } ?: run {
+            title.setText(cws.ci.controlTitle)
+            subtitle.setText("")
+            Pair(Control.STATUS_UNKNOWN, ControlTemplate.NO_TEMPLATE)
+        }
+
+        findBehavior(status, template).apply(this, cws)
+    }
+
+    fun action(action: ControlAction) {
+        controlsController.action(cws.ci, action)
+    }
+
+    private fun findBehavior(status: Int, template: ControlTemplate): Behavior {
+        return when {
+            status == Control.STATUS_UNKNOWN -> UnknownBehavior()
+            template is ToggleTemplate -> ToggleTemplateBehavior()
+            template is ToggleRangeTemplate -> ToggleRangeTemplateBehavior()
+            else -> {
+                object : Behavior {
+                    override fun apply(cvh: ControlViewHolder, cws: ControlWithState) {
+                        cvh.status.setText(cws.control?.getStatusText())
+                        cvh.applyRenderInfo(findRenderInfo(cws.ci.deviceType, false))
+                    }
+                }
+            }
+        }
+    }
+
+    internal fun applyRenderInfo(ri: RenderInfo) {
+        val fg = context.getResources().getColorStateList(ri.foreground, context.getTheme())
+        val bg = context.getResources().getColorStateList(ri.background, context.getTheme())
+        status.setTextColor(fg)
+        statusExtra.setTextColor(fg)
+
+        icon.setImageIcon(Icon.createWithResource(context, ri.iconResourceId))
+        icon.setImageTintList(fg)
+
+        gd.setColor(bg)
+    }
+
+    fun setEnabled(enabled: Boolean) {
+        status.setEnabled(enabled)
+        icon.setEnabled(enabled)
+    }
+}
+
+private interface Behavior {
+    fun apply(cvh: ControlViewHolder, cws: ControlWithState)
+
+    fun findRenderInfo(deviceType: Int, isActive: Boolean): RenderInfo =
+        deviceRenderMap.getOrDefault(deviceType, unknownDeviceMap).getValue(isActive)
+}
+
+private class UnknownBehavior : Behavior {
+    override fun apply(cvh: ControlViewHolder, cws: ControlWithState) {
+        cvh.status.setText("Loading...")
+        cvh.applyRenderInfo(findRenderInfo(cws.ci.deviceType, false))
+    }
+}
+
+private class ToggleRangeTemplateBehavior : Behavior {
+    lateinit var clipLayer: Drawable
+    lateinit var template: ToggleRangeTemplate
+    lateinit var control: Control
+    lateinit var cvh: ControlViewHolder
+    lateinit var rangeTemplate: RangeTemplate
+    lateinit var statusExtra: TextView
+    lateinit var status: TextView
+    lateinit var context: Context
+
+    override fun apply(cvh: ControlViewHolder, cws: ControlWithState) {
+        this.control = cws.control!!
+        this.cvh = cvh
+
+        statusExtra = cvh.statusExtra
+        status = cvh.status
+
+        status.setText(control.getStatusText())
+
+        context = status.getContext()
+
+        cvh.layout.setOnTouchListener(ToggleRangeTouchListener())
+
+        val ld = cvh.layout.getBackground() as LayerDrawable
+        clipLayer = ld.findDrawableByLayerId(R.id.clip_layer)
+
+        template = control.getControlTemplate() as ToggleRangeTemplate
+        rangeTemplate = template.getRange()
+
+        val checked = template.isChecked()
+        val deviceType = control.getDeviceType()
+
+        updateRange((rangeTemplate.getCurrentValue() / 100.0f), checked)
+
+        cvh.setEnabled(checked)
+        cvh.applyRenderInfo(findRenderInfo(deviceType, checked))
+    }
+
+    fun toggle() {
+        cvh.action(BooleanAction(template.getTemplateId(), !template.isChecked()))
+
+        val nextLevel = if (template.isChecked()) MIN_LEVEL else MAX_LEVEL
+        clipLayer.setLevel(nextLevel)
+    }
+
+    fun beginUpdateRange() {
+        status.setVisibility(View.GONE)
+        statusExtra.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources()
+                .getDimensionPixelSize(R.dimen.control_status_expanded).toFloat())
+    }
+
+    fun updateRange(f: Float, checked: Boolean) {
+        clipLayer.setLevel(if (checked) (MAX_LEVEL * f).toInt() else MIN_LEVEL)
+
+        if (checked && f < 100.0f && f > 0.0f) {
+            statusExtra.setText("" + (f * 100.0).toInt() + "%")
+            statusExtra.setVisibility(View.VISIBLE)
+        } else {
+            statusExtra.setText("")
+            statusExtra.setVisibility(View.GONE)
+        }
+    }
+
+    fun endUpdateRange(f: Float) {
+        statusExtra.setText(" - " + (f * 100.0).toInt() + "%")
+
+        val newValue = rangeTemplate.getMinValue() +
+            (f * (rangeTemplate.getMaxValue() - rangeTemplate.getMinValue()))
+
+        statusExtra.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources()
+                .getDimensionPixelSize(R.dimen.control_status_normal).toFloat())
+        status.setVisibility(View.VISIBLE)
+
+        cvh.action(FloatAction(rangeTemplate.getTemplateId(), findNearestStep(newValue)))
+    }
+
+    fun findNearestStep(value: Float): Float {
+        var minDiff = 1000f
+
+        var f = rangeTemplate.getMinValue()
+        while (f <= rangeTemplate.getMaxValue()) {
+            val currentDiff = Math.abs(value - f)
+            if (currentDiff < minDiff) {
+                minDiff = currentDiff
+            } else {
+                return f - rangeTemplate.getStepValue()
+            }
+
+            f += rangeTemplate.getStepValue()
+        }
+
+        return rangeTemplate.getMaxValue()
+    }
+
+    inner class ToggleRangeTouchListener() : View.OnTouchListener {
+        private var initialTouchX: Float = 0.0f
+        private var initialTouchY: Float = 0.0f
+        private var isDragging: Boolean = false
+        private val minDragDiff = 20
+
+        override fun onTouch(v: View, e: MotionEvent): Boolean {
+            when (e.getActionMasked()) {
+                MotionEvent.ACTION_DOWN -> setupTouch(e)
+                MotionEvent.ACTION_MOVE -> detectDrag(v, e)
+                MotionEvent.ACTION_UP -> endTouch(v, e)
+            }
+
+            return true
+        }
+
+        private fun setupTouch(e: MotionEvent) {
+            initialTouchX = e.getX()
+            initialTouchY = e.getY()
+        }
+
+        private fun detectDrag(v: View, e: MotionEvent) {
+            val xDiff = Math.abs(e.getX() - initialTouchX)
+            val yDiff = Math.abs(e.getY() - initialTouchY)
+
+            if (xDiff < minDragDiff) {
+                isDragging = false
+            } else {
+                if (!isDragging) {
+                    this@ToggleRangeTemplateBehavior.beginUpdateRange()
+                }
+                v.getParent().requestDisallowInterceptTouchEvent(true)
+                isDragging = true
+                if (yDiff > xDiff) {
+                    endTouch(v, e)
+                } else {
+                    val percent = Math.max(0.0f, Math.min(1.0f, e.getX() / v.getWidth()))
+                    this@ToggleRangeTemplateBehavior.updateRange(percent, true)
+                }
+            }
+        }
+
+        private fun endTouch(v: View, e: MotionEvent) {
+            if (!isDragging) {
+                this@ToggleRangeTemplateBehavior.toggle()
+            } else {
+                val percent = Math.max(0.0f, Math.min(1.0f, e.getX() / v.getWidth()))
+                this@ToggleRangeTemplateBehavior.endUpdateRange(percent)
+            }
+
+            initialTouchX = 0.0f
+            initialTouchY = 0.0f
+            isDragging = false
+        }
+    }
+}
+
+private class ToggleTemplateBehavior : Behavior {
+    lateinit var clipLayer: Drawable
+    lateinit var template: ToggleTemplate
+    lateinit var control: Control
+    lateinit var cvh: ControlViewHolder
+    lateinit var context: Context
+    lateinit var status: TextView
+
+    override fun apply(cvh: ControlViewHolder, cws: ControlWithState) {
+        this.control = cws.control!!
+        this.cvh = cvh
+        status = cvh.status
+
+        status.setText(control.getStatusText())
+
+        cvh.layout.setOnClickListener(View.OnClickListener() { toggle() })
+
+        val ld = cvh.layout.getBackground() as LayerDrawable
+        clipLayer = ld.findDrawableByLayerId(R.id.clip_layer)
+
+        template = control.getControlTemplate() as ToggleTemplate
+
+        val checked = template.isChecked()
+        val deviceType = control.getDeviceType()
+
+        clipLayer.setLevel(if (checked) MAX_LEVEL else MIN_LEVEL)
+        cvh.setEnabled(checked)
+        cvh.applyRenderInfo(findRenderInfo(deviceType, checked))
+    }
+
+    fun toggle() {
+        cvh.action(BooleanAction(template.getTemplateId(), !template.isChecked()))
+
+        val nextLevel = if (template.isChecked()) MIN_LEVEL else MAX_LEVEL
+        clipLayer.setLevel(nextLevel)
+    }
+}
+
+internal data class RenderInfo(val iconResourceId: Int, val foreground: Int, val background: Int)
+
+private val unknownDeviceMap = mapOf(
+    false to RenderInfo(
+        R.drawable.ic_light_off_gm2_24px,
+        R.color.unknown_foreground,
+        R.color.unknown_foreground),
+    true to RenderInfo(
+        R.drawable.ic_lightbulb_outline_gm2_24px,
+        R.color.unknown_foreground,
+        R.color.unknown_foreground)
+)
+
+private val deviceRenderMap = mapOf<Int, Map<Boolean, RenderInfo>>(
+    DeviceTypes.TYPE_UNKNOWN to unknownDeviceMap,
+    DeviceTypes.TYPE_LIGHT to mapOf(
+        false to RenderInfo(
+            R.drawable.ic_light_off_gm2_24px,
+            R.color.light_foreground,
+            R.color.light_background),
+        true to RenderInfo(
+            R.drawable.ic_lightbulb_outline_gm2_24px,
+            R.color.light_foreground,
+            R.color.light_background)
+    ),
+    DeviceTypes.TYPE_THERMOSTAT to mapOf(
+        false to RenderInfo(
+            R.drawable.ic_device_thermostat_gm2_24px,
+            R.color.light_foreground,
+            R.color.light_background),
+        true to RenderInfo(
+            R.drawable.ic_device_thermostat_gm2_24px,
+            R.color.light_foreground,
+            R.color.light_background)
+    ),
+    DeviceTypes.TYPE_CAMERA to mapOf(
+        false to RenderInfo(
+            R.drawable.ic_videocam_gm2_24px,
+            R.color.light_foreground,
+            R.color.light_background),
+        true to RenderInfo(
+            R.drawable.ic_videocam_gm2_24px,
+            R.color.light_foreground,
+            R.color.light_background)
+    ),
+    DeviceTypes.TYPE_LOCK to mapOf(
+        false to RenderInfo(
+            R.drawable.ic_lock_open_gm2_24px,
+            R.color.lock_foreground,
+            R.color.lock_background),
+        true to RenderInfo(
+            R.drawable.ic_lock_gm2_24px,
+            R.color.lock_foreground,
+            R.color.lock_background)
+    ),
+    DeviceTypes.TYPE_SWITCH to mapOf(
+        false to RenderInfo(
+            R.drawable.ic_switches_gm2_24px,
+            R.color.lock_foreground,
+            R.color.lock_background),
+        true to RenderInfo(
+            R.drawable.ic_switches_gm2_24px,
+            R.color.lock_foreground,
+            R.color.lock_background)
+    ),
+    DeviceTypes.TYPE_OUTLET to mapOf(
+        false to RenderInfo(
+            R.drawable.ic_power_off_gm2_24px,
+            R.color.lock_foreground,
+            R.color.lock_background),
+        true to RenderInfo(
+            R.drawable.ic_power_gm2_24px,
+            R.color.lock_foreground,
+            R.color.lock_background)
+    )
+)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlWithState.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlWithState.kt
new file mode 100644
index 0000000..816f0b2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlWithState.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 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.controls.ui
+
+import android.service.controls.Control
+
+import com.android.systemui.controls.controller.ControlInfo
+
+/**
+ * A container for:
+ * <ul>
+ *  <li>ControlInfo - Basic cached info about a Control
+ *  <li>Control - Actual Control parcelable received directly from
+ *  the participating application
+ * </ul>
+ */
+data class ControlWithState(val ci: ControlInfo, val control: Control?)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt
index 0270c2b..b07a75d 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt
@@ -19,12 +19,15 @@
 import android.content.ComponentName
 import android.service.controls.Control
 import android.service.controls.actions.ControlAction
+import android.view.ViewGroup
 
 interface ControlsUiController {
+    fun show(parent: ViewGroup)
+    fun hide()
     fun onRefreshState(componentName: ComponentName, controls: List<Control>)
     fun onActionResponse(
         componentName: ComponentName,
         controlId: String,
         @ControlAction.ResponseResult response: Int
     )
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 0ace126..926fb6e 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -16,19 +16,204 @@
 
 package com.android.systemui.controls.ui
 
+import android.accounts.Account
+import android.accounts.AccountManager
 import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.ServiceConnection
+import android.os.IBinder
 import android.service.controls.Control
+import android.service.controls.TokenProvider
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+
+import com.android.systemui.controls.controller.ControlsController
+import com.android.systemui.controls.controller.ControlInfo
+import com.android.systemui.controls.management.ControlsProviderSelectorActivity
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.R
+
+import dagger.Lazy
+
+import java.util.concurrent.Executor
 import javax.inject.Inject
 import javax.inject.Singleton
 
+private const val TAG = "ControlsUi"
+
+// TEMP CODE for MOCK
+private const val TOKEN = "https://www.googleapis.com/auth/assistant"
+private const val SCOPE = "oauth2:" + TOKEN
+private var tokenProviderConnection: TokenProviderConnection? = null
+class TokenProviderConnection(val cc: ControlsController, val context: Context)
+    : ServiceConnection {
+    private var mTokenProvider: TokenProvider? = null
+
+    override fun onServiceConnected(cName: ComponentName, binder: IBinder) {
+        Thread({
+            Log.i(TAG, "TokenProviderConnection connected")
+            mTokenProvider = TokenProvider.Stub.asInterface(binder)
+
+            val mLastAccountName = mTokenProvider?.getAccountName()
+
+            if (mLastAccountName == null || mLastAccountName.isEmpty()) {
+                Log.e(TAG, "NO ACCOUNT IS SET. Open HomeMock app")
+            } else {
+                mTokenProvider?.setAuthToken(getAuthToken(mLastAccountName))
+                cc.subscribeToFavorites()
+            }
+        }, "TokenProviderThread").start()
+    }
+
+    override fun onServiceDisconnected(cName: ComponentName) {
+        mTokenProvider = null
+    }
+
+    fun getAuthToken(accountName: String): String? {
+        val am = AccountManager.get(context)
+        val accounts = am.getAccountsByType("com.google")
+        if (accounts == null || accounts.size == 0) {
+            Log.w(TAG, "No com.google accounts found")
+            return null
+        }
+
+        var account: Account? = null
+        for (a in accounts) {
+            if (a.name.equals(accountName)) {
+                account = a
+                break
+            }
+        }
+
+        if (account == null) {
+            account = accounts[0]
+        }
+
+        try {
+            return am.blockingGetAuthToken(account!!, SCOPE, true)
+        } catch (e: Throwable) {
+            Log.e(TAG, "Error getting auth token", e)
+            return null
+        }
+    }
+}
+
 @Singleton
-class ControlsUiControllerImpl @Inject constructor() : ControlsUiController {
+class ControlsUiControllerImpl @Inject constructor (
+    val controlsController: Lazy<ControlsController>,
+    val context: Context,
+    @Main val uiExecutor: Executor
+) : ControlsUiController {
+
+    private lateinit var controlInfos: List<ControlInfo>
+    private val controlsById = mutableMapOf<Pair<ComponentName, String>, ControlWithState>()
+    private val controlViewsById = mutableMapOf<String, ControlViewHolder>()
+    private lateinit var parent: ViewGroup
+
+    override fun show(parent: ViewGroup) {
+        Log.d(TAG, "show()")
+
+        this.parent = parent
+
+        controlInfos = controlsController.get().getFavoriteControls()
+
+        controlInfos.map {
+            ControlWithState(it, null)
+        }.associateByTo(controlsById) { Pair(it.ci.component, it.ci.controlId) }
+
+        if (controlInfos.isEmpty()) {
+            showInitialSetupView()
+        } else {
+            showControlsView()
+        }
+
+        // Temp code to pass auth
+        tokenProviderConnection = TokenProviderConnection(controlsController.get(), context)
+        val serviceIntent = Intent()
+        serviceIntent.setComponent(ComponentName("com.android.systemui.home.mock",
+                "com.android.systemui.home.mock.AuthService"))
+        context.bindService(serviceIntent, tokenProviderConnection!!, Context.BIND_AUTO_CREATE)
+    }
+
+    private fun showInitialSetupView() {
+        val inflater = LayoutInflater.from(context)
+        inflater.inflate(R.layout.controls_no_favorites, parent, true)
+
+        val textView = parent.requireViewById(R.id.controls_title) as TextView
+        textView.setOnClickListener {
+            val i = Intent()
+            i.setComponent(ComponentName(context, ControlsProviderSelectorActivity::class.java))
+            i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
+            context.startActivity(i)
+        }
+    }
+
+    private fun showControlsView() {
+        val inflater = LayoutInflater.from(context)
+        inflater.inflate(R.layout.controls_with_favorites, parent, true)
+
+        val listView = parent.requireViewById(R.id.global_actions_controls_list) as ViewGroup
+        var lastRow: ViewGroup = createRow(inflater, listView)
+        controlInfos.forEach {
+            Log.d(TAG, "favorited control id: " + it.controlId)
+            if (lastRow.getChildCount() == 2) {
+                lastRow = createRow(inflater, listView)
+            }
+            val item = inflater.inflate(
+                R.layout.controls_base_item, lastRow, false) as ViewGroup
+            lastRow.addView(item)
+            val cvh = ControlViewHolder(item, controlsController.get())
+            cvh.bindData(controlsById.get(Pair(it.component, it.controlId))!!)
+            controlViewsById.put(it.controlId, cvh)
+        }
+
+        val moreImageView = parent.requireViewById(R.id.controls_more) as View
+        moreImageView.setOnClickListener {
+            val i = Intent()
+            i.setComponent(ComponentName(context, ControlsProviderSelectorActivity::class.java))
+            i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
+            context.startActivity(i)
+        }
+    }
+
+    override fun hide() {
+        Log.d(TAG, "hide()")
+        controlsController.get().unsubscribe()
+        context.unbindService(tokenProviderConnection)
+        tokenProviderConnection = null
+
+        parent.removeAllViews()
+        controlsById.clear()
+        controlViewsById.clear()
+    }
 
     override fun onRefreshState(componentName: ComponentName, controls: List<Control>) {
-        TODO("not implemented")
+        Log.d(TAG, "onRefreshState()")
+        controls.forEach { c ->
+            controlsById.get(Pair(componentName, c.getControlId()))?.let {
+                Log.d(TAG, "onRefreshState() for id: " + c.getControlId())
+                val cws = ControlWithState(it.ci, c)
+                controlsById.put(Pair(componentName, c.getControlId()), cws)
+
+                uiExecutor.execute {
+                    controlViewsById.get(c.getControlId())?.bindData(cws)
+                }
+            }
+        }
     }
 
     override fun onActionResponse(componentName: ComponentName, controlId: String, response: Int) {
+        Log.d(TAG, "onActionResponse()")
         TODO("not implemented")
     }
-}
\ No newline at end of file
+
+    private fun createRow(inflater: LayoutInflater, parent: ViewGroup): ViewGroup {
+        val row = inflater.inflate(R.layout.controls_row, parent, false) as ViewGroup
+        parent.addView(row)
+        return row
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
index d4e47f6..5de88e1 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
@@ -37,6 +37,7 @@
 import com.android.systemui.statusbar.phone.StatusBarModule;
 import com.android.systemui.statusbar.tv.TvStatusBar;
 import com.android.systemui.theme.ThemeOverlayController;
+import com.android.systemui.toast.ToastUI;
 import com.android.systemui.util.leak.GarbageMonitor;
 import com.android.systemui.volume.VolumeUI;
 
@@ -153,6 +154,12 @@
     @ClassKey(ThemeOverlayController.class)
     public abstract SystemUI bindThemeOverlayController(ThemeOverlayController sysui);
 
+    /** Inject into ToastUI. */
+    @Binds
+    @IntoMap
+    @ClassKey(ToastUI.class)
+    public abstract SystemUI bindToastUI(ToastUI service);
+
     /** Inject into TvStatusBar. */
     @Binds
     @IntoMap
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 83f6d45..80d776a 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -93,12 +93,13 @@
 import com.android.systemui.MultiListLayout.MultiListAdapter;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.controls.ui.ControlsUiController;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
 import com.android.systemui.plugins.GlobalActionsPanelPlugin;
-import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
 import com.android.systemui.statusbar.BlurUtils;
+import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
 import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -183,6 +184,7 @@
     private final IStatusBarService mStatusBarService;
     private final NotificationShadeWindowController mNotificationShadeWindowController;
     private GlobalActionsPanelPlugin mPanelPlugin;
+    private ControlsUiController mControlsUiController;
 
     /**
      * @param context everything needs a context :(
@@ -200,7 +202,8 @@
             TelecomManager telecomManager, MetricsLogger metricsLogger,
             BlurUtils blurUtils, SysuiColorExtractor colorExtractor,
             IStatusBarService statusBarService,
-            NotificationShadeWindowController notificationShadeWindowController) {
+            NotificationShadeWindowController notificationShadeWindowController,
+            ControlsUiController controlsUiController) {
         mContext = new ContextThemeWrapper(context, com.android.systemui.R.style.qs_theme);
         mWindowManagerFuncs = windowManagerFuncs;
         mAudioManager = audioManager;
@@ -220,6 +223,7 @@
         mSysuiColorExtractor = colorExtractor;
         mStatusBarService = statusBarService;
         mNotificationShadeWindowController = notificationShadeWindowController;
+        mControlsUiController = controlsUiController;
 
         // receive broadcasts
         IntentFilter filter = new IntentFilter();
@@ -455,9 +459,12 @@
                                 mKeyguardManager.isDeviceLocked())
                         : null;
 
+        boolean showControls = !mKeyguardManager.isDeviceLocked() && isControlsEnabled(mContext);
+
         ActionsDialog dialog = new ActionsDialog(mContext, mAdapter, panelViewController,
                 mBlurUtils, mSysuiColorExtractor, mStatusBarService,
-                mNotificationShadeWindowController, isControlsEnabled(mContext));
+                mNotificationShadeWindowController,
+                showControls ? mControlsUiController : null);
         dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.
         dialog.setKeyguardShowing(mKeyguardShowing);
 
@@ -1543,13 +1550,15 @@
         private boolean mHadTopUi;
         private final NotificationShadeWindowController mNotificationShadeWindowController;
         private final BlurUtils mBlurUtils;
-        private final boolean mControlsEnabled;
+
+        private ControlsUiController mControlsUiController;
+        private ViewGroup mControlsView;
 
         ActionsDialog(Context context, MyAdapter adapter,
                 GlobalActionsPanelPlugin.PanelViewController plugin, BlurUtils blurUtils,
                 SysuiColorExtractor sysuiColorExtractor, IStatusBarService statusBarService,
                 NotificationShadeWindowController notificationShadeWindowController,
-                boolean controlsEnabled) {
+                ControlsUiController controlsUiController) {
             super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions);
             mContext = context;
             mAdapter = adapter;
@@ -1557,7 +1566,7 @@
             mColorExtractor = sysuiColorExtractor;
             mStatusBarService = statusBarService;
             mNotificationShadeWindowController = notificationShadeWindowController;
-            mControlsEnabled = controlsEnabled;
+            mControlsUiController = controlsUiController;
 
             // Window initialization
             Window window = getWindow();
@@ -1639,6 +1648,7 @@
         private void initializeLayout() {
             setContentView(getGlobalActionsLayoutId(mContext));
             fixNavBarClipping();
+            mControlsView = findViewById(com.android.systemui.R.id.global_actions_controls);
             mGlobalActionsLayout = findViewById(com.android.systemui.R.id.global_actions_view);
             mGlobalActionsLayout.setOutsideTouchListener(view -> dismiss());
             ((View) mGlobalActionsLayout.getParent()).setOnClickListener(view -> dismiss());
@@ -1674,7 +1684,7 @@
         }
 
         private int getGlobalActionsLayoutId(Context context) {
-            if (mControlsEnabled) {
+            if (mControlsUiController != null) {
                 return com.android.systemui.R.layout.global_actions_grid_v2;
             }
 
@@ -1758,6 +1768,9 @@
                                 mBlurUtils.radiusForRatio(animatedValue));
                     })
                     .start();
+            if (mControlsUiController != null) {
+                mControlsUiController.show(mControlsView);
+            }
         }
 
         @Override
@@ -1766,6 +1779,7 @@
                 return;
             }
             mShowing = false;
+            if (mControlsUiController != null) mControlsUiController.hide();
             mGlobalActionsLayout.setTranslationX(0);
             mGlobalActionsLayout.setTranslationY(0);
             mGlobalActionsLayout.setAlpha(1);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 2fc7a9c..14eec59 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -18,6 +18,7 @@
 
 import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
 
+import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
@@ -53,6 +54,7 @@
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -371,6 +373,7 @@
     private boolean mPulsing;
 
     private boolean mLockLater;
+    private boolean mShowHomeOverLockscreen;
 
     private boolean mWakeAndUnlocking;
     private IKeyguardDrawnCallback mDrawnCallback;
@@ -703,6 +706,20 @@
         mStatusBarKeyguardViewManagerLazy = statusBarKeyguardViewManagerLazy;
         mDismissCallbackRegistry = dismissCallbackRegistry;
         mUiBgExecutor = uiBgExecutor;
+        mShowHomeOverLockscreen = DeviceConfig.getBoolean(
+                DeviceConfig.NAMESPACE_SYSTEMUI,
+                NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN,
+                /* defaultValue = */ true);
+        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, mHandler::post,
+                new DeviceConfig.OnPropertiesChangedListener() {
+                    @Override
+                    public void onPropertiesChanged(DeviceConfig.Properties properties) {
+                        if (properties.getKeyset().contains(NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN)) {
+                            mShowHomeOverLockscreen = properties.getBoolean(
+                                    NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN, true /* defaultValue */);
+                        }
+                    }
+                });
     }
 
     public void userActivity() {
@@ -1972,7 +1989,10 @@
             // windows that appear on top, ever
             int flags = StatusBarManager.DISABLE_NONE;
             if (forceHideHomeRecentsButtons || isShowingAndNotOccluded()) {
-                flags |= StatusBarManager.DISABLE_HOME | StatusBarManager.DISABLE_RECENT;
+                if (!mShowHomeOverLockscreen) {
+                    flags |= StatusBarManager.DISABLE_HOME;
+                }
+                flags |= StatusBarManager.DISABLE_RECENT;
             }
 
             if (DEBUG) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 7c0f4f9..3af3701 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -25,6 +25,8 @@
 
 import static com.android.systemui.statusbar.phone.StatusBar.ONLY_CORE_APPS;
 
+import android.annotation.Nullable;
+import android.app.ITransientNotificationCallback;
 import android.app.StatusBarManager;
 import android.app.StatusBarManager.Disable2Flags;
 import android.app.StatusBarManager.DisableFlags;
@@ -119,6 +121,8 @@
     private static final int MSG_TOP_APP_WINDOW_CHANGED            = 50 << MSG_SHIFT;
     private static final int MSG_SHOW_INATTENTIVE_SLEEP_WARNING    = 51 << MSG_SHIFT;
     private static final int MSG_DISMISS_INATTENTIVE_SLEEP_WARNING = 52 << MSG_SHIFT;
+    private static final int MSG_SHOW_TOAST                        = 53 << MSG_SHIFT;
+    private static final int MSG_HIDE_TOAST                        = 54 << MSG_SHIFT;
 
     public static final int FLAG_EXCLUDE_NONE = 0;
     public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -308,6 +312,19 @@
          * due to prolonged user inactivity should be dismissed.
          */
         default void dismissInattentiveSleepWarning(boolean animated) { }
+
+        /**
+         * @see IStatusBar#showToast(String, IBinder, CharSequence, IBinder, int,
+         * ITransientNotificationCallback)
+         */
+        default void showToast(String packageName, IBinder token, CharSequence text,
+                IBinder windowToken, int duration,
+                @Nullable ITransientNotificationCallback callback) { }
+
+        /**
+         * @see IStatusBar#hideToast(String, IBinder) (String, IBinder)
+         */
+        default void hideToast(String packageName, IBinder token) { }
     }
 
     public CommandQueue(Context context) {
@@ -761,6 +778,31 @@
     }
 
     @Override
+    public void showToast(String packageName, IBinder token, CharSequence text,
+            IBinder windowToken, int duration, @Nullable ITransientNotificationCallback callback) {
+        synchronized (mLock) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = packageName;
+            args.arg2 = token;
+            args.arg3 = text;
+            args.arg4 = windowToken;
+            args.arg5 = callback;
+            args.argi1 = duration;
+            mHandler.obtainMessage(MSG_SHOW_TOAST, args).sendToTarget();
+        }
+    }
+
+    @Override
+    public void hideToast(String packageName, IBinder token) {
+        synchronized (mLock) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = packageName;
+            args.arg2 = token;
+            mHandler.obtainMessage(MSG_HIDE_TOAST, args).sendToTarget();
+        }
+    }
+
+    @Override
     public void onBiometricAuthenticated() {
         synchronized (mLock) {
             mHandler.obtainMessage(MSG_BIOMETRIC_AUTHENTICATED).sendToTarget();
@@ -1178,6 +1220,30 @@
                         mCallbacks.get(i).dismissInattentiveSleepWarning((Boolean) msg.obj);
                     }
                     break;
+                case MSG_SHOW_TOAST: {
+                    args = (SomeArgs) msg.obj;
+                    String packageName = (String) args.arg1;
+                    IBinder token = (IBinder) args.arg2;
+                    CharSequence text = (CharSequence) args.arg3;
+                    IBinder windowToken = (IBinder) args.arg4;
+                    ITransientNotificationCallback callback =
+                            (ITransientNotificationCallback) args.arg5;
+                    int duration = args.argi1;
+                    for (Callbacks callbacks : mCallbacks) {
+                        callbacks.showToast(packageName, token, text, windowToken, duration,
+                                callback);
+                    }
+                    break;
+                }
+                case MSG_HIDE_TOAST: {
+                    args = (SomeArgs) msg.obj;
+                    String packageName = (String) args.arg1;
+                    IBinder token = (IBinder) args.arg2;
+                    for (Callbacks callbacks : mCallbacks) {
+                        callbacks.hideToast(packageName, token);
+                    }
+                    break;
+                }
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index c488c6b..86c0d85 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -49,6 +49,7 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.DumpController;
 import com.android.systemui.Dumpable;
+import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.notification.collection.coalescer.CoalescedEvent;
 import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer;
 import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer.BatchableNotificationHandler;
@@ -98,6 +99,7 @@
 @Singleton
 public class NotifCollection implements Dumpable {
     private final IStatusBarService mStatusBarService;
+    private final FeatureFlags mFeatureFlags;
 
     private final Map<String, NotificationEntry> mNotificationSet = new ArrayMap<>();
     private final Collection<NotificationEntry> mReadOnlyNotificationSet =
@@ -111,10 +113,14 @@
     private boolean mAmDispatchingToOtherCode;
 
     @Inject
-    public NotifCollection(IStatusBarService statusBarService, DumpController dumpController) {
+    public NotifCollection(
+            IStatusBarService statusBarService,
+            DumpController dumpController,
+            FeatureFlags featureFlags) {
         Assert.isMainThread();
         mStatusBarService = statusBarService;
         dumpController.registerDumpable(TAG, this);
+        mFeatureFlags = featureFlags;
     }
 
     /** Initializes the NotifCollection and registers it to receive notification events. */
@@ -301,9 +307,12 @@
                 // TODO: (b/145659174) update the sbn's overrideGroupKey in
                 //  NotificationEntry.setRanking instead of here once we fully migrate to the
                 //  NewNotifPipeline
-                final String newOverrideGroupKey = ranking.getOverrideGroupKey();
-                if (!Objects.equals(entry.getSbn().getOverrideGroupKey(), newOverrideGroupKey)) {
-                    entry.getSbn().setOverrideGroupKey(newOverrideGroupKey);
+                if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+                    final String newOverrideGroupKey = ranking.getOverrideGroupKey();
+                    if (!Objects.equals(entry.getSbn().getOverrideGroupKey(),
+                            newOverrideGroupKey)) {
+                        entry.getSbn().setOverrideGroupKey(newOverrideGroupKey);
+                    }
                 }
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 3e3ef0c..9e64748 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -302,14 +302,14 @@
         mForceNavBarHandleOpaque = DeviceConfig.getBoolean(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 NAV_BAR_HANDLE_FORCE_OPAQUE,
-                /* defaultValue = */ false);
+                /* defaultValue = */ true);
         DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, mHandler::post,
                 new DeviceConfig.OnPropertiesChangedListener() {
                     @Override
                     public void onPropertiesChanged(DeviceConfig.Properties properties) {
                         if (properties.getKeyset().contains(NAV_BAR_HANDLE_FORCE_OPAQUE)) {
                             mForceNavBarHandleOpaque = properties.getBoolean(
-                                    NAV_BAR_HANDLE_FORCE_OPAQUE, /* defaultValue = */ false);
+                                    NAV_BAR_HANDLE_FORCE_OPAQUE, /* defaultValue = */ true);
                         }
                     }
                 });
diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
new file mode 100644
index 0000000..dea8c5d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2020 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.toast;
+
+import android.annotation.MainThread;
+import android.annotation.Nullable;
+import android.app.INotificationManager;
+import android.app.ITransientNotificationCallback;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.PixelFormat;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+import android.view.WindowManager;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.internal.R;
+import com.android.systemui.SystemUI;
+import com.android.systemui.statusbar.CommandQueue;
+
+import java.util.Objects;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Controls display of text toasts.
+ */
+@Singleton
+public class ToastUI extends SystemUI implements CommandQueue.Callbacks {
+    private static final String TAG = "ToastUI";
+
+    /**
+     * Values taken from {@link Toast}.
+     */
+    private static final long DURATION_SHORT = 4000;
+    private static final long DURATION_LONG = 7000;
+
+    private final CommandQueue mCommandQueue;
+    private final WindowManager mWindowManager;
+    private final INotificationManager mNotificationManager;
+    private final AccessibilityManager mAccessibilityManager;
+    private ToastEntry mCurrentToast;
+
+    @Inject
+    public ToastUI(Context context, CommandQueue commandQueue) {
+        super(context);
+        mCommandQueue = commandQueue;
+        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+        mNotificationManager = INotificationManager.Stub.asInterface(
+                ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+        mAccessibilityManager = AccessibilityManager.getInstance(context);
+    }
+
+    @Override
+    public void start() {
+        mCommandQueue.addCallback(this);
+    }
+
+    @Override
+    @MainThread
+    public void showToast(String packageName, IBinder token, CharSequence text,
+            IBinder windowToken, int duration, @Nullable ITransientNotificationCallback callback) {
+        if (mCurrentToast != null) {
+            hideCurrentToast();
+        }
+        View view = getView(text);
+        LayoutParams params = getLayoutParams(windowToken, duration);
+        mCurrentToast = new ToastEntry(packageName, token, view, windowToken, callback);
+        try {
+            mWindowManager.addView(view, params);
+        } catch (WindowManager.BadTokenException e) {
+            Log.w(TAG, "Error while attempting to show toast from " + packageName, e);
+            return;
+        }
+        trySendAccessibilityEvent(view, packageName);
+        if (callback != null) {
+            try {
+                callback.onToastShown();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Error calling back " + packageName + " to notify onToastShow()", e);
+            }
+        }
+    }
+
+    @Override
+    @MainThread
+    public void hideToast(String packageName, IBinder token) {
+        if (mCurrentToast == null || !Objects.equals(mCurrentToast.packageName, packageName)
+                || !Objects.equals(mCurrentToast.token, token)) {
+            Log.w(TAG, "Attempt to hide non-current toast from package " + packageName);
+            return;
+        }
+        hideCurrentToast();
+    }
+
+    @MainThread
+    private void hideCurrentToast() {
+        if (mCurrentToast.view.getParent() != null) {
+            mWindowManager.removeViewImmediate(mCurrentToast.view);
+        }
+        String packageName = mCurrentToast.packageName;
+        try {
+            mNotificationManager.finishToken(packageName, mCurrentToast.windowToken);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Error finishing toast window token from package " + packageName, e);
+        }
+        if (mCurrentToast.callback != null) {
+            try {
+                mCurrentToast.callback.onToastHidden();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Error calling back " + packageName + " to notify onToastHide()", e);
+            }
+        }
+        mCurrentToast = null;
+    }
+
+    private void trySendAccessibilityEvent(View view, String packageName) {
+        if (!mAccessibilityManager.isEnabled()) {
+            return;
+        }
+        AccessibilityEvent event = AccessibilityEvent.obtain(
+                AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
+        event.setClassName(Toast.class.getName());
+        event.setPackageName(packageName);
+        view.dispatchPopulateAccessibilityEvent(event);
+        mAccessibilityManager.sendAccessibilityEvent(event);
+    }
+
+    private View getView(CharSequence text) {
+        View view = LayoutInflater.from(mContext).inflate(
+                R.layout.transient_notification, null);
+        TextView textView = view.findViewById(com.android.internal.R.id.message);
+        textView.setText(text);
+        return view;
+    }
+
+    private LayoutParams getLayoutParams(IBinder windowToken, int duration) {
+        WindowManager.LayoutParams params = new WindowManager.LayoutParams();
+        params.height = WindowManager.LayoutParams.WRAP_CONTENT;
+        params.width = WindowManager.LayoutParams.WRAP_CONTENT;
+        params.format = PixelFormat.TRANSLUCENT;
+        params.windowAnimations = com.android.internal.R.style.Animation_Toast;
+        params.type = WindowManager.LayoutParams.TYPE_TOAST;
+        params.setTitle("Toast");
+        params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
+                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+        Configuration config = mContext.getResources().getConfiguration();
+        int specificGravity = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_toastDefaultGravity);
+        int gravity = Gravity.getAbsoluteGravity(specificGravity, config.getLayoutDirection());
+        params.gravity = gravity;
+        if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {
+            params.horizontalWeight = 1.0f;
+        }
+        if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) {
+            params.verticalWeight = 1.0f;
+        }
+        params.x = 0;
+        params.y = mContext.getResources().getDimensionPixelSize(R.dimen.toast_y_offset);
+        params.verticalMargin = 0;
+        params.horizontalMargin = 0;
+        params.packageName = mContext.getPackageName();
+        params.hideTimeoutMilliseconds =
+                (duration == Toast.LENGTH_LONG) ? DURATION_LONG : DURATION_SHORT;
+        params.token = windowToken;
+        return params;
+    }
+
+    private static class ToastEntry {
+        public final String packageName;
+        public final IBinder token;
+        public final View view;
+        public final IBinder windowToken;
+
+        @Nullable
+        public final ITransientNotificationCallback callback;
+
+        private ToastEntry(String packageName, IBinder token, View view, IBinder windowToken,
+                @Nullable ITransientNotificationCallback callback) {
+            this.packageName = packageName;
+            this.token = token;
+            this.view = view;
+            this.windowToken = windowToken;
+            this.callback = callback;
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
index fe8d769..0251f2d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
@@ -33,6 +33,7 @@
 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 static java.util.Objects.requireNonNull;
 
@@ -51,6 +52,7 @@
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.DumpController;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.RankingBuilder;
 import com.android.systemui.statusbar.notification.collection.NoManSimulator.NotifEvent;
 import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason;
@@ -86,6 +88,7 @@
     @Mock private GroupCoalescer mGroupCoalescer;
     @Spy private RecordingCollectionListener mCollectionListener;
     @Mock private CollectionReadyForBuildListener mBuildListener;
+    @Mock private FeatureFlags mFeatureFlags;
 
     @Spy private RecordingLifetimeExtender mExtender1 = new RecordingLifetimeExtender("Extender1");
     @Spy private RecordingLifetimeExtender mExtender2 = new RecordingLifetimeExtender("Extender2");
@@ -105,7 +108,12 @@
         MockitoAnnotations.initMocks(this);
         Assert.sMainLooper = TestableLooper.get(this).getLooper();
 
-        mCollection = new NotifCollection(mStatusBarService, mock(DumpController.class));
+        when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(true);
+        when(mFeatureFlags.isNewNotifPipelineEnabled()).thenReturn(true);
+
+        mCollection = new NotifCollection(mStatusBarService,
+                mock(DumpController.class),
+                mFeatureFlags);
         mCollection.attach(mGroupCoalescer);
         mCollection.addCollectionListener(mCollectionListener);
         mCollection.setBuildListener(mBuildListener);
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
index 79c69304..37ce1d57 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -136,6 +136,12 @@
      */
     public static final int TETHERING_NCM = 4;
 
+    /**
+     * Ethernet tethering type.
+     * @see #startTethering(TetheringRequest, Executor, StartTetheringCallback)
+     */
+    public static final int TETHERING_ETHERNET = 5;
+
     public static final int TETHER_ERROR_NO_ERROR           = 0;
     public static final int TETHER_ERROR_UNKNOWN_IFACE      = 1;
     public static final int TETHER_ERROR_SERVICE_UNAVAIL    = 2;
diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java
index 57cc4dd..190d2509 100644
--- a/packages/Tethering/src/android/net/ip/IpServer.java
+++ b/packages/Tethering/src/android/net/ip/IpServer.java
@@ -93,6 +93,8 @@
     private static final int WIFI_HOST_IFACE_PREFIX_LENGTH = 24;
     private static final String WIFI_P2P_IFACE_ADDR = "192.168.49.1";
     private static final int WIFI_P2P_IFACE_PREFIX_LENGTH = 24;
+    private static final String ETHERNET_IFACE_ADDR = "192.168.50.1";
+    private static final int ETHERNET_IFACE_PREFIX_LENGTH = 24;
 
     // TODO: have PanService use some visible version of this constant
     private static final String BLUETOOTH_IFACE_ADDR = "192.168.44.1";
@@ -426,6 +428,10 @@
             } else if (mInterfaceType == TetheringManager.TETHERING_WIFI_P2P) {
                 srvAddr = (Inet4Address) parseNumericAddress(WIFI_P2P_IFACE_ADDR);
                 prefixLen = WIFI_P2P_IFACE_PREFIX_LENGTH;
+            } else if (mInterfaceType == TetheringManager.TETHERING_ETHERNET) {
+                // TODO: randomize address for tethering too, similarly to wifi
+                srvAddr = (Inet4Address) parseNumericAddress(ETHERNET_IFACE_ADDR);
+                prefixLen = ETHERNET_IFACE_PREFIX_LENGTH;
             } else {
                 // BT configures the interface elsewhere: only start DHCP.
                 // TODO: make all tethering types behave the same way, and delete the bluetooth
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
index 02ba17e..07abe1a 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
@@ -30,6 +30,7 @@
 import static android.net.TetheringManager.EXTRA_AVAILABLE_TETHER;
 import static android.net.TetheringManager.EXTRA_ERRORED_TETHER;
 import static android.net.TetheringManager.TETHERING_BLUETOOTH;
+import static android.net.TetheringManager.TETHERING_ETHERNET;
 import static android.net.TetheringManager.TETHERING_INVALID;
 import static android.net.TetheringManager.TETHERING_NCM;
 import static android.net.TetheringManager.TETHERING_USB;
@@ -68,6 +69,7 @@
 import android.content.res.Resources;
 import android.hardware.usb.UsbManager;
 import android.net.ConnectivityManager;
+import android.net.EthernetManager;
 import android.net.IIntResultListener;
 import android.net.INetd;
 import android.net.ITetheringEventCallback;
@@ -112,6 +114,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.MessageUtils;
@@ -214,6 +217,13 @@
     private boolean mDataSaverEnabled = false;
     private String mWifiP2pTetherInterface = null;
 
+    @GuardedBy("mPublicSync")
+    private EthernetManager.TetheredInterfaceRequest mEthernetIfaceRequest;
+    @GuardedBy("mPublicSync")
+    private String mConfiguredEthernetIface;
+    @GuardedBy("mPublicSync")
+    private EthernetCallback mEthernetCallback;
+
     public Tethering(TetheringDependencies deps) {
         mLog.mark("Tethering.constructed");
         mDeps = deps;
@@ -464,6 +474,10 @@
                 result = setNcmTethering(enable);
                 sendTetherResult(listener, result);
                 break;
+            case TETHERING_ETHERNET:
+                result = setEthernetTethering(enable);
+                sendTetherResult(listener, result);
+                break;
             default:
                 Log.w(TAG, "Invalid tether type.");
                 sendTetherResult(listener, TETHER_ERROR_UNKNOWN_IFACE);
@@ -540,6 +554,57 @@
         }, BluetoothProfile.PAN);
     }
 
+    private int setEthernetTethering(final boolean enable) {
+        final EthernetManager em = (EthernetManager) mContext.getSystemService(
+                Context.ETHERNET_SERVICE);
+        synchronized (mPublicSync) {
+            if (enable) {
+                mEthernetCallback = new EthernetCallback();
+                mEthernetIfaceRequest = em.requestTetheredInterface(mEthernetCallback);
+            } else {
+                if (mConfiguredEthernetIface != null) {
+                    stopEthernetTetheringLocked();
+                    mEthernetIfaceRequest.release();
+                }
+                mEthernetCallback = null;
+            }
+        }
+        return TETHER_ERROR_NO_ERROR;
+    }
+
+    private void stopEthernetTetheringLocked() {
+        if (mConfiguredEthernetIface == null) return;
+        changeInterfaceState(mConfiguredEthernetIface, IpServer.STATE_AVAILABLE);
+        stopTrackingInterfaceLocked(mConfiguredEthernetIface);
+        mConfiguredEthernetIface = null;
+    }
+
+    private class EthernetCallback implements EthernetManager.TetheredInterfaceCallback {
+        @Override
+        public void onAvailable(String iface) {
+            synchronized (mPublicSync) {
+                if (this != mEthernetCallback) {
+                    // Ethernet callback arrived after Ethernet tethering stopped. Ignore.
+                    return;
+                }
+                maybeTrackNewInterfaceLocked(iface, TETHERING_ETHERNET);
+                changeInterfaceState(iface, IpServer.STATE_TETHERED);
+                mConfiguredEthernetIface = iface;
+            }
+        }
+
+        @Override
+        public void onUnavailable() {
+            synchronized (mPublicSync) {
+                if (this != mEthernetCallback) {
+                    // onAvailable called after stopping Ethernet tethering.
+                    return;
+                }
+                stopEthernetTetheringLocked();
+            }
+        }
+    }
+
     int tether(String iface) {
         return tether(iface, IpServer.STATE_TETHERED);
     }
@@ -590,6 +655,7 @@
         stopTethering(TETHERING_WIFI_P2P);
         stopTethering(TETHERING_USB);
         stopTethering(TETHERING_BLUETOOTH);
+        stopTethering(TETHERING_ETHERNET);
     }
 
     int getLastTetherError(String iface) {
diff --git a/packages/Tethering/tests/unit/Android.bp b/packages/Tethering/tests/unit/Android.bp
index 53782fed..13174c5 100644
--- a/packages/Tethering/tests/unit/Android.bp
+++ b/packages/Tethering/tests/unit/Android.bp
@@ -19,6 +19,7 @@
     certificate: "platform",
     srcs: [
         "src/**/*.java",
+        "src/**/*.kt",
     ],
     test_suites: [
         "device-tests",
diff --git a/packages/Tethering/tests/unit/AndroidManifest.xml b/packages/Tethering/tests/unit/AndroidManifest.xml
index 0a1cdd3..530bc07 100644
--- a/packages/Tethering/tests/unit/AndroidManifest.xml
+++ b/packages/Tethering/tests/unit/AndroidManifest.xml
@@ -16,6 +16,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.android.networkstack.tethering.tests.unit">
 
+    <uses-permission android:name="android.permission.TETHER_PRIVILEGED"/>
+
     <application android:debuggable="true">
         <uses-library android:name="android.test.runner" />
     </application>
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 3e74b7a..a5877cc 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -134,6 +134,10 @@
 
     boolean mRequestTouchExplorationMode;
 
+    private boolean mServiceHandlesDoubleTap;
+
+    private boolean mRequestMultiFingerGestures;
+
     boolean mRequestFilterKeyEvents;
 
     boolean mRetrieveInteractiveWindows;
@@ -298,6 +302,10 @@
 
         mRequestTouchExplorationMode = (info.flags
                 & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
+        mServiceHandlesDoubleTap = (info.flags
+                & AccessibilityServiceInfo.FLAG_SERVICE_HANDLES_DOUBLE_TAP) != 0;
+        mRequestMultiFingerGestures = (info.flags
+                & AccessibilityServiceInfo.FLAG_REQUEST_MULTI_FINGER_GESTURES) != 0;
         mRequestFilterKeyEvents = (info.flags
                 & AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS) != 0;
         mRetrieveInteractiveWindows = (info.flags
@@ -1689,4 +1697,12 @@
             msg.sendToTarget();
         }
     }
+
+    public boolean isServiceHandlesDoubleTapEnabled() {
+        return mServiceHandlesDoubleTap;
+    }
+
+    public boolean isMultiFingerGesturesEnabled() {
+        return mRequestMultiFingerGestures;
+    }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 49582a9..efddd86 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -99,9 +99,28 @@
      */
     static final int FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER = 0x00000040;
 
-    static final int FEATURES_AFFECTING_MOTION_EVENTS = FLAG_FEATURE_INJECT_MOTION_EVENTS
-            | FLAG_FEATURE_AUTOCLICK | FLAG_FEATURE_TOUCH_EXPLORATION
-            | FLAG_FEATURE_SCREEN_MAGNIFIER | FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER;
+    /**
+     * Flag for dispatching double tap and double tap and hold to the service.
+     *
+     * @see #setUserAndEnabledFeatures(int, int)
+     */
+    static final int FLAG_SERVICE_HANDLES_DOUBLE_TAP = 0x00000080;
+
+/**
+     * Flag for enabling multi-finger gestures.
+     *
+     * @see #setUserAndEnabledFeatures(int, int)
+     */
+    static final int FLAG_REQUEST_MULTI_FINGER_GESTURES = 0x00000100;
+
+    static final int FEATURES_AFFECTING_MOTION_EVENTS =
+            FLAG_FEATURE_INJECT_MOTION_EVENTS
+                    | FLAG_FEATURE_AUTOCLICK
+                    | FLAG_FEATURE_TOUCH_EXPLORATION
+                    | FLAG_FEATURE_SCREEN_MAGNIFIER
+                    | FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER
+                    | FLAG_SERVICE_HANDLES_DOUBLE_TAP
+                    | FLAG_REQUEST_MULTI_FINGER_GESTURES;
 
     private final Context mContext;
 
@@ -391,6 +410,12 @@
 
             if ((mEnabledFeatures & FLAG_FEATURE_TOUCH_EXPLORATION) != 0) {
                 TouchExplorer explorer = new TouchExplorer(displayContext, mAms);
+                if ((mEnabledFeatures & FLAG_SERVICE_HANDLES_DOUBLE_TAP) != 0) {
+                    explorer.setServiceHandlesDoubleTap(true);
+                }
+                if ((mEnabledFeatures & FLAG_REQUEST_MULTI_FINGER_GESTURES) != 0) {
+                    explorer.setMultiFingerGesturesEnabled(true);
+                }
                 addFirstEventHandler(displayId, explorer);
                 mTouchExplorer.put(displayId, explorer);
             }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index bcaecea..61e1adf 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1610,6 +1610,12 @@
             if (userState.isHandlingAccessibilityEventsLocked()
                     && userState.isTouchExplorationEnabledLocked()) {
                 flags |= AccessibilityInputFilter.FLAG_FEATURE_TOUCH_EXPLORATION;
+                if (userState.isServiceHandlesDoubleTapEnabledLocked()) {
+                    flags |= AccessibilityInputFilter.FLAG_SERVICE_HANDLES_DOUBLE_TAP;
+                }
+                if (userState.isMultiFingerGesturesEnabledLocked()) {
+                    flags |= AccessibilityInputFilter.FLAG_REQUEST_MULTI_FINGER_GESTURES;
+                }
             }
             if (userState.isFilterKeyEventsEnabledLocked()) {
                 flags |= AccessibilityInputFilter.FLAG_FEATURE_FILTER_KEY_EVENTS;
@@ -1882,26 +1888,32 @@
     }
 
     private void updateTouchExplorationLocked(AccessibilityUserState userState) {
-        boolean enabled = mUiAutomationManager.isTouchExplorationEnabledLocked();
+        boolean touchExplorationEnabled = mUiAutomationManager.isTouchExplorationEnabledLocked();
+        boolean serviceHandlesDoubleTapEnabled = false;
+        boolean requestMultiFingerGestures = false;
         final int serviceCount = userState.mBoundServices.size();
         for (int i = 0; i < serviceCount; i++) {
             AccessibilityServiceConnection service = userState.mBoundServices.get(i);
             if (canRequestAndRequestsTouchExplorationLocked(service, userState)) {
-                enabled = true;
+                touchExplorationEnabled = true;
+                serviceHandlesDoubleTapEnabled = service.isServiceHandlesDoubleTapEnabled();
+                requestMultiFingerGestures = service.isMultiFingerGesturesEnabled();
                 break;
             }
         }
-        if (enabled != userState.isTouchExplorationEnabledLocked()) {
-            userState.setTouchExplorationEnabledLocked(enabled);
+        if (touchExplorationEnabled != userState.isTouchExplorationEnabledLocked()) {
+            userState.setTouchExplorationEnabledLocked(touchExplorationEnabled);
             final long identity = Binder.clearCallingIdentity();
             try {
                 Settings.Secure.putIntForUser(mContext.getContentResolver(),
-                        Settings.Secure.TOUCH_EXPLORATION_ENABLED, enabled ? 1 : 0,
+                        Settings.Secure.TOUCH_EXPLORATION_ENABLED, touchExplorationEnabled ? 1 : 0,
                         userState.mUserId);
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
         }
+        userState.setServiceHandlesDoubleTapLocked(serviceHandlesDoubleTapEnabled);
+        userState.setMultiFingerGesturesLocked(requestMultiFingerGestures);
     }
 
     private boolean readAccessibilityShortcutKeySettingLocked(AccessibilityUserState userState) {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
index ebe2af6..4e7da97 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
@@ -103,6 +103,8 @@
     private boolean mIsPerformGesturesEnabled;
     private boolean mIsTextHighContrastEnabled;
     private boolean mIsTouchExplorationEnabled;
+    private boolean mServiceHandlesDoubleTap;
+    private boolean mRequestMultiFingerGestures;
     private int mUserInteractiveUiTimeout;
     private int mUserNonInteractiveUiTimeout;
     private int mNonInteractiveUiTimeout = 0;
@@ -151,6 +153,8 @@
         mAccessibilityShortcutKeyTargets.clear();
         mAccessibilityButtonTargets.clear();
         mIsTouchExplorationEnabled = false;
+        mServiceHandlesDoubleTap = false;
+        mRequestMultiFingerGestures = false;
         mIsDisplayMagnificationEnabled = false;
         mIsAutoclickEnabled = false;
         mUserNonInteractiveUiTimeout = 0;
@@ -351,6 +355,8 @@
         // Touch exploration relies on enabled accessibility.
         if (a11yEnabled && mIsTouchExplorationEnabled) {
             clientState |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED;
+            clientState |= AccessibilityManager.STATE_FLAG_DISPATCH_DOUBLE_TAP;
+            clientState |= AccessibilityManager.STATE_FLAG_REQUEST_MULTI_FINGER_GESTURES;
         }
         if (mIsTextHighContrastEnabled) {
             clientState |= AccessibilityManager.STATE_FLAG_HIGH_TEXT_CONTRAST_ENABLED;
@@ -431,6 +437,10 @@
         pw.println();
         pw.append("     attributes:{id=").append(String.valueOf(mUserId));
         pw.append(", touchExplorationEnabled=").append(String.valueOf(mIsTouchExplorationEnabled));
+        pw.append(", serviceHandlesDoubleTap=")
+                .append(String.valueOf(mServiceHandlesDoubleTap));
+        pw.append(", requestMultiFingerGestures=")
+                .append(String.valueOf(mRequestMultiFingerGestures));
         pw.append(", displayMagnificationEnabled=").append(String.valueOf(
                 mIsDisplayMagnificationEnabled));
         pw.append(", autoclickEnabled=").append(String.valueOf(mIsAutoclickEnabled));
@@ -675,6 +685,22 @@
         mIsTouchExplorationEnabled = enabled;
     }
 
+    public boolean isServiceHandlesDoubleTapEnabledLocked() {
+        return mServiceHandlesDoubleTap;
+    }
+
+    public void setServiceHandlesDoubleTapLocked(boolean enabled) {
+        mServiceHandlesDoubleTap = enabled;
+    }
+
+    public boolean isMultiFingerGesturesEnabledLocked() {
+        return mRequestMultiFingerGestures;
+    }
+
+    public void setMultiFingerGesturesLocked(boolean enabled) {
+        mRequestMultiFingerGestures = enabled;
+    }
+
     public int getUserInteractiveUiTimeoutLocked() {
         return mUserInteractiveUiTimeout;
     }
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java b/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java
index 50d21ba..b5660ae 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java
@@ -65,6 +65,13 @@
     private final Handler mHandler;
     // Listener to be notified of gesture start and end.
     private Listener mListener;
+    // Whether double tap and double tap and hold will be dispatched to the service or handled in
+    // the framework.
+    private boolean mServiceHandlesDoubleTap = false;
+    // Whether multi-finger gestures are enabled.
+    boolean mMultiFingerGesturesEnabled;
+    // A list of all the multi-finger gestures, for easy adding and removal.
+    private final List<GestureMatcher> mMultiFingerGestures = new ArrayList<>();
     // Shared state information.
     private TouchState mState;
 
@@ -154,18 +161,23 @@
      */
     public interface Listener {
         /**
-         * Called when the user has performed a double tap and then held down the second tap.
+         * When FLAG_SERVICE_HANDLES_DOUBLE_TAP is enabled, this method is not called; double-tap
+         * and hold is dispatched via onGestureCompleted. Otherwise, this method is called when the
+         * user has performed a double tap and then held down the second tap.
          */
         void onDoubleTapAndHold();
 
         /**
-         * Called when the user lifts their finger on the second tap of a double tap.
+         * When FLAG_SERVICE_HANDLES_DOUBLE_TAP is enabled, this method is not called; double-tap is
+         * dispatched via onGestureCompleted. Otherwise, this method is called when the user lifts
+         * their finger on the second tap of a double tap.
+         *
          * @return true if the event is consumed, else false
          */
         boolean onDoubleTap();
 
         /**
-         * Called when the system has decided the event stream is a gesture.
+         * Called when the system has decided the event stream is a potential gesture.
          *
          * @return true if the event is consumed, else false
          */
@@ -193,7 +205,13 @@
     public void onStateChanged(
             int gestureId, int state, MotionEvent event, MotionEvent rawEvent, int policyFlags) {
         if (state == GestureMatcher.STATE_GESTURE_STARTED && !mState.isGestureDetecting()) {
-            mListener.onGestureStarted();
+            if (gestureId == GESTURE_DOUBLE_TAP || gestureId == GESTURE_DOUBLE_TAP_AND_HOLD) {
+                if (mServiceHandlesDoubleTap) {
+                    mListener.onGestureStarted();
+                }
+            } else {
+                mListener.onGestureStarted();
+            }
         } else if (state == GestureMatcher.STATE_GESTURE_COMPLETED) {
             onGestureCompleted(gestureId);
         } else if (state == GestureMatcher.STATE_GESTURE_CANCELED && mState.isGestureDetecting()) {
@@ -217,11 +235,23 @@
         // Gestures that complete on a delay call clear() here.
         switch (gestureId) {
             case GESTURE_DOUBLE_TAP:
-                mListener.onDoubleTap();
+                if (mServiceHandlesDoubleTap) {
+                    AccessibilityGestureEvent gestureEvent =
+                            new AccessibilityGestureEvent(gestureId, event.getDisplayId());
+                    mListener.onGestureCompleted(gestureEvent);
+                } else {
+                    mListener.onDoubleTap();
+                }
                 clear();
                 break;
             case GESTURE_DOUBLE_TAP_AND_HOLD:
-                mListener.onDoubleTapAndHold();
+                if (mServiceHandlesDoubleTap) {
+                    AccessibilityGestureEvent gestureEvent =
+                            new AccessibilityGestureEvent(gestureId, event.getDisplayId());
+                    mListener.onGestureCompleted(gestureEvent);
+                } else {
+                    mListener.onDoubleTapAndHold();
+                }
                 clear();
                 break;
             default:
@@ -231,4 +261,27 @@
                 break;
         }
     }
+
+    public boolean isMultiFingerGesturesEnabled() {
+        return mMultiFingerGesturesEnabled;
+    }
+
+    public void setMultiFingerGesturesEnabled(boolean mode) {
+        if (mMultiFingerGesturesEnabled != mode) {
+            mMultiFingerGesturesEnabled = mode;
+            if (mode) {
+                mGestures.addAll(mMultiFingerGestures);
+            } else {
+                mGestures.removeAll(mMultiFingerGestures);
+            }
+        }
+    }
+
+    public void setServiceHandlesDoubleTap(boolean mode) {
+        mServiceHandlesDoubleTap = mode;
+    }
+
+    public boolean isServiceHandlesDoubleTapEnabled() {
+        return mServiceHandlesDoubleTap;
+    }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/MultiTap.java b/services/accessibility/java/com/android/server/accessibility/gestures/MultiTap.java
index 4c9e590..386cb06 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/MultiTap.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/MultiTap.java
@@ -70,6 +70,13 @@
         }
         mBaseX = event.getX();
         mBaseY = event.getY();
+        if (mCurrentTaps + 1 == mTargetTaps) {
+            // Start gesture detecting on down of final tap.
+            // Note that if this instance is matching double tap,
+            // and the service is not requesting to handle double tap, GestureManifold will
+            // ignore this.
+            startGesture(event, rawEvent, policyFlags);
+        }
     }
 
     @Override
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index ba890c5..2cc11c5 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -254,7 +254,10 @@
         } else if (mState.isDelegating()) {
             handleMotionEventStateDelegating(event, rawEvent, policyFlags);
         } else if (mState.isGestureDetecting()) {
-            // Already handled.
+            // Make sure we don't prematurely get TOUCH_INTERACTION_END
+            // It will be delivered on gesture completion or cancelation.
+            // Note that the delay for sending GESTURE_DETECTION_END remains in place.
+            mSendTouchInteractionEndDelayed.cancel();
         } else {
             Slog.e(LOG_TAG, "Illegal state: " + mState);
                 clear(event, policyFlags);
@@ -331,12 +334,8 @@
 
     @Override
     public boolean onGestureCompleted(AccessibilityGestureEvent gestureEvent) {
-        if (!mState.isGestureDetecting()) {
-            return false;
-        }
-
         endGestureDetection(true);
-
+        mSendTouchInteractionEndDelayed.cancel();
         mAms.onGesture(gestureEvent);
 
         return true;
@@ -516,6 +515,9 @@
                 }
                 break;
             case 2:
+                if (mGestureDetector.isMultiFingerGesturesEnabled()) {
+                    return;
+                }
                 // Make sure we don't have any pending transitions to touch exploration
                 mSendHoverEnterAndMoveDelayed.cancel();
                 mSendHoverExitDelayed.cancel();
@@ -538,6 +540,9 @@
                 }
                 break;
             default:
+                if (mGestureDetector.isMultiFingerGesturesEnabled()) {
+                    return;
+                }
                 // More than two pointers are delegated to the view hierarchy.
                 mState.startDelegating();
                 event = MotionEvent.obtainNoHistory(event);
@@ -583,6 +588,9 @@
                         event, MotionEvent.ACTION_HOVER_MOVE, rawEvent, pointerIdBits, policyFlags);
                 break;
             case 2:
+                if (mGestureDetector.isMultiFingerGesturesEnabled()) {
+                    return;
+                }
                 if (mSendHoverEnterAndMoveDelayed.isPending()) {
                     // We have not started sending events so cancel
                     // scheduled sending events.
@@ -610,6 +618,9 @@
                 }
                 break;
             default:
+                if (mGestureDetector.isMultiFingerGesturesEnabled()) {
+                    return;
+                }
                 // Three or more fingers is  something other than touch exploration.
                 if (mSendHoverEnterAndMoveDelayed.isPending()) {
                     // We have not started sending events so cancel
@@ -632,6 +643,10 @@
      */
     private void handleMotionEventStateDragging(
             MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        if (mGestureDetector.isMultiFingerGesturesEnabled()) {
+            // Multi-finger gestures conflict with this functionality.
+            return;
+        }
         int pointerIdBits = 0;
         // Clear the dragging pointer id if it's no longer valid.
         if (event.findPointerIndex(mDraggingPointerId) == -1) {
@@ -742,6 +757,10 @@
      */
     private void handleMotionEventStateDelegating(
             MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        if (mGestureDetector.isMultiFingerGesturesEnabled()) {
+            // Multi-finger gestures conflict with this functionality.
+            return;
+        }
         switch (event.getActionMasked()) {
             case MotionEvent.ACTION_DOWN: {
                 Slog.e(LOG_TAG, "Delegating state can only be reached if "
@@ -875,6 +894,22 @@
     }
 
     /**
+     * Whether to dispatch double tap and double tap and hold to the service rather than handle them
+     * in the framework.
+     */
+    public void setServiceHandlesDoubleTap(boolean mode) {
+        mGestureDetector.setServiceHandlesDoubleTap(mode);
+    }
+
+    /**
+     * This function turns on and off multi-finger gestures. When enabled, multi-finger gestures
+     * will disable delegating and dragging functionality.
+     */
+    public void setMultiFingerGesturesEnabled(boolean enabled) {
+        mGestureDetector.setMultiFingerGesturesEnabled(enabled);
+    }
+
+    /**
      * Class for delayed exiting from gesture detecting mode.
      */
     private final class ExitGestureDetectionModeDelayed implements Runnable {
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 9245a1d..0b7029b 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -109,6 +109,7 @@
 public final class ContentCaptureManagerService extends
         AbstractMasterSystemService<ContentCaptureManagerService, ContentCapturePerUserService> {
 
+    private static final String TAG = ContentCaptureManagerService.class.getSimpleName();
     static final String RECEIVER_BUNDLE_EXTRA_SESSIONS = "sessions";
 
     private static final int MAX_TEMP_SERVICE_DURATION_MS = 1_000 * 60 * 2; // 2 minutes
@@ -167,11 +168,11 @@
         setDeviceConfigProperties();
 
         if (mDevCfgLogHistorySize > 0) {
-            if (debug) Slog.d(mTag, "log history size: " + mDevCfgLogHistorySize);
+            if (debug) Slog.d(TAG, "log history size: " + mDevCfgLogHistorySize);
             mRequestsHistory = new LocalLog(mDevCfgLogHistorySize);
         } else {
             if (debug) {
-                Slog.d(mTag, "disabled log history because size is " + mDevCfgLogHistorySize);
+                Slog.d(TAG, "disabled log history because size is " + mDevCfgLogHistorySize);
             }
             mRequestsHistory = null;
         }
@@ -182,7 +183,7 @@
             final boolean disabled = !isEnabledBySettings(userId);
             // Sets which services are disabled by settings
             if (disabled) {
-                Slog.i(mTag, "user " + userId + " disabled by settings");
+                Slog.i(TAG, "user " + userId + " disabled by settings");
                 if (mDisabledBySettings == null) {
                     mDisabledBySettings = new SparseBooleanArray(1);
                 }
@@ -245,7 +246,7 @@
 
     @Override // from AbstractMasterSystemService
     protected void enforceCallingPermissionForManagement() {
-        getContext().enforceCallingPermission(MANAGE_CONTENT_CAPTURE, mTag);
+        getContext().enforceCallingPermission(MANAGE_CONTENT_CAPTURE, TAG);
     }
 
     @Override // from AbstractMasterSystemService
@@ -269,7 +270,7 @@
                         isEnabledBySettings(userId));
                 return;
             default:
-                Slog.w(mTag, "Unexpected property (" + property + "); updating cache instead");
+                Slog.w(TAG, "Unexpected property (" + property + "); updating cache instead");
         }
     }
 
@@ -306,7 +307,7 @@
                     setFineTuneParamsFromDeviceConfig();
                     return;
                 default:
-                    Slog.i(mTag, "Ignoring change on " + key);
+                    Slog.i(TAG, "Ignoring change on " + key);
             }
         }
     }
@@ -333,7 +334,7 @@
                     ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT,
                     (int) AbstractRemoteService.PERMANENT_BOUND_TIMEOUT_MS);
             if (verbose) {
-                Slog.v(mTag, "setFineTuneParamsFromDeviceConfig(): "
+                Slog.v(TAG, "setFineTuneParamsFromDeviceConfig(): "
                         + "bufferSize=" + mDevCfgMaxBufferSize
                         + ", idleFlush=" + mDevCfgIdleFlushingFrequencyMs
                         + ", textFluxh=" + mDevCfgTextChangeFlushingFrequencyMs
@@ -352,7 +353,7 @@
         verbose = ContentCaptureHelper.sVerbose;
         debug = ContentCaptureHelper.sDebug;
         if (verbose) {
-            Slog.v(mTag, "setLoggingLevelFromDeviceConfig(): level=" + mDevCfgLoggingLevel
+            Slog.v(TAG, "setLoggingLevelFromDeviceConfig(): level=" + mDevCfgLoggingLevel
                     + ", debug=" + debug + ", verbose=" + verbose);
         }
     }
@@ -367,7 +368,7 @@
 
     private void setDisabledByDeviceConfig(@Nullable String explicitlyEnabled) {
         if (verbose) {
-            Slog.v(mTag, "setDisabledByDeviceConfig(): explicitlyEnabled=" + explicitlyEnabled);
+            Slog.v(TAG, "setDisabledByDeviceConfig(): explicitlyEnabled=" + explicitlyEnabled);
         }
         final List<UserInfo> users = getSupportedUsers();
 
@@ -382,17 +383,17 @@
         synchronized (mLock) {
             if (mDisabledByDeviceConfig == newDisabledValue) {
                 if (verbose) {
-                    Slog.v(mTag, "setDisabledByDeviceConfig(): already " + newDisabledValue);
+                    Slog.v(TAG, "setDisabledByDeviceConfig(): already " + newDisabledValue);
                 }
                 return;
             }
             mDisabledByDeviceConfig = newDisabledValue;
 
-            Slog.i(mTag, "setDisabledByDeviceConfig(): set to " + mDisabledByDeviceConfig);
+            Slog.i(TAG, "setDisabledByDeviceConfig(): set to " + mDisabledByDeviceConfig);
             for (int i = 0; i < users.size(); i++) {
                 final int userId = users.get(i).id;
                 boolean disabled = mDisabledByDeviceConfig || isDisabledBySettingsLocked(userId);
-                Slog.i(mTag, "setDisabledByDeviceConfig(): updating service for user "
+                Slog.i(TAG, "setDisabledByDeviceConfig(): updating service for user "
                         + userId + " to " + (disabled ? "'disabled'" : "'enabled'"));
                 updateCachedServiceLocked(userId, disabled);
             }
@@ -408,16 +409,16 @@
             final boolean alreadyEnabled = !mDisabledBySettings.get(userId);
             if (!(enabled ^ alreadyEnabled)) {
                 if (debug) {
-                    Slog.d(mTag, "setContentCaptureFeatureEnabledForUser(): already " + enabled);
+                    Slog.d(TAG, "setContentCaptureFeatureEnabledForUser(): already " + enabled);
                 }
                 return;
             }
             if (enabled) {
-                Slog.i(mTag, "setContentCaptureFeatureEnabled(): enabling service for user "
+                Slog.i(TAG, "setContentCaptureFeatureEnabled(): enabling service for user "
                         + userId);
                 mDisabledBySettings.delete(userId);
             } else {
-                Slog.i(mTag, "setContentCaptureFeatureEnabled(): disabling service for user "
+                Slog.i(TAG, "setContentCaptureFeatureEnabled(): disabling service for user "
                         + userId);
                 mDisabledBySettings.put(userId, true);
             }
@@ -428,7 +429,7 @@
 
     // Called by Shell command.
     void destroySessions(@UserIdInt int userId, @NonNull IResultReceiver receiver) {
-        Slog.i(mTag, "destroySessions() for userId " + userId);
+        Slog.i(TAG, "destroySessions() for userId " + userId);
         enforceCallingPermissionForManagement();
 
         synchronized (mLock) {
@@ -451,7 +452,7 @@
 
     // Called by Shell command.
     void listSessions(int userId, IResultReceiver receiver) {
-        Slog.i(mTag, "listSessions() for userId " + userId);
+        Slog.i(TAG, "listSessions() for userId " + userId);
         enforceCallingPermissionForManagement();
 
         final Bundle resultData = new Bundle();
@@ -498,14 +499,14 @@
         final int callingUid = Binder.getCallingUid();
         final String serviceName = mServiceNameResolver.getServiceName(userId);
         if (serviceName == null) {
-            Slog.e(mTag, methodName + ": called by UID " + callingUid
+            Slog.e(TAG, methodName + ": called by UID " + callingUid
                     + ", but there's no service set for user " + userId);
             return false;
         }
 
         final ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName);
         if (serviceComponent == null) {
-            Slog.w(mTag, methodName + ": invalid service name: " + serviceName);
+            Slog.w(TAG, methodName + ": invalid service name: " + serviceName);
             return false;
         }
 
@@ -516,11 +517,11 @@
         try {
             serviceUid = pm.getPackageUidAsUser(servicePackageName, UserHandle.getCallingUserId());
         } catch (NameNotFoundException e) {
-            Slog.w(mTag, methodName + ": could not verify UID for " + serviceName);
+            Slog.w(TAG, methodName + ": could not verify UID for " + serviceName);
             return false;
         }
         if (callingUid != serviceUid) {
-            Slog.e(mTag, methodName + ": called by UID " + callingUid + ", but service UID is "
+            Slog.e(TAG, methodName + ": called by UID " + callingUid + ", but service UID is "
                     + serviceUid);
             return false;
         }
@@ -543,7 +544,7 @@
             try {
                 result.send(RESULT_CODE_SECURITY_EXCEPTION, bundleFor(e.getMessage()));
             } catch (RemoteException e2) {
-                Slog.w(mTag, "Unable to send security exception (" + e + "): ", e2);
+                Slog.w(TAG, "Unable to send security exception (" + e + "): ", e2);
             }
         }
         return true;
@@ -628,7 +629,7 @@
             try {
                 result.send(RESULT_CODE_OK, bundleFor(connectedServiceComponentName));
             } catch (RemoteException e) {
-                Slog.w(mTag, "Unable to send service component name: " + e);
+                Slog.w(TAG, "Unable to send service component name: " + e);
             }
         }
 
@@ -646,6 +647,7 @@
 
         @Override
         public void shareData(@NonNull DataShareRequest request,
+                @NonNull ICancellationSignal clientCancellationSignal,
                 @NonNull IDataShareWriteAdapter clientAdapter) {
             Preconditions.checkNotNull(request);
             Preconditions.checkNotNull(clientAdapter);
@@ -661,13 +663,14 @@
                     try {
                         clientAdapter.error(DataShareWriteAdapter.ERROR_CONCURRENT_REQUEST);
                     } catch (RemoteException e) {
-                        Slog.e(mTag, "Failed to send error message to client");
+                        Slog.e(TAG, "Failed to send error message to client");
                     }
                     return;
                 }
 
                 service.onDataSharedLocked(request,
-                        new DataShareCallbackDelegate(request, clientAdapter));
+                        new DataShareCallbackDelegate(request, clientCancellationSignal,
+                                clientAdapter));
             }
         }
 
@@ -686,7 +689,7 @@
             try {
                 result.send(enabled ? RESULT_CODE_TRUE : RESULT_CODE_FALSE, /* resultData= */null);
             } catch (RemoteException e) {
-                Slog.w(mTag, "Unable to send isContentCaptureFeatureEnabled(): " + e);
+                Slog.w(TAG, "Unable to send isContentCaptureFeatureEnabled(): " + e);
             }
         }
 
@@ -706,7 +709,7 @@
             try {
                 result.send(RESULT_CODE_OK, bundleFor(componentName));
             } catch (RemoteException e) {
-                Slog.w(mTag, "Unable to send getServiceSettingsIntent(): " + e);
+                Slog.w(TAG, "Unable to send getServiceSettingsIntent(): " + e);
             }
         }
 
@@ -727,13 +730,13 @@
             try {
                 result.send(RESULT_CODE_OK, bundleFor(conditions));
             } catch (RemoteException e) {
-                Slog.w(mTag, "Unable to send getServiceComponentName(): " + e);
+                Slog.w(TAG, "Unable to send getServiceComponentName(): " + e);
             }
         }
 
         @Override
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-            if (!DumpUtils.checkDumpPermission(getContext(), mTag, pw)) return;
+            if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
 
             boolean showHistory = true;
             if (args != null) {
@@ -746,7 +749,7 @@
                             pw.println("Usage: dumpsys content_capture [--no-history]");
                             return;
                         default:
-                            Slog.w(mTag, "Ignoring invalid dump arg: " + arg);
+                            Slog.w(TAG, "Ignoring invalid dump arg: " + arg);
                     }
                 }
             }
@@ -843,7 +846,7 @@
                     final ComponentName componentName =
                             ComponentName.unflattenFromString(serviceName);
                     if (componentName == null) {
-                        Slog.w(mTag, "setServiceInfo(): invalid name: " + serviceName);
+                        Slog.w(TAG, "setServiceInfo(): invalid name: " + serviceName);
                         mServicePackages.remove(userId);
                     } else {
                         mServicePackages.put(userId, componentName.getPackageName());
@@ -869,7 +872,7 @@
                             && packageName.equals(mServicePackages.get(userId))) {
                         // No components whitelisted either, but let it go because it's the
                         // service's own package
-                        if (verbose) Slog.v(mTag, "getOptionsForPackage() lite for " + packageName);
+                        if (verbose) Slog.v(TAG, "getOptionsForPackage() lite for " + packageName);
                         return new ContentCaptureOptions(mDevCfgLoggingLevel);
                     }
                 }
@@ -878,7 +881,7 @@
             // Restrict what temporary services can whitelist
             if (Build.IS_USER && mServiceNameResolver.isTemporary(userId)) {
                 if (!packageName.equals(mServicePackages.get(userId))) {
-                    Slog.w(mTag, "Ignoring package " + packageName + " while using temporary "
+                    Slog.w(TAG, "Ignoring package " + packageName + " while using temporary "
                             + "service " + mServicePackages.get(userId));
                     return null;
                 }
@@ -887,7 +890,7 @@
             if (!packageWhitelisted && whitelistedComponents == null) {
                 // No can do!
                 if (verbose) {
-                    Slog.v(mTag, "getOptionsForPackage(" + packageName + "): not whitelisted");
+                    Slog.v(TAG, "getOptionsForPackage(" + packageName + "): not whitelisted");
                 }
                 return null;
             }
@@ -896,7 +899,7 @@
                     mDevCfgMaxBufferSize, mDevCfgIdleFlushingFrequencyMs,
                     mDevCfgTextChangeFlushingFrequencyMs, mDevCfgLogHistorySize,
                     whitelistedComponents);
-            if (verbose) Slog.v(mTag, "getOptionsForPackage(" + packageName + "): " + options);
+            if (verbose) Slog.v(TAG, "getOptionsForPackage(" + packageName + "): " + options);
             return options;
         }
 
@@ -920,18 +923,21 @@
     private class DataShareCallbackDelegate extends IDataShareCallback.Stub {
 
         @NonNull private final DataShareRequest mDataShareRequest;
+        @NonNull private final ICancellationSignal mClientCancellationSignal;
         @NonNull private final IDataShareWriteAdapter mClientAdapter;
 
         DataShareCallbackDelegate(@NonNull DataShareRequest dataShareRequest,
+                @NonNull ICancellationSignal clientCancellationSignal,
                 @NonNull IDataShareWriteAdapter clientAdapter) {
             mDataShareRequest = dataShareRequest;
+            mClientCancellationSignal = clientCancellationSignal;
             mClientAdapter = clientAdapter;
         }
 
         @Override
-        public void accept(IDataShareReadAdapter serviceAdapter)
-                            throws RemoteException {
-            Slog.i(mTag, "Data share request accepted by Content Capture service");
+        public void accept(ICancellationSignal serviceCancellationSignal,
+                IDataShareReadAdapter serviceAdapter) throws RemoteException {
+            Slog.i(TAG, "Data share request accepted by Content Capture service");
 
             Pair<ParcelFileDescriptor, ParcelFileDescriptor> clientPipe = createPipe();
             if (clientPipe == null) {
@@ -962,17 +968,14 @@
             mClientAdapter.write(source_in);
             serviceAdapter.start(sink_out, cancellationSignalTransport);
 
-            // TODO(b/148264965): use cancellation signals for timeouts and cancelling
             CancellationSignal cancellationSignal =
                     CancellationSignal.fromTransport(cancellationSignalTransport);
 
             cancellationSignal.setOnCancelListener(() -> {
                 try {
-                    // TODO(b/148264965): this should propagate with the cancellation signal to the
-                    // client
-                    mClientAdapter.error(DataShareWriteAdapter.ERROR_UNKNOWN);
+                    mClientCancellationSignal.cancel();
                 } catch (RemoteException e) {
-                    Slog.e(mTag, "Failed to propagate cancel operation to the caller", e);
+                    Slog.e(TAG, "Failed to propagate cancel operation to the caller", e);
                 }
             });
 
@@ -998,7 +1001,7 @@
                         fos.write(byteBuffer, 0 /* offset */, readBytes);
                     }
                 } catch (IOException e) {
-                    Slog.e(mTag, "Failed to pipe client and service streams", e);
+                    Slog.e(TAG, "Failed to pipe client and service streams", e);
                 }
             });
 
@@ -1013,12 +1016,12 @@
                             && !source_out.getFileDescriptor().valid();
 
                     if (finishedSuccessfully) {
-                        Slog.i(mTag, "Content capture data sharing session terminated "
+                        Slog.i(TAG, "Content capture data sharing session terminated "
                                 + "successfully for package '"
                                 + mDataShareRequest.getPackageName()
                                 + "'");
                     } else {
-                        Slog.i(mTag, "Reached the timeout of Content Capture data sharing session "
+                        Slog.i(TAG, "Reached the timeout of Content Capture data sharing session "
                                 + "for package '"
                                 + mDataShareRequest.getPackageName()
                                 + "', terminating the pipe.");
@@ -1029,14 +1032,14 @@
 
                     if (!finishedSuccessfully) {
                         try {
-                            mClientAdapter.error(DataShareWriteAdapter.ERROR_UNKNOWN);
+                            mClientCancellationSignal.cancel();
                         } catch (RemoteException e) {
-                            Slog.e(mTag, "Failed to call error() to client", e);
+                            Slog.e(TAG, "Failed to cancel() the client operation", e);
                         }
                         try {
-                            serviceAdapter.error(DataShareWriteAdapter.ERROR_UNKNOWN);
+                            serviceCancellationSignal.cancel();
                         } catch (RemoteException e) {
-                            Slog.e(mTag, "Failed to call error() to service", e);
+                            Slog.e(TAG, "Failed to cancel() the service operation", e);
                         }
                     }
                 }
@@ -1045,7 +1048,7 @@
 
         @Override
         public void reject() throws RemoteException {
-            Slog.i(mTag, "Data share request rejected by Content Capture service");
+            Slog.i(TAG, "Data share request rejected by Content Capture service");
 
             mClientAdapter.rejected();
         }
@@ -1055,19 +1058,19 @@
             try {
                 fileDescriptors = ParcelFileDescriptor.createPipe();
             } catch (IOException e) {
-                Slog.e(mTag, "Failed to create a content capture data-sharing pipe", e);
+                Slog.e(TAG, "Failed to create a content capture data-sharing pipe", e);
                 return null;
             }
 
             if (fileDescriptors.length != 2) {
-                Slog.e(mTag, "Failed to create a content capture data-sharing pipe, "
+                Slog.e(TAG, "Failed to create a content capture data-sharing pipe, "
                         + "unexpected number of file descriptors");
                 return null;
             }
 
             if (!fileDescriptors[0].getFileDescriptor().valid()
                     || !fileDescriptors[1].getFileDescriptor().valid()) {
-                Slog.e(mTag, "Failed to create a content capture data-sharing pipe, didn't "
+                Slog.e(TAG, "Failed to create a content capture data-sharing pipe, didn't "
                         + "receive a pair of valid file descriptors.");
                 return null;
             }
@@ -1079,7 +1082,7 @@
             try {
                 fd.close();
             } catch (IOException e) {
-                Slog.e(mTag, "Failed to close a file descriptor", e);
+                Slog.e(TAG, "Failed to close a file descriptor", e);
             }
         }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c987dea..8b547c6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1799,7 +1799,7 @@
                 case KILL_APP_ZYGOTE_MSG: {
                     synchronized (ActivityManagerService.this) {
                         final AppZygote appZygote = (AppZygote) msg.obj;
-                        mProcessList.killAppZygoteIfNeededLocked(appZygote);
+                        mProcessList.killAppZygoteIfNeededLocked(appZygote, false /* force */);
                     }
                 } break;
             case CHECK_EXCESSIVE_POWER_USE_MSG: {
@@ -4657,6 +4657,22 @@
     }
 
     @GuardedBy("this")
+    final void forceStopAppZygoteLocked(String packageName, int appId, int userId) {
+        if (packageName == null) {
+            return;
+        }
+        if (appId < 0) {
+            try {
+                appId = UserHandle.getAppId(AppGlobals.getPackageManager()
+                        .getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING, 0));
+            } catch (RemoteException e) {
+            }
+        }
+
+        mProcessList.killAppZygotesLocked(packageName, appId, userId, true /* force */);
+    }
+
+    @GuardedBy("this")
     final boolean forceStopPackageLocked(String packageName, int appId,
             boolean callerWillRestart, boolean purgeCache, boolean doit,
             boolean evenPersistent, boolean uninstalling, int userId, String reason) {
@@ -15636,6 +15652,12 @@
                                                 intent.getIntExtra(Intent.EXTRA_UID, -1)),
                                                 false, true, true, false, fullUninstall, userId,
                                                 removed ? "pkg removed" : "pkg changed");
+                                    } else {
+                                        // Kill any app zygotes always, since they can't fork new
+                                        // processes with references to the old code
+                                        forceStopAppZygoteLocked(ssp, UserHandle.getAppId(
+                                                intent.getIntExtra(Intent.EXTRA_UID, -1)),
+                                                userId);
                                     }
                                     final int cmd = killProcess
                                             ? ApplicationThreadConstants.PACKAGE_REMOVED
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index cf996a5..fa91620 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -567,39 +567,41 @@
         final long lastRxMs = mLastInfo.getControllerRxDurationMillis();
         final long lastEnergy = mLastInfo.getControllerEnergyUsedMicroJoules();
 
-        // We will modify the last info object to be the delta, and store the new
-        // WifiActivityEnergyInfo object as our last one.
-        final WifiActivityEnergyInfo delta = mLastInfo;
-        delta.setTimeSinceBootMillis(latest.getTimeSinceBootMillis());
-        delta.setStackState(latest.getStackState());
+        final long deltaTimeSinceBootMillis = latest.getTimeSinceBootMillis();
+        final int deltaStackState = latest.getStackState();
+        final long deltaControllerTxDurationMillis;
+        final long deltaControllerRxDurationMillis;
+        final long deltaControllerScanDurationMillis;
+        final long deltaControllerIdleDurationMillis;
+        final long deltaControllerEnergyUsedMicroJoules;
 
         final long txTimeMs = latest.getControllerTxDurationMillis() - lastTxMs;
         final long rxTimeMs = latest.getControllerRxDurationMillis() - lastRxMs;
         final long idleTimeMs = latest.getControllerIdleDurationMillis() - lastIdleMs;
         final long scanTimeMs = latest.getControllerScanDurationMillis() - lastScanMs;
 
+        final boolean wasReset;
         if (txTimeMs < 0 || rxTimeMs < 0 || scanTimeMs < 0 || idleTimeMs < 0) {
             // The stats were reset by the WiFi system (which is why our delta is negative).
             // Returns the unaltered stats. The total on time should not exceed the time
-            // duartion between reports.
+            // duration between reports.
             final long totalOnTimeMs = latest.getControllerTxDurationMillis()
                     + latest.getControllerRxDurationMillis()
                     + latest.getControllerIdleDurationMillis();
             if (totalOnTimeMs <= timePeriodMs + MAX_WIFI_STATS_SAMPLE_ERROR_MILLIS) {
-                delta.setControllerEnergyUsedMicroJoules(
-                        latest.getControllerEnergyUsedMicroJoules());
-                delta.setControllerRxDurationMillis(latest.getControllerRxDurationMillis());
-                delta.setControllerTxDurationMillis(latest.getControllerTxDurationMillis());
-                delta.setControllerIdleDurationMillis(latest.getControllerIdleDurationMillis());
-                delta.setControllerScanDurationMillis(latest.getControllerScanDurationMillis());
+                deltaControllerEnergyUsedMicroJoules = latest.getControllerEnergyUsedMicroJoules();
+                deltaControllerRxDurationMillis = latest.getControllerRxDurationMillis();
+                deltaControllerTxDurationMillis = latest.getControllerTxDurationMillis();
+                deltaControllerIdleDurationMillis = latest.getControllerIdleDurationMillis();
+                deltaControllerScanDurationMillis = latest.getControllerScanDurationMillis();
             } else {
-                delta.setControllerEnergyUsedMicroJoules(0);
-                delta.setControllerRxDurationMillis(0);
-                delta.setControllerTxDurationMillis(0);
-                delta.setControllerIdleDurationMillis(0);
-                delta.setControllerScanDurationMillis(0);
+                deltaControllerEnergyUsedMicroJoules = 0;
+                deltaControllerRxDurationMillis = 0;
+                deltaControllerTxDurationMillis = 0;
+                deltaControllerIdleDurationMillis = 0;
+                deltaControllerScanDurationMillis = 0;
             }
-            Slog.v(TAG, "WiFi energy data was reset, new WiFi energy data is " + delta);
+            wasReset = true;
         } else {
             final long totalActiveTimeMs = txTimeMs + rxTimeMs;
             long maxExpectedIdleTimeMs;
@@ -634,21 +636,33 @@
                 maxExpectedIdleTimeMs = timePeriodMs - totalActiveTimeMs;
             }
             // These times seem to be the most reliable.
-            delta.setControllerTxDurationMillis(txTimeMs);
-            delta.setControllerRxDurationMillis(rxTimeMs);
-            delta.setControllerScanDurationMillis(scanTimeMs);
+            deltaControllerTxDurationMillis = txTimeMs;
+            deltaControllerRxDurationMillis = rxTimeMs;
+            deltaControllerScanDurationMillis = scanTimeMs;
             // WiFi calculates the idle time as a difference from the on time and the various
             // Rx + Tx times. There seems to be some missing time there because this sometimes
             // becomes negative. Just cap it at 0 and ensure that it is less than the expected idle
             // time from the difference in timestamps.
             // b/21613534
-            delta.setControllerIdleDurationMillis(
-                    Math.min(maxExpectedIdleTimeMs, Math.max(0, idleTimeMs)));
-            delta.setControllerEnergyUsedMicroJoules(
-                    Math.max(0, latest.getControllerEnergyUsedMicroJoules() - lastEnergy));
+            deltaControllerIdleDurationMillis =
+                    Math.min(maxExpectedIdleTimeMs, Math.max(0, idleTimeMs));
+            deltaControllerEnergyUsedMicroJoules =
+                    Math.max(0, latest.getControllerEnergyUsedMicroJoules() - lastEnergy);
+            wasReset = false;
         }
 
         mLastInfo = latest;
+        WifiActivityEnergyInfo delta = new WifiActivityEnergyInfo(
+                deltaTimeSinceBootMillis,
+                deltaStackState,
+                deltaControllerTxDurationMillis,
+                deltaControllerRxDurationMillis,
+                deltaControllerScanDurationMillis,
+                deltaControllerIdleDurationMillis,
+                deltaControllerEnergyUsedMicroJoules);
+        if (wasReset) {
+            Slog.v(TAG, "WiFi energy data was reset, new WiFi energy data is " + delta);
+        }
         return delta;
     }
 }
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 38cb501..b269c38 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -1875,11 +1875,11 @@
     }
 
     @GuardedBy("mService")
-    public void killAppZygoteIfNeededLocked(AppZygote appZygote) {
+    public void killAppZygoteIfNeededLocked(AppZygote appZygote, boolean force) {
         final ApplicationInfo appInfo = appZygote.getAppInfo();
         ArrayList<ProcessRecord> zygoteProcesses = mAppZygoteProcesses.get(appZygote);
-        if (zygoteProcesses != null && zygoteProcesses.size() == 0) {
-            // Only remove if no longer in use now
+        if (zygoteProcesses != null && (force || zygoteProcesses.size() == 0)) {
+            // Only remove if no longer in use now, or forced kill
             mAppZygotes.remove(appInfo.processName, appInfo.uid);
             mAppZygoteProcesses.remove(appZygote);
             mAppIsolatedUidRangeAllocator.freeUidRangeLocked(appInfo);
@@ -1907,7 +1907,7 @@
                 if (app.removed) {
                     // If we stopped this process because the package hosting it was removed,
                     // there's no point in delaying the app zygote kill.
-                    killAppZygoteIfNeededLocked(appZygote);
+                    killAppZygoteIfNeededLocked(appZygote, false /* force */);
                 } else {
                     Message msg = mService.mHandler.obtainMessage(KILL_APP_ZYGOTE_MSG);
                     msg.obj = appZygote;
@@ -2385,6 +2385,33 @@
     }
 
     @GuardedBy("mService")
+    void killAppZygotesLocked(String packageName, int appId, int userId, boolean force) {
+        // See if there are any app zygotes running for this packageName / UID combination,
+        // and kill it if so.
+        final ArrayList<AppZygote> zygotesToKill = new ArrayList<>();
+        for (SparseArray<AppZygote> appZygotes : mAppZygotes.getMap().values()) {
+            for (int i = 0; i < appZygotes.size(); ++i) {
+                final int appZygoteUid = appZygotes.keyAt(i);
+                if (userId != UserHandle.USER_ALL && UserHandle.getUserId(appZygoteUid) != userId) {
+                    continue;
+                }
+                if (appId >= 0 && UserHandle.getAppId(appZygoteUid) != appId) {
+                    continue;
+                }
+                final AppZygote appZygote = appZygotes.valueAt(i);
+                if (packageName != null
+                        && !packageName.equals(appZygote.getAppInfo().packageName)) {
+                    continue;
+                }
+                zygotesToKill.add(appZygote);
+            }
+        }
+        for (AppZygote appZygote : zygotesToKill) {
+            killAppZygoteIfNeededLocked(appZygote, force);
+        }
+    }
+
+    @GuardedBy("mService")
     final boolean killPackageProcessesLocked(String packageName, int appId,
             int userId, int minOomAdj, boolean callerWillRestart, boolean allowRestart,
             boolean doit, boolean evenPersistent, boolean setRemoved, String reason) {
@@ -2461,29 +2488,7 @@
         for (int i=0; i<N; i++) {
             removeProcessLocked(procs.get(i), callerWillRestart, allowRestart, reason);
         }
-        // See if there are any app zygotes running for this packageName / UID combination,
-        // and kill it if so.
-        final ArrayList<AppZygote> zygotesToKill = new ArrayList<>();
-        for (SparseArray<AppZygote> appZygotes : mAppZygotes.getMap().values()) {
-            for (int i = 0; i < appZygotes.size(); ++i) {
-                final int appZygoteUid = appZygotes.keyAt(i);
-                if (userId != UserHandle.USER_ALL && UserHandle.getUserId(appZygoteUid) != userId) {
-                    continue;
-                }
-                if (appId >= 0 && UserHandle.getAppId(appZygoteUid) != appId) {
-                    continue;
-                }
-                final AppZygote appZygote = appZygotes.valueAt(i);
-                if (packageName != null
-                        && !packageName.equals(appZygote.getAppInfo().packageName)) {
-                    continue;
-                }
-                zygotesToKill.add(appZygote);
-            }
-        }
-        for (AppZygote appZygote : zygotesToKill) {
-            killAppZygoteIfNeededLocked(appZygote);
-        }
+        killAppZygotesLocked(packageName, appId, userId, false /* force */);
         mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_PROCESS_END);
         return N > 0;
     }
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index e7f537b..4ddc391b 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -3451,6 +3451,7 @@
                 if (isLoggable) {
                     Slog.v(TAG, "    Dropping sync operation: account doesn't exist.");
                 }
+                Slog.wtf(TAG, "SYNC_OP_STATE_INVALID: account doesn't exist.");
                 return SYNC_OP_STATE_INVALID;
             }
             // Drop this sync request if it isn't syncable.
@@ -3460,12 +3461,14 @@
                     Slog.v(TAG, "    Dropping sync operation: "
                             + "isSyncable == SYNCABLE_NO_ACCOUNT_ACCESS");
                 }
+                Slog.wtf(TAG, "SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS");
                 return SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS;
             }
             if (state == AuthorityInfo.NOT_SYNCABLE) {
                 if (isLoggable) {
                     Slog.v(TAG, "    Dropping sync operation: isSyncable == NOT_SYNCABLE");
                 }
+                Slog.wtf(TAG, "SYNC_OP_STATE_INVALID: NOT_SYNCABLE");
                 return SYNC_OP_STATE_INVALID;
             }
 
@@ -3484,6 +3487,7 @@
                 if (isLoggable) {
                     Slog.v(TAG, "    Dropping sync operation: disallowed by settings/network.");
                 }
+                Slog.wtf(TAG, "SYNC_OP_STATE_INVALID: disallowed by settings/network");
                 return SYNC_OP_STATE_INVALID;
             }
             return SYNC_OP_STATE_VALID;
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index aa39926..6ff2767 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -87,7 +87,7 @@
             }
             BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder(
                     luxLevels, brightnessLevelsNits);
-            builder.setShortTermModelTimeout(shortTermModelTimeout);
+            builder.setShortTermModelTimeoutMillis(shortTermModelTimeout);
             builder.setShortTermModelLowerLuxMultiplier(SHORT_TERM_MODEL_THRESHOLD_RATIO);
             builder.setShortTermModelUpperLuxMultiplier(SHORT_TERM_MODEL_THRESHOLD_RATIO);
             return new PhysicalMappingStrategy(builder.build(), nitsRange, backlightRange,
@@ -739,10 +739,10 @@
 
         @Override
         public long getShortTermModelTimeout() {
-            if (mConfig.getShortTermModelTimeout() >= 0) {
-                return mConfig.getShortTermModelTimeout();
+            if (mConfig.getShortTermModelTimeoutMillis() >= 0) {
+                return mConfig.getShortTermModelTimeoutMillis();
             } else {
-                return mDefaultConfig.getShortTermModelTimeout();
+                return mDefaultConfig.getShortTermModelTimeoutMillis();
             }
         }
 
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index 214dcc0..11fe15f 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -46,7 +46,6 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.HandlerThread;
-import android.os.RemoteException;
 import android.util.Slog;
 import android.util.StatsLog;
 
@@ -158,8 +157,7 @@
 
     @Override
     public void updateRuleSet(
-            String version, ParceledListSlice<Rule> rules, IntentSender statusReceiver)
-            throws RemoteException {
+            String version, ParceledListSlice<Rule> rules, IntentSender statusReceiver) {
         String ruleProvider = getCallerPackageNameOrThrow();
 
         mHandler.post(
@@ -190,7 +188,7 @@
     }
 
     @Override
-    public String getCurrentRuleSetVersion() throws RemoteException {
+    public String getCurrentRuleSetVersion() {
         getCallerPackageNameOrThrow();
 
         RuleMetadata ruleMetadata = mIntegrityFileManager.readMetadata();
@@ -200,7 +198,7 @@
     }
 
     @Override
-    public String getCurrentRuleSetProvider() throws RemoteException {
+    public String getCurrentRuleSetProvider() {
         getCallerPackageNameOrThrow();
 
         RuleMetadata ruleMetadata = mIntegrityFileManager.readMetadata();
@@ -212,14 +210,6 @@
     private void handleIntegrityVerification(Intent intent) {
         int verificationId = intent.getIntExtra(EXTRA_VERIFICATION_ID, -1);
 
-        // Fail early if we don't have any rules at all.
-        if (!mIntegrityFileManager.initialized()) {
-            Slog.i(TAG, "Rules not initialized. Skipping integrity check.");
-            mPackageManagerInternal.setIntegrityVerificationResult(
-                    verificationId, PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW);
-            return;
-        }
-
         try {
             Slog.i(TAG, "Received integrity verification intent " + intent.toString());
             Slog.i(TAG, "Extras " + intent.getExtras());
diff --git a/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java b/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java
index 1a6b3d8..79e69e1 100644
--- a/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java
+++ b/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java
@@ -76,6 +76,11 @@
     }
 
     private List<Rule> loadRules(AppInstallMetadata appInstallMetadata) {
+        if (!mIntegrityFileManager.initialized()) {
+            Slog.w(TAG, "Integrity rule files are not available. Evaluating only manifest rules.");
+            return new ArrayList<>();
+        }
+
         try {
             return mIntegrityFileManager.readRules(appInstallMetadata);
         } catch (Exception e) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index e92f3ec..eea59ca 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -117,6 +117,7 @@
 import android.app.IActivityManager;
 import android.app.INotificationManager;
 import android.app.ITransientNotification;
+import android.app.ITransientNotificationCallback;
 import android.app.IUriGrantsManager;
 import android.app.Notification;
 import android.app.NotificationChannel;
@@ -255,6 +256,9 @@
 import com.android.server.lights.LogicalLight;
 import com.android.server.notification.ManagedServices.ManagedServiceInfo;
 import com.android.server.notification.ManagedServices.UserProfiles;
+import com.android.server.notification.toast.CustomToastRecord;
+import com.android.server.notification.toast.TextToastRecord;
+import com.android.server.notification.toast.ToastRecord;
 import com.android.server.pm.PackageManagerService;
 import com.android.server.policy.PhoneWindowManager;
 import com.android.server.statusbar.StatusBarManagerInternal;
@@ -295,8 +299,8 @@
 
 /** {@hide} */
 public class NotificationManagerService extends SystemService {
-    static final String TAG = "NotificationService";
-    static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
+    public static final String TAG = "NotificationService";
+    public static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
     public static final boolean ENABLE_CHILD_NOTIFICATIONS
             = SystemProperties.getBoolean("debug.child_notifs", true);
 
@@ -393,6 +397,7 @@
     private PackageManager mPackageManagerClient;
     AudioManager mAudioManager;
     AudioManagerInternal mAudioManagerInternal;
+    // Can be null for wear
     @Nullable StatusBarManagerInternal mStatusBar;
     Vibrator mVibrator;
     private WindowManagerInternal mWindowManagerInternal;
@@ -850,49 +855,6 @@
         out.endDocument();
     }
 
-    private static final class ToastRecord
-    {
-        public final int pid;
-        public final String pkg;
-        public final IBinder token;
-        public final ITransientNotification callback;
-        public int duration;
-        public int displayId;
-        public Binder windowToken;
-
-        ToastRecord(int pid, String pkg, IBinder token, ITransientNotification callback,
-                int duration, Binder windowToken, int displayId) {
-            this.pid = pid;
-            this.pkg = pkg;
-            this.token = token;
-            this.callback = callback;
-            this.duration = duration;
-            this.windowToken = windowToken;
-            this.displayId = displayId;
-        }
-
-        void update(int duration) {
-            this.duration = duration;
-        }
-
-        void dump(PrintWriter pw, String prefix, DumpFilter filter) {
-            if (filter != null && !filter.matches(pkg)) return;
-            pw.println(prefix + this);
-        }
-
-        @Override
-        public final String toString()
-        {
-            return "ToastRecord{"
-                + Integer.toHexString(System.identityHashCode(this))
-                + " pkg=" + pkg
-                + " token=" + token
-                + " callback=" + callback
-                + " duration=" + duration
-                + "}";
-        }
-    }
-
     @VisibleForTesting
     final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
 
@@ -2643,6 +2605,19 @@
         return userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId;
     }
 
+    private ToastRecord getToastRecord(int pid, String packageName, IBinder token,
+            @Nullable CharSequence text, @Nullable ITransientNotification callback, int duration,
+            Binder windowToken, int displayId,
+            @Nullable ITransientNotificationCallback textCallback) {
+        if (callback == null) {
+            return new TextToastRecord(this, mStatusBar, pid, packageName, token, text, duration,
+                    windowToken, displayId, textCallback);
+        } else {
+            return new CustomToastRecord(this, pid, packageName, token, callback, duration,
+                    windowToken, displayId);
+        }
+    }
+
     @VisibleForTesting
     NotificationManagerInternal getInternalService() {
         return mInternalService;
@@ -2654,28 +2629,30 @@
         // ============================================================================
 
         @Override
-        public void enqueueTextToast(String pkg, IBinder token, ITransientNotification callback,
-                int duration, int displayId) {
-            enqueueToast(pkg, token, callback, duration, displayId, false);
+        public void enqueueTextToast(String pkg, IBinder token, CharSequence text, int duration,
+                int displayId, @Nullable ITransientNotificationCallback callback) {
+            enqueueToast(pkg, token, text, null, duration, displayId, callback);
         }
 
         @Override
         public void enqueueToast(String pkg, IBinder token, ITransientNotification callback,
                 int duration, int displayId) {
-            enqueueToast(pkg, token, callback, duration, displayId, true);
+            enqueueToast(pkg, token, null, callback, duration, displayId, null);
         }
 
-        private void enqueueToast(String pkg, IBinder token, ITransientNotification callback,
-                int duration, int displayId, boolean isCustomToast) {
+        private void enqueueToast(String pkg, IBinder token, @Nullable CharSequence text,
+                @Nullable ITransientNotification callback, int duration, int displayId,
+                @Nullable ITransientNotificationCallback textCallback) {
             if (DBG) {
-                Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
+                Slog.i(TAG, "enqueueToast pkg=" + pkg + " token=" + token
                         + " duration=" + duration + " displayId=" + displayId);
             }
 
-            if (pkg == null || callback == null || token == null) {
-                Slog.e(TAG, "Not enqueuing toast. pkg=" + pkg + " callback=" + callback + " token="
-                        + token);
-                return ;
+            if (pkg == null || (text == null && callback == null)
+                    || (text != null && callback != null) || token == null) {
+                Slog.e(TAG, "Not enqueuing toast. pkg=" + pkg + " text=" + text + " callback="
+                        + " token=" + token);
+                return;
             }
 
             final int callingUid = Binder.getCallingUid();
@@ -2703,7 +2680,7 @@
                 return;
             }
 
-            if (isCustomToast && !appIsForeground && !isSystemToast) {
+            if (callback != null && !appIsForeground && !isSystemToast) {
                 boolean block;
                 try {
                     block = mPlatformCompat.isChangeEnabledByPackageName(
@@ -2745,28 +2722,28 @@
                             int count = 0;
                             final int N = mToastQueue.size();
                             for (int i=0; i<N; i++) {
-                                 final ToastRecord r = mToastQueue.get(i);
-                                 if (r.pkg.equals(pkg)) {
-                                     count++;
-                                     if (count >= MAX_PACKAGE_NOTIFICATIONS) {
-                                         Slog.e(TAG, "Package has already posted " + count
+                                final ToastRecord r = mToastQueue.get(i);
+                                if (r.pkg.equals(pkg)) {
+                                    count++;
+                                    if (count >= MAX_PACKAGE_NOTIFICATIONS) {
+                                        Slog.e(TAG, "Package has already posted " + count
                                                 + " toasts. Not showing more. Package=" + pkg);
-                                         return;
-                                     }
-                                 }
+                                        return;
+                                    }
+                                }
                             }
                         }
 
                         Binder windowToken = new Binder();
                         mWindowManagerInternal.addWindowToken(windowToken, TYPE_TOAST, displayId);
-                        record = new ToastRecord(callingPid, pkg, token, callback, duration,
-                                windowToken, displayId);
+                        record = getToastRecord(callingPid, pkg, token, text, callback, duration,
+                                windowToken, displayId, textCallback);
                         mToastQueue.add(record);
                         index = mToastQueue.size() - 1;
-                        keepProcessAliveIfNeededLocked(callingPid);
+                        keepProcessAliveForToastIfNeededLocked(callingPid);
                     }
                     // If it's at index 0, it's the current toast.  It doesn't matter if it's
-                    // new or just been updated.  Call back and tell it to show itself.
+                    // new or just been updated, show it.
                     // If the callback fails, this will remove it from the list, so don't
                     // assume that it's valid after this.
                     if (index == 0) {
@@ -6935,40 +6912,22 @@
     void showNextToastLocked() {
         ToastRecord record = mToastQueue.get(0);
         while (record != null) {
-            if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
-            try {
-                record.callback.show(record.windowToken);
+            if (record.show()) {
                 scheduleDurationReachedLocked(record);
                 return;
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Object died trying to show notification " + record.callback
-                        + " in package " + record.pkg);
-                // remove it from the list and let the process die
-                int index = mToastQueue.indexOf(record);
-                if (index >= 0) {
-                    mToastQueue.remove(index);
-                }
-                keepProcessAliveIfNeededLocked(record.pid);
-                if (mToastQueue.size() > 0) {
-                    record = mToastQueue.get(0);
-                } else {
-                    record = null;
-                }
             }
+            int index = mToastQueue.indexOf(record);
+            if (index >= 0) {
+                mToastQueue.remove(index);
+            }
+            record = (mToastQueue.size() > 0) ? mToastQueue.get(0) : null;
         }
     }
 
     @GuardedBy("mToastQueue")
     void cancelToastLocked(int index) {
         ToastRecord record = mToastQueue.get(index);
-        try {
-            record.callback.hide();
-        } catch (RemoteException e) {
-            Slog.w(TAG, "Object died trying to hide notification " + record.callback
-                    + " in package " + record.pkg);
-            // don't worry about this, we're about to remove it from
-            // the list anyway
-        }
+        record.hide();
 
         ToastRecord lastToast = mToastQueue.remove(index);
 
@@ -6981,7 +6940,7 @@
         // one way or another.
         scheduleKillTokenTimeout(lastToast);
 
-        keepProcessAliveIfNeededLocked(record.pid);
+        keepProcessAliveForToastIfNeededLocked(record.pid);
         if (mToastQueue.size() > 0) {
             // Show the next one. If the callback fails, this will remove
             // it from the list, so don't assume that the list hasn't changed
@@ -7004,7 +6963,7 @@
     {
         mHandler.removeCallbacksAndMessages(r);
         Message m = Message.obtain(mHandler, MESSAGE_DURATION_REACHED, r);
-        int delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
+        int delay = r.getDuration() == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
         // Accessibility users may need longer timeout duration. This api compares original delay
         // with user's preference and return longer one. It returns original delay if there's no
         // preference.
@@ -7053,13 +7012,21 @@
         return -1;
     }
 
+    /**
+     * Adjust process {@code pid} importance according to whether it has toasts in the queue or not.
+     */
+    public void keepProcessAliveForToastIfNeeded(int pid) {
+        synchronized (mToastQueue) {
+            keepProcessAliveForToastIfNeededLocked(pid);
+        }
+    }
+
     @GuardedBy("mToastQueue")
-    void keepProcessAliveIfNeededLocked(int pid)
-    {
+    private void keepProcessAliveForToastIfNeededLocked(int pid) {
         int toastCount = 0; // toasts from this pid
         ArrayList<ToastRecord> list = mToastQueue;
-        int N = list.size();
-        for (int i=0; i<N; i++) {
+        int n = list.size();
+        for (int i = 0; i < n; i++) {
             ToastRecord r = list.get(i);
             if (r.pid == pid) {
                 toastCount++;
diff --git a/services/core/java/com/android/server/notification/toast/CustomToastRecord.java b/services/core/java/com/android/server/notification/toast/CustomToastRecord.java
new file mode 100644
index 0000000..aca6f48
--- /dev/null
+++ b/services/core/java/com/android/server/notification/toast/CustomToastRecord.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.notification.toast;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+import static com.android.server.notification.NotificationManagerService.DBG;
+
+import android.app.ITransientNotification;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.notification.NotificationManagerService;
+
+/**
+ * Represents a custom toast, a toast whose view is provided by the app.
+ */
+public class CustomToastRecord extends ToastRecord {
+    private static final String TAG = NotificationManagerService.TAG;
+
+    public final ITransientNotification callback;
+
+    public CustomToastRecord(
+            NotificationManagerService notificationManager, int pid, String packageName,
+            IBinder token, ITransientNotification callback, int duration, Binder windowToken,
+            int displayId) {
+        super(notificationManager, pid, packageName, token, duration, windowToken, displayId);
+        this.callback = checkNotNull(callback);
+    }
+
+    @Override
+    public boolean show() {
+        if (DBG) {
+            Slog.d(TAG, "Show pkg=" + pkg + " callback=" + callback);
+        }
+        try {
+            callback.show(windowToken);
+            return true;
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Object died trying to show custom toast " + token + " in package "
+                    + pkg);
+            mNotificationManager.keepProcessAliveForToastIfNeeded(pid);
+            return false;
+        }
+    }
+
+    @Override
+    public void hide() {
+        try {
+            callback.hide();
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Object died trying to hide custom toast " + token + " in package "
+                    + pkg);
+
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "CustomToastRecord{"
+                + Integer.toHexString(System.identityHashCode(this))
+                + " token=" + token
+                + " packageName=" + pkg
+                + " callback=" + callback
+                + " duration=" + getDuration()
+                + "}";
+    }
+}
diff --git a/services/core/java/com/android/server/notification/toast/TextToastRecord.java b/services/core/java/com/android/server/notification/toast/TextToastRecord.java
new file mode 100644
index 0000000..3c231b4
--- /dev/null
+++ b/services/core/java/com/android/server/notification/toast/TextToastRecord.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.notification.toast;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+import static com.android.server.notification.NotificationManagerService.DBG;
+
+import android.annotation.Nullable;
+import android.app.ITransientNotificationCallback;
+import android.os.Binder;
+import android.os.IBinder;
+import android.util.Slog;
+
+import com.android.server.notification.NotificationManagerService;
+import com.android.server.statusbar.StatusBarManagerInternal;
+
+/**
+ * Represents a text toast, a toast rendered by the system that contains only text.
+ */
+public class TextToastRecord extends ToastRecord {
+    private static final String TAG = NotificationManagerService.TAG;
+
+    public final CharSequence text;
+    @Nullable
+    private final StatusBarManagerInternal mStatusBar;
+    @Nullable
+    private final ITransientNotificationCallback mCallback;
+
+    public TextToastRecord(NotificationManagerService notificationManager,
+            @Nullable StatusBarManagerInternal statusBarManager, int pid, String packageName,
+            IBinder token, CharSequence text, int duration, Binder windowToken, int displayId,
+            @Nullable ITransientNotificationCallback callback) {
+        super(notificationManager, pid, packageName, token, duration, windowToken, displayId);
+        mStatusBar = statusBarManager;
+        mCallback = callback;
+        this.text = checkNotNull(text);
+    }
+
+    @Override
+    public boolean show() {
+        if (DBG) {
+            Slog.d(TAG, "Show pkg=" + pkg + " text=" + text);
+        }
+        if (mStatusBar == null) {
+            Slog.w(TAG, "StatusBar not available to show text toast for package " + pkg);
+            return false;
+        }
+        mStatusBar.showToast(pkg, token, text, windowToken, getDuration(), mCallback);
+        return true;
+    }
+
+    @Override
+    public void hide() {
+        // If it's null, show() would have returned false
+        checkNotNull(mStatusBar, "Cannot hide toast that wasn't shown");
+
+        mStatusBar.hideToast(pkg, token);
+    }
+
+    @Override
+    public String toString() {
+        return "TextToastRecord{"
+                + Integer.toHexString(System.identityHashCode(this))
+                + " token=" + token
+                + " packageName=" + pkg
+                + " text=" + text
+                + " duration=" + getDuration()
+                + "}";
+    }
+}
diff --git a/services/core/java/com/android/server/notification/toast/ToastRecord.java b/services/core/java/com/android/server/notification/toast/ToastRecord.java
new file mode 100644
index 0000000..ef75a6f
--- /dev/null
+++ b/services/core/java/com/android/server/notification/toast/ToastRecord.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.notification.toast;
+
+import android.os.Binder;
+import android.os.IBinder;
+
+import com.android.server.notification.NotificationManagerService;
+import com.android.server.notification.NotificationManagerService.DumpFilter;
+
+import java.io.PrintWriter;
+
+/**
+ * Represents a toast, a transient notification.
+ */
+public abstract class ToastRecord {
+    public final int pid;
+    public final String pkg;
+    public final IBinder token;
+    public final int displayId;
+    public final Binder windowToken;
+    protected final NotificationManagerService mNotificationManager;
+    private int mDuration;
+
+    protected ToastRecord(
+            NotificationManagerService notificationManager,
+            int pid, String pkg, IBinder token, int duration,
+            Binder windowToken, int displayId) {
+        this.mNotificationManager = notificationManager;
+        this.pid = pid;
+        this.pkg = pkg;
+        this.token = token;
+        this.windowToken = windowToken;
+        this.displayId = displayId;
+        mDuration = duration;
+    }
+
+    /**
+     * This method is responsible for showing the toast represented by this object.
+     *
+     * @return True if it was successfully shown.
+     */
+    public abstract boolean show();
+
+    /**
+     * This method is responsible for hiding the toast represented by this object.
+     */
+    public abstract void hide();
+
+    /**
+     * Returns the duration of this toast, which can be {@link android.widget.Toast#LENGTH_SHORT}
+     * or {@link android.widget.Toast#LENGTH_LONG}.
+     */
+    public int getDuration() {
+        return mDuration;
+    }
+
+    /**
+     * Updates toast duration.
+     */
+    public void update(int duration) {
+        mDuration = duration;
+    }
+
+    /**
+     * Dumps a textual representation of this object.
+     */
+    public void dump(PrintWriter pw, String prefix, DumpFilter filter) {
+        if (filter != null && !filter.matches(pkg)) {
+            return;
+        }
+        pw.println(prefix + this);
+    }
+}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index a223326..1246e40 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -2145,8 +2145,12 @@
     }
 
     String getInstallerPackageName() {
+        return getInstallSource().installerPackageName;
+    }
+
+    InstallSource getInstallSource() {
         synchronized (mLock) {
-            return mInstallSource.installerPackageName;
+            return mInstallSource;
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6c8e7b0..de6b7d5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2725,7 +2725,7 @@
         t.traceBegin("get system config");
         SystemConfig systemConfig = SystemConfig.getInstance();
         mAvailableFeatures = systemConfig.getAvailableFeatures();
-        ApplicationPackageManager.invalidateHasSystemFeatureCache();
+        ApplicationPackageManager.invalidateSysFeatureCache();
         t.traceEnd();
 
         mProtectedPackages = new ProtectedPackages(mContext);
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index c3e7f62..da0d820 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -333,8 +333,6 @@
                 KeyEvent.KEYCODE_CALCULATOR, Intent.CATEGORY_APP_CALCULATOR);
     }
 
-    private static final int USER_ACTIVITY_NOTIFICATION_DELAY = 200;
-
     /** Amount of time (in milliseconds) to wait for windows drawn before powering on. */
     static final int WAITING_FOR_DRAWN_TIMEOUT = 1000;
 
@@ -487,7 +485,6 @@
 
     private boolean mPendingKeyguardOccluded;
     private boolean mKeyguardOccludedChanged;
-    private boolean mNotifyUserActivity;
 
     SleepToken mScreenOffSleepToken;
     volatile boolean mKeyguardOccluded;
@@ -627,8 +624,7 @@
     private static final int MSG_LAUNCH_ASSIST = 23;
     private static final int MSG_LAUNCH_ASSIST_LONG_PRESS = 24;
     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_RINGER_TOGGLE_CHORD = 26;
 
     private class PolicyHandler extends Handler {
         @Override
@@ -708,13 +704,6 @@
                 case MSG_HANDLE_ALL_APPS:
                     launchAllAppsAction();
                     break;
-                case MSG_NOTIFY_USER_ACTIVITY:
-                    removeMessages(MSG_NOTIFY_USER_ACTIVITY);
-                    Intent intent = new Intent(ACTION_USER_ACTIVITY_NOTIFICATION);
-                    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-                    mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
-                            android.Manifest.permission.USER_ACTIVITY);
-                    break;
                 case MSG_RINGER_TOGGLE_CHORD:
                     handleRingerChordGesture();
                     break;
@@ -4892,13 +4881,6 @@
         mHandler.sendEmptyMessage(MSG_HIDE_BOOT_MESSAGE);
     }
 
-    @Override
-    public void requestUserActivityNotification() {
-        if (!mNotifyUserActivity && !mHandler.hasMessages(MSG_NOTIFY_USER_ACTIVITY)) {
-            mNotifyUserActivity = true;
-        }
-    }
-
     /** {@inheritDoc} */
     @Override
     public void userActivity() {
@@ -4920,12 +4902,6 @@
                 mHandler.postDelayed(mScreenLockTimeout, mLockScreenTimeout);
             }
         }
-
-        if (mDefaultDisplayPolicy.isAwake() && mNotifyUserActivity) {
-            mHandler.sendEmptyMessageDelayed(MSG_NOTIFY_USER_ACTIVITY,
-                    USER_ACTIVITY_NOTIFICATION_DELAY);
-            mNotifyUserActivity = false;
-        }
     }
 
     class ScreenLockTimeout implements Runnable {
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index c39da5f..e81214e 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -1438,12 +1438,6 @@
     }
 
     /**
-     * Requests that the WindowManager sends
-     * WindowManagerPolicyConstants#ACTION_USER_ACTIVITY_NOTIFICATION on the next user activity.
-     */
-    public void requestUserActivityNotification();
-
-    /**
      * Registers an IDisplayFoldListener.
      */
     default void registerDisplayFoldListener(IDisplayFoldListener listener) {}
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 39d1a51..92e5a01 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -1268,6 +1268,7 @@
                 continue;
             }
             StatsEvent e = StatsEvent.newBuilder()
+                    .setAtomId(atomTag)
                     .writeInt(managedProcess.uid)
                     .writeString(managedProcess.processName)
                     .writeInt(managedProcess.pid)
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index 95ffd8f..d88dccb 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -16,7 +16,10 @@
 
 package com.android.server.statusbar;
 
+import android.annotation.Nullable;
+import android.app.ITransientNotificationCallback;
 import android.os.Bundle;
+import android.os.IBinder;
 import android.view.InsetsState.InternalInsetsType;
 import android.view.WindowInsetsController.Appearance;
 
@@ -123,4 +126,15 @@
 
     /** @see com.android.internal.statusbar.IStatusBar#abortTransient */
     void abortTransient(int displayId, @InternalInsetsType int[] types);
+
+    /**
+     * @see com.android.internal.statusbar.IStatusBar#showToast(String, IBinder, CharSequence,
+     * IBinder, int, ITransientNotificationCallback)
+     */
+    void showToast(String packageName, IBinder token, CharSequence text,
+            IBinder windowToken, int duration,
+            @Nullable ITransientNotificationCallback textCallback);
+
+    /** @see com.android.internal.statusbar.IStatusBar#hideToast(String, IBinder)  */
+    void hideToast(String packageName, IBinder token);
 }
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 870c81f..3f7d373 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -21,6 +21,7 @@
 
 import android.annotation.Nullable;
 import android.app.ActivityThread;
+import android.app.ITransientNotificationCallback;
 import android.app.Notification;
 import android.app.StatusBarManager;
 import android.content.ComponentName;
@@ -500,6 +501,26 @@
                 } catch (RemoteException ex) { }
             }
         }
+
+        @Override
+        public void showToast(String packageName, IBinder token, CharSequence text,
+                IBinder windowToken, int duration,
+                @Nullable ITransientNotificationCallback callback) {
+            if (mBar != null) {
+                try {
+                    mBar.showToast(packageName, token, text, windowToken, duration, callback);
+                } catch (RemoteException ex) { }
+            }
+        }
+
+        @Override
+        public void hideToast(String packageName, IBinder token) {
+            if (mBar != null) {
+                try {
+                    mBar.hideToast(packageName, token);
+                } catch (RemoteException ex) { }
+            }
+        }
     };
 
     private final GlobalActionsProvider mGlobalActionsProvider = new GlobalActionsProvider() {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 36bee87..bf89bab 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2099,6 +2099,7 @@
      * the above app windows specify orientation, the orientation is computed from the child window
      * container, e.g. {@link AppWindowToken#getOrientation(int)}.
      */
+    @ScreenOrientation
     @Override
     int getOrientation() {
         final WindowManagerPolicy policy = mWmService.mPolicy;
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index f90f224..da77314 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -1001,18 +1001,22 @@
      * Given an orientation constant, returns the appropriate surface rotation, taking into account
      * sensors, docking mode, rotation lock, and other factors.
      *
-     * @param orientation An orientation constant, such as
-     *                    {@link ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}.
+     * @param orientation  An orientation constant, such as
+     *                     {@link ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}.
      * @param lastRotation The most recently used rotation.
      * @return The surface rotation to use.
      */
     @VisibleForTesting
-    int rotationForOrientation(int orientation, int lastRotation) {
-        ProtoLog.v(WM_DEBUG_ORIENTATION, "rotationForOrientation(orient=%d, last=%d); user=%d %s",
-                    orientation, lastRotation, mUserRotation,
-                    mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED
-                            ? "USER_ROTATION_LOCKED" : ""
-                        );
+    @Surface.Rotation
+    int rotationForOrientation(@ScreenOrientation int orientation,
+            @Surface.Rotation int lastRotation) {
+        ProtoLog.v(WM_DEBUG_ORIENTATION,
+                "rotationForOrientation(orient=%s (%d), last=%s (%d)); user=%s (%d) %s",
+                ActivityInfo.screenOrientationToString(orientation), orientation,
+                Surface.rotationToString(lastRotation), lastRotation,
+                Surface.rotationToString(mUserRotation), mUserRotation,
+                mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED
+                        ? "USER_ROTATION_LOCKED" : "");
 
         if (isFixedToUserRotation()) {
             return mUserRotation;
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index bfb69172..e7aca89 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -370,6 +370,11 @@
             }
         }
 
+        ProtoLog.d(WM_DEBUG_ORIENTATION, "Start rotation animation. customAnim=%s, "
+                        + "mCurRotation=%s, mOriginalRotation=%s",
+                customAnim, Surface.rotationToString(mCurRotation),
+                Surface.rotationToString(mOriginalRotation));
+
         mRotateExitAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
         mRotateExitAnimation.restrictDuration(maxAnimationDuration);
         mRotateExitAnimation.scaleCurrentDuration(animationScale);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 19461c5..9dba0d3 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -367,6 +367,7 @@
      * Display rotation as of the last time {@link #setBounds(Rect)} was called or this task was
      * moved to a new display.
      */
+    @Surface.Rotation
     private int mRotation;
 
     // For comparison with DisplayContent bounds.
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 0ab5f91..015b92c 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1079,8 +1079,9 @@
             if (wc.fillsParent() || orientation != SCREEN_ORIENTATION_UNSPECIFIED) {
                 // Use the orientation if the container fills its parent or requested an explicit
                 // orientation that isn't SCREEN_ORIENTATION_UNSPECIFIED.
-                ProtoLog.v(WM_DEBUG_ORIENTATION, "%s is requesting orientation %d (%s)", toString(),
-                        orientation, ActivityInfo.screenOrientationToString(orientation));
+                ProtoLog.v(WM_DEBUG_ORIENTATION, "%s is requesting orientation %d (%s)",
+                        wc.toString(), orientation,
+                        ActivityInfo.screenOrientationToString(orientation));
                 return orientation;
             }
         }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 1360711..e130830 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -7032,15 +7032,6 @@
         mPolicy.registerShortcutKey(shortcutCode, shortcutKeyReceiver);
     }
 
-    @Override
-    public void requestUserActivityNotification() {
-        if (!checkCallingPermission(android.Manifest.permission.USER_ACTIVITY,
-                "requestUserActivityNotification()")) {
-            throw new SecurityException("Requires USER_ACTIVITY permission");
-        }
-        mPolicy.requestUserActivityNotification();
-    }
-
     private final class LocalService extends WindowManagerInternal {
 
         @Override
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
index 1c88c40..e724e60 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
@@ -20,6 +20,7 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -27,6 +28,9 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+import static com.android.server.job.JobSchedulerService.FREQUENT_INDEX;
+import static com.android.server.job.JobSchedulerService.RARE_INDEX;
+import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -568,6 +572,48 @@
         assertFalse(controller.isStandbyExceptionRequestedLocked(UID_RED));
     }
 
+    @Test
+    public void testRestrictedJobTracking() {
+        final JobStatus networked = createJobStatus(createJob()
+                .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1), 0)
+                .setRequiredNetworkType(JobInfo.NETWORK_TYPE_CELLULAR), UID_RED);
+        final JobStatus unnetworked = createJobStatus(createJob(), UID_BLUE);
+        networked.setStandbyBucket(FREQUENT_INDEX);
+        unnetworked.setStandbyBucket(FREQUENT_INDEX);
+
+        final Network cellularNet = new Network(101);
+        final NetworkCapabilities cellularCaps =
+                createCapabilities().addTransportType(TRANSPORT_CELLULAR);
+        reset(mConnManager);
+        answerNetwork(UID_RED, cellularNet, cellularCaps);
+        answerNetwork(UID_BLUE, cellularNet, cellularCaps);
+
+        final ConnectivityController controller = new ConnectivityController(mService);
+        controller.maybeStartTrackingJobLocked(networked, null);
+        controller.maybeStartTrackingJobLocked(unnetworked, null);
+
+        assertTrue(networked.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
+        assertFalse(unnetworked.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
+
+        networked.setStandbyBucket(RESTRICTED_INDEX);
+        unnetworked.setStandbyBucket(RESTRICTED_INDEX);
+        controller.startTrackingRestrictedJobLocked(networked);
+        controller.startTrackingRestrictedJobLocked(unnetworked);
+        assertFalse(networked.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
+        // Unnetworked shouldn't be affected by ConnectivityController since it doesn't have a
+        // connectivity constraint.
+        assertFalse(unnetworked.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
+
+        networked.setStandbyBucket(RARE_INDEX);
+        unnetworked.setStandbyBucket(RARE_INDEX);
+        controller.stopTrackingRestrictedJobLocked(networked);
+        controller.stopTrackingRestrictedJobLocked(unnetworked);
+        assertTrue(networked.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
+        // Unnetworked shouldn't be affected by ConnectivityController since it doesn't have a
+        // connectivity constraint.
+        assertFalse(unnetworked.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
+    }
+
     private void answerNetwork(int uid, Network net, NetworkCapabilities caps) {
         when(mConnManager.getActiveNetworkForUid(eq(uid))).thenReturn(net);
         when(mConnManager.getNetworkCapabilities(eq(net))).thenReturn(caps);
diff --git a/services/tests/servicestests/src/com/android/server/WatchdogDiagnosticsTest.java b/services/tests/servicestests/src/com/android/server/WatchdogDiagnosticsTest.java
index 4d229ef..625766a 100644
--- a/services/tests/servicestests/src/com/android/server/WatchdogDiagnosticsTest.java
+++ b/services/tests/servicestests/src/com/android/server/WatchdogDiagnosticsTest.java
@@ -157,6 +157,8 @@
             String expected =
                     "TestThread2 annotated stack trace:\n" +
                     "    at java.lang.Object.wait(Native Method)\n" +
+                    "    at java.lang.Object.wait(Object.java:442)\n" +
+                    "    at java.lang.Object.wait(Object.java:568)\n" +
                     "    at com.android.server.WatchdogDiagnosticsTest$TestThread2.y(" +
                             "WatchdogDiagnosticsTest.java:91)\n" +
                     "    - locked <HASH> (a java.lang.String)\n" +
diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
index 9a63393..770afb0 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
@@ -32,11 +32,9 @@
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.mockito.internal.verification.VerificationModeFactory.times;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -59,7 +57,6 @@
 import androidx.test.InstrumentationRegistry;
 
 import com.android.internal.R;
-import com.android.server.LocalServices;
 import com.android.server.integrity.engine.RuleEvaluationEngine;
 import com.android.server.integrity.model.IntegrityCheckResult;
 import com.android.server.testutils.TestUtils;
@@ -147,29 +144,8 @@
         when(mIntegrityFileManager.initialized()).thenReturn(true);
     }
 
-    // This is not a test of the class, but more of a safeguard that we don't block any install in
-    // the default case. This is needed because we don't have any emergency kill switch to disable
-    // this component.
-    @Test
-    public void default_allow() throws Exception {
-        LocalServices.removeServiceForTest(PackageManagerInternal.class);
-        LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal);
-        mService = AppIntegrityManagerServiceImpl.create(mMockContext);
-        ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
-                ArgumentCaptor.forClass(BroadcastReceiver.class);
-        verify(mMockContext, times(2))
-                .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
-        Intent intent = makeVerificationIntent();
-
-        broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent);
-
-        // Since we are not mocking handler in this case, we must wait.
-        // 2 seconds should be a sensible timeout.
-        Thread.sleep(2000);
-        verify(mPackageManagerInternal)
-                .setIntegrityVerificationResult(
-                        1, PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW);
-    }
+    // TODO(b/148370598): Implement a test to validate that allow response is retuned when the test
+    //    request times out.
 
     @Test
     public void updateRuleSet_notAuthorized() throws Exception {
@@ -381,10 +357,10 @@
         broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent);
         runJobInHandler();
 
+        // The evaluation will still run since we still evaluate manifest based rules.
         verify(mPackageManagerInternal)
                 .setIntegrityVerificationResult(
                         1, PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW);
-        verify(mSpyPackageManager, never()).getPackageArchiveInfo(any(), anyInt());
     }
 
     @Test
@@ -432,8 +408,8 @@
 
     private Intent makeVerificationIntent() throws Exception {
         PackageInfo packageInfo =
-                mRealContext.getPackageManager().getPackageInfo(TEST_FRAMEWORK_PACKAGE,
-                        PackageManager.GET_SIGNATURES);
+                mRealContext.getPackageManager()
+                        .getPackageInfo(TEST_FRAMEWORK_PACKAGE, PackageManager.GET_SIGNATURES);
         doReturn(packageInfo)
                 .when(mSpyPackageManager)
                 .getPackageInfo(eq(INSTALLER), anyInt());
diff --git a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java
index 9915702..26b2096 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java
@@ -16,12 +16,12 @@
 
 package com.android.server.integrity.engine;
 
-import static org.junit.Assert.assertEquals;
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.when;
 
 import android.content.integrity.AppInstallMetadata;
-import android.content.integrity.Rule;
 
 import com.android.server.integrity.IntegrityFileManager;
 import com.android.server.integrity.model.IntegrityCheckResult;
@@ -36,7 +36,6 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 @RunWith(JUnit4.class)
@@ -68,33 +67,28 @@
     public void testAllowedInstallers_empty() {
         Map<String, String> allowedInstallers = Collections.emptyMap();
 
-        assertEquals(
-                IntegrityCheckResult.Effect.ALLOW,
-                mEngine.evaluate(
-                        getAppInstallMetadataBuilder()
-                                .setInstallerName(INSTALLER_1)
-                                .setInstallerCertificate(INSTALLER_1_CERT)
-                                .build(),
-                        allowedInstallers)
-                        .getEffect());
-        assertEquals(
-                IntegrityCheckResult.Effect.ALLOW,
-                mEngine.evaluate(
-                        getAppInstallMetadataBuilder()
-                                .setInstallerName(INSTALLER_2)
-                                .setInstallerCertificate(INSTALLER_2_CERT)
-                                .build(),
-                        allowedInstallers)
-                        .getEffect());
-        assertEquals(
-                IntegrityCheckResult.Effect.ALLOW,
-                mEngine.evaluate(
-                        getAppInstallMetadataBuilder()
-                                .setInstallerName(RANDOM_INSTALLER)
-                                .setInstallerCertificate(RANDOM_INSTALLER_CERT)
-                                .build(),
-                        allowedInstallers)
-                        .getEffect());
+        AppInstallMetadata appInstallMetadata1 =
+                getAppInstallMetadataBuilder()
+                        .setInstallerName(INSTALLER_1)
+                        .setInstallerCertificate(INSTALLER_1_CERT)
+                        .build();
+        AppInstallMetadata appInstallMetadata2 =
+                getAppInstallMetadataBuilder()
+                        .setInstallerName(INSTALLER_2)
+                        .setInstallerCertificate(INSTALLER_2_CERT)
+                        .build();
+        AppInstallMetadata appInstallMetadata3 =
+                getAppInstallMetadataBuilder()
+                        .setInstallerName(RANDOM_INSTALLER)
+                        .setInstallerCertificate(RANDOM_INSTALLER_CERT)
+                        .build();
+
+        assertThat(mEngine.evaluate(appInstallMetadata1, allowedInstallers).getEffect())
+                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
+        assertThat(mEngine.evaluate(appInstallMetadata2, allowedInstallers).getEffect())
+                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
+        assertThat(mEngine.evaluate(appInstallMetadata3, allowedInstallers).getEffect())
+                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
     }
 
     @Test
@@ -102,87 +96,100 @@
         Map<String, String> allowedInstallers =
                 Collections.singletonMap(INSTALLER_1, INSTALLER_1_CERT);
 
-        assertEquals(
-                IntegrityCheckResult.Effect.ALLOW,
-                mEngine.evaluate(
-                        getAppInstallMetadataBuilder()
-                                .setInstallerName(INSTALLER_1)
-                                .setInstallerCertificate(INSTALLER_1_CERT)
-                                .build(),
-                        allowedInstallers)
-                        .getEffect());
-        assertEquals(
-                IntegrityCheckResult.Effect.DENY,
-                mEngine.evaluate(
-                        getAppInstallMetadataBuilder()
-                                .setInstallerName(RANDOM_INSTALLER)
-                                .setInstallerCertificate(INSTALLER_1_CERT)
-                                .build(),
-                        allowedInstallers)
-                        .getEffect());
-        assertEquals(
-                IntegrityCheckResult.Effect.DENY,
-                mEngine.evaluate(
-                        getAppInstallMetadataBuilder()
-                                .setInstallerName(INSTALLER_1)
-                                .setInstallerCertificate(RANDOM_INSTALLER_CERT)
-                                .build(),
-                        allowedInstallers)
-                        .getEffect());
-        assertEquals(
-                IntegrityCheckResult.Effect.DENY,
-                mEngine.evaluate(
-                        getAppInstallMetadataBuilder()
-                                .setInstallerName(RANDOM_INSTALLER)
-                                .setInstallerCertificate(RANDOM_INSTALLER_CERT)
-                                .build(),
-                        allowedInstallers)
-                        .getEffect());
+        AppInstallMetadata appInstallMetadata1 =
+                getAppInstallMetadataBuilder()
+                        .setInstallerName(INSTALLER_1)
+                        .setInstallerCertificate(INSTALLER_1_CERT)
+                        .build();
+        assertThat(mEngine.evaluate(appInstallMetadata1, allowedInstallers).getEffect())
+                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
+
+        AppInstallMetadata appInstallMetadata2 =
+                getAppInstallMetadataBuilder()
+                        .setInstallerName(RANDOM_INSTALLER)
+                        .setInstallerCertificate(INSTALLER_1_CERT)
+                        .build();
+        assertThat(mEngine.evaluate(appInstallMetadata2, allowedInstallers).getEffect())
+                .isEqualTo(IntegrityCheckResult.Effect.DENY);
+
+        AppInstallMetadata appInstallMetadata3 =
+                getAppInstallMetadataBuilder()
+                        .setInstallerName(INSTALLER_1)
+                        .setInstallerCertificate(RANDOM_INSTALLER_CERT)
+                        .build();
+        assertThat(mEngine.evaluate(appInstallMetadata3, allowedInstallers).getEffect())
+                .isEqualTo(IntegrityCheckResult.Effect.DENY);
+
+        AppInstallMetadata appInstallMetadata4 =
+                getAppInstallMetadataBuilder()
+                        .setInstallerName(INSTALLER_1)
+                        .setInstallerCertificate(RANDOM_INSTALLER_CERT)
+                        .build();
+        assertThat(mEngine.evaluate(appInstallMetadata4, allowedInstallers).getEffect())
+                .isEqualTo(IntegrityCheckResult.Effect.DENY);
     }
 
     @Test
     public void testAllowedInstallers_multipleElement() {
-        List<Rule> rules = new ArrayList<>();
         Map<String, String> allowedInstallers = new HashMap<>(2);
         allowedInstallers.put(INSTALLER_1, INSTALLER_1_CERT);
         allowedInstallers.put(INSTALLER_2, INSTALLER_2_CERT);
 
-        assertEquals(
-                IntegrityCheckResult.Effect.ALLOW,
-                mEngine.evaluate(
-                        getAppInstallMetadataBuilder()
-                                .setInstallerName(INSTALLER_1)
-                                .setInstallerCertificate(INSTALLER_1_CERT)
-                                .build(),
-                        allowedInstallers)
-                        .getEffect());
-        assertEquals(
-                IntegrityCheckResult.Effect.ALLOW,
-                mEngine.evaluate(
-                        getAppInstallMetadataBuilder()
-                                .setInstallerName(INSTALLER_2)
-                                .setInstallerCertificate(INSTALLER_2_CERT)
-                                .build(),
-                        allowedInstallers)
-                        .getEffect());
-        assertEquals(
-                IntegrityCheckResult.Effect.DENY,
-                mEngine.evaluate(
-                        getAppInstallMetadataBuilder()
-                                .setInstallerName(INSTALLER_1)
-                                .setInstallerCertificate(INSTALLER_2_CERT)
-                                .build(),
-                        allowedInstallers)
-                        .getEffect());
-        assertEquals(
-                IntegrityCheckResult.Effect.DENY,
-                mEngine.evaluate(
-                        getAppInstallMetadataBuilder()
-                                .setInstallerName(INSTALLER_2)
-                                .setInstallerCertificate(INSTALLER_1_CERT)
-                                .build(),
-                        allowedInstallers)
-                        .getEffect());
+        AppInstallMetadata appInstallMetadata1 =
+                getAppInstallMetadataBuilder()
+                        .setInstallerName(INSTALLER_1)
+                        .setInstallerCertificate(INSTALLER_1_CERT)
+                        .build();
+        assertThat(mEngine.evaluate(appInstallMetadata1, allowedInstallers).getEffect())
+                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
+
+        AppInstallMetadata appInstallMetadata2 =
+                getAppInstallMetadataBuilder()
+                        .setInstallerName(INSTALLER_2)
+                        .setInstallerCertificate(INSTALLER_2_CERT)
+                        .build();
+        assertThat(mEngine.evaluate(appInstallMetadata2, allowedInstallers).getEffect())
+                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
+
+        AppInstallMetadata appInstallMetadata3 =
+                getAppInstallMetadataBuilder()
+                        .setInstallerName(INSTALLER_1)
+                        .setInstallerCertificate(INSTALLER_2_CERT)
+                        .build();
+        assertThat(mEngine.evaluate(appInstallMetadata3, allowedInstallers).getEffect())
+                .isEqualTo(IntegrityCheckResult.Effect.DENY);
+
+        AppInstallMetadata appInstallMetadata4 =
+                getAppInstallMetadataBuilder()
+                        .setInstallerName(INSTALLER_2)
+                        .setInstallerCertificate(INSTALLER_1_CERT)
+                        .build();
+        assertThat(mEngine.evaluate(appInstallMetadata4, allowedInstallers).getEffect())
+                .isEqualTo(IntegrityCheckResult.Effect.DENY);
+    }
+
+    @Test
+    public void manifestBasedRuleEvaluationWorksEvenWhenIntegrityFilesAreUnavailable() {
+        when(mIntegrityFileManager.initialized()).thenReturn(false);
+
+        Map<String, String> allowedInstallers =
+                Collections.singletonMap(INSTALLER_1, INSTALLER_1_CERT);
+
+        AppInstallMetadata appInstallMetadata1 =
+                getAppInstallMetadataBuilder()
+                        .setInstallerName(INSTALLER_1)
+                        .setInstallerCertificate(INSTALLER_1_CERT)
+                        .build();
+        assertThat(mEngine.evaluate(appInstallMetadata1, allowedInstallers).getEffect())
+                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
+
+        AppInstallMetadata appInstallMetadata2 =
+                getAppInstallMetadataBuilder()
+                        .setInstallerName(RANDOM_INSTALLER)
+                        .setInstallerCertificate(INSTALLER_1_CERT)
+                        .build();
+        assertThat(mEngine.evaluate(appInstallMetadata2, allowedInstallers).getEffect())
+                .isEqualTo(IntegrityCheckResult.Effect.DENY);
     }
 
     /** Returns a builder with all fields filled with some dummy data. */
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
index a8674a8..bfe0c15 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
@@ -156,7 +156,8 @@
         if (isMultiPackage) {
             params.isMultiPackage = true;
         }
-        InstallSource installSource = InstallSource.create("testInstaller", null, "testInstaller");
+        InstallSource installSource = InstallSource.create("testInstallInitiator",
+                "testInstallOriginator", "testInstaller");
         return new PackageInstallerSession(
                 /* callback */ null,
                 /* context */null,
@@ -297,6 +298,8 @@
         assertEquals(expected.userId, actual.userId);
         assertSessionParamsEquivalent(expected.params, actual.params);
         assertEquals(expected.getInstallerUid(), actual.getInstallerUid());
+        assertEquals(expected.getInstallerPackageName(), actual.getInstallerPackageName());
+        assertInstallSourcesEquivalent(expected.getInstallSource(), actual.getInstallSource());
         assertEquals(expected.stageDir.getAbsolutePath(), actual.stageDir.getAbsolutePath());
         assertEquals(expected.stageCid, actual.stageCid);
         assertEquals(expected.isPrepared(), actual.isPrepared());
@@ -316,4 +319,10 @@
         assertEquals(expected.getParentSessionId(), actual.getParentSessionId());
         assertArrayEquals(expected.getChildSessionIds(), actual.getChildSessionIds());
     }
+
+    private void assertInstallSourcesEquivalent(InstallSource expected, InstallSource actual) {
+        assertEquals(expected.installerPackageName, actual.installerPackageName);
+        assertEquals(expected.initiatingPackageName, actual.initiatingPackageName);
+        assertEquals(expected.originatingPackageName, actual.originatingPackageName);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
index ac27a08..5df8568 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
@@ -153,6 +153,25 @@
         assertTrue(mUserManagerService.isUserOfType(testId, typeName));
     }
 
+    /** Test UserInfo.supportsSwitchTo() for precreated users. */
+    @Test
+    public void testSupportSwitchTo_preCreated() throws Exception {
+        UserInfo userInfo = createUser(100, FLAG_FULL, null);
+        userInfo.preCreated = true;
+        assertFalse("Switching to a precreated user should be disabled",
+                userInfo.supportsSwitchTo());
+
+        userInfo.preCreated = false;
+        assertTrue("Switching to a full, real user should be allowed", userInfo.supportsSwitchTo());
+    }
+
+    /** Test UserInfo.supportsSwitchTo() for profiles. */
+    @Test
+    public void testSupportSwitchTo_profile() throws Exception {
+        UserInfo userInfo = createUser(100, FLAG_PROFILE, null);
+        assertFalse("Switching to a profiles should be disabled", userInfo.supportsSwitchTo());
+    }
+
     /** Tests upgradeIfNecessaryLP (but without locking) for upgrading from version 8 to 9+. */
     @Test
     public void testUpgradeIfNecessaryLP_9() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 9f45044..3a68924 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -406,10 +406,6 @@
     }
 
     @Override
-    public void requestUserActivityNotification() {
-    }
-
-    @Override
     public boolean setAodShowing(boolean aodShowing) {
         return false;
     }
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index acf51f3..f54f8d1 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -265,6 +265,29 @@
     public static final String EVENT_HANDOVER_FAILED =
             "android.telecom.event.HANDOVER_FAILED";
 
+
+    /**
+     * Reject reason used with {@link #reject(int)} to indicate that the user is rejecting this
+     * call because they have declined to answer it.  This typically means that they are unable
+     * to answer the call at this time and would prefer it be sent to voicemail.
+     */
+    public static final int REJECT_REASON_DECLINED = 1;
+
+    /**
+     * Reject reason used with {@link #reject(int)} to indicate that the user is rejecting this
+     * call because it is an unwanted call.  This allows the user to indicate that they are
+     * rejecting a call because it is likely a nuisance call.
+     */
+    public static final int REJECT_REASON_UNWANTED = 2;
+
+    /**
+     * @hide
+     */
+    @IntDef(prefix = { "REJECT_REASON_" },
+            value = {REJECT_REASON_DECLINED, REJECT_REASON_UNWANTED})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface RejectReason {};
+
     public static class Details {
         /** @hide */
         @Retention(RetentionPolicy.SOURCE)
@@ -1520,6 +1543,16 @@
     }
 
     /**
+     * Instructs the {@link ConnectionService} providing this {@link #STATE_RINGING} call that the
+     * user has chosen to reject the call and has indicated a reason why the call is being rejected.
+     *
+     * @param rejectReason the reason the call is being rejected.
+     */
+    public void reject(@RejectReason int rejectReason) {
+        mInCallAdapter.rejectCall(mTelecomCallId, rejectReason);
+    }
+
+    /**
      * Instructs this {@code Call} to disconnect.
      */
     public void disconnect() {
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index c934625..72c66d2 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -3037,6 +3037,17 @@
     public void onReject() {}
 
     /**
+     * Notifies this Connection, which is in {@link #STATE_RINGING}, of a request to reject.
+     * <p>
+     * For managed {@link ConnectionService}s, this will be called when the user rejects a call via
+     * the default dialer's {@link InCallService} using {@link Call#reject(int)}.
+     * @param rejectReason the reason the user provided for rejecting the call.
+     */
+    public void onReject(@android.telecom.Call.RejectReason int rejectReason) {
+        // to be implemented by ConnectionService.
+    }
+
+    /**
      * Notifies this Connection, which is in {@link #STATE_RINGING}, of
      * a request to reject with a message.
      */
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 440f044..00c2918 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -194,6 +194,7 @@
     private static final int MSG_CREATE_CONFERENCE = 35;
     private static final int MSG_CREATE_CONFERENCE_COMPLETE = 36;
     private static final int MSG_CREATE_CONFERENCE_FAILED = 37;
+    private static final int MSG_REJECT_WITH_REASON = 38;
 
     private static Connection sNullConnection;
 
@@ -450,6 +451,21 @@
         }
 
         @Override
+        public void rejectWithReason(String callId,
+                @android.telecom.Call.RejectReason int rejectReason, Session.Info sessionInfo) {
+            Log.startSession(sessionInfo, SESSION_REJECT);
+            try {
+                SomeArgs args = SomeArgs.obtain();
+                args.arg1 = callId;
+                args.argi1 = rejectReason;
+                args.arg2 = Log.createSubsession();
+                mHandler.obtainMessage(MSG_REJECT_WITH_REASON, args).sendToTarget();
+            } finally {
+                Log.endSession();
+            }
+        }
+
+        @Override
         public void rejectWithMessage(String callId, String message, Session.Info sessionInfo) {
             Log.startSession(sessionInfo, SESSION_REJECT_MESSAGE);
             try {
@@ -1053,6 +1069,17 @@
                     }
                     break;
                 }
+                case MSG_REJECT_WITH_REASON: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_REJECT);
+                    try {
+                        reject((String) args.arg1, args.argi1);
+                    } finally {
+                        args.recycle();
+                        Log.endSession();
+                    }
+                    break;
+                }
                 case MSG_REJECT_WITH_MESSAGE: {
                     SomeArgs args = (SomeArgs) msg.obj;
                     Log.continueSession((Session) args.arg3,
@@ -1981,6 +2008,11 @@
         findConnectionForAction(callId, "reject").onReject(rejectWithMessage);
     }
 
+    private void reject(String callId, @android.telecom.Call.RejectReason int rejectReason) {
+        Log.d(this, "reject %s with reason %d", callId, rejectReason);
+        findConnectionForAction(callId, "reject").onReject(rejectReason);
+    }
+
     private void silence(String callId) {
         Log.d(this, "silence %s", callId);
         findConnectionForAction(callId, "silence").onSilence();
diff --git a/telecomm/java/android/telecom/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java
index 2612468..594c1eb 100644
--- a/telecomm/java/android/telecom/InCallAdapter.java
+++ b/telecomm/java/android/telecom/InCallAdapter.java
@@ -89,6 +89,19 @@
     }
 
     /**
+     * Instructs Telecom to reject the specified call.
+     *
+     * @param callId The identifier of the call to reject.
+     * @param rejectReason The reason the call was rejected.
+     */
+    public void rejectCall(String callId, @Call.RejectReason int rejectReason) {
+        try {
+            mAdapter.rejectCallWithReason(callId, rejectReason);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
      * Instructs Telecom to disconnect the specified call.
      *
      * @param callId The identifier of the call to disconnect.
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index 96f2483..4249dff 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -77,6 +77,8 @@
 
     void reject(String callId, in Session.Info sessionInfo);
 
+    void rejectWithReason(String callId, int rejectReason, in Session.Info sessionInfo);
+
     void rejectWithMessage(String callId, String message, in Session.Info sessionInfo);
 
     void disconnect(String callId, in Session.Info sessionInfo);
diff --git a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
index 60745e4..eb2d714 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
@@ -34,6 +34,8 @@
 
     void rejectCall(String callId, boolean rejectWithMessage, String textMessage);
 
+    void rejectCallWithReason(String callId, int rejectReason);
+
     void disconnectCall(String callId);
 
     void holdCall(String callId);
diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java
index 9e6dfef..db17a95 100644
--- a/telephony/java/android/telephony/Annotation.java
+++ b/telephony/java/android/telephony/Annotation.java
@@ -598,6 +598,48 @@
     }
 
     /**
+     * Call forwarding function status
+     */
+    @IntDef(prefix = { "STATUS_" }, value = {
+        CallForwardingInfo.STATUS_ACTIVE,
+        CallForwardingInfo.STATUS_INACTIVE,
+        CallForwardingInfo.STATUS_UNKNOWN_ERROR,
+        CallForwardingInfo.STATUS_NOT_SUPPORTED,
+        CallForwardingInfo.STATUS_FDN_CHECK_FAILURE
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CallForwardingStatus {
+    }
+
+    /**
+     * Call forwarding reason types
+     */
+    @IntDef(flag = true, prefix = { "REASON_" }, value = {
+        CallForwardingInfo.REASON_UNCONDITIONAL,
+        CallForwardingInfo.REASON_BUSY,
+        CallForwardingInfo.REASON_NO_REPLY,
+        CallForwardingInfo.REASON_NOT_REACHABLE,
+        CallForwardingInfo.REASON_ALL,
+        CallForwardingInfo.REASON_ALL_CONDITIONAL
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CallForwardingReason {
+    }
+
+    /**
+     * Call waiting function status
+     */
+    @IntDef(prefix = { "CALL_WAITING_STATUS_" }, value = {
+        TelephonyManager.CALL_WAITING_STATUS_ACTIVE,
+        TelephonyManager.CALL_WAITING_STATUS_INACTIVE,
+        TelephonyManager.CALL_WAITING_STATUS_NOT_SUPPORTED,
+        TelephonyManager.CALL_WAITING_STATUS_UNKNOWN_ERROR
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CallWaitingStatus {
+    }
+
+    /**
      * UICC SIM Application Types
      */
     @IntDef(prefix = { "APPTYPE_" }, value = {
diff --git a/telephony/java/android/telephony/CallForwardingInfo.aidl b/telephony/java/android/telephony/CallForwardingInfo.aidl
new file mode 100644
index 0000000..2019e07
--- /dev/null
+++ b/telephony/java/android/telephony/CallForwardingInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2020, 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.telephony;
+
+parcelable CallForwardingInfo;
\ No newline at end of file
diff --git a/telephony/java/android/telephony/CallForwardingInfo.java b/telephony/java/android/telephony/CallForwardingInfo.java
new file mode 100644
index 0000000..33ad5e8
--- /dev/null
+++ b/telephony/java/android/telephony/CallForwardingInfo.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2020 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.telephony;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.Annotation.CallForwardingReason;
+import android.telephony.Annotation.CallForwardingStatus;
+
+import java.util.Objects;
+
+/**
+ * Defines the call forwarding information.
+ * @hide
+ */
+@SystemApi
+public final class CallForwardingInfo implements Parcelable {
+    private static final String TAG = "CallForwardingInfo";
+
+    /**
+     * Indicates the call forwarding status is inactive.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int STATUS_INACTIVE = 0;
+
+    /**
+     * Indicates the call forwarding status is active.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int STATUS_ACTIVE = 1;
+
+    /**
+     * Indicates the call forwarding could not be enabled because the recipient is not on
+     * Fixed Dialing Number (FDN) list.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int STATUS_FDN_CHECK_FAILURE = 2;
+
+    /**
+     * Indicates the call forwarding status is with an unknown error.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int STATUS_UNKNOWN_ERROR = 3;
+
+    /**
+     * Indicates the call forwarding is not supported (e.g. called via CDMA).
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int STATUS_NOT_SUPPORTED = 4;
+
+    /**
+     * Indicates the call forwarding reason is "unconditional".
+     * Reference: 3GPP TS 27.007 version 10.3.0 Release 10 - 7.11 Call forwarding number
+     *            and conditions +CCFC
+     * @hide
+     */
+    @SystemApi
+    public static final int REASON_UNCONDITIONAL = 0;
+
+    /**
+     * Indicates the call forwarding status is "busy".
+     * Reference: 3GPP TS 27.007 version 10.3.0 Release 10 - 7.11 Call forwarding number
+     *            and conditions +CCFC
+     * @hide
+     */
+    @SystemApi
+    public static final int REASON_BUSY = 1;
+
+    /**
+     * Indicates the call forwarding reason is "no reply".
+     * Reference: 3GPP TS 27.007 version 10.3.0 Release 10 - 7.11 Call forwarding number
+     *            and conditions +CCFC
+     * @hide
+     */
+    @SystemApi
+    public static final int REASON_NO_REPLY = 2;
+
+    /**
+     * Indicates the call forwarding reason is "not reachable".
+     * Reference: 3GPP TS 27.007 version 10.3.0 Release 10 - 7.11 Call forwarding number
+     *            and conditions +CCFC
+     * @hide
+     */
+    @SystemApi
+    public static final int REASON_NOT_REACHABLE = 3;
+
+    /**
+     * Indicates the call forwarding reason is "all", for setting all call forwarding reasons
+     * simultaneously (unconditional, busy, no reply, and not reachable).
+     * Reference: 3GPP TS 27.007 version 10.3.0 Release 10 - 7.11 Call forwarding number
+     *            and conditions +CCFC
+     * @hide
+     */
+    @SystemApi
+    public static final int REASON_ALL = 4;
+
+    /**
+     * Indicates the call forwarding reason is "all_conditional", for setting all conditional call
+     * forwarding reasons simultaneously (busy, no reply, and not reachable).
+     * Reference: 3GPP TS 27.007 version 10.3.0 Release 10 - 7.11 Call forwarding number
+     *            and conditions +CCFC
+     * @hide
+     */
+    @SystemApi
+    public static final int REASON_ALL_CONDITIONAL = 5;
+
+    /**
+     * The call forwarding status.
+     */
+    private @CallForwardingStatus int mStatus;
+
+    /**
+     * The call forwarding reason indicates the condition under which calls will be forwarded.
+     * Reference: 3GPP TS 27.007 version 10.3.0 Release 10 - 7.11 Call forwarding number
+     *            and conditions +CCFC
+     */
+    private @CallForwardingReason int mReason;
+
+    /**
+     * The phone number to which calls will be forwarded.
+     * Reference: 3GPP TS 27.007 version 10.3.0 Release 10 - 7.11 Call forwarding number
+     *            and conditions +CCFC
+     */
+    private String mNumber;
+
+    /**
+     * Gets the timeout (in seconds) before the forwarding is attempted.
+     */
+    private int mTimeSeconds;
+
+    /**
+     * Construct a CallForwardingInfo.
+     *
+     * @param status the call forwarding status
+     * @param reason the call forwarding reason
+     * @param number the phone number to which calls will be forwarded
+     * @param timeSeconds the timeout (in seconds) before the forwarding is attempted
+     * @hide
+     */
+    @SystemApi
+    public CallForwardingInfo(@CallForwardingStatus int status, @CallForwardingReason int reason,
+            @Nullable String number, int timeSeconds) {
+        mStatus = status;
+        mReason = reason;
+        mNumber = number;
+        mTimeSeconds = timeSeconds;
+    }
+
+    /**
+     * Returns the call forwarding status.
+     *
+     * @return the call forwarding status.
+     *
+     * @hide
+     */
+    @SystemApi
+    public @CallForwardingStatus int getStatus() {
+        return mStatus;
+    }
+
+    /**
+     * Returns the call forwarding reason. The call forwarding reason indicates the condition
+     * under which calls will be forwarded.  For example, {@link #REASON_NO_REPLY} indicates
+     * that calls will be forward to {@link #getNumber()} when the user fails to answer the call.
+     *
+     * @return the call forwarding reason.
+     *
+     * @hide
+     */
+    @SystemApi
+    public @CallForwardingReason int getReason() {
+        return mReason;
+    }
+
+    /**
+     * Returns the phone number to which calls will be forwarded.
+     *
+     * @return the number calls will be forwarded to, or {@code null} if call forwarding
+     * is being disabled.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getNumber() {
+        return mNumber;
+    }
+
+    /**
+     * Gets the timeout (in seconds) before the forwarding is attempted. For example,
+     * if {@link #REASON_NO_REPLY} is the call forwarding reason, the device will wait this
+     * duration of time before forwarding the call to {@link #getNumber()}.
+     *
+     * Reference: 3GPP TS 27.007 version 10.3.0 Release 10
+     *            7.11 Call forwarding number and conditions +CCFC
+     *
+     * @return the timeout (in seconds) before the forwarding is attempted.
+     *
+     * @hide
+     */
+    @SystemApi
+    @SuppressLint("MethodNameUnits")
+    public int getTimeoutSeconds() {
+        return mTimeSeconds;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(mNumber);
+        out.writeInt(mStatus);
+        out.writeInt(mReason);
+        out.writeInt(mTimeSeconds);
+    }
+
+    private CallForwardingInfo(Parcel in) {
+        mNumber = in.readString();
+        mStatus = in.readInt();
+        mReason = in.readInt();
+        mTimeSeconds = in.readInt();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+
+        if (!(o instanceof CallForwardingInfo)) {
+            return false;
+        }
+
+        CallForwardingInfo other = (CallForwardingInfo) o;
+        return mStatus == other.mStatus
+                && mNumber == other.mNumber
+                && mReason == other.mReason
+                && mTimeSeconds == other.mTimeSeconds;
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public int hashCode() {
+        return Objects.hash(mStatus, mNumber, mReason, mTimeSeconds);
+    }
+
+    public static final @NonNull Parcelable.Creator<CallForwardingInfo> CREATOR =
+            new Parcelable.Creator<CallForwardingInfo>() {
+                @Override
+                public CallForwardingInfo createFromParcel(Parcel in) {
+                    return new CallForwardingInfo(in);
+                }
+
+                @Override
+                public CallForwardingInfo[] newArray(int size) {
+                    return new CallForwardingInfo[size];
+                }
+            };
+
+    /**
+     * @hide
+     */
+    @Override
+    public String toString() {
+        return "[CallForwardingInfo: status=" + mStatus
+                + ", reason= " + mReason
+                + ", timeSec= " + mTimeSeconds + " seconds"
+                + ", number=" + Rlog.pii(TAG, mNumber) + "]";
+    }
+}
diff --git a/telephony/java/android/telephony/ImsManager.java b/telephony/java/android/telephony/ImsManager.java
index 9b4292f..704e5aa 100644
--- a/telephony/java/android/telephony/ImsManager.java
+++ b/telephony/java/android/telephony/ImsManager.java
@@ -27,11 +27,7 @@
 
 /**
  * Provides access to information about Telephony IMS services on the device.
- *
- * @hide
  */
-@SystemApi
-@TestApi
 @SystemService(Context.TELEPHONY_IMS_SERVICE)
 public class ImsManager {
 
@@ -45,7 +41,10 @@
      * <p class="note">
      * Carrier applications may listen to this broadcast to be notified of possible IMS provisioning
      * issues.
+     * @hide
      */
+    @SystemApi
+    @TestApi
     // Moved from TelephonyIntents, need to keep backwards compatibility with OEM apps that have
     // this value hard-coded in BroadcastReceiver.
     @SuppressLint("ActionValue")
@@ -104,7 +103,10 @@
      * @param subscriptionId The ID of the subscription that this ImsRcsManager will use.
      * @throws IllegalArgumentException if the subscription is invalid.
      * @return a ImsRcsManager instance with the specific subscription ID.
+     * @hide
      */
+    @SystemApi
+    @TestApi
     @NonNull
     public ImsRcsManager getImsRcsManager(int subscriptionId) {
         if (!SubscriptionManager.isValidSubscriptionId(subscriptionId)) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 86913a6..584b000 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -69,7 +69,9 @@
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
 import android.telephony.Annotation.ApnType;
+import android.telephony.Annotation.CallForwardingReason;
 import android.telephony.Annotation.CallState;
+import android.telephony.Annotation.CallWaitingStatus;
 import android.telephony.Annotation.NetworkType;
 import android.telephony.Annotation.RadioPowerState;
 import android.telephony.Annotation.SimActivationState;
@@ -12765,6 +12767,191 @@
     }
 
     /**
+     * Gets the voice call forwarding info {@link CallForwardingInfo}, given the call forward
+     * reason.
+     *
+     * @param callForwardingReason the call forwarding reasons
+     *
+     * @throws IllegalArgumentException if callForwardingReason is not any of
+     * {@link CallForwardingInfo.REASON_UNCONDITIONAL}, {@link CallForwardingInfo.REASON_BUSY},
+     * {@link CallForwardingInfo.REASON_NO_REPLY}, {@link CallForwardingInfo.REASON_NOT_REACHABLE},
+     * {@link CallForwardingInfo.REASON_ALL}, {@link CallForwardingInfo.REASON_ALL_CONDITIONAL}
+     *
+     * @return {@link CallForwardingInfo} with the status {@link CallForwardingInfo#STATUS_ACTIVE}
+     * or {@link CallForwardingInfo#STATUS_INACTIVE} and the target phone number to forward calls
+     * to, if it's available. Otherwise, it will return a {@link CallForwardingInfo} with status
+     * {@link CallForwardingInfo#STATUS_UNKNOWN_ERROR},
+     * {@link CallForwardingInfo#STATUS_NOT_SUPPORTED},
+     * or {@link CallForwardingInfo#STATUS_FDN_CHECK_FAILURE} depending on the situation.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @NonNull
+    public CallForwardingInfo getCallForwarding(@CallForwardingReason int callForwardingReason) {
+        if (callForwardingReason < CallForwardingInfo.REASON_UNCONDITIONAL
+                || callForwardingReason > CallForwardingInfo.REASON_ALL_CONDITIONAL) {
+            throw new IllegalArgumentException("callForwardingReason is out of range");
+        }
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.getCallForwarding(getSubId(), callForwardingReason);
+            }
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "getCallForwarding RemoteException", ex);
+        } catch (NullPointerException ex) {
+            Rlog.e(TAG, "getCallForwarding NPE", ex);
+        }
+        return new CallForwardingInfo(
+                CallForwardingInfo.STATUS_UNKNOWN_ERROR, 0 /* reason */, null /* number */,
+                        0 /* timeout */);
+    }
+
+    /**
+     * Sets the voice call forwarding info including status (enable/disable), call forwarding
+     * reason, the number to forward, and the timeout before the forwarding is attempted.
+     *
+     * @param callForwardingInfo {@link CallForwardingInfo} to setup the call forwarding.
+     * Enabling if {@link CallForwardingInfo#getStatus()} returns
+     * {@link CallForwardingInfo#STATUS_ACTIVE}; Disabling if
+     * {@link CallForwardingInfo#getStatus()} returns {@link CallForwardingInfo#STATUS_INACTIVE}.
+     *
+     * @throws IllegalArgumentException if any of the following for parameter callForwardingInfo:
+     * 0) it is {@code null}.
+     * 1) {@link CallForwardingInfo#getStatus()} returns neither
+     * {@link CallForwardingInfo#STATUS_ACTIVE} nor {@link CallForwardingInfo#STATUS_INACTIVE}.
+     * 2) {@link CallForwardingInfo#getReason()} is not any of
+     * {@link CallForwardingInfo.REASON_UNCONDITIONAL}, {@link CallForwardingInfo.REASON_BUSY},
+     * {@link CallForwardingInfo.REASON_NO_REPLY}, {@link CallForwardingInfo.REASON_NOT_REACHABLE},
+     * {@link CallForwardingInfo.REASON_ALL}, {@link CallForwardingInfo.REASON_ALL_CONDITIONAL}
+     * 3) {@link CallForwardingInfo#getNumber()} returns {@code null}.
+     * 4) {@link CallForwardingInfo#getTimeoutSeconds()} doesn't return a positive value.
+     *
+     * @return {@code true} to indicate it was set successfully; {@code false} otherwise.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    public boolean setCallForwarding(@NonNull CallForwardingInfo callForwardingInfo) {
+        if (callForwardingInfo == null) {
+            throw new IllegalArgumentException("callForwardingInfo is null");
+        }
+        int callForwardingStatus = callForwardingInfo.getStatus();
+        if (callForwardingStatus != CallForwardingInfo.STATUS_ACTIVE
+                && callForwardingStatus != CallForwardingInfo.STATUS_INACTIVE) {
+            throw new IllegalArgumentException(
+                    "callForwardingStatus is neither active nor inactive");
+        }
+        int callForwardingReason = callForwardingInfo.getReason();
+        if (callForwardingReason < CallForwardingInfo.REASON_UNCONDITIONAL
+                || callForwardingReason > CallForwardingInfo.REASON_ALL_CONDITIONAL) {
+            throw new IllegalArgumentException("callForwardingReason is out of range");
+        }
+        if (callForwardingInfo.getNumber() == null) {
+            throw new IllegalArgumentException("callForwarding number is null");
+        }
+        if (callForwardingInfo.getTimeoutSeconds() <= 0) {
+            throw new IllegalArgumentException("callForwarding timeout isn't positive");
+        }
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.setCallForwarding(getSubId(), callForwardingInfo);
+            }
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "setCallForwarding RemoteException", ex);
+        } catch (NullPointerException ex) {
+            Rlog.e(TAG, "setCallForwarding NPE", ex);
+        }
+        return false;
+    }
+
+    /**
+     * Indicates the call waiting status is active.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int CALL_WAITING_STATUS_ACTIVE = 1;
+
+    /**
+     * Indicates the call waiting status is inactive.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int CALL_WAITING_STATUS_INACTIVE = 2;
+
+    /**
+     * Indicates the call waiting status is with an unknown error.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int CALL_WAITING_STATUS_UNKNOWN_ERROR = 3;
+
+    /**
+     * Indicates the call waiting is not supported (e.g. called via CDMA).
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int CALL_WAITING_STATUS_NOT_SUPPORTED = 4;
+
+    /**
+     * Gets the status of voice call waiting function. Call waiting function enables the waiting
+     * for the incoming call when it reaches the user who is busy to make another call and allows
+     * users to decide whether to switch to the incoming call.
+     *
+     * @return the status of call waiting function.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public @CallWaitingStatus int getCallWaitingStatus() {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.getCallWaitingStatus(getSubId());
+            }
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "getCallWaitingStatus RemoteException", ex);
+        } catch (NullPointerException ex) {
+            Rlog.e(TAG, "getCallWaitingStatus NPE", ex);
+        }
+        return CALL_WAITING_STATUS_UNKNOWN_ERROR;
+    }
+
+    /**
+     * Sets the status for voice call waiting function. Call waiting function enables the waiting
+     * for the incoming call when it reaches the user who is busy to make another call and allows
+     * users to decide whether to switch to the incoming call.
+     *
+     * @param isEnable {@code true} to enable; {@code false} to disable.
+     * @return {@code true} to indicate it was set successfully; {@code false} otherwise.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    public boolean setCallWaitingStatus(boolean isEnable) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.setCallWaitingStatus(getSubId(), isEnable);
+            }
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "setCallWaitingStatus RemoteException", ex);
+        } catch (NullPointerException ex) {
+            Rlog.e(TAG, "setCallWaitingStatus NPE", ex);
+        }
+        return false;
+    }
+
+    /**
      * Set allowing mobile data during voice call. This is used for allowing data on the non-default
      * data SIM. When a voice call is placed on the non-default data SIM on DSDS devices, users will
      * not be able to use mobile data. By calling this API, data will be temporarily enabled on the
diff --git a/telephony/java/android/telephony/ims/ImsException.java b/telephony/java/android/telephony/ims/ImsException.java
index cb3f0f9..643f452 100644
--- a/telephony/java/android/telephony/ims/ImsException.java
+++ b/telephony/java/android/telephony/ims/ImsException.java
@@ -61,7 +61,6 @@
      * This is a configuration error and there should be no retry. The subscription used for this
      * operation is either invalid or has become inactive. The active subscriptions can be queried
      * with {@link SubscriptionManager#getActiveSubscriptionInfoList()}.
-     * @hide
      */
     public static final int CODE_ERROR_INVALID_SUBSCRIPTION = 3;
 
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index 5fdef83..3341fa7 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -56,7 +56,8 @@
  * registration and MmTel capability status callbacks, as well as query/modify user settings for the
  * associated subscription.
  *
- * @see #createForSubscriptionId(int)
+ * Use {@link android.telephony.ims.ImsManager#getImsMmTelManager(int)} to get an instance of this
+ * manager.
  */
 public class ImsMmTelManager implements RegistrationManager {
 
@@ -228,8 +229,13 @@
      * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
      *
      * @throws IllegalArgumentException if the subscription is invalid.
-     *
+     * @deprecated Use {@link android.telephony.ims.ImsManager#getImsMmTelManager(int)} to get an
+     * instance of this class.
+     * @hide
      */
+    @SystemApi
+    @TestApi
+    @Deprecated
     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
     @RequiresPermission(anyOf = {
             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
@@ -245,7 +251,7 @@
     }
 
     /**
-     * Only visible for testing, use {@link #createForSubscriptionId(int)} instead.
+     * Only visible for testing, use {@link ImsManager#getImsMmTelManager(int)} instead.
      * @hide
      */
     @VisibleForTesting
@@ -255,7 +261,7 @@
 
     /**
      * Registers a {@link RegistrationCallback} with the system, which will provide registration
-     * updates for the subscription specified in {@link #createForSubscriptionId(int)}. Use
+     * updates for the subscription specified in {@link ImsManager#getImsMmTelManager(int)}. Use
      * {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to Subscription changed
      * events and call {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up.
      *
@@ -453,7 +459,7 @@
     /**
      * Registers a {@link CapabilityCallback} with the system, which will provide MmTel service
      * availability updates for the subscription specified in
-     * {@link #createForSubscriptionId(int)}. The method {@see #isAvailable(int, int)}
+     * {@link ImsManager#getImsMmTelManager(int)}. The method {@see #isAvailable(int, int)}
      * can also be used to query this information at any time.
      *
      * Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to
diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java
index 62bc2ae..2b3072e 100644
--- a/telephony/java/android/telephony/ims/ImsService.java
+++ b/telephony/java/android/telephony/ims/ImsService.java
@@ -60,9 +60,10 @@
  * The telephony framework will then bind to the ImsService you have defined in your manifest
  * if you are either:
  * 1) Defined as the default ImsService for the device in the device overlay using
- *    "config_ims_package".
+ *    "config_ims_mmtel_package" or "config_ims_rcs_package".
  * 2) Defined as a Carrier Provided ImsService in the Carrier Configuration using
- *    {@link CarrierConfigManager#KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING}.
+ *    {@link CarrierConfigManager#KEY_CONFIG_IMS_MMTEL_PACKAGE_OVERRIDE_STRING} or
+ *    {@link CarrierConfigManager#KEY_CONFIG_IMS_RCS_PACKAGE_OVERRIDE_STRING}.
  *
  * There are two ways to define to the platform which {@link ImsFeature}s this {@link ImsService}
  * supports, dynamic or static definitions.
diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
index 3e2903f..57b9b7a 100644
--- a/telephony/java/android/telephony/ims/RcsContactUceCapability.java
+++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
@@ -16,10 +16,11 @@
 
 package android.telephony.ims;
 
-import android.annotation.IntDef;
+import android.annotation.LongDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -37,6 +38,7 @@
  * @hide
  */
 @SystemApi
+@TestApi
 public final class RcsContactUceCapability implements Parcelable {
 
     /** Supports 1-to-1 chat */
@@ -99,11 +101,16 @@
     public static final int CAPABILITY_CHAT_BOT_ROLE = (1 << 27);
     /** Supports the unidirectional plug-ins framework. */
     public static final int CAPABILITY_PLUG_IN = (1 << 28);
+    /** Supports standalone Chatbot communication. */
+    public static final int CAPABILITY_STANDALONE_CHAT_BOT = (1 << 29);
+    /** Supports MMTEL based call composer. */
+    public static final int CAPABILITY_MMTEL_CALL_COMPOSER = (1 << 30);
+
 
 
     /** @hide*/
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = "CAPABILITY_", flag = true, value = {
+    @LongDef(prefix = "CAPABILITY_", flag = true, value = {
             CAPABILITY_CHAT_STANDALONE,
             CAPABILITY_CHAT_SESSION,
             CAPABILITY_CHAT_SESSION_STORE_FORWARD,
@@ -132,7 +139,9 @@
             CAPABILITY_SHARED_SKETCH,
             CAPABILITY_CHAT_BOT,
             CAPABILITY_CHAT_BOT_ROLE,
-            CAPABILITY_PLUG_IN
+            CAPABILITY_PLUG_IN,
+            CAPABILITY_STANDALONE_CHAT_BOT,
+            CAPABILITY_MMTEL_CALL_COMPOSER
     })
     public @interface CapabilityFlag {}
 
@@ -159,11 +168,11 @@
          * @param type The capability to map to a service URI that is different from the contact's
          *         URI.
          */
-        public @NonNull Builder add(@CapabilityFlag int type, @NonNull Uri serviceUri) {
+        public @NonNull Builder add(@CapabilityFlag long type, @NonNull Uri serviceUri) {
             mCapabilities.mCapabilities |= type;
             // Put each of these capabilities into the map separately.
-            for (int shift = 0; shift < Integer.SIZE; shift++) {
-                int cap = type & (1 << shift);
+            for (long shift = 0; shift < Integer.SIZE; shift++) {
+                long cap = type & (1 << shift);
                 if (cap != 0) {
                     mCapabilities.mServiceMap.put(cap, serviceUri);
                     // remove that capability from the field.
@@ -181,7 +190,7 @@
          * Add a UCE capability flag that this contact supports.
          * @param type the capability that the contact supports.
          */
-        public @NonNull Builder add(@CapabilityFlag int type) {
+        public @NonNull Builder add(@CapabilityFlag long type) {
             mCapabilities.mCapabilities |= type;
             return this;
         }
@@ -207,7 +216,7 @@
     private final Uri mContactUri;
     private long mCapabilities;
     private List<String> mExtensionTags = new ArrayList<>();
-    private Map<Integer, Uri> mServiceMap = new HashMap<>();
+    private Map<Long, Uri> mServiceMap = new HashMap<>();
 
     /**
      * Use {@link Builder} to build an instance of this interface.
@@ -225,7 +234,7 @@
         // read mServiceMap as key,value pair
         int mapSize = in.readInt();
         for (int i = 0; i < mapSize; i++) {
-            mServiceMap.put(in.readInt(), in.readParcelable(Uri.class.getClassLoader()));
+            mServiceMap.put(in.readLong(), in.readParcelable(Uri.class.getClassLoader()));
         }
     }
 
@@ -250,8 +259,8 @@
         // write mServiceMap as key,value pairs
         int mapSize = mServiceMap.keySet().size();
         out.writeInt(mapSize);
-        for (int key : mServiceMap.keySet()) {
-            out.writeInt(key);
+        for (long key : mServiceMap.keySet()) {
+            out.writeLong(key);
             out.writeParcelable(mServiceMap.get(key), 0);
         }
     }
@@ -266,7 +275,7 @@
      * @param type The capability flag to query.
      * @return true if the capability flag specified is set, false otherwise.
      */
-    public boolean isCapable(@CapabilityFlag int type) {
+    public boolean isCapable(@CapabilityFlag long type) {
         return (mCapabilities & type) > 0;
     }
 
@@ -290,13 +299,13 @@
      * <p>
      * This will typically be the contact {@link Uri} available via {@link #getContactUri()} unless
      * a different service {@link Uri} was associated with this capability using
-     * {@link Builder#add(int, Uri)}.
+     * {@link Builder#add(long, Uri)}.
      *
      * @return a String containing the {@link Uri} associated with the service tag or
      * {@code null} if this capability is not set as capable.
-     * @see #isCapable(int)
+     * @see #isCapable(long)
      */
-    public @Nullable Uri getServiceUri(@CapabilityFlag int type) {
+    public @Nullable Uri getServiceUri(@CapabilityFlag long type) {
         Uri result = mServiceMap.getOrDefault(type, null);
         // If the capability is capable, but does not have a service URI associated, use the default
         // contact URI.
diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java
index 7216776..72a00ce 100644
--- a/telephony/java/android/telephony/ims/RcsUceAdapter.java
+++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java
@@ -174,7 +174,6 @@
      * Provides a one-time callback for the response to a UCE request. After this callback is called
      * by the framework, the reference to this callback will be discarded on the service side.
      * @see #requestCapabilities(Executor, List, CapabilitiesCallback)
-     * @hide
      */
     public static class CapabilitiesCallback {
 
@@ -226,10 +225,9 @@
      * {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not
      * available. This can happen if the ImsService has crashed, for example, or if the subscription
      * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
-     * @hide
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    public void requestCapabilities(@CallbackExecutor Executor executor,
+    public void requestCapabilities(@NonNull @CallbackExecutor Executor executor,
             @NonNull List<Uri> contactNumbers,
             @NonNull CapabilitiesCallback c) throws ImsException {
         if (c == null) {
@@ -289,7 +287,6 @@
      * {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not
      * available. This can happen if the ImsService has crashed, for example, or if the subscription
      * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
-     * @hide
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public @PublishState int getUcePublishState() throws ImsException {
diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index f3aea49..7ff8735 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -259,10 +259,7 @@
             super(capabilities);
         }
 
-        /**
-         * @hide
-         */
-        @SystemApi @TestApi
+        /** @hide */
         @IntDef(flag = true,
                 value = {
                         CAPABILITY_TYPE_VOICE,
@@ -396,10 +393,7 @@
     @SystemApi @TestApi
     public static final int PROCESS_CALL_CSFB = 1;
 
-    /**
-    * @hide
-    */
-    @SystemApi @TestApi
+    /** @hide */
     @IntDef(flag = true,
             value = {
                     PROCESS_CALL_IMS,
@@ -513,7 +507,7 @@
      * @param callProfile The {@link ImsCallProfile} IMS call profile with details.
      *        This can be null if no call information is available for the rejected call.
      * @param reason The {@link ImsReasonInfo} call rejection reason.
-     * * @hide
+     * @hide
      */
     @SystemApi @TestApi
     public final void notifyRejectedCall(@NonNull ImsCallProfile callProfile,
diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
index 884a0bc..8e67621 100644
--- a/telephony/java/android/telephony/ims/feature/RcsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -349,9 +349,8 @@
      *
      * @return An instance of {@link RcsSipOptionsImplBase} that implements SIP options exchange if
      * it is supported by the device.
-     * @hide
      */
-    public RcsSipOptionsImplBase getOptionsExchangeImpl() {
+    public @NonNull RcsSipOptionsImplBase getOptionsExchangeImpl() {
         // Base Implementation, override to implement functionality
         return new RcsSipOptionsImplBase();
     }
@@ -365,9 +364,8 @@
      *
      * @return An instance of {@link RcsPresenceExchangeImplBase} that implements presence
      * exchange if it is supported by the device.
-     * @hide
      */
-    public RcsPresenceExchangeImplBase getPresenceExchangeImpl() {
+    public @NonNull RcsPresenceExchangeImplBase getPresenceExchangeImpl() {
         // Base Implementation, override to implement functionality.
         return new RcsPresenceExchangeImplBase();
     }
diff --git a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
index f4367da..e8f69ea 100644
--- a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
@@ -410,6 +410,13 @@
      * Rejects an incoming call or session update.
      *
      * @param reason reason code to reject an incoming call, defined in {@link ImsReasonInfo}.
+     *               The {@link android.telecom.InCallService} (dialer app) can use the
+     *               {@link android.telecom.Call#reject(int)} API to reject a call while specifying
+     *               a user-indicated reason for rejecting the call.
+     *               Normal call declines ({@link android.telecom.Call#REJECT_REASON_DECLINED}) will
+     *               map to {@link ImsReasonInfo#CODE_USER_DECLINE}.
+     *               Unwanted calls ({@link android.telecom.Call#REJECT_REASON_UNWANTED}) will map
+     *               to {@link ImsReasonInfo#CODE_SIP_USER_MARKED_UNWANTED}.
      * {@link ImsCallSession.Listener#callSessionStartFailed}
      */
     public void reject(int reason) {
diff --git a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java
index fda295a..a24af2f 100644
--- a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java
+++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java
@@ -17,6 +17,8 @@
 package android.telephony.ims.stub;
 
 import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.RemoteException;
 import android.telephony.ims.ImsException;
 import android.telephony.ims.aidl.IRcsFeatureListener;
@@ -32,6 +34,8 @@
  *
  * @hide
  */
+@SystemApi
+@TestApi
 public class RcsCapabilityExchange {
 
     /**  Service is unknown. */
diff --git a/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java
index bb03448..f200ea2 100644
--- a/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java
@@ -18,6 +18,8 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.net.Uri;
 import android.os.RemoteException;
 import android.telephony.ims.ImsException;
@@ -37,6 +39,8 @@
  *
  * @hide
  */
+@SystemApi
+@TestApi
 public class RcsPresenceExchangeImplBase extends RcsCapabilityExchange {
 
     private static final String LOG_TAG = "RcsPresenceExchangeIB";
diff --git a/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java b/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java
index 1c68fc0..355c4dd 100644
--- a/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java
@@ -19,6 +19,8 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.net.Uri;
 import android.os.RemoteException;
 import android.telephony.ims.ImsException;
@@ -35,6 +37,8 @@
  *
  * @hide
  */
+@SystemApi
+@TestApi
 public class RcsSipOptionsImplBase extends RcsCapabilityExchange {
 
     private static final String LOG_TAG = "RcsSipOptionsImplBase";
@@ -69,6 +73,11 @@
      */
     public static final int RESPONSE_DOES_NOT_EXIST_ANYWHERE = 4;
 
+    /**
+     * Indicates that the remote user responded with a 400 BAD REQUEST response.
+     */
+    public static final int RESPONSE_BAD_REQUEST = 5;
+
     /** @hide*/
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = "RESPONSE_", value = {
@@ -77,7 +86,8 @@
             RESPONSE_TEMPORARILY_UNAVAILABLE,
             RESPONSE_REQUEST_TIMEOUT,
             RESPONSE_NOT_FOUND,
-            RESPONSE_DOES_NOT_EXIST_ANYWHERE
+            RESPONSE_DOES_NOT_EXIST_ANYWHERE,
+            RESPONSE_BAD_REQUEST
     })
     public @interface SipResponseCode {}
 
@@ -188,7 +198,6 @@
      * @param reason A non-null String containing the reason associated with the SIP code.
      * @param operationToken The token provided by the framework when
      *         {@link #onRemoteCapabilityRequest(Uri, RcsContactUceCapability, int)} was called.
-     *
      */
     public void respondToCapabilityRequestWithError(@NonNull Uri contactUri,
             @SipResponseCode int code, @NonNull String reason, int operationToken) {
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 3f573c9..beb3c8c 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -29,6 +29,7 @@
 import android.service.carrier.CarrierIdentifier;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
+import android.telephony.CallForwardingInfo;
 import android.telephony.CarrierRestrictionRules;
 import android.telephony.CellIdentity;
 import android.telephony.CellInfo;
@@ -1633,6 +1634,79 @@
     NetworkStats getVtDataUsage(int subId, boolean perUidStats);
 
     /**
+     * Gets the voice call forwarding info {@link CallForwardingInfo}, given the call forward
+     * reason.
+     *
+     * @param callForwardingReason the call forwarding reasons which are the bitwise-OR combination
+     * of the following constants:
+     * <ol>
+     * <li>{@link CallForwardingInfo#REASON_BUSY} </li>
+     * <li>{@link CallForwardingInfo#REASON_NO_REPLY} </li>
+     * <li>{@link CallForwardingInfo#REASON_NOT_REACHABLE} </li>
+     * </ol>
+     *
+     * @throws IllegalArgumentException if callForwardingReason is not a bitwise-OR combination
+     * of {@link CallForwardingInfo.REASON_BUSY}, {@link CallForwardingInfo.REASON_BUSY},
+     * {@link CallForwardingInfo.REASON_NOT_REACHABLE}
+     *
+     * @return {@link CallForwardingInfo} with the status {@link CallForwardingInfo#STATUS_ACTIVE}
+     * or {@link CallForwardingInfo#STATUS_INACTIVE} and the target phone number to forward calls
+     * to, if it's available. Otherwise, it will return a {@link CallForwardingInfo} with status
+     * {@link CallForwardingInfo#STATUS_NOT_SUPPORTED} or
+     * {@link CallForwardingInfo#STATUS_FDN_CHECK_FAILURE} depending on the situation.
+     *
+     * @hide
+     */
+    CallForwardingInfo getCallForwarding(int subId, int callForwardingReason);
+
+    /**
+     * Sets the voice call forwarding info including status (enable/disable), call forwarding
+     * reason, the number to forward, and the timeout before the forwarding is attempted.
+     *
+     * @param callForwardingInfo {@link CallForwardingInfo} to setup the call forwarding.
+     * Enabling if {@link CallForwardingInfo#getStatus()} returns
+     * {@link CallForwardingInfo#STATUS_ACTIVE}; Disabling if
+     * {@link CallForwardingInfo#getStatus()} returns {@link CallForwardingInfo#STATUS_INACTIVE}.
+     *
+     * @throws IllegalArgumentException if any of the following:
+     * 0) callForwardingInfo is null.
+     * 1) {@link CallForwardingInfo#getStatus()} for callForwardingInfo returns neither
+     * {@link CallForwardingInfo#STATUS_ACTIVE} nor {@link CallForwardingInfo#STATUS_INACTIVE}.
+     * 2) {@link CallForwardingInfo#getReason()} for callForwardingInfo doesn't return the
+     * bitwise-OR combination of {@link CallForwardingInfo.REASON_BUSY},
+     * {@link CallForwardingInfo.REASON_BUSY}, {@link CallForwardingInfo.REASON_NOT_REACHABLE}
+     * 3) {@link CallForwardingInfo#getNumber()} for callForwardingInfo returns null.
+     * 4) {@link CallForwardingInfo#getTimeout()} for callForwardingInfo returns nagetive value.
+     *
+     * @return {@code true} to indicate it was set successfully; {@code false} otherwise.
+     *
+     * @hide
+     */
+    boolean setCallForwarding(int subId, in CallForwardingInfo callForwardingInfo);
+
+    /**
+     * Gets the status of voice call waiting function. Call waiting function enables the waiting
+     * for the incoming call when it reaches the user who is busy to make another call and allows
+     * users to decide whether to switch to the incoming call.
+     *
+     * @return the status of call waiting function.
+     * @hide
+     */
+    int getCallWaitingStatus(int subId);
+
+    /**
+     * Sets the status for voice call waiting function. Call waiting function enables the waiting
+     * for the incoming call when it reaches the user who is busy to make another call and allows
+     * users to decide whether to switch to the incoming call.
+     *
+     * @param isEnable {@code true} to enable; {@code false} to disable.
+     * @return {@code true} to indicate it was set successfully; {@code false} otherwise.
+     *
+     * @hide
+     */
+    boolean setCallWaitingStatus(int subId, boolean isEnable);
+
+    /**
      * Policy control of data connection. Usually used when data limit is passed.
      * @param enabled True if enabling the data, otherwise disabling.
      * @param subId Subscription index
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 48f7850..d41a6c8 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -317,16 +317,8 @@
             "com.android.internal.telephony.ACTION_LINE1_NUMBER_ERROR_DETECTED";
 
     /**
-     * Broadcast action to notify radio bug.
-     *
-     * Requires the READ_PRIVILEGED_PHONE_STATE permission.
-     *
-     * @hide
+     * Broadcast sent when a user activity is detected.
      */
-    public static final String ACTION_REPORT_RADIO_BUG =
-            "com.android.internal.telephony.ACTION_REPORT_RADIO_BUG";
-
-    // ACTION_REPORT_RADIO_BUG extra keys
-    public static final String EXTRA_SLOT_ID = "slotId";
-    public static final String EXTRA_RADIO_BUG_TYPE = "radioBugType";
+    public static final String ACTION_USER_ACTIVITY_NOTIFICATION =
+            "android.intent.action.USER_ACTIVITY_NOTIFICATION";
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java
index ae55a75..8559cb9 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java
@@ -30,10 +30,12 @@
 import android.view.Surface;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.FlakyTest;
 import androidx.test.filters.LargeTest;
 
 import org.junit.Before;
 import org.junit.FixMethodOrder;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.MethodSorters;
@@ -50,6 +52,8 @@
 @LargeTest
 @RunWith(Parameterized.class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest(bugId = 147659548)
+@Ignore("Waiting bug feedback")
 public class SeamlessAppRotationTest extends FlickerTestBase {
     private int mBeginRotation;
     private int mEndRotation;
diff --git a/tests/net/common/java/android/net/LinkAddressTest.java b/tests/net/common/java/android/net/LinkAddressTest.java
index e566e44..06c6301 100644
--- a/tests/net/common/java/android/net/LinkAddressTest.java
+++ b/tests/net/common/java/android/net/LinkAddressTest.java
@@ -326,26 +326,23 @@
         assertParcelSane(l, 6);
     }
 
-    /*
     @Test
     public void testDeprecationTime() {
         try {
             new LinkAddress(V6_ADDRESS, 64, 0, 456,
-                    LinkAddress.LIFETIME_UNKNOWN,
-                    SystemClock.elapsedRealtime() + 200000);
+                    LinkAddress.LIFETIME_UNKNOWN, 100000L);
             fail("Only one time provided should cause exception");
         } catch (IllegalArgumentException expected) { }
 
         try {
             new LinkAddress(V6_ADDRESS, 64, 0, 456,
-                    SystemClock.elapsedRealtime() - 100000,
-                    SystemClock.elapsedRealtime() - 200000);
+                    200000L, 100000L);
             fail("deprecation time later than expiration time should cause exception");
         } catch (IllegalArgumentException expected) { }
 
         try {
             new LinkAddress(V6_ADDRESS, 64, 0, 456,
-                    -2, SystemClock.elapsedRealtime());
+                    -2, 100000L);
             fail("negative deprecation time should cause exception");
         } catch (IllegalArgumentException expected) { }
     }
@@ -354,14 +351,13 @@
     public void testExpirationTime() {
         try {
             new LinkAddress(V6_ADDRESS, 64, 0, 456,
-                    SystemClock.elapsedRealtime() + 200000,
-                    LinkAddress.LIFETIME_UNKNOWN);
+                    200000L, LinkAddress.LIFETIME_UNKNOWN);
             fail("Only one time provided should cause exception");
         } catch (IllegalArgumentException expected) { }
 
         try {
             new LinkAddress(V6_ADDRESS, 64, 0, 456,
-                    SystemClock.elapsedRealtime() - 10000, -2);
+                    100000L, -2);
             fail("negative expiration time should cause exception");
         } catch (IllegalArgumentException expected) { }
     }
@@ -374,12 +370,12 @@
         // Test if deprecated bit was added/remove automatically based on the provided deprecation
         // time
         l = new LinkAddress(V6_ADDRESS, 64, 0, RT_SCOPE_HOST,
-                SystemClock.elapsedRealtime() - 100000, LinkAddress.LIFETIME_PERMANENT);
+                1L, LinkAddress.LIFETIME_PERMANENT);
         // Check if the flag is added automatically.
         assertTrue((l.getFlags() & IFA_F_DEPRECATED) != 0);
 
         l = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED, RT_SCOPE_HOST,
-                SystemClock.elapsedRealtime() + 100000, LinkAddress.LIFETIME_PERMANENT);
+                SystemClock.elapsedRealtime() + 100000L, LinkAddress.LIFETIME_PERMANENT);
         // Check if the flag is removed automatically.
         assertTrue((l.getFlags() & IFA_F_DEPRECATED) == 0);
 
@@ -389,12 +385,10 @@
         assertTrue((l.getFlags() & IFA_F_PERMANENT) != 0);
 
         l = new LinkAddress(V6_ADDRESS, 64, IFA_F_PERMANENT, RT_SCOPE_HOST,
-                SystemClock.elapsedRealtime() - 100000,
-                SystemClock.elapsedRealtime() + 100000);
+                1000L, SystemClock.elapsedRealtime() + 100000L);
         // Check if the permanent flag is removed
         assertTrue((l.getFlags() & IFA_F_PERMANENT) == 0);
-    }*/
-
+    }
 
     private void assertGlobalPreferred(LinkAddress l, String msg) {
         assertTrue(msg, l.isGlobalPreferred());
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 419bcb1..f8d48c5 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -178,7 +178,7 @@
      * If connected to a network suggestion or specifier, store the package name of the app,
      * else null.
      */
-    private String mAppPackageName;
+    private String mRequestingPackageName;
 
     /**
      * Running total count of lost (not ACKed) transmitted unicast data packets.
@@ -201,68 +201,68 @@
      */
     public long rxSuccess;
 
-    private double mTxBadRate;
+    private double mLostTxPacketsPerSecond;
 
     /**
      * Average rate of lost transmitted packets, in units of packets per second.
      * @hide
      */
     @SystemApi
-    public double getTxBadRate() {
-        return mTxBadRate;
+    public double getLostTxPacketsPerSecond() {
+        return mLostTxPacketsPerSecond;
     }
 
     /** @hide */
-    public void setTxBadRate(double txBadRate) {
-        mTxBadRate = txBadRate;
+    public void setLostTxPacketsPerSecond(double lostTxPacketsPerSecond) {
+        mLostTxPacketsPerSecond = lostTxPacketsPerSecond;
     }
 
-    private double mTxRetriesRate;
+    private double mTxRetriedTxPacketsPerSecond;
 
     /**
      * Average rate of transmitted retry packets, in units of packets per second.
      * @hide
      */
     @SystemApi
-    public double getTxRetriesRate() {
-        return mTxRetriesRate;
+    public double getRetriedTxPacketsPerSecond() {
+        return mTxRetriedTxPacketsPerSecond;
     }
 
     /** @hide */
-    public void setTxRetriesRate(double txRetriesRate) {
-        mTxRetriesRate = txRetriesRate;
+    public void setRetriedTxPacketsRate(double txRetriedTxPacketsPerSecond) {
+        mTxRetriedTxPacketsPerSecond = txRetriedTxPacketsPerSecond;
     }
 
-    private double mTxSuccessRate;
+    private double mSuccessfulTxPacketsPerSecond;
 
     /**
      * Average rate of successfully transmitted unicast packets, in units of packets per second.
      * @hide
      */
     @SystemApi
-    public double getTxSuccessRate() {
-        return mTxSuccessRate;
+    public double getSuccessfulTxPacketsPerSecond() {
+        return mSuccessfulTxPacketsPerSecond;
     }
 
     /** @hide */
-    public void setTxSuccessRate(double txSuccessRate) {
-        mTxSuccessRate = txSuccessRate;
+    public void setSuccessfulTxPacketsPerSecond(double successfulTxPacketsPerSecond) {
+        mSuccessfulTxPacketsPerSecond = successfulTxPacketsPerSecond;
     }
 
-    private double mRxSuccessRate;
+    private double mSuccessfulRxPacketsPerSecond;
 
     /**
      * Average rate of received unicast data packets, in units of packets per second.
      * @hide
      */
     @SystemApi
-    public double getRxSuccessRate() {
-        return mRxSuccessRate;
+    public double getSuccessfulRxPacketsPerSecond() {
+        return mSuccessfulRxPacketsPerSecond;
     }
 
     /** @hide */
-    public void setRxSuccessRate(double rxSuccessRate) {
-        mRxSuccessRate = rxSuccessRate;
+    public void setSuccessfulRxPacketsPerSecond(double successfulRxPacketsPerSecond) {
+        mSuccessfulRxPacketsPerSecond = successfulRxPacketsPerSecond;
     }
 
     /** @hide */
@@ -319,17 +319,17 @@
         setMeteredHint(false);
         setEphemeral(false);
         setOsuAp(false);
-        setAppPackageName(null);
+        setRequestingPackageName(null);
         setFQDN(null);
         setProviderFriendlyName(null);
         txBad = 0;
         txSuccess = 0;
         rxSuccess = 0;
         txRetries = 0;
-        mTxBadRate = 0;
-        mTxSuccessRate = 0;
-        mRxSuccessRate = 0;
-        mTxRetriesRate = 0;
+        mLostTxPacketsPerSecond = 0;
+        mSuccessfulTxPacketsPerSecond = 0;
+        mSuccessfulRxPacketsPerSecond = 0;
+        mTxRetriedTxPacketsPerSecond = 0;
         score = 0;
     }
 
@@ -353,8 +353,8 @@
             mMeteredHint = source.mMeteredHint;
             mEphemeral = source.mEphemeral;
             mTrusted = source.mTrusted;
-            mAppPackageName =
-                    source.mAppPackageName;
+            mRequestingPackageName =
+                    source.mRequestingPackageName;
             mOsuAp = source.mOsuAp;
             mFqdn = source.mFqdn;
             mProviderFriendlyName = source.mProviderFriendlyName;
@@ -362,10 +362,10 @@
             txRetries = source.txRetries;
             txSuccess = source.txSuccess;
             rxSuccess = source.rxSuccess;
-            mTxBadRate = source.mTxBadRate;
-            mTxRetriesRate = source.mTxRetriesRate;
-            mTxSuccessRate = source.mTxSuccessRate;
-            mRxSuccessRate = source.mRxSuccessRate;
+            mLostTxPacketsPerSecond = source.mLostTxPacketsPerSecond;
+            mTxRetriedTxPacketsPerSecond = source.mTxRetriedTxPacketsPerSecond;
+            mSuccessfulTxPacketsPerSecond = source.mSuccessfulTxPacketsPerSecond;
+            mSuccessfulRxPacketsPerSecond = source.mSuccessfulRxPacketsPerSecond;
             score = source.score;
             mWifiStandard = source.mWifiStandard;
             mMaxSupportedTxLinkSpeed = source.mMaxSupportedTxLinkSpeed;
@@ -777,8 +777,8 @@
     }
 
     /** {@hide} */
-    public void setAppPackageName(@Nullable String packageName) {
-        mAppPackageName = packageName;
+    public void setRequestingPackageName(@Nullable String packageName) {
+        mRequestingPackageName = packageName;
     }
 
     /**
@@ -788,8 +788,8 @@
      * @hide
      */
     @SystemApi
-    public @Nullable String getAppPackageName() {
-        return mAppPackageName;
+    public @Nullable String getRequestingPackageName() {
+        return mRequestingPackageName;
     }
 
 
@@ -956,16 +956,16 @@
         dest.writeInt(mTrusted ? 1 : 0);
         dest.writeInt(score);
         dest.writeLong(txSuccess);
-        dest.writeDouble(mTxSuccessRate);
+        dest.writeDouble(mSuccessfulTxPacketsPerSecond);
         dest.writeLong(txRetries);
-        dest.writeDouble(mTxRetriesRate);
+        dest.writeDouble(mTxRetriedTxPacketsPerSecond);
         dest.writeLong(txBad);
-        dest.writeDouble(mTxBadRate);
+        dest.writeDouble(mLostTxPacketsPerSecond);
         dest.writeLong(rxSuccess);
-        dest.writeDouble(mRxSuccessRate);
+        dest.writeDouble(mSuccessfulRxPacketsPerSecond);
         mSupplicantState.writeToParcel(dest, flags);
         dest.writeInt(mOsuAp ? 1 : 0);
-        dest.writeString(mAppPackageName);
+        dest.writeString(mRequestingPackageName);
         dest.writeString(mFqdn);
         dest.writeString(mProviderFriendlyName);
         dest.writeInt(mWifiStandard);
@@ -1000,16 +1000,16 @@
                 info.mTrusted = in.readInt() != 0;
                 info.score = in.readInt();
                 info.txSuccess = in.readLong();
-                info.mTxSuccessRate = in.readDouble();
+                info.mSuccessfulTxPacketsPerSecond = in.readDouble();
                 info.txRetries = in.readLong();
-                info.mTxRetriesRate = in.readDouble();
+                info.mTxRetriedTxPacketsPerSecond = in.readDouble();
                 info.txBad = in.readLong();
-                info.mTxBadRate = in.readDouble();
+                info.mLostTxPacketsPerSecond = in.readDouble();
                 info.rxSuccess = in.readLong();
-                info.mRxSuccessRate = in.readDouble();
+                info.mSuccessfulRxPacketsPerSecond = in.readDouble();
                 info.mSupplicantState = SupplicantState.CREATOR.createFromParcel(in);
                 info.mOsuAp = in.readInt() != 0;
-                info.mAppPackageName = in.readString();
+                info.mRequestingPackageName = in.readString();
                 info.mFqdn = in.readString();
                 info.mProviderFriendlyName = in.readString();
                 info.mWifiStandard = in.readInt();
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index fb3e794..c7475ee 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -4854,13 +4854,19 @@
     /**
      * Set Wi-Fi verbose logging level from developer settings.
      *
-     * @param verbose the verbose logging level to set. 0 will disable verbose logging, a positive
-     *                integer will enable verbose logging.
+     * @param enable true to enable verbose logging, false to disable.
      *
      * @hide
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+    public void setVerboseLoggingEnabled(boolean enable) {
+        enableVerboseLogging(enable ? 1 : 0);
+    }
+
+    /** @hide */
+    @UnsupportedAppUsage
+    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
     public void enableVerboseLogging (int verbose) {
         try {
             mService.enableVerboseLogging(verbose);
@@ -4871,15 +4877,23 @@
     }
 
     /**
-     * Get the persisted WiFi verbose logging level, set by {@link #enableVerboseLogging(int)}.
+     * Get the persisted Wi-Fi verbose logging level, set by
+     * {@link #setVerboseLoggingEnabled(boolean)}.
      * No permissions are required to call this method.
      *
-     * @return 0 to indicate that verbose logging is disabled, a positive integer to indicate that
-     * verbose logging is enabled.
+     * @return true to indicate that verbose logging is enabled, false to indicate that verbose
+     * logging is disabled.
      *
      * @hide
      */
     @SystemApi
+    public boolean isVerboseLoggingEnabled() {
+        return getVerboseLoggingLevel() > 0;
+    }
+
+    /** @hide */
+    // TODO(b/145484145): remove once SUW stops calling this via reflection
+    @UnsupportedAppUsage
     public int getVerboseLoggingLevel() {
         try {
             return mService.getVerboseLoggingLevel();
@@ -5204,7 +5218,7 @@
      * level from wifi service.
      */
     private void updateVerboseLoggingEnabledFromService() {
-        mVerboseLoggingEnabled = getVerboseLoggingLevel() > 0;
+        mVerboseLoggingEnabled = isVerboseLoggingEnabled();
     }
 
     /**
diff --git a/wifi/tests/README.md b/wifi/tests/README.md
index b0594f2..f909404 100644
--- a/wifi/tests/README.md
+++ b/wifi/tests/README.md
@@ -8,12 +8,9 @@
 The easiest way to run tests is simply run
 
 ```
-frameworks/base/wifi/tests/runtests.sh
+atest android.net.wifi
 ```
 
-`runtests.sh` will build the test project and all of its dependencies and push the APK to the
-connected device. It will then run the tests on the device.
-
 To pick up changes in framework/base, you will need to:
 1. rebuild the framework library 'make -j32'
 2. sync over the updated library to the device 'adb sync'
@@ -24,22 +21,6 @@
 2. adb reboot
 3. adb remount
 
-See below for a few example of options to limit which tests are run.
-See the
-[AndroidJUnitRunner Documentation](https://developer.android.com/reference/android/support/test/runner/AndroidJUnitRunner.html)
-for more details on the supported options.
-
-```
-runtests.sh -e package android.net.wifi
-runtests.sh -e class android.net.wifi.WifiScannerTest
-```
-
-If you manually build and push the test APK to the device you can run tests using
-
-```
-adb shell am instrument -w 'android.net.wifi.test/androidx.test.runner.AndroidJUnitRunner'
-```
-
 ## Adding Tests
 Tests can be added by adding classes to the src directory. JUnit4 style test cases can
 be written by simply annotating test methods with `org.junit.Test`.
diff --git a/wifi/tests/runtests.sh b/wifi/tests/runtests.sh
deleted file mode 100755
index 4024371..0000000
--- a/wifi/tests/runtests.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/usr/bin/env bash
-
-if [ -z $ANDROID_BUILD_TOP ]; then
-  echo "You need to source and lunch before you can use this script"
-  exit 1
-fi
-
-echo "Running tests"
-
-set -e # fail early
-
-echo "+ mmma -j32 $ANDROID_BUILD_TOP/frameworks/base/wifi/tests"
-# NOTE Don't actually run the command above since this shell doesn't inherit functions from the
-#      caller.
-$ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode MODULES-IN-frameworks-base-wifi-tests
-
-set -x # print commands
-
-adb wait-for-device
-
-TARGET_ARCH=$($ANDROID_BUILD_TOP/build/soong/soong_ui.bash --dumpvar-mode TARGET_ARCH)
-adb install -r -g "$OUT/testcases/FrameworksWifiApiTests/$TARGET_ARCH/FrameworksWifiApiTests.apk"
-
-adb shell am instrument --no-hidden-api-checks -w "$@" \
-  'android.net.wifi.test/androidx.test.runner.AndroidJUnitRunner'
diff --git a/wifi/tests/src/android/net/wifi/WifiInfoTest.java b/wifi/tests/src/android/net/wifi/WifiInfoTest.java
index 04759ac..311bbc4 100644
--- a/wifi/tests/src/android/net/wifi/WifiInfoTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiInfoTest.java
@@ -64,7 +64,7 @@
         writeWifiInfo.setOsuAp(true);
         writeWifiInfo.setFQDN(TEST_FQDN);
         writeWifiInfo.setProviderFriendlyName(TEST_PROVIDER_NAME);
-        writeWifiInfo.setAppPackageName(TEST_PACKAGE_NAME);
+        writeWifiInfo.setRequestingPackageName(TEST_PACKAGE_NAME);
         writeWifiInfo.setWifiStandard(TEST_WIFI_STANDARD);
         writeWifiInfo.setMaxSupportedTxLinkSpeedMbps(TEST_MAX_SUPPORTED_TX_LINK_SPEED_MBPS);
         writeWifiInfo.setMaxSupportedRxLinkSpeedMbps(TEST_MAX_SUPPORTED_RX_LINK_SPEED_MBPS);
@@ -83,7 +83,7 @@
         assertTrue(readWifiInfo.isTrusted());
         assertTrue(readWifiInfo.isOsuAp());
         assertTrue(readWifiInfo.isPasspointAp());
-        assertEquals(TEST_PACKAGE_NAME, readWifiInfo.getAppPackageName());
+        assertEquals(TEST_PACKAGE_NAME, readWifiInfo.getRequestingPackageName());
         assertEquals(TEST_FQDN, readWifiInfo.getPasspointFqdn());
         assertEquals(TEST_PROVIDER_NAME, readWifiInfo.getPasspointProviderFriendlyName());
         assertEquals(TEST_WIFI_STANDARD, readWifiInfo.getWifiStandard());