Merge changes from topic "cherrypick-nssnapshot_move-jqegvlbi07"

* changes:
  [automerged blank] [MS55.1] Move NetworkStateSnapshot into module folder 2p: d9101cda97
  [MS55.1] Move NetworkStateSnapshot into module folder
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index c706a3a..8237383 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -25,6 +25,7 @@
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.AlarmManager;
@@ -127,28 +128,47 @@
    <pre>
 
    digraph {
+     subgraph cluster_legend {
+       label="Legend"
+
+       wakeup_alarm [label="Entering this state requires a wakeup alarm",color=red,shape=box]
+       nonwakeup_alarm [
+         label="This state can be entered from a non-wakeup alarm",color=blue,shape=oval
+       ]
+       no_alarm [label="This state doesn't require an alarm",color=black,shape=diamond]
+     }
+
      subgraph deep {
        label="deep";
 
-       STATE_ACTIVE [label="STATE_ACTIVE\nScreen on OR Charging OR Alarm going off soon"]
-       STATE_INACTIVE [label="STATE_INACTIVE\nScreen off AND Not charging"]
+       STATE_ACTIVE [
+         label="STATE_ACTIVE\nScreen on OR Charging OR Alarm going off soon",
+         color=black,shape=diamond
+       ]
+       STATE_INACTIVE [
+         label="STATE_INACTIVE\nScreen off AND Not charging",color=black,shape=diamond
+       ]
        STATE_QUICK_DOZE_DELAY [
          label="STATE_QUICK_DOZE_DELAY\n"
              + "Screen off AND Not charging\n"
-             + "Location, motion detection, and significant motion monitoring turned off"
+             + "Location, motion detection, and significant motion monitoring turned off",
+         color=black,shape=diamond
        ]
        STATE_IDLE_PENDING [
-         label="STATE_IDLE_PENDING\nSignificant motion monitoring turned on"
+         label="STATE_IDLE_PENDING\nSignificant motion monitoring turned on",
+         color=red,shape=box
        ]
-       STATE_SENSING [label="STATE_SENSING\nMonitoring for ANY motion"]
+       STATE_SENSING [label="STATE_SENSING\nMonitoring for ANY motion",color=red,shape=box]
        STATE_LOCATING [
-         label="STATE_LOCATING\nRequesting location, motion monitoring still on"
+         label="STATE_LOCATING\nRequesting location, motion monitoring still on",
+         color=red,shape=box
        ]
        STATE_IDLE [
          label="STATE_IDLE\nLocation and motion detection turned off\n"
-             + "Significant motion monitoring state unchanged"
+             + "Significant motion monitoring state unchanged",
+         color=red,shape=box
        ]
-       STATE_IDLE_MAINTENANCE [label="STATE_IDLE_MAINTENANCE\n"]
+       STATE_IDLE_MAINTENANCE [label="STATE_IDLE_MAINTENANCE\n",color=red,shape=box]
 
        STATE_ACTIVE -> STATE_INACTIVE [
          label="becomeInactiveIfAppropriateLocked() AND Quick Doze not enabled"
@@ -213,19 +233,22 @@
        label="light"
 
        LIGHT_STATE_ACTIVE [
-         label="LIGHT_STATE_ACTIVE\nScreen on OR Charging OR Alarm going off soon"
+         label="LIGHT_STATE_ACTIVE\nScreen on OR Charging OR Alarm going off soon",
+         color=black,shape=diamond
        ]
-       LIGHT_STATE_INACTIVE [label="LIGHT_STATE_INACTIVE\nScreen off AND Not charging"]
-       LIGHT_STATE_PRE_IDLE [
-         label="LIGHT_STATE_PRE_IDLE\n"
-             + "Delay going into LIGHT_STATE_IDLE due to some running jobs or alarms"
+       LIGHT_STATE_INACTIVE [
+         label="LIGHT_STATE_INACTIVE\nScreen off AND Not charging",
+         color=black,shape=diamond
        ]
-       LIGHT_STATE_IDLE [label="LIGHT_STATE_IDLE\n"]
+       LIGHT_STATE_IDLE [label="LIGHT_STATE_IDLE\n",color=blue,shape=oval]
        LIGHT_STATE_WAITING_FOR_NETWORK [
          label="LIGHT_STATE_WAITING_FOR_NETWORK\n"
-             + "Coming out of LIGHT_STATE_IDLE, waiting for network"
+             + "Coming out of LIGHT_STATE_IDLE, waiting for network",
+         color=black,shape=diamond
        ]
-       LIGHT_STATE_IDLE_MAINTENANCE [label="LIGHT_STATE_IDLE_MAINTENANCE\n"]
+       LIGHT_STATE_IDLE_MAINTENANCE [
+         label="LIGHT_STATE_IDLE_MAINTENANCE\n",color=red,shape=box
+       ]
        LIGHT_STATE_OVERRIDE [
          label="LIGHT_STATE_OVERRIDE\nDevice in deep doze, light no longer changing states"
        ]
@@ -236,16 +259,9 @@
        LIGHT_STATE_ACTIVE -> LIGHT_STATE_OVERRIDE [label="deep goes to STATE_IDLE"]
 
        LIGHT_STATE_INACTIVE -> LIGHT_STATE_ACTIVE [label="becomeActiveLocked()"]
-       LIGHT_STATE_INACTIVE -> LIGHT_STATE_PRE_IDLE [label="active jobs"]
-       LIGHT_STATE_INACTIVE -> LIGHT_STATE_IDLE [label="no active jobs"]
+       LIGHT_STATE_INACTIVE -> LIGHT_STATE_IDLE [label="some time transpires"]
        LIGHT_STATE_INACTIVE -> LIGHT_STATE_OVERRIDE [label="deep goes to STATE_IDLE"]
 
-       LIGHT_STATE_PRE_IDLE -> LIGHT_STATE_ACTIVE [label="becomeActiveLocked()"]
-       LIGHT_STATE_PRE_IDLE -> LIGHT_STATE_IDLE [
-         label="stepLightIdleStateLocked(), exitMaintenanceEarlyIfNeededLocked()"
-       ]
-       LIGHT_STATE_PRE_IDLE -> LIGHT_STATE_OVERRIDE [label="deep goes to STATE_IDLE"]
-
        LIGHT_STATE_IDLE -> LIGHT_STATE_ACTIVE [label="becomeActiveLocked()"]
        LIGHT_STATE_IDLE -> LIGHT_STATE_WAITING_FOR_NETWORK [label="no network"]
        LIGHT_STATE_IDLE -> LIGHT_STATE_IDLE_MAINTENANCE
@@ -421,9 +437,6 @@
     /** Device is inactive (screen off) and we are waiting to for the first light idle. */
     @VisibleForTesting
     static final int LIGHT_STATE_INACTIVE = 1;
-    /** Device is about to go idle for the first time, wait for current work to complete. */
-    @VisibleForTesting
-    static final int LIGHT_STATE_PRE_IDLE = 3;
     /** Device is in the light idle state, trying to stay asleep as much as possible. */
     @VisibleForTesting
     static final int LIGHT_STATE_IDLE = 4;
@@ -434,7 +447,7 @@
     /** Device is in the light idle state, but temporarily out of idle to do regular maintenance. */
     @VisibleForTesting
     static final int LIGHT_STATE_IDLE_MAINTENANCE = 6;
-    /** Device light idle state is overriden, now applying deep doze state. */
+    /** Device light idle state is overridden, now applying deep doze state. */
     @VisibleForTesting
     static final int LIGHT_STATE_OVERRIDE = 7;
 
@@ -443,7 +456,6 @@
         switch (state) {
             case LIGHT_STATE_ACTIVE: return "ACTIVE";
             case LIGHT_STATE_INACTIVE: return "INACTIVE";
-            case LIGHT_STATE_PRE_IDLE: return "PRE_IDLE";
             case LIGHT_STATE_IDLE: return "IDLE";
             case LIGHT_STATE_WAITING_FOR_NETWORK: return "WAITING_FOR_NETWORK";
             case LIGHT_STATE_IDLE_MAINTENANCE: return "IDLE_MAINTENANCE";
@@ -468,10 +480,10 @@
     @GuardedBy("this")
     private long mNextLightIdleDelay;
     @GuardedBy("this")
-    private long mNextLightIdleDelayFlex;
-    @GuardedBy("this")
     private long mNextLightAlarmTime;
     @GuardedBy("this")
+    private long mNextLightMaintenanceAlarmTime;
+    @GuardedBy("this")
     private long mNextSensingTimeoutAlarmTime;
 
     /** How long a light idle maintenance window should last. */
@@ -658,13 +670,21 @@
         }
     };
 
-    private final AlarmManager.OnAlarmListener mLightAlarmListener
-            = new AlarmManager.OnAlarmListener() {
-        @Override
-        public void onAlarm() {
-            synchronized (DeviceIdleController.this) {
-                stepLightIdleStateLocked("s:alarm");
-            }
+    private final AlarmManager.OnAlarmListener mLightAlarmListener = () -> {
+        if (DEBUG) {
+            Slog.d(TAG, "Light progression alarm fired");
+        }
+        synchronized (DeviceIdleController.this) {
+            stepLightIdleStateLocked("s:alarm");
+        }
+    };
+
+    private final AlarmManager.OnAlarmListener mLightMaintenanceAlarmListener = () -> {
+        if (DEBUG) {
+            Slog.d(TAG, "Light maintenance alarm fired");
+        }
+        synchronized (DeviceIdleController.this) {
+            stepLightIdleStateLocked("s:alarm");
         }
     };
 
@@ -928,11 +948,7 @@
         private static final String KEY_FLEX_TIME_SHORT = "flex_time_short";
         private static final String KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT =
                 "light_after_inactive_to";
-        private static final String KEY_LIGHT_PRE_IDLE_TIMEOUT = "light_pre_idle_to";
         private static final String KEY_LIGHT_IDLE_TIMEOUT = "light_idle_to";
-        private static final String KEY_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX =
-                "light_idle_to_initial_flex";
-        private static final String KEY_LIGHT_MAX_IDLE_TIMEOUT_FLEX = "light_max_idle_to_flex";
         private static final String KEY_LIGHT_IDLE_FACTOR = "light_idle_factor";
         private static final String KEY_LIGHT_MAX_IDLE_TIMEOUT = "light_max_idle_to";
         private static final String KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET =
@@ -978,15 +994,9 @@
         private static final long DEFAULT_FLEX_TIME_SHORT =
                 !COMPRESS_TIME ? 60 * 1000L : 5 * 1000L;
         private static final long DEFAULT_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT =
-                !COMPRESS_TIME ? 60 * 1000L : 15 * 1000L;
-        private static final long DEFAULT_LIGHT_PRE_IDLE_TIMEOUT =
-                !COMPRESS_TIME ? 3 * 60 * 1000L : 30 * 1000L;
+                !COMPRESS_TIME ? 4 * 60 * 1000L : 30 * 1000L;
         private static final long DEFAULT_LIGHT_IDLE_TIMEOUT =
                 !COMPRESS_TIME ? 5 * 60 * 1000L : 15 * 1000L;
-        private static final long DEFAULT_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX =
-                !COMPRESS_TIME ? 60 * 1000L : 5 * 1000L;
-        private static final long DEFAULT_LIGHT_MAX_IDLE_TIMEOUT_FLEX =
-                !COMPRESS_TIME ? 15 * 60 * 1000L : 60 * 1000L;
         private static final float DEFAULT_LIGHT_IDLE_FACTOR = 2f;
         private static final long DEFAULT_LIGHT_MAX_IDLE_TIMEOUT =
                 !COMPRESS_TIME ? 15 * 60 * 1000L : 60 * 1000L;
@@ -1054,15 +1064,6 @@
         public long LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT = DEFAULT_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT;
 
         /**
-         * This is amount of time we will wait from the point where we decide we would
-         * like to go idle until we actually do, while waiting for jobs and other current
-         * activity to finish.
-         *
-         * @see #KEY_LIGHT_PRE_IDLE_TIMEOUT
-         */
-        public long LIGHT_PRE_IDLE_TIMEOUT = DEFAULT_LIGHT_PRE_IDLE_TIMEOUT;
-
-        /**
          * This is the initial time that we will run in light idle maintenance mode.
          *
          * @see #KEY_LIGHT_IDLE_TIMEOUT
@@ -1070,21 +1071,6 @@
         public long LIGHT_IDLE_TIMEOUT = DEFAULT_LIGHT_IDLE_TIMEOUT;
 
         /**
-         * This is the initial alarm window size that we will tolerate for light idle maintenance
-         * timing.
-         *
-         * @see #KEY_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX
-         */
-        public long LIGHT_IDLE_TIMEOUT_INITIAL_FLEX = DEFAULT_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX;
-
-        /**
-         * This is the maximum value that {@link #LIGHT_IDLE_TIMEOUT_INITIAL_FLEX} should take.
-         *
-         * @see #KEY_LIGHT_MAX_IDLE_TIMEOUT_FLEX
-         */
-        public long LIGHT_MAX_IDLE_TIMEOUT_FLEX = DEFAULT_LIGHT_MAX_IDLE_TIMEOUT_FLEX;
-
-        /**
          * Scaling factor to apply to the light idle mode time each time we complete a cycle.
          *
          * @see #KEY_LIGHT_IDLE_FACTOR
@@ -1327,24 +1313,10 @@
                                     KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT,
                                     DEFAULT_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT);
                             break;
-                        case KEY_LIGHT_PRE_IDLE_TIMEOUT:
-                            LIGHT_PRE_IDLE_TIMEOUT = properties.getLong(
-                                    KEY_LIGHT_PRE_IDLE_TIMEOUT, DEFAULT_LIGHT_PRE_IDLE_TIMEOUT);
-                            break;
                         case KEY_LIGHT_IDLE_TIMEOUT:
                             LIGHT_IDLE_TIMEOUT = properties.getLong(
                                     KEY_LIGHT_IDLE_TIMEOUT, DEFAULT_LIGHT_IDLE_TIMEOUT);
                             break;
-                        case KEY_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX:
-                            LIGHT_IDLE_TIMEOUT_INITIAL_FLEX = properties.getLong(
-                                    KEY_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX,
-                                    DEFAULT_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX);
-                            break;
-                        case KEY_LIGHT_MAX_IDLE_TIMEOUT_FLEX:
-                            LIGHT_MAX_IDLE_TIMEOUT_FLEX = properties.getLong(
-                                    KEY_LIGHT_MAX_IDLE_TIMEOUT_FLEX,
-                                    DEFAULT_LIGHT_MAX_IDLE_TIMEOUT_FLEX);
-                            break;
                         case KEY_LIGHT_IDLE_FACTOR:
                             LIGHT_IDLE_FACTOR = Math.max(1, properties.getFloat(
                                     KEY_LIGHT_IDLE_FACTOR, DEFAULT_LIGHT_IDLE_FACTOR));
@@ -1497,22 +1469,10 @@
             TimeUtils.formatDuration(LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT, pw);
             pw.println();
 
-            pw.print("    "); pw.print(KEY_LIGHT_PRE_IDLE_TIMEOUT); pw.print("=");
-            TimeUtils.formatDuration(LIGHT_PRE_IDLE_TIMEOUT, pw);
-            pw.println();
-
             pw.print("    "); pw.print(KEY_LIGHT_IDLE_TIMEOUT); pw.print("=");
             TimeUtils.formatDuration(LIGHT_IDLE_TIMEOUT, pw);
             pw.println();
 
-            pw.print("    "); pw.print(KEY_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX); pw.print("=");
-            TimeUtils.formatDuration(LIGHT_IDLE_TIMEOUT_INITIAL_FLEX, pw);
-            pw.println();
-
-            pw.print("    "); pw.print(KEY_LIGHT_MAX_IDLE_TIMEOUT_FLEX); pw.print("=");
-            TimeUtils.formatDuration(LIGHT_MAX_IDLE_TIMEOUT_FLEX, pw);
-            pw.println();
-
             pw.print("    "); pw.print(KEY_LIGHT_IDLE_FACTOR); pw.print("=");
             pw.print(LIGHT_IDLE_FACTOR);
             pw.println();
@@ -3088,7 +3048,7 @@
             if (conn != mNetworkConnected) {
                 mNetworkConnected = conn;
                 if (conn && mLightState == LIGHT_STATE_WAITING_FOR_NETWORK) {
-                    stepLightIdleStateLocked("network");
+                    stepLightIdleStateLocked("network", /* forceProgression */ true);
                 }
             }
         }
@@ -3343,7 +3303,11 @@
             if (DEBUG) Slog.d(TAG, "Moved from LIGHT_STATE_ACTIVE to LIGHT_STATE_INACTIVE");
             resetLightIdleManagementLocked();
             scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT,
-                    mConstants.FLEX_TIME_SHORT, true);
+                    mConstants.FLEX_TIME_SHORT);
+            // After moving in INACTIVE, the maintenance window should start the time inactive
+            // timeout and a single light idle period.
+            scheduleLightMaintenanceAlarmLocked(
+                    mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT + mConstants.LIGHT_IDLE_TIMEOUT);
             EventLogTags.writeDeviceIdleLight(mLightState, "no activity");
         }
     }
@@ -3364,9 +3328,9 @@
 
     @GuardedBy("this")
     private void resetLightIdleManagementLocked() {
-        mNextLightIdleDelay = 0;
-        mNextLightIdleDelayFlex = 0;
-        mCurLightIdleBudget = 0;
+        mNextLightIdleDelay = mConstants.LIGHT_IDLE_TIMEOUT;
+        mMaintenanceStartTime = 0;
+        mCurLightIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
         cancelLightAlarmLocked();
     }
 
@@ -3401,90 +3365,115 @@
     }
 
     @GuardedBy("this")
-    void stepLightIdleStateLocked(String reason) {
-        if (mLightState == LIGHT_STATE_OVERRIDE) {
+    private void stepLightIdleStateLocked(String reason) {
+        stepLightIdleStateLocked(reason, false);
+    }
+
+    @GuardedBy("this")
+    @VisibleForTesting
+    @SuppressLint("WakelockTimeout")
+    void stepLightIdleStateLocked(String reason, boolean forceProgression) {
+        if (mLightState == LIGHT_STATE_ACTIVE || mLightState == LIGHT_STATE_OVERRIDE) {
             // If we are already in deep device idle mode, then
             // there is nothing left to do for light mode.
             return;
         }
 
-        if (DEBUG) Slog.d(TAG, "stepLightIdleStateLocked: mLightState=" + mLightState);
+        if (DEBUG) {
+            Slog.d(TAG, "stepLightIdleStateLocked: mLightState=" + lightStateToString(mLightState)
+                    + " force=" + forceProgression);
+        }
         EventLogTags.writeDeviceIdleLightStep();
 
-        switch (mLightState) {
-            case LIGHT_STATE_INACTIVE:
-                mCurLightIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
-                // Reset the upcoming idle delays.
-                mNextLightIdleDelay = mConstants.LIGHT_IDLE_TIMEOUT;
-                mNextLightIdleDelayFlex = mConstants.LIGHT_IDLE_TIMEOUT_INITIAL_FLEX;
-                mMaintenanceStartTime = 0;
-                if (!isOpsInactiveLocked()) {
-                    // We have some active ops going on...  give them a chance to finish
-                    // before going in to our first idle.
-                    mLightState = LIGHT_STATE_PRE_IDLE;
-                    EventLogTags.writeDeviceIdleLight(mLightState, reason);
-                    scheduleLightAlarmLocked(mConstants.LIGHT_PRE_IDLE_TIMEOUT,
-                            mConstants.FLEX_TIME_SHORT, true);
-                    break;
+        final long nowElapsed = mInjector.getElapsedRealtime();
+        final boolean crossedMaintenanceTime =
+                mNextLightMaintenanceAlarmTime > 0 && nowElapsed >= mNextLightMaintenanceAlarmTime;
+        final boolean crossedProgressionTime =
+                mNextLightAlarmTime > 0 && nowElapsed >= mNextLightAlarmTime;
+        final boolean enterMaintenance;
+        if (crossedMaintenanceTime) {
+            if (crossedProgressionTime) {
+                enterMaintenance = (mNextLightAlarmTime <= mNextLightMaintenanceAlarmTime);
+            } else {
+                enterMaintenance = true;
+            }
+        } else if (crossedProgressionTime) {
+            enterMaintenance = false;
+        } else if (forceProgression) {
+            // This will happen for adb commands, unit tests,
+            // and when we're in WAITING_FOR_NETWORK and the network connects.
+            enterMaintenance =
+                    mLightState == LIGHT_STATE_IDLE
+                            || mLightState == LIGHT_STATE_WAITING_FOR_NETWORK;
+        } else {
+            Slog.wtfStack(TAG, "stepLightIdleStateLocked called in invalid state");
+            return;
+        }
+
+        if (enterMaintenance) {
+            if (mNetworkConnected || mLightState == LIGHT_STATE_WAITING_FOR_NETWORK) {
+                // We have been idling long enough, now it is time to do some work.
+                mActiveIdleOpCount = 1;
+                mActiveIdleWakeLock.acquire();
+                mMaintenanceStartTime = SystemClock.elapsedRealtime();
+                if (mCurLightIdleBudget < mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET) {
+                    mCurLightIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
+                } else if (mCurLightIdleBudget > mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET) {
+                    mCurLightIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET;
                 }
-                // Nothing active, fall through to immediately idle.
-            case LIGHT_STATE_PRE_IDLE:
-            case LIGHT_STATE_IDLE_MAINTENANCE:
-                if (mMaintenanceStartTime != 0) {
-                    long duration = SystemClock.elapsedRealtime() - mMaintenanceStartTime;
-                    if (duration < mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET) {
-                        // We didn't use up all of our minimum budget; add this to the reserve.
-                        mCurLightIdleBudget +=
-                                (mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET - duration);
-                    } else {
-                        // We used more than our minimum budget; this comes out of the reserve.
-                        mCurLightIdleBudget -=
-                                (duration - mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET);
-                    }
-                }
-                mMaintenanceStartTime = 0;
-                scheduleLightAlarmLocked(mNextLightIdleDelay, mNextLightIdleDelayFlex, false);
                 mNextLightIdleDelay = Math.min(mConstants.LIGHT_MAX_IDLE_TIMEOUT,
                         (long) (mNextLightIdleDelay * mConstants.LIGHT_IDLE_FACTOR));
-                mNextLightIdleDelayFlex = Math.min(mConstants.LIGHT_MAX_IDLE_TIMEOUT_FLEX,
-                        (long) (mNextLightIdleDelayFlex * mConstants.LIGHT_IDLE_FACTOR));
-                if (DEBUG) Slog.d(TAG, "Moved to LIGHT_STATE_IDLE.");
-                mLightState = LIGHT_STATE_IDLE;
-                EventLogTags.writeDeviceIdleLight(mLightState, reason);
-                addEvent(EVENT_LIGHT_IDLE, null);
-                mGoingIdleWakeLock.acquire();
-                mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON_LIGHT);
-                break;
-            case LIGHT_STATE_IDLE:
-            case LIGHT_STATE_WAITING_FOR_NETWORK:
-                if (mNetworkConnected || mLightState == LIGHT_STATE_WAITING_FOR_NETWORK) {
-                    // We have been idling long enough, now it is time to do some work.
-                    mActiveIdleOpCount = 1;
-                    mActiveIdleWakeLock.acquire();
-                    mMaintenanceStartTime = SystemClock.elapsedRealtime();
-                    if (mCurLightIdleBudget < mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET) {
-                        mCurLightIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
-                    } else if (mCurLightIdleBudget > mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET) {
-                        mCurLightIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET;
-                    }
-                    scheduleLightAlarmLocked(mCurLightIdleBudget, mConstants.FLEX_TIME_SHORT, true);
-                    if (DEBUG) Slog.d(TAG,
-                            "Moved from LIGHT_STATE_IDLE to LIGHT_STATE_IDLE_MAINTENANCE.");
-                    mLightState = LIGHT_STATE_IDLE_MAINTENANCE;
-                    EventLogTags.writeDeviceIdleLight(mLightState, reason);
-                    addEvent(EVENT_LIGHT_MAINTENANCE, null);
-                    mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
-                } else {
-                    // We'd like to do maintenance, but currently don't have network
-                    // connectivity...  let's try to wait until the network comes back.
-                    // We'll only wait for another full idle period, however, and then give up.
-                    scheduleLightAlarmLocked(mNextLightIdleDelay,
-                            mNextLightIdleDelayFlex / 2, true);
-                    if (DEBUG) Slog.d(TAG, "Moved to LIGHT_WAITING_FOR_NETWORK.");
-                    mLightState = LIGHT_STATE_WAITING_FOR_NETWORK;
-                    EventLogTags.writeDeviceIdleLight(mLightState, reason);
+                // We're entering MAINTENANCE. It should end curLightIdleBudget time from now.
+                // The next maintenance window should be curLightIdleBudget + nextLightIdleDelay
+                // time from now.
+                scheduleLightAlarmLocked(mCurLightIdleBudget, mConstants.FLEX_TIME_SHORT);
+                scheduleLightMaintenanceAlarmLocked(mCurLightIdleBudget + mNextLightIdleDelay);
+                if (DEBUG) {
+                    Slog.d(TAG, "Moved from " + lightStateToString(mLightState)
+                            + " to LIGHT_STATE_IDLE_MAINTENANCE");
                 }
-                break;
+                mLightState = LIGHT_STATE_IDLE_MAINTENANCE;
+                EventLogTags.writeDeviceIdleLight(mLightState, reason);
+                addEvent(EVENT_LIGHT_MAINTENANCE, null);
+                mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
+            } else {
+                // We'd like to do maintenance, but currently don't have network
+                // connectivity...  let's try to wait until the network comes back.
+                // We'll only wait for another full idle period, however, and then give up.
+                scheduleLightMaintenanceAlarmLocked(mNextLightIdleDelay);
+                mNextLightAlarmTime = 0;
+                if (DEBUG) Slog.d(TAG, "Moved to LIGHT_WAITING_FOR_NETWORK.");
+                mLightState = LIGHT_STATE_WAITING_FOR_NETWORK;
+                EventLogTags.writeDeviceIdleLight(mLightState, reason);
+            }
+        } else {
+            if (mMaintenanceStartTime != 0) {
+                // Cap duration at budget since the non-wakeup alarm to exit maintenance may
+                // not fire at the exact intended time, but once the system is up, we will stop
+                // more ongoing work.
+                long duration = Math.min(mCurLightIdleBudget,
+                        SystemClock.elapsedRealtime() - mMaintenanceStartTime);
+                if (duration < mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET) {
+                    // We didn't use up all of our minimum budget; add this to the reserve.
+                    mCurLightIdleBudget +=
+                            (mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET - duration);
+                } else {
+                    // We used more than our minimum budget; this comes out of the reserve.
+                    mCurLightIdleBudget -=
+                            (duration - mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET);
+                }
+            }
+            mMaintenanceStartTime = 0;
+            // We're entering IDLE. We may have used less than curLightIdleBudget for the
+            // maintenance window, so reschedule the alarm starting from now.
+            scheduleLightMaintenanceAlarmLocked(mNextLightIdleDelay);
+            mNextLightAlarmTime = 0;
+            if (DEBUG) Slog.d(TAG, "Moved to LIGHT_STATE_IDLE.");
+            mLightState = LIGHT_STATE_IDLE;
+            EventLogTags.writeDeviceIdleLight(mLightState, reason);
+            addEvent(EVENT_LIGHT_IDLE, null);
+            mGoingIdleWakeLock.acquire();
+            mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON_LIGHT);
         }
     }
 
@@ -3839,8 +3828,7 @@
 
     @GuardedBy("this")
     void exitMaintenanceEarlyIfNeededLocked() {
-        if (mState == STATE_IDLE_MAINTENANCE || mLightState == LIGHT_STATE_IDLE_MAINTENANCE
-                || mLightState == LIGHT_STATE_PRE_IDLE) {
+        if (mState == STATE_IDLE_MAINTENANCE || mLightState == LIGHT_STATE_IDLE_MAINTENANCE) {
             if (isOpsInactiveLocked()) {
                 final long now = SystemClock.elapsedRealtime();
                 if (DEBUG) {
@@ -3853,10 +3841,8 @@
                 }
                 if (mState == STATE_IDLE_MAINTENANCE) {
                     stepIdleStateLocked("s:early");
-                } else if (mLightState == LIGHT_STATE_PRE_IDLE) {
-                    stepLightIdleStateLocked("s:predone");
                 } else {
-                    stepLightIdleStateLocked("s:early");
+                    stepLightIdleStateLocked("s:early", /* forceProgression */ true);
                 }
             }
         }
@@ -3969,6 +3955,10 @@
             mNextLightAlarmTime = 0;
             mAlarmManager.cancel(mLightAlarmListener);
         }
+        if (mNextLightMaintenanceAlarmTime != 0) {
+            mNextLightMaintenanceAlarmTime = 0;
+            mAlarmManager.cancel(mLightMaintenanceAlarmListener);
+        }
     }
 
     @GuardedBy("this")
@@ -4035,26 +4025,54 @@
     }
 
     @GuardedBy("this")
-    void scheduleLightAlarmLocked(long delay, long flex, boolean wakeup) {
+    @VisibleForTesting
+    void scheduleLightAlarmLocked(long delay, long flex) {
         if (DEBUG) {
             Slog.d(TAG, "scheduleLightAlarmLocked(" + delay
                     + (mConstants.USE_WINDOW_ALARMS ? "/" + flex : "")
-                    + ", wakeup=" + wakeup + ")");
+                    + ")");
         }
-        mNextLightAlarmTime = SystemClock.elapsedRealtime() + delay;
+        mNextLightAlarmTime = mInjector.getElapsedRealtime() + delay;
         if (mConstants.USE_WINDOW_ALARMS) {
             mAlarmManager.setWindow(
-                    wakeup ? AlarmManager.ELAPSED_REALTIME_WAKEUP : AlarmManager.ELAPSED_REALTIME,
+                    AlarmManager.ELAPSED_REALTIME,
                     mNextLightAlarmTime, flex,
                     "DeviceIdleController.light", mLightAlarmListener, mHandler);
         } else {
             mAlarmManager.set(
-                    wakeup ? AlarmManager.ELAPSED_REALTIME_WAKEUP : AlarmManager.ELAPSED_REALTIME,
+                    AlarmManager.ELAPSED_REALTIME,
                     mNextLightAlarmTime,
                     "DeviceIdleController.light", mLightAlarmListener, mHandler);
         }
     }
 
+    @GuardedBy("this")
+    @VisibleForTesting
+    void scheduleLightMaintenanceAlarmLocked(long delay) {
+        if (DEBUG) {
+            Slog.d(TAG, "scheduleLightMaintenanceAlarmLocked(" + delay + ")");
+        }
+        mNextLightMaintenanceAlarmTime = mInjector.getElapsedRealtime() + delay;
+        mAlarmManager.setWindow(
+                AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                mNextLightMaintenanceAlarmTime, mConstants.FLEX_TIME_SHORT,
+                "DeviceIdleController.light", mLightMaintenanceAlarmListener, mHandler);
+    }
+
+    @VisibleForTesting
+    long getNextLightAlarmTimeForTesting() {
+        synchronized (this) {
+            return mNextLightAlarmTime;
+        }
+    }
+
+    @VisibleForTesting
+    long getNextLightMaintenanceAlarmTimeForTesting() {
+        synchronized (this) {
+            return mNextLightMaintenanceAlarmTime;
+        }
+    }
+
     private void scheduleMotionRegistrationAlarmLocked() {
         if (DEBUG) Slog.d(TAG, "scheduleMotionRegistrationAlarmLocked");
         long nextMotionRegistrationAlarmTime =
@@ -4424,7 +4442,7 @@
                         pw.print("Stepped to deep: ");
                         pw.println(stateToString(mState));
                     } else if ("light".equals(arg)) {
-                        stepLightIdleStateLocked("s:shell");
+                        stepLightIdleStateLocked("s:shell", /* forceProgression */ true);
                         pw.print("Stepped to light: "); pw.println(lightStateToString(mLightState));
                     } else {
                         pw.println("Unknown idle mode: " + arg);
@@ -4464,7 +4482,7 @@
                         becomeInactiveIfAppropriateLocked();
                         int curLightState = mLightState;
                         while (curLightState != LIGHT_STATE_IDLE) {
-                            stepLightIdleStateLocked("s:shell");
+                            stepLightIdleStateLocked("s:shell", /* forceProgression */ true);
                             if (curLightState == mLightState) {
                                 pw.print("Unable to go light idle; stopped at ");
                                 pw.println(lightStateToString(mLightState));
@@ -5076,19 +5094,19 @@
             if (mNextLightIdleDelay != 0) {
                 pw.print("  mNextLightIdleDelay=");
                 TimeUtils.formatDuration(mNextLightIdleDelay, pw);
-                if (mConstants.USE_WINDOW_ALARMS) {
-                    pw.print(" (flex=");
-                    TimeUtils.formatDuration(mNextLightIdleDelayFlex, pw);
-                    pw.println(")");
-                } else {
-                    pw.println();
-                }
+                pw.println();
             }
             if (mNextLightAlarmTime != 0) {
                 pw.print("  mNextLightAlarmTime=");
                 TimeUtils.formatDuration(mNextLightAlarmTime, SystemClock.elapsedRealtime(), pw);
                 pw.println();
             }
+            if (mNextLightMaintenanceAlarmTime != 0) {
+                pw.print("  mNextLightMaintenanceAlarmTime=");
+                TimeUtils.formatDuration(
+                        mNextLightMaintenanceAlarmTime, SystemClock.elapsedRealtime(), pw);
+                pw.println();
+            }
             if (mCurLightIdleBudget != 0) {
                 pw.print("  mCurLightIdleBudget=");
                 TimeUtils.formatDuration(mCurLightIdleBudget, pw);
diff --git a/core/api/current.txt b/core/api/current.txt
index 8a54759..08387fc 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -111,6 +111,7 @@
     field public static final String MANAGE_MEDIA = "android.permission.MANAGE_MEDIA";
     field public static final String MANAGE_ONGOING_CALLS = "android.permission.MANAGE_ONGOING_CALLS";
     field public static final String MANAGE_OWN_CALLS = "android.permission.MANAGE_OWN_CALLS";
+    field public static final String MANAGE_WIFI_AUTO_JOIN = "android.permission.MANAGE_WIFI_AUTO_JOIN";
     field public static final String MASTER_CLEAR = "android.permission.MASTER_CLEAR";
     field public static final String MEDIA_CONTENT_CONTROL = "android.permission.MEDIA_CONTENT_CONTROL";
     field public static final String MODIFY_AUDIO_SETTINGS = "android.permission.MODIFY_AUDIO_SETTINGS";
@@ -121,6 +122,7 @@
     field public static final String NFC = "android.permission.NFC";
     field public static final String NFC_PREFERRED_PAYMENT_INFO = "android.permission.NFC_PREFERRED_PAYMENT_INFO";
     field public static final String NFC_TRANSACTION_EVENT = "android.permission.NFC_TRANSACTION_EVENT";
+    field public static final String OVERRIDE_WIFI_CONFIG = "android.permission.OVERRIDE_WIFI_CONFIG";
     field public static final String PACKAGE_USAGE_STATS = "android.permission.PACKAGE_USAGE_STATS";
     field @Deprecated public static final String PERSISTENT_ACTIVITY = "android.permission.PERSISTENT_ACTIVITY";
     field public static final String POST_NOTIFICATIONS = "android.permission.POST_NOTIFICATIONS";
@@ -3061,6 +3063,7 @@
     method @NonNull public final android.accessibilityservice.AccessibilityButtonController getAccessibilityButtonController();
     method @NonNull public final android.accessibilityservice.AccessibilityButtonController getAccessibilityButtonController(int);
     method @NonNull @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public final android.accessibilityservice.FingerprintGestureController getFingerprintGestureController();
+    method @Nullable public final android.accessibilityservice.InputMethod getInputMethod();
     method @NonNull public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
     method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
     method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
@@ -3073,6 +3076,7 @@
     method public boolean isNodeInCache(@NonNull android.view.accessibility.AccessibilityNodeInfo);
     method public abstract void onAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
     method public final android.os.IBinder onBind(android.content.Intent);
+    method @NonNull public android.accessibilityservice.InputMethod onCreateInputMethod();
     method @Deprecated protected boolean onGesture(int);
     method public boolean onGesture(@NonNull android.accessibilityservice.AccessibilityGestureEvent);
     method public abstract void onInterrupt();
@@ -3260,6 +3264,7 @@
     field public static final int FEEDBACK_VISUAL = 8; // 0x8
     field public static final int FLAG_ENABLE_ACCESSIBILITY_VOLUME = 128; // 0x80
     field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
+    field public static final int FLAG_INPUT_METHOD_EDITOR = 32768; // 0x8000
     field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
     field public static final int FLAG_REQUEST_2_FINGER_PASSTHROUGH = 8192; // 0x2000
     field public static final int FLAG_REQUEST_ACCESSIBILITY_BUTTON = 256; // 0x100
@@ -3320,6 +3325,28 @@
     method public boolean willContinue();
   }
 
+  public class InputMethod {
+    ctor protected InputMethod(@NonNull android.accessibilityservice.AccessibilityService);
+    method @Nullable public final android.accessibilityservice.InputMethod.AccessibilityInputConnection getCurrentInputConnection();
+    method @Nullable public final android.view.inputmethod.EditorInfo getCurrentInputEditorInfo();
+    method public final boolean getCurrentInputStarted();
+    method public void onFinishInput();
+    method public void onStartInput(@NonNull android.view.inputmethod.EditorInfo, boolean);
+    method public void onUpdateSelection(int, int, int, int, int, int);
+  }
+
+  public final class InputMethod.AccessibilityInputConnection {
+    method public void clearMetaKeyStates(int);
+    method public void commitText(@NonNull CharSequence, int, @Nullable android.view.inputmethod.TextAttribute);
+    method public void deleteSurroundingText(int, int);
+    method public int getCursorCapsMode(int);
+    method @Nullable public android.view.inputmethod.SurroundingText getSurroundingText(@IntRange(from=0) int, @IntRange(from=0) int, int);
+    method public void performContextMenuAction(int);
+    method public void performEditorAction(int);
+    method public void sendKeyEvent(@NonNull android.view.KeyEvent);
+    method public void setSelection(int, int);
+  }
+
   public final class MagnificationConfig implements android.os.Parcelable {
     method public int describeContents();
     method public float getCenterX();
@@ -4243,6 +4270,7 @@
     method @Deprecated public final void setProgressBarIndeterminate(boolean);
     method @Deprecated public final void setProgressBarIndeterminateVisibility(boolean);
     method @Deprecated public final void setProgressBarVisibility(boolean);
+    method public void setRecentsScreenshotEnabled(boolean);
     method public void setRequestedOrientation(int);
     method public final void setResult(int);
     method public final void setResult(int, android.content.Intent);
@@ -7334,6 +7362,7 @@
     method public int getCurrentFailedPasswordAttempts();
     method @Nullable public java.util.List<java.lang.String> getDelegatePackages(@NonNull android.content.ComponentName, @NonNull String);
     method @NonNull public java.util.List<java.lang.String> getDelegatedScopes(@Nullable android.content.ComponentName, @NonNull String);
+    method @Nullable public String getDeviceManagerRoleHolderPackageName();
     method public CharSequence getDeviceOwnerLockScreenInfo();
     method @Nullable public android.graphics.drawable.Drawable getDrawable(@NonNull String, @NonNull String, @NonNull java.util.concurrent.Callable<android.graphics.drawable.Drawable>);
     method @Nullable public android.graphics.drawable.Drawable getDrawable(@NonNull String, @NonNull String, @NonNull String, @NonNull java.util.concurrent.Callable<android.graphics.drawable.Drawable>);
@@ -7629,6 +7658,7 @@
     field public static final String EXTRA_PROVISIONING_MODE = "android.app.extra.PROVISIONING_MODE";
     field public static final String EXTRA_PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT = "android.app.extra.PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT";
     field public static final String EXTRA_PROVISIONING_SERIAL_NUMBER = "android.app.extra.PROVISIONING_SERIAL_NUMBER";
+    field public static final String EXTRA_PROVISIONING_SHOULD_LAUNCH_RESULT_INTENT = "android.app.extra.PROVISIONING_SHOULD_LAUNCH_RESULT_INTENT";
     field public static final String EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS = "android.app.extra.PROVISIONING_SKIP_EDUCATION_SCREENS";
     field public static final String EXTRA_PROVISIONING_SKIP_ENCRYPTION = "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
     field @Deprecated public static final String EXTRA_PROVISIONING_SKIP_USER_CONSENT = "android.app.extra.PROVISIONING_SKIP_USER_CONSENT";
@@ -7651,6 +7681,7 @@
     field public static final String EXTRA_RESOURCE_ID = "android.app.extra.RESOURCE_ID";
     field public static final String EXTRA_RESOURCE_TYPE_DRAWABLE = "android.app.extra.RESOURCE_TYPE_DRAWABLE";
     field public static final String EXTRA_RESOURCE_TYPE_STRING = "android.app.extra.RESOURCE_TYPE_STRING";
+    field public static final String EXTRA_RESULT_LAUNCH_INTENT = "android.app.extra.RESULT_LAUNCH_INTENT";
     field public static final int FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY = 1; // 0x1
     field public static final int FLAG_MANAGED_CAN_ACCESS_PARENT = 2; // 0x2
     field public static final int FLAG_PARENT_CAN_ACCESS_MANAGED = 1; // 0x1
@@ -26438,7 +26469,7 @@
     method @NonNull public android.net.Ikev2VpnProfile.Builder setAuthPsk(@NonNull byte[]);
     method @NonNull public android.net.Ikev2VpnProfile.Builder setAuthUsernamePassword(@NonNull String, @NonNull String, @Nullable java.security.cert.X509Certificate);
     method @NonNull public android.net.Ikev2VpnProfile.Builder setBypassable(boolean);
-    method @NonNull public android.net.Ikev2VpnProfile.Builder setExcludeLocalRoutes(boolean);
+    method @NonNull public android.net.Ikev2VpnProfile.Builder setLocalRoutesExcluded(boolean);
     method @NonNull public android.net.Ikev2VpnProfile.Builder setMaxMtu(int);
     method @NonNull public android.net.Ikev2VpnProfile.Builder setMetered(boolean);
     method @NonNull public android.net.Ikev2VpnProfile.Builder setProxy(@Nullable android.net.ProxyInfo);
@@ -26516,7 +26547,7 @@
   }
 
   public abstract class PlatformVpnProfile {
-    method public final boolean getExcludeLocalRoutes();
+    method public final boolean areLocalRoutesExcluded();
     method public final boolean getRequiresInternetValidation();
     method public final int getType();
     method @NonNull public final String getTypeString();
@@ -32003,6 +32034,7 @@
     method public boolean isDemoUser();
     method public static boolean isHeadlessSystemUserMode();
     method public boolean isManagedProfile();
+    method public boolean isProfile();
     method public boolean isQuietModeEnabled(android.os.UserHandle);
     method public boolean isSystemUser();
     method public boolean isUserAGoat();
@@ -38838,6 +38870,7 @@
     field public static final int NOTIFICATION_CHANNEL_OR_GROUP_UPDATED = 2; // 0x2
     field public static final int REASON_APP_CANCEL = 8; // 0x8
     field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9
+    field public static final int REASON_ASSISTANT_CANCEL = 22; // 0x16
     field public static final int REASON_CANCEL = 2; // 0x2
     field public static final int REASON_CANCEL_ALL = 3; // 0x3
     field public static final int REASON_CHANNEL_BANNED = 17; // 0x11
@@ -43283,6 +43316,7 @@
     method public boolean isVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle);
     method public boolean isWorldPhone();
     method @Deprecated public void listen(android.telephony.PhoneStateListener, int);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void rebootModem();
     method public void registerTelephonyCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyCallback);
     method public void registerTelephonyCallback(boolean, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyCallback);
     method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void requestCellInfoUpdate(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
@@ -51984,8 +52018,8 @@
     method @NonNull public android.view.accessibility.CaptioningManager.CaptionStyle getUserStyle();
     method public boolean isCallCaptioningEnabled();
     method public final boolean isEnabled();
-    method public final boolean isSystemAudioCaptioningRequested();
-    method public final boolean isSystemAudioCaptioningUiRequested();
+    method public final boolean isSystemAudioCaptioningEnabled();
+    method public final boolean isSystemAudioCaptioningUiEnabled();
     method public void removeCaptioningChangeListener(@NonNull android.view.accessibility.CaptioningManager.CaptioningChangeListener);
   }
 
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index d7517b2..c3c5367 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -195,7 +195,6 @@
     field public static final String MANAGE_USER_OEM_UNLOCK_STATE = "android.permission.MANAGE_USER_OEM_UNLOCK_STATE";
     field public static final String MANAGE_WALLPAPER_EFFECTS_GENERATION = "android.permission.MANAGE_WALLPAPER_EFFECTS_GENERATION";
     field public static final String MANAGE_WEAK_ESCROW_TOKEN = "android.permission.MANAGE_WEAK_ESCROW_TOKEN";
-    field public static final String MANAGE_WIFI_AUTO_JOIN = "android.permission.MANAGE_WIFI_AUTO_JOIN";
     field public static final String MANAGE_WIFI_COUNTRY_CODE = "android.permission.MANAGE_WIFI_COUNTRY_CODE";
     field public static final String MARK_DEVICE_ORGANIZATION_OWNED = "android.permission.MARK_DEVICE_ORGANIZATION_OWNED";
     field public static final String MODIFY_APPWIDGET_BIND_PERMISSIONS = "android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS";
@@ -227,7 +226,6 @@
     field public static final String OBSERVE_SENSOR_PRIVACY = "android.permission.OBSERVE_SENSOR_PRIVACY";
     field public static final String OPEN_ACCESSIBILITY_DETAILS_SETTINGS = "android.permission.OPEN_ACCESSIBILITY_DETAILS_SETTINGS";
     field public static final String OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD = "android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD";
-    field public static final String OVERRIDE_WIFI_CONFIG = "android.permission.OVERRIDE_WIFI_CONFIG";
     field public static final String PACKAGE_VERIFICATION_AGENT = "android.permission.PACKAGE_VERIFICATION_AGENT";
     field public static final String PACKET_KEEPALIVE_OFFLOAD = "android.permission.PACKET_KEEPALIVE_OFFLOAD";
     field public static final String PEERS_MAC_ADDRESS = "android.permission.PEERS_MAC_ADDRESS";
@@ -1147,11 +1145,16 @@
     field public static final String EXTRA_PROVISIONING_ORGANIZATION_NAME = "android.app.extra.PROVISIONING_ORGANIZATION_NAME";
     field public static final String EXTRA_PROVISIONING_RETURN_BEFORE_POLICY_COMPLIANCE = "android.app.extra.PROVISIONING_RETURN_BEFORE_POLICY_COMPLIANCE";
     field public static final String EXTRA_PROVISIONING_ROLE_HOLDER_CUSTOM_USER_CONSENT_INTENT = "android.app.extra.PROVISIONING_ROLE_HOLDER_CUSTOM_USER_CONSENT_INTENT";
+    field public static final String EXTRA_PROVISIONING_ROLE_HOLDER_EXTRAS_BUNDLE = "android.app.extra.PROVISIONING_ROLE_HOLDER_EXTRAS_BUNDLE";
+    field public static final String EXTRA_PROVISIONING_ROLE_HOLDER_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_ROLE_HOLDER_PACKAGE_DOWNLOAD_COOKIE_HEADER";
+    field public static final String EXTRA_PROVISIONING_ROLE_HOLDER_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_ROLE_HOLDER_PACKAGE_DOWNLOAD_LOCATION";
+    field public static final String EXTRA_PROVISIONING_ROLE_HOLDER_SIGNATURE_CHECKSUM = "android.app.extra.PROVISIONING_ROLE_HOLDER_SIGNATURE_CHECKSUM";
     field public static final String EXTRA_PROVISIONING_SKIP_OWNERSHIP_DISCLAIMER = "android.app.extra.PROVISIONING_SKIP_OWNERSHIP_DISCLAIMER";
     field public static final String EXTRA_PROVISIONING_SUPPORTED_MODES = "android.app.extra.PROVISIONING_SUPPORTED_MODES";
     field public static final String EXTRA_PROVISIONING_SUPPORT_URL = "android.app.extra.PROVISIONING_SUPPORT_URL";
     field public static final String EXTRA_PROVISIONING_TRIGGER = "android.app.extra.PROVISIONING_TRIGGER";
     field public static final String EXTRA_RESTRICTION = "android.app.extra.RESTRICTION";
+    field public static final String EXTRA_ROLE_HOLDER_PROVISIONING_INITIATOR_PACKAGE = "android.app.extra.ROLE_HOLDER_PROVISIONING_INITIATOR_PACKAGE";
     field public static final String EXTRA_ROLE_HOLDER_STATE = "android.app.extra.ROLE_HOLDER_STATE";
     field public static final int FLAG_SUPPORTED_MODES_DEVICE_OWNER = 4; // 0x4
     field public static final int FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED = 1; // 0x1
@@ -1359,14 +1362,13 @@
     method @NonNull public android.app.ambientcontext.AmbientContextEventRequest.Builder setOptions(@NonNull android.os.PersistableBundle);
   }
 
-  public final class AmbientContextEventResponse implements android.os.Parcelable {
-    method public int describeContents();
-    method @Nullable public android.app.PendingIntent getActionPendingIntent();
-    method @NonNull public java.util.List<android.app.ambientcontext.AmbientContextEvent> getEvents();
-    method @NonNull public String getPackageName();
-    method public int getStatusCode();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.app.ambientcontext.AmbientContextEventResponse> CREATOR;
+  public final class AmbientContextManager {
+    method @NonNull public static java.util.List<android.app.ambientcontext.AmbientContextEvent> getEventsFromIntent(@NonNull android.content.Intent);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT) public void queryAmbientContextServiceStatus(@NonNull java.util.Set<java.lang.Integer>, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT) public void registerObserver(@NonNull android.app.ambientcontext.AmbientContextEventRequest, @NonNull android.app.PendingIntent, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT) public void startConsentActivity(@NonNull java.util.Set<java.lang.Integer>);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT) public void unregisterObserver();
+    field public static final String EXTRA_AMBIENT_CONTEXT_EVENTS = "android.app.ambientcontext.extra.AMBIENT_CONTEXT_EVENTS";
     field public static final int STATUS_ACCESS_DENIED = 5; // 0x5
     field public static final int STATUS_MICROPHONE_DISABLED = 4; // 0x4
     field public static final int STATUS_NOT_SUPPORTED = 2; // 0x2
@@ -1375,27 +1377,14 @@
     field public static final int STATUS_UNKNOWN = 0; // 0x0
   }
 
-  public static final class AmbientContextEventResponse.Builder {
-    ctor public AmbientContextEventResponse.Builder();
-    method @NonNull public android.app.ambientcontext.AmbientContextEventResponse.Builder addEvent(@NonNull android.app.ambientcontext.AmbientContextEvent);
-    method @NonNull public android.app.ambientcontext.AmbientContextEventResponse build();
-    method @NonNull public android.app.ambientcontext.AmbientContextEventResponse.Builder setActionPendingIntent(@NonNull android.app.PendingIntent);
-    method @NonNull public android.app.ambientcontext.AmbientContextEventResponse.Builder setPackageName(@NonNull String);
-    method @NonNull public android.app.ambientcontext.AmbientContextEventResponse.Builder setStatusCode(int);
-  }
-
-  public final class AmbientContextManager {
-    method @Nullable public static android.app.ambientcontext.AmbientContextEventResponse getResponseFromIntent(@NonNull android.content.Intent);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT) public void registerObserver(@NonNull android.app.ambientcontext.AmbientContextEventRequest, @NonNull android.app.PendingIntent);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT) public void unregisterObserver();
-    field public static final String EXTRA_AMBIENT_CONTEXT_EVENT_RESPONSE = "android.app.ambientcontext.extra.AMBIENT_CONTEXT_EVENT_RESPONSE";
-  }
-
 }
 
 package android.app.assist {
 
-  public class ActivityId {
+  public final class ActivityId implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.assist.ActivityId> CREATOR;
   }
 
   public static class AssistStructure.ViewNode {
@@ -2778,8 +2767,8 @@
     method @NonNull public java.util.Set<android.os.UserHandle> getUsersWithMatchingAccounts();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.companion.virtual.VirtualDeviceParams> CREATOR;
-    field public static final int LOCK_STATE_ALWAYS_LOCKED = 0; // 0x0
     field public static final int LOCK_STATE_ALWAYS_UNLOCKED = 1; // 0x1
+    field public static final int LOCK_STATE_DEFAULT = 0; // 0x0
   }
 
   public static final class VirtualDeviceParams.Builder {
@@ -6667,7 +6656,7 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.TIS_EXTENSION_INTERFACE) public java.util.List<java.lang.String> getAvailableExtensionInterfaceNames(@NonNull String);
     method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public java.util.List<android.media.tv.TvStreamConfig> getAvailableTvStreamConfigList(String);
     method @RequiresPermission("android.permission.TUNER_RESOURCE_ACCESS") public int getClientPid(@NonNull String);
-    method public int getClientPriority(int, @Nullable String);
+    method @RequiresPermission("android.permission.TUNER_RESOURCE_ACCESS") public int getClientPriority(int, @Nullable String);
     method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TUNED_INFO) public java.util.List<android.media.tv.TunedInfo> getCurrentTunedInfos();
     method @NonNull @RequiresPermission("android.permission.DVB_DEVICE") public java.util.List<android.media.tv.DvbDeviceInfo> getDvbDeviceList();
     method @Nullable @RequiresPermission(android.Manifest.permission.TIS_EXTENSION_INTERFACE) public android.os.IBinder getExtensionInterface(@NonNull String, @NonNull String);
@@ -9659,7 +9648,6 @@
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isManagedProfile(int);
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isMediaSharedWithParent();
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isPrimaryUser();
-    method public boolean isProfile();
     method public boolean isRestrictedProfile();
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional=true) public boolean isRestrictedProfile(@NonNull android.os.UserHandle);
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isSameProfileGroup(@NonNull android.os.UserHandle, @NonNull android.os.UserHandle);
@@ -10701,14 +10689,45 @@
 
 package android.service.ambientcontext {
 
+  public final class AmbientContextDetectionResult implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public java.util.List<android.app.ambientcontext.AmbientContextEvent> getEvents();
+    method @NonNull public String getPackageName();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.service.ambientcontext.AmbientContextDetectionResult> CREATOR;
+  }
+
+  public static final class AmbientContextDetectionResult.Builder {
+    ctor public AmbientContextDetectionResult.Builder();
+    method @NonNull public android.service.ambientcontext.AmbientContextDetectionResult.Builder addEvent(@NonNull android.app.ambientcontext.AmbientContextEvent);
+    method @NonNull public android.service.ambientcontext.AmbientContextDetectionResult build();
+    method @NonNull public android.service.ambientcontext.AmbientContextDetectionResult.Builder setPackageName(@NonNull String);
+  }
+
   public abstract class AmbientContextDetectionService extends android.app.Service {
     ctor public AmbientContextDetectionService();
     method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
-    method public abstract void onStartDetection(@NonNull android.app.ambientcontext.AmbientContextEventRequest, @NonNull String, @NonNull java.util.function.Consumer<android.app.ambientcontext.AmbientContextEventResponse>);
+    method @BinderThread public abstract void onQueryServiceStatus(@NonNull int[], @NonNull String, @NonNull java.util.function.Consumer<android.service.ambientcontext.AmbientContextDetectionServiceStatus>);
+    method @BinderThread public abstract void onStartDetection(@NonNull android.app.ambientcontext.AmbientContextEventRequest, @NonNull String, @NonNull java.util.function.Consumer<android.service.ambientcontext.AmbientContextDetectionResult>, @NonNull java.util.function.Consumer<android.service.ambientcontext.AmbientContextDetectionServiceStatus>);
     method public abstract void onStopDetection(@NonNull String);
     field public static final String SERVICE_INTERFACE = "android.service.ambientcontext.AmbientContextDetectionService";
   }
 
+  public final class AmbientContextDetectionServiceStatus implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public String getPackageName();
+    method public int getStatusCode();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.service.ambientcontext.AmbientContextDetectionServiceStatus> CREATOR;
+  }
+
+  public static final class AmbientContextDetectionServiceStatus.Builder {
+    ctor public AmbientContextDetectionServiceStatus.Builder();
+    method @NonNull public android.service.ambientcontext.AmbientContextDetectionServiceStatus build();
+    method @NonNull public android.service.ambientcontext.AmbientContextDetectionServiceStatus.Builder setPackageName(@NonNull String);
+    method @NonNull public android.service.ambientcontext.AmbientContextDetectionServiceStatus.Builder setStatusCode(int);
+  }
+
 }
 
 package android.service.appprediction {
@@ -13256,7 +13275,7 @@
     method public boolean needsOtaServiceProvisioning();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyOtaEmergencyNumberDbInstalled();
     method @RequiresPermission(android.Manifest.permission.REBOOT) public int prepareForUnattendedReboot();
-    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio();
+    method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void removeCarrierPrivilegesListener(@NonNull android.telephony.TelephonyManager.CarrierPrivilegesListener);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void reportDefaultNetworkStatus(boolean);
     method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.MODIFY_PHONE_STATE}) public void requestCellInfoUpdate(@NonNull android.os.WorkSource, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
@@ -15531,8 +15550,8 @@
   }
 
   public class CaptioningManager {
-    method @RequiresPermission(android.Manifest.permission.SET_SYSTEM_AUDIO_CAPTION) public final void setSystemAudioCaptioningRequested(boolean);
-    method @RequiresPermission(android.Manifest.permission.SET_SYSTEM_AUDIO_CAPTION) public final void setSystemAudioCaptioningUiRequested(boolean);
+    method @RequiresPermission(android.Manifest.permission.SET_SYSTEM_AUDIO_CAPTION) public final void setSystemAudioCaptioningEnabled(boolean);
+    method @RequiresPermission(android.Manifest.permission.SET_SYSTEM_AUDIO_CAPTION) public final void setSystemAudioCaptioningUiEnabled(boolean);
   }
 
 }
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 5bd6ca8..bcc7e4a 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -278,6 +278,7 @@
   }
 
   public final class GameManager {
+    method @RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE) public int getGameMode(@NonNull String);
     method @RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE) public boolean isAngleEnabled(@NonNull String);
     method public void setGameServiceProvider(@Nullable String);
   }
@@ -569,9 +570,13 @@
 
 package android.app.assist {
 
-  public class ActivityId {
+  public final class ActivityId implements android.os.Parcelable {
+    ctor public ActivityId(int, @Nullable android.os.IBinder);
+    method public int describeContents();
     method public int getTaskId();
     method @Nullable public android.os.IBinder getToken();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.assist.ActivityId> CREATOR;
   }
 
 }
@@ -2862,6 +2867,7 @@
     method public default void setShouldShowSystemDecors(int, boolean);
     method public default void setShouldShowWithInsecureKeyguard(int, boolean);
     method public default boolean shouldShowSystemDecors(int);
+    method @Nullable public default android.graphics.Bitmap snapshotTaskForRecents(@IntRange(from=0) int);
     field public static final int DISPLAY_IME_POLICY_FALLBACK_DISPLAY = 1; // 0x1
     field public static final int DISPLAY_IME_POLICY_HIDE = 2; // 0x2
     field public static final int DISPLAY_IME_POLICY_LOCAL = 0; // 0x0
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 50473f1..cf3ca20 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -40,6 +40,8 @@
 import android.graphics.Region;
 import android.hardware.HardwareBuffer;
 import android.hardware.display.DisplayManager;
+import android.inputmethodservice.IInputMethodSessionWrapper;
+import android.inputmethodservice.RemoteInputConnection;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
@@ -65,14 +67,23 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 import android.view.accessibility.AccessibilityWindowInfo;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputBinding;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputMethodSession;
 
+import com.android.internal.inputmethod.CancellationGroup;
 import com.android.internal.os.HandlerCaller;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.internal.view.IInputContext;
+import com.android.internal.view.IInputMethodSession;
+import com.android.internal.view.IInputSessionWithIdCallback;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
 import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.Executor;
@@ -627,6 +638,21 @@
         void onAccessibilityButtonAvailabilityChanged(boolean available);
         /** This is called when the system action list is changed. */
         void onSystemActionsChanged();
+        /** This is called when an app requests ime sessions or when the service is enabled. */
+        void createImeSession(IInputSessionWithIdCallback callback);
+        /**
+         * This is called when InputMethodManagerService requests to set the session enabled or
+         * disabled
+         */
+        void setImeSessionEnabled(InputMethodSession session, boolean enabled);
+        /** This is called when an app binds input or when the service is enabled. */
+        void bindInput(InputBinding binding);
+        /** This is called when an app unbinds input or when the service is disabled. */
+        void unbindInput();
+        /** This is called when an app starts input or when the service is enabled. */
+        void startInput(@Nullable InputConnection inputConnection,
+                @NonNull EditorInfo editorInfo, boolean restarting,
+                @NonNull IBinder startInputToken);
     }
 
     /**
@@ -763,6 +789,8 @@
             new SparseArray<>(0);
 
     private SoftKeyboardController mSoftKeyboardController;
+    private InputMethod mInputMethod;
+    private boolean mInputMethodInitialized = false;
     private final SparseArray<AccessibilityButtonController> mAccessibilityButtonControllers =
             new SparseArray<>(0);
 
@@ -797,6 +825,17 @@
             for (int i = 0; i < mMagnificationControllers.size(); i++) {
                 mMagnificationControllers.valueAt(i).onServiceConnectedLocked();
             }
+            AccessibilityServiceInfo info = getServiceInfo();
+            if (info != null) {
+                boolean requestIme = (info.flags
+                        & AccessibilityServiceInfo.FLAG_INPUT_METHOD_EDITOR) != 0;
+                if (requestIme && !mInputMethodInitialized) {
+                    mInputMethod = onCreateInputMethod();
+                    mInputMethodInitialized = true;
+                }
+            } else {
+                Log.e(LOG_TAG, "AccessibilityServiceInfo is null in dispatchServiceConnected");
+            }
         }
         if (mSoftKeyboardController != null) {
             mSoftKeyboardController.onServiceConnected();
@@ -1849,6 +1888,32 @@
         }
     }
 
+    /**
+     * The default implementation returns our default {@link InputMethod}. Subclasses can override
+     * it to provide their own customized version. Accessibility services need to set the
+     * {@link AccessibilityServiceInfo#FLAG_INPUT_METHOD_EDITOR} flag to use input method APIs.
+     *
+     * @return the InputMethod.
+     */
+    @NonNull
+    public InputMethod onCreateInputMethod() {
+        return new InputMethod(this);
+    }
+
+    /**
+     * Returns the InputMethod instance after the system calls {@link #onCreateInputMethod()},
+     * which may be used to input text or get editable text selection change notifications. It will
+     * return null if the accessibility service doesn't set the
+     * {@link AccessibilityServiceInfo#FLAG_INPUT_METHOD_EDITOR} flag or the system doesn't call
+     * {@link #onCreateInputMethod()}.
+     *
+     * @return the InputMethod instance
+     */
+    @Nullable
+    public final InputMethod getInputMethod() {
+        return mInputMethod;
+    }
+
     private void onSoftKeyboardShowModeChanged(int showMode) {
         if (mSoftKeyboardController != null) {
             mSoftKeyboardController.dispatchSoftKeyboardShowModeChanged(showMode);
@@ -2657,6 +2722,47 @@
             public void onSystemActionsChanged() {
                 AccessibilityService.this.onSystemActionsChanged();
             }
+
+            @Override
+            public void createImeSession(IInputSessionWithIdCallback callback) {
+                if (mInputMethod != null) {
+                    mInputMethod.createImeSession(callback);
+                }
+            }
+
+            @Override
+            public void setImeSessionEnabled(InputMethodSession session, boolean enabled) {
+                if (mInputMethod != null) {
+                    mInputMethod.setImeSessionEnabled(session, enabled);
+                }
+            }
+
+            @Override
+            public void bindInput(InputBinding binding) {
+                if (mInputMethod != null) {
+                    mInputMethod.bindInput(binding);
+                }
+            }
+
+            @Override
+            public void unbindInput() {
+                if (mInputMethod != null) {
+                    mInputMethod.unbindInput();
+                }
+            }
+
+            @Override
+            public void startInput(@Nullable InputConnection inputConnection,
+                    @NonNull EditorInfo editorInfo, boolean restarting,
+                    @NonNull IBinder startInputToken) {
+                if (mInputMethod != null) {
+                    if (restarting) {
+                        mInputMethod.restartInput(inputConnection, editorInfo);
+                    } else {
+                        mInputMethod.startInput(inputConnection, editorInfo);
+                    }
+                }
+            }
         });
     }
 
@@ -2682,6 +2788,11 @@
         private static final int DO_ACCESSIBILITY_BUTTON_CLICKED = 12;
         private static final int DO_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED = 13;
         private static final int DO_ON_SYSTEM_ACTIONS_CHANGED = 14;
+        private static final int DO_CREATE_IME_SESSION = 15;
+        private static final int DO_SET_IME_SESSION_ENABLED = 16;
+        private static final int DO_BIND_INPUT = 17;
+        private static final int DO_UNBIND_INPUT = 18;
+        private static final int DO_START_INPUT = 19;
 
         private final HandlerCaller mCaller;
 
@@ -2690,6 +2801,22 @@
 
         private int mConnectionId = AccessibilityInteractionClient.NO_ID;
 
+        /**
+         * This is not {@null} only between {@link #bindInput(InputBinding)} and
+         * {@link #unbindInput()} so that {@link RemoteInputConnection} can query if
+         * {@link #unbindInput()} has already been called or not, mainly to avoid unnecessary
+         * blocking operations.
+         *
+         * <p>This field must be set and cleared only from the binder thread(s), where the system
+         * guarantees that {@link #bindInput(InputBinding)},
+         * {@link #startInput(IBinder, IInputContext, EditorInfo, boolean)}, and
+         * {@link #unbindInput()} are called with the same order as the original calls
+         * in {@link com.android.server.inputmethod.InputMethodManagerService}.
+         * See {@link IBinder#FLAG_ONEWAY} for detailed semantics.</p>
+         */
+        @Nullable
+        CancellationGroup mCancellationGroup = null;
+
         public IAccessibilityServiceClientWrapper(Context context, Looper looper,
                 Callbacks callback) {
             mCallback = callback;
@@ -2783,6 +2910,70 @@
             mCaller.sendMessage(mCaller.obtainMessage(DO_ON_SYSTEM_ACTIONS_CHANGED));
         }
 
+        /** This is called when an app requests ime sessions or when the service is enabled. */
+        public void createImeSession(IInputSessionWithIdCallback callback) {
+            final Message message = mCaller.obtainMessageO(DO_CREATE_IME_SESSION, callback);
+            mCaller.sendMessage(message);
+        }
+
+        /**
+         * This is called when InputMethodManagerService requests to set the session enabled or
+         * disabled
+         */
+        public void setImeSessionEnabled(IInputMethodSession session, boolean enabled) {
+            try {
+                InputMethodSession ls = ((IInputMethodSessionWrapper)
+                        session).getInternalInputMethodSession();
+                if (ls == null) {
+                    Log.w(LOG_TAG, "Session is already finished: " + session);
+                    return;
+                }
+                mCaller.sendMessage(mCaller.obtainMessageIO(
+                        DO_SET_IME_SESSION_ENABLED, enabled ? 1 : 0, ls));
+            } catch (ClassCastException e) {
+                Log.w(LOG_TAG, "Incoming session not of correct type: " + session, e);
+            }
+        }
+
+        /** This is called when an app binds input or when the service is enabled. */
+        public void bindInput(InputBinding binding) {
+            if (mCancellationGroup != null) {
+                Log.e(LOG_TAG, "bindInput must be paired with unbindInput.");
+            }
+            mCancellationGroup = new CancellationGroup();
+            InputConnection ic = new RemoteInputConnection(new WeakReference<>(() -> mContext),
+                    IInputContext.Stub.asInterface(binding.getConnectionToken()),
+                    mCancellationGroup);
+            InputBinding nu = new InputBinding(ic, binding);
+            final Message message = mCaller.obtainMessageO(DO_BIND_INPUT, nu);
+            mCaller.sendMessage(message);
+        }
+
+        /** This is called when an app unbinds input or when the service is disabled. */
+        public void unbindInput() {
+            if (mCancellationGroup != null) {
+                // Signal the flag then forget it.
+                mCancellationGroup.cancelAll();
+                mCancellationGroup = null;
+            } else {
+                Log.e(LOG_TAG, "unbindInput must be paired with bindInput.");
+            }
+            mCaller.sendMessage(mCaller.obtainMessage(DO_UNBIND_INPUT));
+        }
+
+        /** This is called when an app starts input or when the service is enabled. */
+        public void startInput(IBinder startInputToken, IInputContext inputContext,
+                EditorInfo editorInfo, boolean restarting) {
+            if (mCancellationGroup == null) {
+                Log.e(LOG_TAG, "startInput must be called after bindInput.");
+                mCancellationGroup = new CancellationGroup();
+            }
+            final Message message = mCaller.obtainMessageOOOOII(DO_START_INPUT, startInputToken,
+                    inputContext, editorInfo, mCancellationGroup, restarting ? 1 : 0,
+                    0 /* unused */);
+            mCaller.sendMessage(message);
+        }
+
         @Override
         public void onMotionEvent(MotionEvent event) {
             final Message message = PooledLambda.obtainMessage(
@@ -2948,6 +3139,50 @@
                     }
                     return;
                 }
+                case DO_CREATE_IME_SESSION: {
+                    if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
+                        IInputSessionWithIdCallback callback =
+                                (IInputSessionWithIdCallback) message.obj;
+                        mCallback.createImeSession(callback);
+                    }
+                    return;
+                }
+                case DO_SET_IME_SESSION_ENABLED: {
+                    if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
+                        mCallback.setImeSessionEnabled((InputMethodSession) message.obj,
+                                message.arg1 != 0);
+                    }
+                    return;
+                }
+                case DO_BIND_INPUT: {
+                    if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
+                        mCallback.bindInput((InputBinding) message.obj);
+                    }
+                    return;
+                }
+                case DO_UNBIND_INPUT: {
+                    if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
+                        mCallback.unbindInput();
+                    }
+                    return;
+                }
+                case DO_START_INPUT: {
+                    if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
+                        final SomeArgs args = (SomeArgs) message.obj;
+                        final IBinder startInputToken = (IBinder) args.arg1;
+                        final IInputContext inputContext = (IInputContext) args.arg2;
+                        final EditorInfo info = (EditorInfo) args.arg3;
+                        final CancellationGroup cancellationGroup = (CancellationGroup) args.arg4;
+                        final boolean restarting = args.argi5 == 1;
+                        final InputConnection ic = inputContext != null
+                                ? new RemoteInputConnection(new WeakReference<>(() -> mContext),
+                                inputContext, cancellationGroup) : null;
+                        info.makeCompatible(mContext.getApplicationInfo().targetSdkVersion);
+                        mCallback.startInput(ic, info, restarting, startInputToken);
+                        args.recycle();
+                    }
+                    return;
+                }
                 default:
                     Log.w(LOG_TAG, "Unknown message type " + message.what);
             }
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 6988048..85e7854 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -390,6 +390,15 @@
      */
     public static final int FLAG_SEND_MOTION_EVENTS = 0x0004000;
 
+    /**
+     * This flag makes the AccessibilityService an input method editor with a subset of input
+     * method editor capabilities: get the {@link android.view.inputmethod.InputConnection} and get
+     * text selection change notifications.
+     *
+     * @see AccessibilityService#getInputMethod()
+     */
+    public static final int FLAG_INPUT_METHOD_EDITOR = 0x0008000;
+
     /** {@hide} */
     public static final int FLAG_FORCE_DIRECT_BOOT_AWARE = 0x00010000;
 
@@ -497,6 +506,7 @@
      * @see #FLAG_ENABLE_ACCESSIBILITY_VOLUME
      * @see #FLAG_REQUEST_ACCESSIBILITY_BUTTON
      * @see #FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK
+     * @see #FLAG_INPUT_METHOD_EDITOR
      */
     public int flags;
 
@@ -1356,6 +1366,8 @@
                 return "FLAG_REQUEST_FINGERPRINT_GESTURES";
             case FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK:
                 return "FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK";
+            case FLAG_INPUT_METHOD_EDITOR:
+                return "FLAG_INPUT_METHOD_EDITOR";
             default:
                 return null;
         }
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
index 375383d..94da61f 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
@@ -24,6 +24,11 @@
 import android.accessibilityservice.MagnificationConfig;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputBinding;
+import com.android.internal.view.IInputContext;
+import com.android.internal.view.IInputMethodSession;
+import com.android.internal.view.IInputSessionWithIdCallback;
 
 /**
  * Top-level interface to an accessibility service component.
@@ -63,4 +68,15 @@
     void onAccessibilityButtonAvailabilityChanged(boolean available);
 
     void onSystemActionsChanged();
+
+    void createImeSession(IInputSessionWithIdCallback callback);
+
+    void setImeSessionEnabled(IInputMethodSession session, boolean enabled);
+
+    void bindInput(in InputBinding binding);
+
+    void unbindInput();
+
+    void startInput(in IBinder startInputToken, in IInputContext inputContext,
+                in EditorInfo editorInfo, boolean restarting);
 }
diff --git a/core/java/android/accessibilityservice/InputMethod.java b/core/java/android/accessibilityservice/InputMethod.java
new file mode 100644
index 0000000..001d804
--- /dev/null
+++ b/core/java/android/accessibilityservice/InputMethod.java
@@ -0,0 +1,637 @@
+/*
+ * Copyright (C) 2022 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.accessibilityservice;
+
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.graphics.Rect;
+import android.inputmethodservice.IInputMethodSessionWrapper;
+import android.inputmethodservice.RemoteInputConnection;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.Trace;
+import android.util.Log;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.CursorAnchorInfo;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.ExtractedText;
+import android.view.inputmethod.InputBinding;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.InputMethodSession;
+import android.view.inputmethod.SurroundingText;
+import android.view.inputmethod.TextAttribute;
+
+import com.android.internal.view.IInputContext;
+import com.android.internal.view.IInputSessionWithIdCallback;
+
+import java.util.concurrent.Executor;
+
+/**
+ * This class provides input method APIs. Some public methods such as
+ * @link #onUpdateSelection(int, int, int, int, int, int)} do nothing by default and service
+ * developers should override them as needed. Developers should also override
+ * {@link AccessibilityService#onCreateInputMethod()} to return
+ * their custom InputMethod implementation. Accessibility services also need to set the
+ * {@link AccessibilityServiceInfo#FLAG_INPUT_METHOD_EDITOR} flag to use input method APIs.
+ */
+public class InputMethod {
+    private static final String LOG_TAG = "A11yInputMethod";
+
+    private final AccessibilityService mService;
+    private InputBinding mInputBinding;
+    private InputConnection mInputConnection;
+    private boolean mInputStarted;
+    private InputConnection mStartedInputConnection;
+    private EditorInfo mInputEditorInfo;
+
+    protected InputMethod(@NonNull AccessibilityService service) {
+        mService = service;
+    }
+
+    /**
+     * Retrieve the currently active InputConnection that is bound to
+     * the input method, or null if there is none.
+     */
+    @Nullable
+    public final AccessibilityInputConnection getCurrentInputConnection() {
+        InputConnection ic = mStartedInputConnection;
+        if (ic != null) {
+            return new AccessibilityInputConnection(ic);
+        }
+        if (mInputConnection != null) {
+            return new AccessibilityInputConnection(mInputConnection);
+        }
+        return null;
+    }
+
+    /**
+     * Whether the input has started.
+     */
+    public final boolean getCurrentInputStarted() {
+        return mInputStarted;
+    }
+
+    /**
+     * Get the EditorInfo which describes several attributes of a text editing object
+     * that an accessibility service is communicating with (typically an EditText).
+     */
+    @Nullable
+    public final EditorInfo getCurrentInputEditorInfo() {
+        return mInputEditorInfo;
+    }
+
+    /**
+     * Called to inform the accessibility service that text input has started in an
+     * editor.  You should use this callback to initialize the state of your
+     * input to match the state of the editor given to it.
+     *
+     * @param attribute  The attributes of the editor that input is starting
+     *                   in.
+     * @param restarting Set to true if input is restarting in the same
+     *                   editor such as because the application has changed the text in
+     *                   the editor.  Otherwise will be false, indicating this is a new
+     *                   session with the editor.
+     */
+    public void onStartInput(@NonNull EditorInfo attribute, boolean restarting) {
+        // Intentionally empty
+    }
+
+    /**
+     * Called to inform the accessibility service that text input has finished in
+     * the last editor. At this point there may be a call to
+     * {@link #onStartInput(EditorInfo, boolean)} to perform input in a
+     * new editor, or the accessibility service may be left idle. This method is
+     * <em>not</em> called when input restarts in the same editor.
+     *
+     * <p>The default
+     * implementation uses the InputConnection to clear any active composing
+     * text; you can override this (not calling the base class implementation)
+     * to perform whatever behavior you would like.
+     */
+    public void onFinishInput() {
+        InputConnection ic = mStartedInputConnection != null ? mStartedInputConnection
+                : mInputConnection;
+        if (ic != null) {
+            ic.finishComposingText();
+        }
+    }
+
+    /**
+     * Called when the application has reported a new selection region of
+     * the text. This is called whether or not the accessibility service has requested
+     * extracted text updates, although if so it will not receive this call
+     * if the extracted text has changed as well.
+     *
+     * <p>Be careful about changing the text in reaction to this call with
+     * methods such as setComposingText, commitText or
+     * deleteSurroundingText. If the cursor moves as a result, this method
+     * will be called again, which may result in an infinite loop.
+     */
+    public void onUpdateSelection(int oldSelStart, int oldSelEnd, int newSelStart,
+            int newSelEnd, int candidatesStart, int candidatesEnd) {
+        // Intentionally empty
+    }
+
+    final void createImeSession(IInputSessionWithIdCallback callback) {
+        InputMethodSession session = onCreateInputMethodSessionInterface();
+        try {
+            IInputMethodSessionWrapper wrap =
+                    new IInputMethodSessionWrapper(mService, session, null);
+            callback.sessionCreated(wrap, mService.getConnectionId());
+        } catch (RemoteException ignored) {
+        }
+    }
+
+    final void setImeSessionEnabled(@NonNull InputMethodSession session, boolean enabled) {
+        ((InputMethodSessionForAccessibility) session).setEnabled(enabled);
+    }
+
+    final void bindInput(@NonNull InputBinding binding) {
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "AccessibilityService.bindInput");
+        mInputBinding = binding;
+        mInputConnection = binding.getConnection();
+        Log.v(LOG_TAG, "bindInput(): binding=" + binding
+                + " ic=" + mInputConnection);
+        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+    }
+
+    final void unbindInput() {
+        Log.v(LOG_TAG, "unbindInput(): binding=" + mInputBinding
+                + " ic=" + mInputConnection);
+        // Unbind input is per process per display.
+        mInputBinding = null;
+        mInputConnection = null;
+    }
+
+    final void startInput(@Nullable InputConnection ic, @NonNull EditorInfo attribute) {
+        Log.v(LOG_TAG, "startInput(): editor=" + attribute);
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.startInput");
+        doStartInput(ic, attribute, false /* restarting */);
+        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+    }
+
+    final void restartInput(@Nullable InputConnection ic, @NonNull EditorInfo attribute) {
+        Log.v(LOG_TAG, "restartInput(): editor=" + attribute);
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.restartInput");
+        doStartInput(ic, attribute, true /* restarting */);
+        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+    }
+
+
+    final void doStartInput(InputConnection ic, EditorInfo attribute, boolean restarting) {
+        if (!restarting && mInputStarted) {
+            doFinishInput();
+        }
+        mInputStarted = true;
+        mStartedInputConnection = ic;
+        mInputEditorInfo = attribute;
+        Log.v(LOG_TAG, "CALL: onStartInput");
+        onStartInput(attribute, restarting);
+    }
+
+    final void doFinishInput() {
+        Log.v(LOG_TAG, "CALL: doFinishInput");
+        if (mInputStarted) {
+            Log.v(LOG_TAG, "CALL: onFinishInput");
+            onFinishInput();
+        }
+        mInputStarted = false;
+        mStartedInputConnection = null;
+    }
+
+    private InputMethodSession onCreateInputMethodSessionInterface() {
+        return new InputMethodSessionForAccessibility();
+    }
+
+    /**
+     * This class provides the allowed list of {@link InputConnection} APIs for
+     * accessibility services.
+     */
+    public final class AccessibilityInputConnection {
+        private InputConnection mIc;
+        AccessibilityInputConnection(InputConnection ic) {
+            this.mIc = ic;
+        }
+
+        /**
+         * Commit text to the text box and set the new cursor position. This method is
+         * used to allow the IME to provide extra information while setting up text.
+         *
+         * <p>This method commits the contents of the currently composing text, and then
+         * moves the cursor according to {@code newCursorPosition}. If there
+         * is no composing text when this method is called, the new text is
+         * inserted at the cursor position, removing text inside the selection
+         * if any.
+         *
+         * <p>Calling this method will cause the editor to call
+         * {@link #onUpdateSelection(int, int, int, int,
+         * int, int)} on the current accessibility service after the batch input is over.
+         * <strong>Editor authors</strong>, for this to happen you need to
+         * make the changes known to the accessibility service by calling
+         * {@link InputMethodManager#updateSelection(View, int, int, int, int)},
+         * but be careful to wait until the batch edit is over if one is
+         * in progress.</p>
+         *
+         * @param text The text to commit. This may include styles.
+         * @param newCursorPosition The new cursor position around the text,
+         *        in Java characters. If > 0, this is relative to the end
+         *        of the text - 1; if <= 0, this is relative to the start
+         *        of the text. So a value of 1 will always advance the cursor
+         *        to the position after the full text being inserted. Note that
+         *        this means you can't position the cursor within the text,
+         *        because the editor can make modifications to the text
+         *        you are providing so it is not possible to correctly specify
+         *        locations there.
+         * @param textAttribute The extra information about the text.
+         */
+        public void commitText(@NonNull CharSequence text, int newCursorPosition,
+                @Nullable TextAttribute textAttribute) {
+            if (mIc != null) {
+                mIc.commitText(text, newCursorPosition, textAttribute);
+            }
+        }
+
+        /**
+         * Set the selection of the text editor. To set the cursor
+         * position, start and end should have the same value.
+         *
+         * <p>Since this moves the cursor, calling this method will cause
+         * the editor to call
+         * {@link android.inputmethodservice.InputMethodService#onUpdateSelection(int, int, int,
+         * int,int, int)} on the current IME after the batch input is over.
+         * <strong>Editor authors</strong>, for this to happen you need to
+         * make the changes known to the input method by calling
+         * {@link InputMethodManager#updateSelection(View, int, int, int, int)},
+         * but be careful to wait until the batch edit is over if one is
+         * in progress.</p>
+         *
+         * <p>This has no effect on the composing region which must stay
+         * unchanged. The order of start and end is not important. In
+         * effect, the region from start to end and the region from end to
+         * start is the same. Editor authors, be ready to accept a start
+         * that is greater than end.</p>
+         *
+         * @param start the character index where the selection should start.
+         * @param end the character index where the selection should end.
+         */
+        public void setSelection(int start, int end) {
+            if (mIc != null) {
+                mIc.setSelection(start, end);
+            }
+        }
+
+        /**
+         * Gets the surrounding text around the current cursor, with <var>beforeLength</var>
+         * characters of text before the cursor (start of the selection), <var>afterLength</var>
+         * characters of text after the cursor (end of the selection), and all of the selected
+         * text. The range are for java characters, not glyphs that can be multiple characters.
+         *
+         * <p>This method may fail either if the input connection has become invalid (such as its
+         * process crashing), or the client is taking too long to respond with the text (it is
+         * given a couple seconds to return), or the protocol is not supported. In any of these
+         * cases, null is returned.
+         *
+         * <p>This method does not affect the text in the editor in any way, nor does it affect the
+         * selection or composing spans.</p>
+         *
+         * <p>If {@link InputConnection#GET_TEXT_WITH_STYLES} is supplied as flags, the editor
+         * should return a {@link android.text.Spanned} with all the spans set on the text.</p>
+         *
+         * <p><strong>Accessibility service authors:</strong> please consider this will trigger an
+         * IPC round-trip that will take some time. Assume this method consumes a lot of time.
+         *
+         * @param beforeLength The expected length of the text before the cursor.
+         * @param afterLength The expected length of the text after the cursor.
+         * @param flags Supplies additional options controlling how the text is returned. May be
+         *              either {@code 0} or {@link InputConnection#GET_TEXT_WITH_STYLES}.
+         * @return an {@link android.view.inputmethod.SurroundingText} object describing the
+         * surrounding text and state of selection, or null if the input connection is no longer
+         * valid, or the editor can't comply with the request for some reason, or the application
+         * does not implement this method. The length of the returned text might be less than the
+         * sum of <var>beforeLength</var> and <var>afterLength</var> .
+         * @throws IllegalArgumentException if {@code beforeLength} or {@code afterLength} is
+         * negative.
+         */
+        @Nullable
+        public SurroundingText getSurroundingText(
+                @IntRange(from = 0) int beforeLength, @IntRange(from = 0) int afterLength,
+                @InputConnection.GetTextType int flags) {
+            if (mIc != null) {
+                return mIc.getSurroundingText(beforeLength, afterLength, flags);
+            }
+            return null;
+        }
+
+        /**
+         * Delete <var>beforeLength</var> characters of text before the
+         * current cursor position, and delete <var>afterLength</var>
+         * characters of text after the current cursor position, excluding
+         * the selection. Before and after refer to the order of the
+         * characters in the string, not to their visual representation:
+         * this means you don't have to figure out the direction of the
+         * text and can just use the indices as-is.
+         *
+         * <p>The lengths are supplied in Java chars, not in code points
+         * or in glyphs.</p>
+         *
+         * <p>Since this method only operates on text before and after the
+         * selection, it can't affect the contents of the selection. This
+         * may affect the composing span if the span includes characters
+         * that are to be deleted, but otherwise will not change it. If
+         * some characters in the composing span are deleted, the
+         * composing span will persist but get shortened by however many
+         * chars inside it have been removed.</p>
+         *
+         * <p><strong>Accessibility service authors:</strong> please be careful not to
+         * delete only half of a surrogate pair. Also take care not to
+         * delete more characters than are in the editor, as that may have
+         * ill effects on the application. Calling this method will cause
+         * the editor to call
+         * {@link android.inputmethodservice.InputMethodService#onUpdateSelection(int, int, int, int,
+         * int, int)} on your service after the batch input is over.</p>
+         *
+         * <p><strong>Editor authors:</strong> please be careful of race
+         * conditions in implementing this call. An IME can make a change
+         * to the text or change the selection position and use this
+         * method right away; you need to make sure the effects are
+         * consistent with the results of the latest edits. Also, although
+         * the IME should not send lengths bigger than the contents of the
+         * string, you should check the values for overflows and trim the
+         * indices to the size of the contents to avoid crashes. Since
+         * this changes the contents of the editor, you need to make the
+         * changes known to the input method by calling
+         * {@link InputMethodManager#updateSelection(View, int, int, int, int)},
+         * but be careful to wait until the batch edit is over if one is
+         * in progress.</p>
+         *
+         * @param beforeLength The number of characters before the cursor to be deleted, in code
+         *        unit. If this is greater than the number of existing characters between the
+         *        beginning of the text and the cursor, then this method does not fail but deletes
+         *        all the characters in that range.
+         * @param afterLength The number of characters after the cursor to be deleted, in code unit.
+         *        If this is greater than the number of existing characters between the cursor and
+         *        the end of the text, then this method does not fail but deletes all the characters
+         *        in that range.
+         */
+        public void deleteSurroundingText(int beforeLength, int afterLength) {
+            if (mIc != null) {
+                mIc.deleteSurroundingText(beforeLength, afterLength);
+            }
+        }
+
+        /**
+         * Send a key event to the process that is currently attached
+         * through this input connection. The event will be dispatched
+         * like a normal key event, to the currently focused view; this
+         * generally is the view that is providing this InputConnection,
+         * but due to the asynchronous nature of this protocol that can
+         * not be guaranteed and the focus may have changed by the time
+         * the event is received.
+         *
+         * <p>This method can be used to send key events to the
+         * application. For example, an on-screen keyboard may use this
+         * method to simulate a hardware keyboard. There are three types
+         * of standard keyboards, numeric (12-key), predictive (20-key)
+         * and ALPHA (QWERTY). You can specify the keyboard type by
+         * specify the device id of the key event.</p>
+         *
+         * <p>You will usually want to set the flag
+         * {@link KeyEvent#FLAG_SOFT_KEYBOARD KeyEvent.FLAG_SOFT_KEYBOARD}
+         * on all key event objects you give to this API; the flag will
+         * not be set for you.</p>
+         *
+         * <p>Note that it's discouraged to send such key events in normal
+         * operation; this is mainly for use with
+         * {@link android.text.InputType#TYPE_NULL} type text fields. Use
+         * the {@link #commitText} family of methods to send text to the
+         * application instead.</p>
+         *
+         * @param event The key event.
+         *
+         * @see KeyEvent
+         * @see KeyCharacterMap#NUMERIC
+         * @see KeyCharacterMap#PREDICTIVE
+         * @see KeyCharacterMap#ALPHA
+         */
+        public void sendKeyEvent(@NonNull KeyEvent event) {
+            if (mIc != null) {
+                mIc.sendKeyEvent(event);
+            }
+        }
+
+        /**
+         * Have the editor perform an action it has said it can do.
+         *
+         * @param editorAction This must be one of the action constants for
+         * {@link EditorInfo#imeOptions EditorInfo.imeOptions}, such as
+         * {@link EditorInfo#IME_ACTION_GO EditorInfo.EDITOR_ACTION_GO}, or the value of
+         * {@link EditorInfo#actionId EditorInfo.actionId} if a custom action is available.
+         */
+        public void performEditorAction(int editorAction) {
+            if (mIc != null) {
+                mIc.performEditorAction(editorAction);
+            }
+        }
+
+        /**
+         * Perform a context menu action on the field. The given id may be one of:
+         * {@link android.R.id#selectAll},
+         * {@link android.R.id#startSelectingText}, {@link android.R.id#stopSelectingText},
+         * {@link android.R.id#cut}, {@link android.R.id#copy},
+         * {@link android.R.id#paste}, {@link android.R.id#copyUrl},
+         * or {@link android.R.id#switchInputMethod}
+         */
+        public void performContextMenuAction(int id) {
+            if (mIc != null) {
+                mIc.performContextMenuAction(id);
+            }
+        }
+
+        /**
+         * Retrieve the current capitalization mode in effect at the
+         * current cursor position in the text. See
+         * {@link android.text.TextUtils#getCapsMode TextUtils.getCapsMode}
+         * for more information.
+         *
+         * <p>This method may fail either if the input connection has
+         * become invalid (such as its process crashing) or the client is
+         * taking too long to respond with the text (it is given a couple
+         * seconds to return). In either case, 0 is returned.</p>
+         *
+         * <p>This method does not affect the text in the editor in any
+         * way, nor does it affect the selection or composing spans.</p>
+         *
+         * <p><strong>Editor authors:</strong> please be careful of race
+         * conditions in implementing this call. An IME can change the
+         * cursor position and use this method right away; you need to make
+         * sure the returned value is consistent with the results of the
+         * latest edits and changes to the cursor position.</p>
+         *
+         * @param reqModes The desired modes to retrieve, as defined by
+         * {@link android.text.TextUtils#getCapsMode TextUtils.getCapsMode}. These
+         * constants are defined so that you can simply pass the current
+         * {@link EditorInfo#inputType TextBoxAttribute.contentType} value
+         * directly in to here.
+         * @return the caps mode flags that are in effect at the current
+         * cursor position. See TYPE_TEXT_FLAG_CAPS_* in {@link android.text.InputType}.
+         */
+        public int getCursorCapsMode(int reqModes) {
+            if (mIc != null) {
+                return mIc.getCursorCapsMode(reqModes);
+            }
+            return 0;
+        }
+
+        /**
+         * Clear the given meta key pressed states in the given input
+         * connection.
+         *
+         * <p>This can be used by the accessibility service to clear the meta key states set
+         * by a hardware keyboard with latched meta keys, if the editor
+         * keeps track of these.</p>
+         *
+         * @param states The states to be cleared, may be one or more bits as
+         * per {@link KeyEvent#getMetaState() KeyEvent.getMetaState()}.
+         */
+        public void clearMetaKeyStates(int states) {
+            if (mIc != null) {
+                mIc.clearMetaKeyStates(states);
+            }
+        }
+    }
+
+    /**
+     * Concrete implementation of InputMethodSession that provides all of the standard behavior
+     * for an input method session.
+     */
+    private final class InputMethodSessionForAccessibility implements InputMethodSession {
+        boolean mEnabled = true;
+
+        public void setEnabled(boolean enabled) {
+            mEnabled = enabled;
+        }
+
+        @Override
+        public void finishInput() {
+            if (mEnabled) {
+                doFinishInput();
+            }
+        }
+
+        @Override
+        public void updateSelection(int oldSelStart, int oldSelEnd, int newSelStart,
+                int newSelEnd, int candidatesStart, int candidatesEnd) {
+            if (mEnabled) {
+                InputMethod.this.onUpdateSelection(oldSelEnd, oldSelEnd, newSelStart,
+                        newSelEnd, candidatesStart, candidatesEnd);
+            }
+        }
+
+        @Override
+        public void viewClicked(boolean focusChanged) {
+        }
+
+        @Override
+        public void updateCursor(@NonNull Rect newCursor) {
+        }
+
+        @Override
+        public void displayCompletions(
+                @SuppressLint("ArrayReturn") @NonNull CompletionInfo[] completions) {
+        }
+
+        @Override
+        public void updateExtractedText(int token, @NonNull ExtractedText text) {
+        }
+
+        public void dispatchKeyEvent(int seq, @NonNull KeyEvent event,
+                @NonNull @CallbackExecutor Executor executor, @NonNull EventCallback callback) {
+        }
+
+        @Override
+        public void dispatchKeyEvent(int seq, @NonNull KeyEvent event,
+                @NonNull EventCallback callback) {
+        }
+
+        public void dispatchTrackballEvent(int seq, @NonNull MotionEvent event,
+                @NonNull @CallbackExecutor Executor executor, @NonNull EventCallback callback) {
+        }
+
+        @Override
+        public void dispatchTrackballEvent(int seq, @NonNull MotionEvent event,
+                @NonNull EventCallback callback) {
+        }
+
+        public void dispatchGenericMotionEvent(int seq, @NonNull MotionEvent event,
+                @NonNull @CallbackExecutor Executor executor, @NonNull EventCallback callback) {
+        }
+
+        @Override
+        public void dispatchGenericMotionEvent(int seq, @NonNull MotionEvent event,
+                @NonNull EventCallback callback) {
+        }
+
+        @Override
+        public void appPrivateCommand(@NonNull String action, @NonNull Bundle data) {
+        }
+
+        @Override
+        public void toggleSoftInput(int showFlags, int hideFlags) {
+        }
+
+        @Override
+        public void updateCursorAnchorInfo(@NonNull CursorAnchorInfo cursorAnchorInfo) {
+        }
+
+        @Override
+        public void notifyImeHidden() {
+        }
+
+        @Override
+        public void removeImeSurface() {
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public void invalidateInputInternal(EditorInfo editorInfo, IInputContext inputContext,
+                int sessionId) {
+            // TODO(b/217788708): Add automated test.
+            if (mStartedInputConnection instanceof RemoteInputConnection) {
+                final RemoteInputConnection ric =
+                        (RemoteInputConnection) mStartedInputConnection;
+                if (!ric.isSameConnection(inputContext)) {
+                    // This is not an error, and can be safely ignored.
+                    return;
+                }
+                editorInfo.makeCompatible(
+                        mService.getApplicationInfo().targetSdkVersion);
+                restartInput(new RemoteInputConnection(ric, sessionId), editorInfo);
+            }
+        }
+    }
+}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index e7b6646..a31aa28 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -8662,8 +8662,18 @@
     }
 
     /**
-     * If set to true, this indicates to the system that it should never take a
-     * screenshot of the activity to be used as a representation while it is not in a started state.
+     * @hide
+     */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.S,
+            publicAlternatives = "Use {@link #setRecentsScreenshotEnabled(boolean)} instead.")
+    public void setDisablePreviewScreenshots(boolean disable) {
+        setRecentsScreenshotEnabled(!disable);
+    }
+
+    /**
+     * If set to false, this indicates to the system that it should never take a
+     * screenshot of the activity to be used as a representation in recents screen. By default, this
+     * value is {@code true}.
      * <p>
      * Note that the system may use the window background of the theme instead to represent
      * the window when it is not running.
@@ -8676,12 +8686,10 @@
      * {@link android.service.voice.VoiceInteractionService} requests a screenshot via
      * {@link android.service.voice.VoiceInteractionSession#SHOW_WITH_SCREENSHOT}.
      *
-     * @param disable {@code true} to disable preview screenshots; {@code false} otherwise.
-     * @hide
+     * @param enabled {@code true} to enable recents screenshots; {@code false} otherwise.
      */
-    @UnsupportedAppUsage
-    public void setDisablePreviewScreenshots(boolean disable) {
-        ActivityClient.getInstance().setDisablePreviewScreenshots(mToken, disable);
+    public void setRecentsScreenshotEnabled(boolean enabled) {
+        ActivityClient.getInstance().setRecentsScreenshotEnabled(mToken, enabled);
     }
 
     /**
diff --git a/core/java/android/app/ActivityClient.java b/core/java/android/app/ActivityClient.java
index 605a1fa..4715e0f 100644
--- a/core/java/android/app/ActivityClient.java
+++ b/core/java/android/app/ActivityClient.java
@@ -438,9 +438,9 @@
         }
     }
 
-    void setDisablePreviewScreenshots(IBinder token, boolean disable) {
+    void setRecentsScreenshotEnabled(IBinder token, boolean enabled) {
         try {
-            getActivityClientController().setDisablePreviewScreenshots(token, disable);
+            getActivityClientController().setRecentsScreenshotEnabled(token, enabled);
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index a58ceaa..cce7dd3 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -215,14 +215,6 @@
     public abstract boolean isSystemReady();
 
     /**
-     * Returns package name given pid.
-     *
-     * @param pid The pid we are searching package name for.
-     */
-    @Nullable
-    public abstract String getPackageNameByPid(int pid);
-
-    /**
      * Sets if the given pid has an overlay UI or not.
      *
      * @param pid The pid we are setting overlay UI for.
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 5b8969e..61d1865 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2132,7 +2132,16 @@
                     Looper.myLooper().quit();
                     break;
                 case RECEIVER:
-                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveComp");
+                    if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
+                        ReceiverData rec = (ReceiverData) msg.obj;
+                        if (rec.intent != null) {
+                            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+                                    "broadcastReceiveComp: " + rec.intent.getAction());
+                        } else {
+                            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+                                    "broadcastReceiveComp");
+                        }
+                    }
                     handleReceiver((ReceiverData)msg.obj);
                     Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                     break;
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 8181a74..ec2115c 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1998,7 +1998,7 @@
     private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
             String instanceName, Handler handler, Executor executor, UserHandle user) {
         // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser and
-        // ActivityManagerService.LocalService.startAndBindSupplementalProcessService
+        // ActivityManagerLocal.bindSupplementalProcessService
         IServiceConnection sd;
         if (conn == null) {
             throw new IllegalArgumentException("connection is null");
diff --git a/core/java/android/app/GameManager.java b/core/java/android/app/GameManager.java
index 040399e..6f49c9e 100644
--- a/core/java/android/app/GameManager.java
+++ b/core/java/android/app/GameManager.java
@@ -109,6 +109,7 @@
      *
      * @hide
      */
+    @TestApi
     @UserHandleAware
     @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE)
     public @GameMode int getGameMode(@NonNull String packageName) {
diff --git a/core/java/android/app/IActivityClientController.aidl b/core/java/android/app/IActivityClientController.aidl
index 396e552..f9439cb 100644
--- a/core/java/android/app/IActivityClientController.aidl
+++ b/core/java/android/app/IActivityClientController.aidl
@@ -115,8 +115,8 @@
             int enterAnim, int exitAnim, int backgroundColor);
     int setVrMode(in IBinder token, boolean enabled, in ComponentName packageName);
 
-    /** See {@link android.app.Activity#setDisablePreviewScreenshots}. */
-    oneway void setDisablePreviewScreenshots(in IBinder token, boolean disable);
+    /** See {@link android.app.Activity#setRecentsScreenshotEnabled}. */
+    oneway void setRecentsScreenshotEnabled(in IBinder token, boolean enabled);
 
     /**
      * It should only be called from home activity to remove its outdated snapshot. The home
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index c5add66..cc8b182 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -130,6 +130,7 @@
             in ProfilerInfo profilerInfo, in Bundle options, int userId);
     int startAssistantActivity(in String callingPackage, in String callingFeatureId, int callingPid,
             int callingUid, in Intent intent, in String resolvedType, in Bundle options, int userId);
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_ACTIVITY)")
     int startActivityFromGameSession(IApplicationThread caller, in String callingPackage,
             in String callingFeatureId, int callingPid, int callingUid, in Intent intent,
             int taskId, int userId);
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index a74438a..e0c69df 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -381,10 +381,6 @@
      * Force the global system in or out of touch mode. This can be used if your
      * instrumentation relies on the UI being in one more or the other when it starts.
      *
-     * <p><b>Note:</b> Starting from Android {@link Build.VERSION_CODES#TIRAMISU}, this method
-     * will only have an effect if the calling process is also the focused window owner or has
-     * {@link android.permission#MODIFY_TOUCH_MODE_STATE} permission granted.
-     *
      * @param inTouch Set to true to be in touch mode, false to be in focus mode.
      */
     public void setInTouchMode(boolean inTouch) {
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 38e344e..77c7c6f 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -1734,7 +1734,11 @@
                         return;
                     }
 
-                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg");
+                    if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
+                        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+                                "broadcastReceiveReg: " + intent.getAction());
+                    }
+
                     try {
                         ClassLoader cl = mReceiver.getClass().getClassLoader();
                         intent.setExtrasClassLoader(cl);
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 4aa2d2e..392f52a 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -2573,11 +2573,18 @@
      * method will return false regardless of input.
      * </p>
      * <p>
-     * The provided URI must meet the requirements for a URI associated with a
-     * {@link Person}: it may be the {@code String} representation of a
-     * {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}, or a
-     * <code>mailto:</code> or <code>tel:</code> schema URI matching an entry in the
-     * Contacts database. See also {@link Person.Builder#setUri} and
+     * The provided URI should be a <code>tel:</code> or <code>mailto:</code> schema URI indicating
+     * the source of the call. For an accurate answer regarding whether the caller matches the
+     * user's permitted contacts, the path part of the URI must match an entry the Contacts database
+     * in the appropriate column.
+     * </p>
+     * <p>
+     * Passing in a {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI} is also
+     * permissible, but should only be used for priority contact interruptions and may not provide
+     * accurate results in the case of repeat callers.
+     * </p>
+     * <p>
+     * See also {@link Person.Builder#setUri} and
      * {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}
      * for more information.
      * </p>
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index f5f2fe0..eeb4705 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -25,7 +25,7 @@
 import android.app.admin.DevicePolicyManager;
 import android.app.admin.IDevicePolicyManager;
 import android.app.ambientcontext.AmbientContextManager;
-import android.app.ambientcontext.IAmbientContextEventObserver;
+import android.app.ambientcontext.IAmbientContextManager;
 import android.app.appsearch.AppSearchManagerFrameworkInitializer;
 import android.app.blob.BlobStoreManagerFrameworkInitializer;
 import android.app.cloudsearch.CloudSearchManager;
@@ -1542,8 +1542,8 @@
                             throws ServiceNotFoundException {
                         IBinder iBinder = ServiceManager.getServiceOrThrow(
                                 Context.AMBIENT_CONTEXT_SERVICE);
-                        IAmbientContextEventObserver manager =
-                                IAmbientContextEventObserver.Stub.asInterface(iBinder);
+                        IAmbientContextManager manager =
+                                IAmbientContextManager.Stub.asInterface(iBinder);
                         return new AmbientContextManager(ctx.getOuterContext(), manager);
                     }});
 
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index b41b5f00..2af8905 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -63,9 +63,14 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityWindowInfo;
 import android.view.accessibility.IAccessibilityInteractionConnection;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputBinding;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputMethodSession;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.internal.view.IInputSessionWithIdCallback;
 
 import libcore.io.IoUtils;
 
@@ -1566,6 +1571,29 @@
                 }
 
                 @Override
+                public void createImeSession(IInputSessionWithIdCallback callback) {
+                    /* do nothing */
+                }
+
+                @Override
+                public void setImeSessionEnabled(InputMethodSession session, boolean enabled) {
+                }
+
+                @Override
+                public void bindInput(InputBinding binding) {
+                }
+
+                @Override
+                public void unbindInput() {
+                }
+
+                @Override
+                public void startInput(@Nullable InputConnection inputConnection,
+                        @NonNull EditorInfo editorInfo, boolean restarting,
+                        @NonNull IBinder startInputToken) {
+                }
+
+                @Override
                 public boolean onGesture(AccessibilityGestureEvent gestureEvent) {
                     /* do nothing */
                     return false;
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 71d4ab4..e52ae51 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -720,6 +720,125 @@
             "android.app.extra.PROVISIONING_ALLOW_OFFLINE";
 
     /**
+     * A String extra holding a url that specifies the download location of the device manager
+     * role holder package.
+     *
+     * <p>This is only meant to be used in cases when a specific variant of the role holder package
+     * is needed (such as a debug variant). If not provided, the default variant of the device
+     * manager role holder package is downloaded.
+     *
+     * <p>Use in an intent with action {@link #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE}
+     * or in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+     * provisioning via an NFC bump.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_PROVISIONING_ROLE_HOLDER_PACKAGE_DOWNLOAD_LOCATION =
+            "android.app.extra.PROVISIONING_ROLE_HOLDER_PACKAGE_DOWNLOAD_LOCATION";
+
+    /**
+     * A String extra holding the URL-safe base64 encoded SHA-256 checksum of any signature of the
+     * android package archive at the download location specified in {@link
+     * #EXTRA_PROVISIONING_ROLE_HOLDER_PACKAGE_DOWNLOAD_LOCATION}.
+     *
+     * <p>The signatures of an android package archive can be obtained using
+     * {@link android.content.pm.PackageManager#getPackageArchiveInfo} with flag
+     * {@link android.content.pm.PackageManager#GET_SIGNING_CERTIFICATES}.
+     *
+     * <p>If {@link #EXTRA_PROVISIONING_ROLE_HOLDER_PACKAGE_DOWNLOAD_LOCATION} is provided, it must
+     * be accompanied by this extra. The provided checksum must match the checksum of any signature
+     * of the file at the download location. If the checksum does not match an error will be shown
+     * to the user and the user will be asked to factory reset the device.
+     *
+     * <p>Use in an intent with action {@link #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE}
+     * or in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+     * provisioning via an NFC bump.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_PROVISIONING_ROLE_HOLDER_SIGNATURE_CHECKSUM =
+            "android.app.extra.PROVISIONING_ROLE_HOLDER_SIGNATURE_CHECKSUM";
+
+    /**
+     * A String extra holding a http cookie header which should be used in the http request to the
+     * url specified in {@link #EXTRA_PROVISIONING_ROLE_HOLDER_PACKAGE_DOWNLOAD_LOCATION}.
+     *
+     * <p>Use in an intent with action {@link #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE}
+     * or in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+     * provisioning via an NFC bump.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_PROVISIONING_ROLE_HOLDER_PACKAGE_DOWNLOAD_COOKIE_HEADER =
+            "android.app.extra.PROVISIONING_ROLE_HOLDER_PACKAGE_DOWNLOAD_COOKIE_HEADER";
+
+    /**
+     * An extra of type {@link android.os.PersistableBundle} that allows the provisioning initiator
+     * to pass data to the device manager role holder.
+     *
+     * <p>The device manager role holder will receive this extra via the {@link
+     * #ACTION_ROLE_HOLDER_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE} intent.
+     *
+     * <p>The contents of this extra are up to the contract between the provisioning initiator
+     * and the device manager role holder.
+     *
+     * <p>Use in an intent with action {@link #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE}
+     * or in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+     * provisioning via an NFC bump.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_PROVISIONING_ROLE_HOLDER_EXTRAS_BUNDLE =
+            "android.app.extra.PROVISIONING_ROLE_HOLDER_EXTRAS_BUNDLE";
+
+    /**
+     * A String extra containing the package name of the provisioning initiator.
+     *
+     * <p>Use in an intent with action {@link
+     * #ACTION_ROLE_HOLDER_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE}.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_ROLE_HOLDER_PROVISIONING_INITIATOR_PACKAGE =
+            "android.app.extra.ROLE_HOLDER_PROVISIONING_INITIATOR_PACKAGE";
+
+    /**
+     * An {@link Intent} result extra specifying the {@link Intent} to be launched after
+     * provisioning is finalized.
+     *
+     * <p>If {@link #EXTRA_PROVISIONING_SHOULD_LAUNCH_RESULT_INTENT} is set to {@code false},
+     * this result will be supplied as part of the result {@link Intent} for provisioning actions
+     * such as {@link #ACTION_PROVISION_MANAGED_PROFILE}. This result will also be supplied as
+     * part of the result {@link Intent} for the device manager role holder provisioning actions.
+     */
+    public static final String EXTRA_RESULT_LAUNCH_INTENT =
+            "android.app.extra.RESULT_LAUNCH_INTENT";
+
+    /**
+     * A boolean extra that determines whether the provisioning flow should launch the resulting
+     * launch intent, if one is supplied by the device manager role holder via {@link
+     * #EXTRA_RESULT_LAUNCH_INTENT}. Default value is {@code false}.
+     *
+     * <p>If {@code true}, the resulting intent will be launched by the provisioning flow, if one
+     * is supplied by the device manager role holder.
+     *
+     * <p>If {@code false}, the resulting intent will be returned as {@link
+     * #EXTRA_RESULT_LAUNCH_INTENT} to the provisioning initiator, if one is supplied by the device
+     * manager role holder. It will be the responsibility of the provisioning initiator to launch
+     * this {@link Intent} after provisioning completes.
+     *
+     * <p>This extra is respected when provided via the provisioning intent actions such as {@link
+     * #ACTION_PROVISION_MANAGED_PROFILE}.
+     */
+    public static final String EXTRA_PROVISIONING_SHOULD_LAUNCH_RESULT_INTENT =
+            "android.app.extra.PROVISIONING_SHOULD_LAUNCH_RESULT_INTENT";
+
+    /**
      * Action: Bugreport sharing with device owner has been accepted by the user.
      *
      * @hide
@@ -3585,10 +3704,11 @@
     @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
             android.Manifest.permission.INTERACT_ACROSS_USERS})
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    @UserHandleAware
     public void acknowledgeNewUserDisclaimer() {
         if (mService != null) {
             try {
-                mService.acknowledgeNewUserDisclaimer();
+                mService.acknowledgeNewUserDisclaimer(mContext.getUserId());
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -3596,17 +3716,18 @@
     }
 
     /**
-     * Checks whether the new managed user disclaimer was viewed by the current user.
+     * Checks whether the new managed user disclaimer was viewed by the user.
      *
      * @hide
      */
     @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
             android.Manifest.permission.INTERACT_ACROSS_USERS})
     @TestApi
+    @UserHandleAware
     public boolean isNewUserDisclaimerAcknowledged() {
         if (mService != null) {
             try {
-                return mService.isNewUserDisclaimerAcknowledged();
+                return mService.isNewUserDisclaimerAcknowledged(mContext.getUserId());
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -15516,4 +15637,40 @@
             }
         }
     }
+
+    /**
+     * Returns the package name of the device manager role holder.
+     *
+     * <p>If the device manager role holder is not configured for this device, returns {@code null}.
+     */
+    @Nullable
+    public String getDeviceManagerRoleHolderPackageName() {
+        String deviceManagerConfig =
+                mContext.getString(com.android.internal.R.string.config_deviceManager);
+        return extractPackageNameFromDeviceManagerConfig(deviceManagerConfig);
+    }
+
+    /**
+     * Retrieves the package name for a given {@code deviceManagerConfig}.
+     *
+     * <p>Valid configs look like:
+     * <ul>
+     *     <li>{@code com.package.name}</li>
+     *     <li>{@code com.package.name:<SHA256 checksum>}</li>
+     * </ul>
+     *
+     * <p>If the supplied {@code deviceManagerConfig} is {@code null} or empty, returns
+     * {@code null}.
+     */
+    @Nullable
+    private String extractPackageNameFromDeviceManagerConfig(
+            @Nullable String deviceManagerConfig) {
+        if (TextUtils.isEmpty(deviceManagerConfig)) {
+            return null;
+        }
+        if (deviceManagerConfig.contains(":")) {
+            return deviceManagerConfig.split(":")[0];
+        }
+        return deviceManagerConfig;
+    }
 }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 0e1caca..eedc042 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -271,8 +271,8 @@
     int logoutUserInternal(); // AIDL doesn't allow overloading name (logoutUser())
     int getLogoutUserId();
     List<UserHandle> getSecondaryUsers(in ComponentName who);
-    void acknowledgeNewUserDisclaimer();
-    boolean isNewUserDisclaimerAcknowledged();
+    void acknowledgeNewUserDisclaimer(int userId);
+    boolean isNewUserDisclaimerAcknowledged(int userId);
 
     void enableSystemApp(in ComponentName admin, in String callerPackage, in String packageName);
     int enableSystemAppWithIntent(in ComponentName admin, in String callerPackage, in Intent intent);
diff --git a/core/java/android/app/ambientcontext/AmbientContextEventRequest.java b/core/java/android/app/ambientcontext/AmbientContextEventRequest.java
index 82b16a2..0557acb 100644
--- a/core/java/android/app/ambientcontext/AmbientContextEventRequest.java
+++ b/core/java/android/app/ambientcontext/AmbientContextEventRequest.java
@@ -23,6 +23,9 @@
 import android.os.PersistableBundle;
 import android.util.ArraySet;
 
+import com.android.internal.util.AnnotationValidations;
+import com.android.internal.util.Preconditions;
+
 import java.util.HashSet;
 import java.util.Set;
 
@@ -36,15 +39,17 @@
     @NonNull private final Set<Integer> mEventTypes;
     @NonNull private final PersistableBundle mOptions;
 
-    AmbientContextEventRequest(
+    private AmbientContextEventRequest(
             @NonNull Set<Integer> eventTypes,
             @NonNull PersistableBundle options) {
         this.mEventTypes = eventTypes;
-        com.android.internal.util.AnnotationValidations.validate(
-                NonNull.class, null, mEventTypes);
+        AnnotationValidations.validate(NonNull.class, null, mEventTypes);
+        Preconditions.checkArgument(!eventTypes.isEmpty(), "eventTypes cannot be empty");
+        for (int eventType : eventTypes) {
+            AnnotationValidations.validate(AmbientContextEvent.EventCode.class, null, eventType);
+        }
         this.mOptions = options;
-        com.android.internal.util.AnnotationValidations.validate(
-                NonNull.class, null, mOptions);
+        AnnotationValidations.validate(NonNull.class, null, mOptions);
     }
 
     /**
@@ -80,16 +85,20 @@
 
     /** @hide */
     @SuppressWarnings({"unchecked", "RedundantCast"})
-    AmbientContextEventRequest(@NonNull Parcel in) {
+    private AmbientContextEventRequest(@NonNull Parcel in) {
         Set<Integer> eventTypes = (Set<Integer>) in.readArraySet(Integer.class.getClassLoader());
         PersistableBundle options = (PersistableBundle) in.readTypedObject(
                 PersistableBundle.CREATOR);
 
         this.mEventTypes = eventTypes;
-        com.android.internal.util.AnnotationValidations.validate(
+        AnnotationValidations.validate(
                 NonNull.class, null, mEventTypes);
+        Preconditions.checkArgument(!eventTypes.isEmpty(), "eventTypes cannot be empty");
+        for (int eventType : eventTypes) {
+            AnnotationValidations.validate(AmbientContextEvent.EventCode.class, null, eventType);
+        }
         this.mOptions = options;
-        com.android.internal.util.AnnotationValidations.validate(
+        AnnotationValidations.validate(
                 NonNull.class, null, mOptions);
     }
 
diff --git a/core/java/android/app/ambientcontext/AmbientContextEventResponse.java b/core/java/android/app/ambientcontext/AmbientContextEventResponse.java
deleted file mode 100644
index 472a78b..0000000
--- a/core/java/android/app/ambientcontext/AmbientContextEventResponse.java
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright (C) 2022 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.ambientcontext;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.app.PendingIntent;
-import android.os.Parcelable;
-
-import com.android.internal.util.AnnotationValidations;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Represents a response from the {@code AmbientContextEvent} service.
- *
- * @hide
- */
-@SystemApi
-public final class AmbientContextEventResponse implements Parcelable {
-    /**
-     * An unknown status.
-     */
-    public static final int STATUS_UNKNOWN = 0;
-    /**
-     * The value of the status code that indicates success.
-     */
-    public static final int STATUS_SUCCESS = 1;
-    /**
-     * The value of the status code that indicates one or more of the
-     * requested events are not supported.
-     */
-    public static final int STATUS_NOT_SUPPORTED = 2;
-    /**
-     * The value of the status code that indicates service not available.
-     */
-    public static final int STATUS_SERVICE_UNAVAILABLE = 3;
-    /**
-     * The value of the status code that microphone is disabled.
-     */
-    public static final int STATUS_MICROPHONE_DISABLED = 4;
-    /**
-     * The value of the status code that the app is not granted access.
-     */
-    public static final int STATUS_ACCESS_DENIED = 5;
-
-    /** @hide */
-    @IntDef(prefix = { "STATUS_" }, value = {
-            STATUS_UNKNOWN,
-            STATUS_SUCCESS,
-            STATUS_NOT_SUPPORTED,
-            STATUS_SERVICE_UNAVAILABLE,
-            STATUS_MICROPHONE_DISABLED,
-            STATUS_ACCESS_DENIED
-    }) public @interface StatusCode {}
-
-    @StatusCode private final int mStatusCode;
-    @NonNull private final List<AmbientContextEvent> mEvents;
-    @NonNull private final String mPackageName;
-    @Nullable private final PendingIntent mActionPendingIntent;
-
-    /** @hide */
-    public static String statusToString(@StatusCode int value) {
-        switch (value) {
-            case STATUS_UNKNOWN:
-                return "STATUS_UNKNOWN";
-            case STATUS_SUCCESS:
-                return "STATUS_SUCCESS";
-            case STATUS_NOT_SUPPORTED:
-                return "STATUS_NOT_SUPPORTED";
-            case STATUS_SERVICE_UNAVAILABLE:
-                return "STATUS_SERVICE_UNAVAILABLE";
-            case STATUS_MICROPHONE_DISABLED:
-                return "STATUS_MICROPHONE_DISABLED";
-            case STATUS_ACCESS_DENIED:
-                return "STATUS_ACCESS_DENIED";
-            default: return Integer.toHexString(value);
-        }
-    }
-
-    AmbientContextEventResponse(
-            @StatusCode int statusCode,
-            @NonNull List<AmbientContextEvent> events,
-            @NonNull String packageName,
-            @Nullable PendingIntent actionPendingIntent) {
-        this.mStatusCode = statusCode;
-        AnnotationValidations.validate(StatusCode.class, null, mStatusCode);
-        this.mEvents = events;
-        AnnotationValidations.validate(NonNull.class, null, mEvents);
-        this.mPackageName = packageName;
-        AnnotationValidations.validate(NonNull.class, null, mPackageName);
-        this.mActionPendingIntent = actionPendingIntent;
-    }
-
-    /**
-     * The status of the response.
-     */
-    public @StatusCode int getStatusCode() {
-        return mStatusCode;
-    }
-
-    /**
-     * The detected event.
-     */
-    public @NonNull List<AmbientContextEvent> getEvents() {
-        return mEvents;
-    }
-
-    /**
-     * The package to deliver the response to.
-     */
-    public @NonNull String getPackageName() {
-        return mPackageName;
-    }
-
-    /**
-     * A {@link PendingIntent} that the client should call to allow further actions by user.
-     * For example, with {@link STATUS_ACCESS_DENIED}, the PendingIntent can redirect users to the
-     * grant access activity.
-     */
-    public @Nullable PendingIntent getActionPendingIntent() {
-        return mActionPendingIntent;
-    }
-
-    @Override
-    public String toString() {
-        return "AmbientContextEventResponse { " + "statusCode = " + mStatusCode + ", "
-                + "events = " + mEvents + ", " + "packageName = " + mPackageName + ", "
-                + "callbackPendingIntent = " + mActionPendingIntent + " }";
-    }
-
-    @Override
-    public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
-        byte flg = 0;
-        if (mActionPendingIntent != null) flg |= 0x8;
-        dest.writeByte(flg);
-        dest.writeInt(mStatusCode);
-        dest.writeParcelableList(mEvents, flags);
-        dest.writeString(mPackageName);
-        if (mActionPendingIntent != null) dest.writeTypedObject(mActionPendingIntent, flags);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    /** @hide */
-    @SuppressWarnings({"unchecked", "RedundantCast"})
-    AmbientContextEventResponse(@NonNull android.os.Parcel in) {
-        byte flg = in.readByte();
-        int statusCode = in.readInt();
-        List<AmbientContextEvent> events = new ArrayList<>();
-        in.readParcelableList(events, AmbientContextEvent.class.getClassLoader(),
-                AmbientContextEvent.class);
-        String packageName = in.readString();
-        PendingIntent callbackPendingIntent = (flg & 0x8) == 0 ? null
-                : (PendingIntent) in.readTypedObject(PendingIntent.CREATOR);
-
-        this.mStatusCode = statusCode;
-        AnnotationValidations.validate(
-                StatusCode.class, null, mStatusCode);
-        this.mEvents = events;
-        AnnotationValidations.validate(
-                NonNull.class, null, mEvents);
-        this.mPackageName = packageName;
-        AnnotationValidations.validate(
-                NonNull.class, null, mPackageName);
-        this.mActionPendingIntent = callbackPendingIntent;
-    }
-
-    public static final @NonNull Parcelable.Creator<AmbientContextEventResponse> CREATOR =
-            new Parcelable.Creator<AmbientContextEventResponse>() {
-        @Override
-        public AmbientContextEventResponse[] newArray(int size) {
-            return new AmbientContextEventResponse[size];
-        }
-
-        @Override
-        public AmbientContextEventResponse createFromParcel(@NonNull android.os.Parcel in) {
-            return new AmbientContextEventResponse(in);
-        }
-    };
-
-    /**
-     * A builder for {@link AmbientContextEventResponse}
-     */
-    @SuppressWarnings("WeakerAccess")
-    public static final class Builder {
-        private @StatusCode int mStatusCode;
-        private @NonNull List<AmbientContextEvent> mEvents;
-        private @NonNull String mPackageName;
-        private @Nullable PendingIntent mCallbackPendingIntent;
-        private long mBuilderFieldsSet = 0L;
-
-        public Builder() {
-        }
-
-        /**
-         * The status of the response.
-         */
-        public @NonNull Builder setStatusCode(@StatusCode int value) {
-            checkNotUsed();
-            mBuilderFieldsSet |= 0x1;
-            mStatusCode = value;
-            return this;
-        }
-
-        /**
-         * Adds an event to the builder.
-         */
-        public @NonNull Builder addEvent(@NonNull AmbientContextEvent value) {
-            checkNotUsed();
-            if (mEvents == null) {
-                mBuilderFieldsSet |= 0x2;
-                mEvents = new ArrayList<>();
-            }
-            mEvents.add(value);
-            return this;
-        }
-
-        /**
-         * The package to deliver the response to.
-         */
-        public @NonNull Builder setPackageName(@NonNull String value) {
-            checkNotUsed();
-            mBuilderFieldsSet |= 0x4;
-            mPackageName = value;
-            return this;
-        }
-
-        /**
-         * A {@link PendingIntent} that the client should call to allow further actions by user.
-         * For example, with {@link STATUS_ACCESS_DENIED}, the PendingIntent can redirect users to
-         * the grant access activity.
-         */
-        public @NonNull Builder setActionPendingIntent(@NonNull PendingIntent value) {
-            checkNotUsed();
-            mBuilderFieldsSet |= 0x8;
-            mCallbackPendingIntent = value;
-            return this;
-        }
-
-        /** Builds the instance. This builder should not be touched after calling this! */
-        public @NonNull AmbientContextEventResponse build() {
-            checkNotUsed();
-            mBuilderFieldsSet |= 0x10; // Mark builder used
-
-            if ((mBuilderFieldsSet & 0x1) == 0) {
-                mStatusCode = STATUS_UNKNOWN;
-            }
-            if ((mBuilderFieldsSet & 0x2) == 0) {
-                mEvents = new ArrayList<>();
-            }
-            if ((mBuilderFieldsSet & 0x4) == 0) {
-                mPackageName = "";
-            }
-            if ((mBuilderFieldsSet & 0x8) == 0) {
-                mCallbackPendingIntent = null;
-            }
-            AmbientContextEventResponse o = new AmbientContextEventResponse(
-                    mStatusCode,
-                    mEvents,
-                    mPackageName,
-                    mCallbackPendingIntent);
-            return o;
-        }
-
-        private void checkNotUsed() {
-            if ((mBuilderFieldsSet & 0x10) != 0) {
-                throw new IllegalStateException(
-                        "This Builder should not be reused. Use a new Builder instance instead");
-            }
-        }
-    }
-}
diff --git a/core/java/android/app/ambientcontext/AmbientContextManager.java b/core/java/android/app/ambientcontext/AmbientContextManager.java
index 6841d1b..7f913e7 100644
--- a/core/java/android/app/ambientcontext/AmbientContextManager.java
+++ b/core/java/android/app/ambientcontext/AmbientContextManager.java
@@ -17,116 +17,280 @@
 package android.app.ambientcontext;
 
 import android.Manifest;
+import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
+import android.os.Binder;
+import android.os.RemoteCallback;
 import android.os.RemoteException;
 
 import com.android.internal.util.Preconditions;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
 /**
- * Allows granted apps to register for particular pre-defined {@link AmbientContextEvent}s.
- * After successful registration, the app receives a callback on the provided {@link PendingIntent}
- * when the requested event is detected.
- * <p />
- *
- * Example:
- *
- * <pre><code>
- *     // Create request
- *     AmbientContextEventRequest request = new AmbientContextEventRequest.Builder()
- *         .addEventType(AmbientContextEvent.EVENT_COUGH)
- *         .addEventTYpe(AmbientContextEvent.EVENT_SNORE)
- *         .build();
- *     // Create PendingIntent
- *     Intent intent = new Intent(actionString, null, context, MyBroadcastReceiver.class)
- *         .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- *     PendingIntent pendingIntent = PendingIntents.getBroadcastMutable(context, 0, intent, 0);
- *     // Register for events
- *     AmbientContextManager ambientContextManager =
- *         context.getSystemService(AmbientContextManager.class);
- *    ambientContextManager.registerObserver(request, pendingIntent);
- *
- *    // Handle the callback intent in your receiver
- *    {@literal @}Override
- *    protected void onReceive(Context context, Intent intent) {
- *      AmbientContextEventResponse response =
- *          AmbientContextManager.getResponseFromIntent(intent);
- *      if (response != null) {
- *        if (response.getStatusCode() == AmbientContextEventResponse.STATUS_SUCCESS) {
- *          // Do something useful with response.getEvent()
- *        } else if (response.getStatusCode() == AmbientContextEventResponse.STATUS_ACCESS_DENIED) {
- *          // Redirect users to grant access
- *          PendingIntent callbackPendingIntent = response.getCallbackPendingIntent();
- *          if (callbackPendingIntent != null) {
- *            callbackPendingIntent.send();
- *          }
- *        } else ...
- *      }
- *    }
- * </code></pre>
+ * Allows granted apps to register for event types defined in {@link AmbientContextEvent}.
+ * After registration, the app receives a Consumer callback of the service status.
+ * If it is {@link STATUS_SUCCESSFUL}, when the requested events are detected, the provided
+ * {@link PendingIntent} callback will receive the list of detected {@link AmbientContextEvent}s.
+ * If it is {@link STATUS_ACCESS_DENIED}, the app can call {@link #startConsentActivity}
+ * to load the consent screen.
  *
  * @hide
  */
 @SystemApi
 @SystemService(Context.AMBIENT_CONTEXT_SERVICE)
 public final class AmbientContextManager {
-
     /**
-     * The key of an Intent extra indicating the response.
+     * The bundle key for the service status query result, used in
+     * {@code RemoteCallback#sendResult}.
+     *
+     * @hide
      */
-    public static final String EXTRA_AMBIENT_CONTEXT_EVENT_RESPONSE =
-            "android.app.ambientcontext.extra.AMBIENT_CONTEXT_EVENT_RESPONSE";
+    public static final String STATUS_RESPONSE_BUNDLE_KEY =
+            "android.app.ambientcontext.AmbientContextStatusBundleKey";
 
     /**
-     * Allows clients to retrieve the response from the intent.
+     * The key of an intent extra indicating a list of detected {@link AmbientContextEvent}s.
+     * The intent is sent to the app in the app's registered {@link PendingIntent}.
+     */
+    public static final String EXTRA_AMBIENT_CONTEXT_EVENTS =
+            "android.app.ambientcontext.extra.AMBIENT_CONTEXT_EVENTS";
+
+    /**
+     * An unknown status.
+     */
+    public static final int STATUS_UNKNOWN = 0;
+
+    /**
+     * The value of the status code that indicates success.
+     */
+    public static final int STATUS_SUCCESS = 1;
+
+    /**
+     * The value of the status code that indicates one or more of the
+     * requested events are not supported.
+     */
+    public static final int STATUS_NOT_SUPPORTED = 2;
+
+    /**
+     * The value of the status code that indicates service not available.
+     */
+    public static final int STATUS_SERVICE_UNAVAILABLE = 3;
+
+    /**
+     * The value of the status code that microphone is disabled.
+     */
+    public static final int STATUS_MICROPHONE_DISABLED = 4;
+
+    /**
+     * The value of the status code that the app is not granted access.
+     */
+    public static final int STATUS_ACCESS_DENIED = 5;
+
+    /** @hide */
+    @IntDef(prefix = { "STATUS_" }, value = {
+            STATUS_UNKNOWN,
+            STATUS_SUCCESS,
+            STATUS_NOT_SUPPORTED,
+            STATUS_SERVICE_UNAVAILABLE,
+            STATUS_MICROPHONE_DISABLED,
+            STATUS_ACCESS_DENIED
+    }) public @interface StatusCode {}
+
+    /**
+     * Allows clients to retrieve the list of {@link AmbientContextEvent}s from the intent.
+     *
      * @param intent received from the PendingIntent callback
      *
-     * @return the AmbientContextEventResponse, or null if not present
+     * @return the list of events, or an empty list if the intent doesn't have such events.
      */
-    @Nullable
-    public static AmbientContextEventResponse getResponseFromIntent(
-            @NonNull Intent intent) {
-        if (intent.hasExtra(AmbientContextManager.EXTRA_AMBIENT_CONTEXT_EVENT_RESPONSE)) {
-            return intent.getParcelableExtra(EXTRA_AMBIENT_CONTEXT_EVENT_RESPONSE);
+    @NonNull public static List<AmbientContextEvent> getEventsFromIntent(@NonNull Intent intent) {
+        if (intent.hasExtra(AmbientContextManager.EXTRA_AMBIENT_CONTEXT_EVENTS)) {
+            return intent.getParcelableArrayListExtra(EXTRA_AMBIENT_CONTEXT_EVENTS);
         } else {
-            return null;
+            return new ArrayList<>();
         }
     }
 
     private final Context mContext;
-    private final IAmbientContextEventObserver mService;
+    private final IAmbientContextManager mService;
 
     /**
      * {@hide}
      */
-    public AmbientContextManager(Context context, IAmbientContextEventObserver service) {
+    public AmbientContextManager(Context context, IAmbientContextManager service) {
         mContext = context;
         mService = service;
     }
 
     /**
+     * Queries the {@link AmbientContextEvent} service status for the calling package, and
+     * sends the result to the {@link Consumer} right after the call. This is used by foreground
+     * apps to check whether the requested events are enabled for detection on the device.
+     * If all events are enabled for detection, the response has
+     * {@link AmbientContextManager#STATUS_SUCCESS}.
+     * If any of the events are not consented by user, the response has
+     * {@link AmbientContextManager#STATUS_ACCESS_DENIED}, and the app can
+     * call {@link #startConsentActivity} to redirect the user to the consent screen.
+     * <p />
+     *
+     * Example:
+     *
+     * <pre><code>
+     *   Set<Integer> eventTypes = new HashSet<>();
+     *   eventTypes.add(AmbientContextEvent.EVENT_COUGH);
+     *   eventTypes.add(AmbientContextEvent.EVENT_SNORE);
+     *
+     *   // Create Consumer
+     *   Consumer<Integer> statusConsumer = response -> {
+     *     int status = status.getStatusCode();
+     *     if (status == AmbientContextManager.STATUS_SUCCESS) {
+     *       // Show user it's enabled
+     *     } else if (status == AmbientContextManager.STATUS_ACCESS_DENIED) {
+     *       // Send user to grant access
+     *       startConsentActivity(eventTypes);
+     *     }
+     *   };
+     *
+     *   // Query status
+     *   AmbientContextManager ambientContextManager =
+     *       context.getSystemService(AmbientContextManager.class);
+     *   ambientContextManager.queryAmbientContextStatus(eventTypes, executor, statusConsumer);
+     * </code></pre>
+     *
+     * @param eventTypes The set of event codes to check status on.
+     * @param executor Executor on which to run the consumer callback.
+     * @param consumer The consumer that handles the status code.
+     */
+    @RequiresPermission(Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT)
+    public void queryAmbientContextServiceStatus(
+            @NonNull @AmbientContextEvent.EventCode Set<Integer> eventTypes,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull @StatusCode Consumer<Integer> consumer) {
+        try {
+            RemoteCallback callback = new RemoteCallback(result -> {
+                int status = result.getInt(STATUS_RESPONSE_BUNDLE_KEY);
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    executor.execute(() -> consumer.accept(status));
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            });
+            mService.queryServiceStatus(integerSetToIntArray(eventTypes),
+                    mContext.getOpPackageName(), callback);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Requests the consent data host to open an activity that allows users to modify consent.
+     *
+     * @param eventTypes The set of event codes to be consented.
+     */
+    @RequiresPermission(Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT)
+    public void startConsentActivity(
+            @NonNull @AmbientContextEvent.EventCode Set<Integer> eventTypes) {
+        try {
+            mService.startConsentActivity(
+                    integerSetToIntArray(eventTypes), mContext.getOpPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    @NonNull
+    private static int[] integerSetToIntArray(@NonNull Set<Integer> integerSet) {
+        int[] intArray = new int[integerSet.size()];
+        int i = 0;
+        for (Integer type : integerSet) {
+            intArray[i++] = type;
+        }
+        return intArray;
+    }
+
+    /**
      * Allows app to register as a {@link AmbientContextEvent} observer. The
      * observer receives a callback on the provided {@link PendingIntent} when the requested
      * event is detected. Registering another observer from the same package that has already been
      * registered will override the previous observer.
+     * <p />
+     *
+     * Example:
+     *
+     * <pre><code>
+     *   // Create request
+     *   AmbientContextEventRequest request = new AmbientContextEventRequest.Builder()
+     *       .addEventType(AmbientContextEvent.EVENT_COUGH)
+     *       .addEventType(AmbientContextEvent.EVENT_SNORE)
+     *       .build();
+     *
+     *   // Create PendingIntent for delivering detection results to my receiver
+     *   Intent intent = new Intent(actionString, null, context, MyBroadcastReceiver.class)
+     *       .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+     *   PendingIntent pendingIntent =
+     *       PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+     *
+     *   // Create Consumer of service status
+     *   Consumer<Integer> statusConsumer = status -> {
+     *       if (status == AmbientContextManager.STATUS_ACCESS_DENIED) {
+     *         // User did not consent event detection. See #queryAmbientContextServiceStatus and
+     *         // #startConsentActivity
+     *       }
+     *   };
+     *
+     *   // Register as observer
+     *   AmbientContextManager ambientContextManager =
+     *       context.getSystemService(AmbientContextManager.class);
+     *   ambientContextManager.registerObserver(request, pendingIntent, executor, statusConsumer);
+     *
+     *   // Handle the list of {@link AmbientContextEvent}s in your receiver
+     *   {@literal @}Override
+     *   protected void onReceive(Context context, Intent intent) {
+     *     List<AmbientContextEvent> events = AmbientContextManager.getEventsFromIntent(intent);
+     *     if (!events.isEmpty()) {
+     *       // Do something useful with the events.
+     *     }
+     *   }
+     * </code></pre>
      *
      * @param request The request with events to observe.
-     * @param pendingIntent A mutable {@link PendingIntent} that will be dispatched when any
-     *                     requested event is detected.
+     * @param resultPendingIntent A mutable {@link PendingIntent} that will be dispatched after the
+     *                            requested events are detected.
+     * @param executor Executor on which to run the consumer callback.
+     * @param statusConsumer A consumer that handles the status code, which is returned
+     *                      right after the call.
      */
     @RequiresPermission(Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT)
     public void registerObserver(
             @NonNull AmbientContextEventRequest request,
-            @NonNull PendingIntent pendingIntent) {
-        Preconditions.checkArgument(!pendingIntent.isImmutable());
+            @NonNull PendingIntent resultPendingIntent,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull @StatusCode Consumer<Integer> statusConsumer) {
+        Preconditions.checkArgument(!resultPendingIntent.isImmutable());
         try {
-            mService.registerObserver(request, pendingIntent);
+            RemoteCallback callback = new RemoteCallback(result -> {
+                int statusCode =  result.getInt(STATUS_RESPONSE_BUNDLE_KEY);
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    executor.execute(() -> statusConsumer.accept(statusCode));
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            });
+            mService.registerObserver(request, resultPendingIntent, callback);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/ambientcontext/IAmbientContextEventObserver.aidl b/core/java/android/app/ambientcontext/IAmbientContextManager.aidl
similarity index 66%
rename from core/java/android/app/ambientcontext/IAmbientContextEventObserver.aidl
rename to core/java/android/app/ambientcontext/IAmbientContextManager.aidl
index 9032fe1..3b15bcb 100644
--- a/core/java/android/app/ambientcontext/IAmbientContextEventObserver.aidl
+++ b/core/java/android/app/ambientcontext/IAmbientContextManager.aidl
@@ -18,13 +18,19 @@
 
 import android.app.PendingIntent;
 import android.app.ambientcontext.AmbientContextEventRequest;
+import android.os.RemoteCallback;
 
 /**
- * Interface for an AmbientContextEventManager that provides access to AmbientContextEvents.
+ * Interface for an AmbientContextManager that provides access to AmbientContextEvents.
  *
  * @hide
  */
-oneway interface IAmbientContextEventObserver {
-    void registerObserver(in AmbientContextEventRequest request, in PendingIntent pendingIntent);
+oneway interface IAmbientContextManager {
+    void registerObserver(in AmbientContextEventRequest request,
+        in PendingIntent resultPendingIntent,
+        in RemoteCallback statusCallback);
     void unregisterObserver(in String callingPackage);
+    void queryServiceStatus(in int[] eventTypes, in String callingPackage,
+        in RemoteCallback statusCallback);
+    void startConsentActivity(in int[] eventTypes, in String callingPackage);
 }
\ No newline at end of file
diff --git a/core/java/android/app/assist/ActivityId.java b/core/java/android/app/assist/ActivityId.java
index fb0d056..1cc4b02 100644
--- a/core/java/android/app/assist/ActivityId.java
+++ b/core/java/android/app/assist/ActivityId.java
@@ -22,6 +22,7 @@
 import android.annotation.TestApi;
 import android.os.IBinder;
 import android.os.Parcel;
+import android.os.Parcelable;
 import android.service.contentcapture.ContentCaptureService;
 import android.view.contentcapture.ContentCaptureContext;
 import android.view.translation.UiTranslationManager;
@@ -38,7 +39,8 @@
  */
 @Immutable
 @SystemApi
-public class ActivityId {
+@TestApi
+public final class ActivityId implements Parcelable {
 
     /**
      * The identifier of the task this activity is in.
@@ -53,6 +55,7 @@
     /**
      * @hide
      */
+    @TestApi
     public ActivityId(int taskId, @Nullable IBinder activityId) {
         mTaskId = taskId;
         mActivityId = activityId;
@@ -87,13 +90,39 @@
     }
 
     /**
-     * @hide
+     * {@inheritDoc}
      */
-    public void writeToParcel(@NonNull Parcel dest, int parcelableFlags) {
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeInt(mTaskId);
         dest.writeStrongBinder(mActivityId);
     }
 
+    /**
+     * Creates {@link ActivityId} instances from parcels.
+     */
+    @NonNull
+    public static final Parcelable.Creator<ActivityId> CREATOR =
+            new Parcelable.Creator<ActivityId>() {
+                @Override
+                public ActivityId createFromParcel(Parcel parcel) {
+                    return new ActivityId(parcel);
+                }
+
+                @Override
+                public ActivityId[] newArray(int size) {
+                    return new ActivityId[size];
+                }
+            };
+
     @Override
     public String toString() {
         return "ActivityId { taskId = " + mTaskId + ", activityId = " + mActivityId + " }";
diff --git a/core/java/android/companion/AssociationRequest.java b/core/java/android/companion/AssociationRequest.java
index bd8ba9e..257530b 100644
--- a/core/java/android/companion/AssociationRequest.java
+++ b/core/java/android/companion/AssociationRequest.java
@@ -260,9 +260,9 @@
     }
 
     /**
-     * Indicates that the application would prefer the CompanionDeviceManager to collect an explicit
-     * confirmation from the user before creating an association, even if such confirmation is not
-     * required.
+     * Indicates whether the application requires the {@link CompanionDeviceManager} service to
+     * collect an explicit confirmation from the user before creating an association, even if
+     * such confirmation is not required from the service's perspective.
      *
      * @see Builder#setForceConfirmation(boolean)
      */
@@ -391,9 +391,9 @@
         }
 
         /**
-         * Indicates whether the application would prefer the CompanionDeviceManager to collect an
-         * explicit confirmation from the user before creating an association, even if such
-         * confirmation is not required.
+         * Indicates whether the application requires the {@link CompanionDeviceManager} service to
+         * collect an explicit confirmation from the user before creating an association, even if
+         * such confirmation is not required from the service's perspective.
          */
         @RequiresPermission(REQUEST_COMPANION_SELF_MANAGED)
         @NonNull
diff --git a/core/java/android/companion/virtual/VirtualDeviceParams.java b/core/java/android/companion/virtual/VirtualDeviceParams.java
index 1d0f7c0..45d0ad5 100644
--- a/core/java/android/companion/virtual/VirtualDeviceParams.java
+++ b/core/java/android/companion/virtual/VirtualDeviceParams.java
@@ -48,15 +48,16 @@
 
     /** @hide */
     @IntDef(prefix = "LOCK_STATE_",
-            value = {LOCK_STATE_ALWAYS_LOCKED, LOCK_STATE_ALWAYS_UNLOCKED})
+            value = {LOCK_STATE_DEFAULT, LOCK_STATE_ALWAYS_UNLOCKED})
     @Retention(RetentionPolicy.SOURCE)
     @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
     public @interface LockState {}
 
     /**
-     * Indicates that the lock state of the virtual device should be always locked.
+     * Indicates that the lock state of the virtual device will be the same as the default physical
+     * display.
      */
-    public static final int LOCK_STATE_ALWAYS_LOCKED = 0;
+    public static final int LOCK_STATE_DEFAULT = 0;
 
     /**
      * Indicates that the lock state of the virtual device should be always unlocked.
@@ -199,7 +200,7 @@
      */
     public static final class Builder {
 
-        private @LockState int mLockState = LOCK_STATE_ALWAYS_LOCKED;
+        private @LockState int mLockState = LOCK_STATE_DEFAULT;
         private Set<UserHandle> mUsersWithMatchingAccounts;
         @Nullable private Set<ComponentName> mBlockedActivities;
         @Nullable private Set<ComponentName> mAllowedActivities;
@@ -207,9 +208,9 @@
         /**
          * Sets the lock state of the device. The permission {@code ADD_ALWAYS_UNLOCKED_DISPLAY}
          * is required if this is set to {@link #LOCK_STATE_ALWAYS_UNLOCKED}.
-         * The default is {@link #LOCK_STATE_ALWAYS_LOCKED}.
+         * The default is {@link #LOCK_STATE_DEFAULT}.
          *
-         * @param lockState The lock state, either {@link #LOCK_STATE_ALWAYS_LOCKED} or
+         * @param lockState The lock state, either {@link #LOCK_STATE_DEFAULT} or
          *   {@link #LOCK_STATE_ALWAYS_UNLOCKED}.
          */
         @RequiresPermission(value = ADD_ALWAYS_UNLOCKED_DISPLAY, conditional = true)
diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
index eccbb40..75356d1 100644
--- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
@@ -41,7 +41,9 @@
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethodSession;
 
-class IInputMethodSessionWrapper extends IInputMethodSession.Stub
+/** @hide */
+// TODO(b/215636776): move IInputMethodSessionWrapper to proper package
+public class IInputMethodSessionWrapper extends IInputMethodSession.Stub
         implements HandlerCaller.Callback {
     private static final String TAG = "InputMethodWrapper";
 
diff --git a/core/java/android/inputmethodservice/InputMethodServiceInternal.java b/core/java/android/inputmethodservice/InputMethodServiceInternal.java
index 7cd4ff6..09dbb2735 100644
--- a/core/java/android/inputmethodservice/InputMethodServiceInternal.java
+++ b/core/java/android/inputmethodservice/InputMethodServiceInternal.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.content.Context;
 import android.os.Bundle;
 import android.view.inputmethod.InputConnection;
@@ -31,8 +32,11 @@
  * framework classes for internal use.
  *
  * <p>CAVEATS: {@link AbstractInputMethodService} does not support all the methods here.</p>
+ *
+ * @hide
  */
-interface InputMethodServiceInternal {
+// TODO(b/215636776): move InputMethodServiceInternal to proper package
+public interface InputMethodServiceInternal {
     /**
      * @return {@link Context} associated with the service.
      */
@@ -70,7 +74,8 @@
      * closed for you after you return.
      * @param args additional arguments to the dump request.
      */
-    default void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
+    default void dump(@SuppressLint("UseParcelFileDescriptor") @NonNull FileDescriptor fd,
+            @NonNull PrintWriter fout, @NonNull String[] args) {
     }
 
     /**
@@ -81,6 +86,6 @@
      * @param where {@code where} parameter to be passed.
      * @param icProto {@code icProto} parameter to be passed.
      */
-    default void triggerServiceDump(String where, @Nullable byte[] icProto) {
+    default void triggerServiceDump(@NonNull String where, @Nullable byte[] icProto) {
     }
 }
diff --git a/core/java/android/inputmethodservice/RemoteInputConnection.java b/core/java/android/inputmethodservice/RemoteInputConnection.java
index 9ef2579..6b7815d 100644
--- a/core/java/android/inputmethodservice/RemoteInputConnection.java
+++ b/core/java/android/inputmethodservice/RemoteInputConnection.java
@@ -53,8 +53,11 @@
  *
  * <p>See also {@link IInputContext} for the actual {@link android.os.Binder} IPC protocols under
  * the hood.</p>
+ *
+ * @hide
  */
-final class RemoteInputConnection implements InputConnection {
+// TODO(b/215636776): move RemoteInputConnection to proper package
+public final class RemoteInputConnection implements InputConnection {
     private static final String TAG = "RemoteInputConnection";
 
     private static final int MAX_WAIT_TIME_MILLIS = 2000;
@@ -95,7 +98,7 @@
     @NonNull
     private final CancellationGroup mCancellationGroup;
 
-    RemoteInputConnection(
+    public RemoteInputConnection(
             @NonNull WeakReference<InputMethodServiceInternal> inputMethodService,
             IInputContext inputContext, @NonNull CancellationGroup cancellationGroup) {
         mImsInternal = new InputMethodServiceInternalHolder(inputMethodService);
@@ -108,7 +111,7 @@
         return mInvoker.isSameConnection(inputContext);
     }
 
-    RemoteInputConnection(@NonNull RemoteInputConnection original, int sessionId) {
+    public RemoteInputConnection(@NonNull RemoteInputConnection original, int sessionId) {
         mImsInternal = original.mImsInternal;
         mInvoker = original.mInvoker.cloneWithSessionId(sessionId);
         mCancellationGroup = original.mCancellationGroup;
diff --git a/core/java/android/net/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java
index ec752fd..0fd3e03 100644
--- a/core/java/android/net/Ikev2VpnProfile.java
+++ b/core/java/android/net/Ikev2VpnProfile.java
@@ -547,7 +547,8 @@
         if (profile.excludeLocalRoutes && !profile.isBypassable) {
             Log.w(TAG, "ExcludeLocalRoutes should only be set in the bypassable VPN");
         }
-        builder.setExcludeLocalRoutes(profile.excludeLocalRoutes && profile.isBypassable);
+
+        builder.setLocalRoutesExcluded(profile.excludeLocalRoutes && profile.isBypassable);
         builder.setRequiresInternetValidation(profile.requiresInternetValidation);
 
         return builder.build();
@@ -1104,7 +1105,7 @@
          */
         @NonNull
         @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
-        public Builder setExcludeLocalRoutes(boolean excludeLocalRoutes) {
+        public Builder setLocalRoutesExcluded(boolean excludeLocalRoutes) {
             mExcludeLocalRoutes = excludeLocalRoutes;
             return this;
         }
diff --git a/core/java/android/net/PlatformVpnProfile.java b/core/java/android/net/PlatformVpnProfile.java
index 8bd1c8d..c0fb4cf 100644
--- a/core/java/android/net/PlatformVpnProfile.java
+++ b/core/java/android/net/PlatformVpnProfile.java
@@ -83,7 +83,7 @@
     /**
      * Returns whether the local traffic is exempted from the VPN.
      */
-    public final boolean getExcludeLocalRoutes() {
+    public final boolean areLocalRoutesExcluded() {
         return mExcludeLocalRoutes;
     }
 
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index f1d4ba0..de1dc80 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -52,10 +52,9 @@
 import android.view.Display;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.os.BatterySipper;
-import com.android.internal.os.BatteryStatsHelper;
 import com.android.internal.os.BatteryUsageStatsProvider;
-import com.android.internal.os.PowerCalculator;
+
+import com.google.android.collect.Lists;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -70,6 +69,7 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 
 /**
@@ -3539,6 +3539,44 @@
         }
     }
 
+    /**
+     * Converts charge in mAh to string.
+     */
+    public static String formatCharge(double power) {
+        return formatValue(power);
+    }
+
+    /**
+     * Converts double to string, limiting small values to 3 significant figures.
+     */
+    private static String formatValue(double value) {
+        if (value == 0) return "0";
+
+        final String format;
+        if (value < .00001) {
+            format = "%.8f";
+        } else if (value < .0001) {
+            format = "%.7f";
+        } else if (value < .001) {
+            format = "%.6f";
+        } else if (value < .01) {
+            format = "%.5f";
+        } else if (value < .1) {
+            format = "%.4f";
+        } else if (value < 1) {
+            format = "%.3f";
+        } else if (value < 10) {
+            format = "%.2f";
+        } else if (value < 100) {
+            format = "%.1f";
+        } else {
+            format = "%.0f";
+        }
+
+        // Use English locale because this is never used in UI (only in checkin and dump).
+        return String.format(Locale.ENGLISH, format, value);
+    }
+
     private static long roundUsToMs(long timeUs) {
         return (timeUs + 500) / 1000;
     }
@@ -4025,7 +4063,7 @@
             sb.append("     ");
             sb.append(controllerName);
             sb.append(" Battery drain: ").append(
-                    PowerCalculator.formatCharge(powerDrainMaMs / MILLISECONDS_IN_HOUR));
+                    formatCharge(powerDrainMaMs / MILLISECONDS_IN_HOUR));
             sb.append("mAh");
             pw.println(sb.toString());
         }
@@ -4424,10 +4462,10 @@
 
         final BatteryUsageStats stats = getBatteryUsageStats(context);
         dumpLine(pw, 0 /* uid */, category, POWER_USE_SUMMARY_DATA,
-                PowerCalculator.formatCharge(stats.getBatteryCapacity()),
-                PowerCalculator.formatCharge(stats.getConsumedPower()),
-                PowerCalculator.formatCharge(stats.getDischargedPowerRange().getLower()),
-                PowerCalculator.formatCharge(stats.getDischargedPowerRange().getUpper()));
+                formatCharge(stats.getBatteryCapacity()),
+                formatCharge(stats.getConsumedPower()),
+                formatCharge(stats.getDischargedPowerRange().getLower()),
+                formatCharge(stats.getDischargedPowerRange().getUpper()));
         final BatteryConsumer deviceConsumer = stats.getAggregateBatteryConsumer(
                 BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE);
         for (@BatteryConsumer.PowerComponent int powerComponent = 0;
@@ -4437,7 +4475,7 @@
                 label = "???";
             }
             dumpLine(pw, 0 /* uid */, category, POWER_USE_ITEM_DATA, label,
-                    PowerCalculator.formatCharge(deviceConsumer.getConsumedPower(powerComponent)),
+                    formatCharge(deviceConsumer.getConsumedPower(powerComponent)),
                     shouldHidePowerComponent(powerComponent) ? 1 : 0, "0", "0");
         }
 
@@ -4447,11 +4485,10 @@
         for (int i = 0; i < uidBatteryConsumers.size(); i++) {
             UidBatteryConsumer consumer = uidBatteryConsumers.get(i);
             dumpLine(pw, consumer.getUid(), category, POWER_USE_ITEM_DATA, "uid",
-                    PowerCalculator.formatCharge(consumer.getConsumedPower()),
+                    formatCharge(consumer.getConsumedPower()),
                     proportionalAttributionCalculator.isSystemBatteryConsumer(consumer) ? 1 : 0,
-                    PowerCalculator.formatCharge(
-                            consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN)),
-                    PowerCalculator.formatCharge(
+                    formatCharge(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN)),
+                    formatCharge(
                             proportionalAttributionCalculator.getProportionalPowerMah(consumer)));
         }
 
@@ -4885,11 +4922,11 @@
     }
 
     private void printmAh(PrintWriter printer, double power) {
-        printer.print(PowerCalculator.formatCharge(power));
+        printer.print(formatCharge(power));
     }
 
     private void printmAh(StringBuilder sb, double power) {
-        sb.append(PowerCalculator.formatCharge(power));
+        sb.append(formatCharge(power));
     }
 
     /**
@@ -4936,7 +4973,7 @@
             sb.setLength(0);
             sb.append(prefix);
                 sb.append("  Estimated battery capacity: ");
-            sb.append(PowerCalculator.formatCharge(estimatedBatteryCapacity));
+            sb.append(formatCharge(estimatedBatteryCapacity));
                 sb.append(" mAh");
             pw.println(sb.toString());
         }
@@ -4946,7 +4983,7 @@
             sb.setLength(0);
             sb.append(prefix);
             sb.append("  Last learned battery capacity: ");
-            sb.append(PowerCalculator.formatCharge(lastLearnedBatteryCapacity / 1000));
+            sb.append(formatCharge(lastLearnedBatteryCapacity / 1000));
             sb.append(" mAh");
             pw.println(sb.toString());
         }
@@ -4955,7 +4992,7 @@
             sb.setLength(0);
             sb.append(prefix);
             sb.append("  Min learned battery capacity: ");
-            sb.append(PowerCalculator.formatCharge(minLearnedBatteryCapacity / 1000));
+            sb.append(formatCharge(minLearnedBatteryCapacity / 1000));
             sb.append(" mAh");
             pw.println(sb.toString());
         }
@@ -4964,7 +5001,7 @@
             sb.setLength(0);
             sb.append(prefix);
             sb.append("  Max learned battery capacity: ");
-            sb.append(PowerCalculator.formatCharge(maxLearnedBatteryCapacity / 1000));
+            sb.append(formatCharge(maxLearnedBatteryCapacity / 1000));
             sb.append(" mAh");
             pw.println(sb.toString());
         }
@@ -5028,7 +5065,7 @@
             sb.setLength(0);
             sb.append(prefix);
                 sb.append("  Discharge: ");
-            sb.append(PowerCalculator.formatCharge(dischargeCount / 1000.0));
+            sb.append(formatCharge(dischargeCount / 1000.0));
                 sb.append(" mAh");
             pw.println(sb.toString());
         }
@@ -5038,7 +5075,7 @@
             sb.setLength(0);
             sb.append(prefix);
                 sb.append("  Screen off discharge: ");
-            sb.append(PowerCalculator.formatCharge(dischargeScreenOffCount / 1000.0));
+            sb.append(formatCharge(dischargeScreenOffCount / 1000.0));
                 sb.append(" mAh");
             pw.println(sb.toString());
         }
@@ -5048,7 +5085,7 @@
             sb.setLength(0);
             sb.append(prefix);
             sb.append("  Screen doze discharge: ");
-            sb.append(PowerCalculator.formatCharge(dischargeScreenDozeCount / 1000.0));
+            sb.append(formatCharge(dischargeScreenDozeCount / 1000.0));
             sb.append(" mAh");
             pw.println(sb.toString());
         }
@@ -5058,7 +5095,7 @@
             sb.setLength(0);
             sb.append(prefix);
                 sb.append("  Screen on discharge: ");
-            sb.append(PowerCalculator.formatCharge(dischargeScreenOnCount / 1000.0));
+            sb.append(formatCharge(dischargeScreenOnCount / 1000.0));
                 sb.append(" mAh");
             pw.println(sb.toString());
         }
@@ -5068,7 +5105,7 @@
             sb.setLength(0);
             sb.append(prefix);
             sb.append("  Device light doze discharge: ");
-            sb.append(PowerCalculator.formatCharge(dischargeLightDozeCount / 1000.0));
+            sb.append(formatCharge(dischargeLightDozeCount / 1000.0));
             sb.append(" mAh");
             pw.println(sb.toString());
         }
@@ -5078,7 +5115,7 @@
             sb.setLength(0);
             sb.append(prefix);
             sb.append("  Device deep doze discharge: ");
-            sb.append(PowerCalculator.formatCharge(dischargeDeepDozeCount / 1000.0));
+            sb.append(formatCharge(dischargeDeepDozeCount / 1000.0));
             sb.append(" mAh");
             pw.println(sb.toString());
         }
@@ -5212,7 +5249,7 @@
         for (int iu = 0; iu < NU; iu++) {
             final Uid u = uidStats.valueAt(iu);
 
-            final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelocks
+            final ArrayMap<String, ? extends Uid.Wakelock> wakelocks
                     = u.getWakelockStats();
             for (int iw=wakelocks.size()-1; iw>=0; iw--) {
                 final Uid.Wakelock wl = wakelocks.valueAt(iw);
@@ -5621,34 +5658,38 @@
                         .build());
         stats.dump(pw, prefix);
 
-        final BatteryStatsHelper helper = new BatteryStatsHelper(context, false, wifiOnly);
-        helper.create(this);
-        helper.refreshStats(which, UserHandle.USER_ALL);
-
-        final List<BatterySipper> sippers = helper.getMobilemsppList();
-        if (sippers != null && sippers.size() > 0) {
-            pw.print(prefix); pw.println("  Per-app mobile ms per packet:");
+        List<UidMobileRadioStats> uidMobileRadioStats =
+                getUidMobileRadioStats(stats.getUidBatteryConsumers());
+        if (uidMobileRadioStats.size() > 0) {
+            pw.print(prefix);
+            pw.println("  Per-app mobile ms per packet:");
             long totalTime = 0;
-            for (int i=0; i<sippers.size(); i++) {
-                final BatterySipper bs = sippers.get(i);
+            for (int i = 0; i < uidMobileRadioStats.size(); i++) {
+                final UidMobileRadioStats mrs = uidMobileRadioStats.get(i);
                 sb.setLength(0);
-                sb.append(prefix); sb.append("    Uid ");
-                UserHandle.formatUid(sb, bs.uidObj.getUid());
+                sb.append(prefix);
+                sb.append("    Uid ");
+                UserHandle.formatUid(sb, mrs.uid);
                 sb.append(": ");
-                sb.append(PowerCalculator.formatCharge(bs.mobilemspp));
-                sb.append(" ("); sb.append(bs.mobileRxPackets+bs.mobileTxPackets);
-                sb.append(" packets over "); formatTimeMsNoSpace(sb, bs.mobileActive);
-                sb.append(") "); sb.append(bs.mobileActiveCount); sb.append("x");
-                pw.println(sb.toString());
-                totalTime += bs.mobileActive;
+                sb.append(formatValue(mrs.millisecondsPerPacket));
+                sb.append(" (");
+                sb.append(mrs.rxPackets + mrs.txPackets);
+                sb.append(" packets over ");
+                formatTimeMsNoSpace(sb, mrs.radioActiveMs);
+                sb.append(") ");
+                sb.append(mrs.radioActiveCount);
+                sb.append("x");
+                pw.println(sb);
+                totalTime += mrs.radioActiveMs;
             }
             sb.setLength(0);
             sb.append(prefix);
             sb.append("    TOTAL TIME: ");
             formatTimeMs(sb, totalTime);
-            sb.append("("); sb.append(formatRatioLocked(totalTime, whichBatteryRealtime));
+            sb.append("(");
+            sb.append(formatRatioLocked(totalTime, whichBatteryRealtime));
             sb.append(")");
-            pw.println(sb.toString());
+            pw.println(sb);
             pw.println();
         }
 
@@ -5668,13 +5709,13 @@
         };
 
         if (reqUid < 0) {
-            final Map<String, ? extends BatteryStats.Timer> kernelWakelocks
+            final Map<String, ? extends Timer> kernelWakelocks
                     = getKernelWakelockStats();
             if (kernelWakelocks.size() > 0) {
                 final ArrayList<TimerEntry> ktimers = new ArrayList<>();
-                for (Map.Entry<String, ? extends BatteryStats.Timer> ent
+                for (Map.Entry<String, ? extends Timer> ent
                         : kernelWakelocks.entrySet()) {
-                    final BatteryStats.Timer timer = ent.getValue();
+                    final Timer timer = ent.getValue();
                     final long totalTimeMillis = computeWakeLock(timer, rawRealtime, which);
                     if (totalTimeMillis > 0) {
                         ktimers.add(new TimerEntry(ent.getKey(), 0, timer, totalTimeMillis));
@@ -5859,8 +5900,7 @@
                     packets = 1;
                 }
                 sb.append(" @ ");
-                sb.append(PowerCalculator.formatCharge(
-                        uidMobileActiveTime / 1000 / (double) packets));
+                sb.append(formatCharge(uidMobileActiveTime / 1000 / (double) packets));
                 sb.append(" mspp");
                 pw.println(sb.toString());
             }
@@ -6068,7 +6108,7 @@
                 }
             }
 
-            final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelocks
+            final ArrayMap<String, ? extends Uid.Wakelock> wakelocks
                     = u.getWakelockStats();
             long totalFullWakelock = 0, totalPartialWakelock = 0, totalWindowWakelock = 0;
             long totalDrawWakelock = 0;
@@ -6296,7 +6336,7 @@
             uidActivity |= printTimer(pw, sb, u.getAudioTurnedOnTimer(), rawRealtime, which,
                     prefix, "Audio");
 
-            final SparseArray<? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats();
+            final SparseArray<? extends Uid.Sensor> sensors = u.getSensorStats();
             final int NSE = sensors.size();
             for (int ise=0; ise<NSE; ise++) {
                 final Uid.Sensor se = sensors.valueAt(ise);
@@ -6439,7 +6479,7 @@
                 }
             }
 
-            final ArrayMap<String, ? extends BatteryStats.Uid.Proc> processStats
+            final ArrayMap<String, ? extends Uid.Proc> processStats
                     = u.getProcessStats();
             for (int ipr=processStats.size()-1; ipr>=0; ipr--) {
                 final Uid.Proc ps = processStats.valueAt(ipr);
@@ -6513,7 +6553,7 @@
                 }
             }
 
-            final ArrayMap<String, ? extends BatteryStats.Uid.Pkg> packageStats
+            final ArrayMap<String, ? extends Uid.Pkg> packageStats
                     = u.getPackageStats();
             for (int ipkg=packageStats.size()-1; ipkg>=0; ipkg--) {
                 pw.print(prefix); pw.print("    Apk "); pw.print(packageStats.keyAt(ipkg));
@@ -6530,7 +6570,7 @@
                 }
                 final ArrayMap<String, ? extends  Uid.Pkg.Serv> serviceStats = ps.getServiceStats();
                 for (int isvc=serviceStats.size()-1; isvc>=0; isvc--) {
-                    final BatteryStats.Uid.Pkg.Serv ss = serviceStats.valueAt(isvc);
+                    final Uid.Pkg.Serv ss = serviceStats.valueAt(isvc);
                     final long startTime = ss.getStartTime(batteryUptime, which);
                     final int starts = ss.getStarts(which);
                     final int launches = ss.getLaunches(which);
@@ -8551,7 +8591,10 @@
         proto.end(sToken);
     }
 
-    private static boolean checkWifiOnly(Context context) {
+    /**
+     * Returns true if the device does not have data-capable telephony.
+     */
+    public static boolean checkWifiOnly(Context context) {
         final TelephonyManager tm = context.getSystemService(TelephonyManager.class);
         if (tm == null) {
             return false;
@@ -8652,4 +8695,57 @@
             return false;
         }
     }
+
+    private static class UidMobileRadioStats {
+        public final int uid;
+        public final long rxPackets;
+        public final long txPackets;
+        public final long radioActiveMs;
+        public final int radioActiveCount;
+        public final double millisecondsPerPacket;
+
+        private UidMobileRadioStats(int uid, long rxPackets, long txPackets, long radioActiveMs,
+                int radioActiveCount, double millisecondsPerPacket) {
+            this.uid = uid;
+            this.txPackets = txPackets;
+            this.rxPackets = rxPackets;
+            this.radioActiveMs = radioActiveMs;
+            this.radioActiveCount = radioActiveCount;
+            this.millisecondsPerPacket = millisecondsPerPacket;
+        }
+    }
+
+    private List<UidMobileRadioStats> getUidMobileRadioStats(
+            List<UidBatteryConsumer> uidBatteryConsumers) {
+        final SparseArray<? extends Uid> uidStats = getUidStats();
+        List<UidMobileRadioStats> uidMobileRadioStats = Lists.newArrayList();
+        for (int i = 0; i < uidBatteryConsumers.size(); i++) {
+            final UidBatteryConsumer consumer = uidBatteryConsumers.get(i);
+            if (consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO) == 0) {
+                continue;
+            }
+
+            final int uid = consumer.getUid();
+            final Uid u = uidStats.get(uid);
+            final long rxPackets = u.getNetworkActivityPackets(
+                    BatteryStats.NETWORK_MOBILE_RX_DATA, STATS_SINCE_CHARGED);
+            final long txPackets = u.getNetworkActivityPackets(
+                    BatteryStats.NETWORK_MOBILE_TX_DATA, STATS_SINCE_CHARGED);
+            if (rxPackets == 0 && txPackets == 0) {
+                continue;
+            }
+            final long radioActiveMs = u.getMobileRadioActiveTime(STATS_SINCE_CHARGED) / 1000;
+            final int radioActiveCount = u.getMobileRadioActiveCount(STATS_SINCE_CHARGED);
+            final double msPerPacket = (double) radioActiveMs / (rxPackets + txPackets);
+            if (msPerPacket == 0) {
+                continue;
+            }
+            uidMobileRadioStats.add(
+                    new UidMobileRadioStats(uid, rxPackets, txPackets, radioActiveMs,
+                            radioActiveCount, msPerPacket));
+        }
+        uidMobileRadioStats.sort(
+                (lhs, rhs) -> Double.compare(rhs.millisecondsPerPacket, lhs.millisecondsPerPacket));
+        return uidMobileRadioStats;
+    }
 }
diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java
index d41a5fe..58f9336 100644
--- a/core/java/android/os/BatteryUsageStats.java
+++ b/core/java/android/os/BatteryUsageStats.java
@@ -597,20 +597,21 @@
 
         dumpSortedBatteryConsumers(pw, prefix, getUidBatteryConsumers());
         dumpSortedBatteryConsumers(pw, prefix, getUserBatteryConsumers());
+        pw.println();
     }
 
     private void printPowerComponent(PrintWriter pw, String prefix, String label,
             double devicePowerMah, double appsPowerMah, int powerModel, long durationMs) {
         StringBuilder sb = new StringBuilder();
         sb.append(prefix).append("      ").append(label).append(": ")
-                .append(PowerCalculator.formatCharge(devicePowerMah));
+                .append(BatteryStats.formatCharge(devicePowerMah));
         if (powerModel != BatteryConsumer.POWER_MODEL_UNDEFINED
                 && powerModel != BatteryConsumer.POWER_MODEL_POWER_PROFILE) {
             sb.append(" [");
             sb.append(BatteryConsumer.powerModelToString(powerModel));
             sb.append("]");
         }
-        sb.append(" apps: ").append(PowerCalculator.formatCharge(appsPowerMah));
+        sb.append(" apps: ").append(BatteryStats.formatCharge(appsPowerMah));
         if (durationMs != 0) {
             sb.append(" duration: ");
             BatteryStats.formatTimeMs(sb, durationMs);
diff --git a/core/java/android/os/PowerComponents.java b/core/java/android/os/PowerComponents.java
index 48e1116..6051712 100644
--- a/core/java/android/os/PowerComponents.java
+++ b/core/java/android/os/PowerComponents.java
@@ -26,8 +26,6 @@
 import android.util.TypedXmlSerializer;
 import android.util.proto.ProtoOutputStream;
 
-import com.android.internal.os.PowerCalculator;
-
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -170,7 +168,7 @@
                 separator = " ";
                 sb.append(key.toShortString());
                 sb.append("=");
-                sb.append(PowerCalculator.formatCharge(componentPower));
+                sb.append(BatteryStats.formatCharge(componentPower));
 
                 if (durationMs != 0) {
                     sb.append(" (");
@@ -194,7 +192,7 @@
             separator = " ";
             sb.append(getCustomPowerComponentName(customComponentId));
             sb.append("=");
-            sb.append(PowerCalculator.formatCharge(customComponentPower));
+            sb.append(BatteryStats.formatCharge(customComponentPower));
         }
 
         pw.print(sb);
diff --git a/core/java/android/os/UidBatteryConsumer.java b/core/java/android/os/UidBatteryConsumer.java
index 1a082d1..a1ff923 100644
--- a/core/java/android/os/UidBatteryConsumer.java
+++ b/core/java/android/os/UidBatteryConsumer.java
@@ -136,7 +136,7 @@
         }
 
         sb.append(" ").append(processStateToString(processState)).append(": ")
-                .append(PowerCalculator.formatCharge(power));
+                .append(BatteryStats.formatCharge(power));
     }
 
     static UidBatteryConsumer create(BatteryConsumerData data) {
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 373179c..c597a1a 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -2509,12 +2509,12 @@
     }
 
     /**
-     * Checks if the calling context user is running in a profile.
+     * Checks if the calling context user is running in a profile. A profile is a user that
+     * typically has its own separate data but shares its UI with some parent user. For example, a
+     * {@link #isManagedProfile() managed profile} is a type of profile.
      *
      * @return whether the caller is in a profile.
-     * @hide
      */
-    @SystemApi
     @UserHandleAware(
             requiresAnyOfPermissionsIfNotCallerProfileGroup = {
                     android.Manifest.permission.MANAGE_USERS,
diff --git a/core/java/android/os/logcat/ILogcatManagerService.aidl b/core/java/android/os/logcat/ILogcatManagerService.aidl
index 02db274..68b5679 100644
--- a/core/java/android/os/logcat/ILogcatManagerService.aidl
+++ b/core/java/android/os/logcat/ILogcatManagerService.aidl
@@ -22,7 +22,5 @@
 interface ILogcatManagerService {
     void startThread(in int uid, in int gid, in int pid, in int fd);
     void finishThread(in int uid, in int gid, in int pid, in int fd);
-    void approve(in int uid, in int gid, in int pid, in int fd);
-    void decline(in int uid, in int gid, in int pid, in int fd);
 }
 
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index bf94ab5..464567b 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4501,6 +4501,13 @@
         public static final String SCREEN_OFF_TIMEOUT = "screen_off_timeout";
 
         /**
+         * The amount of time in milliseconds before the device goes to sleep or begins to dream
+         * after a period of inactivity while it is docked.
+         * @hide
+         */
+        public static final String SCREEN_OFF_TIMEOUT_DOCKED = "screen_off_timeout_docked";
+
+        /**
          * The screen backlight brightness between 0 and 255.
          */
         @Readable
@@ -10314,6 +10321,34 @@
                 "nearby_fast_pair_settings_devices_component";
 
         /**
+         * Current provider of the component for requesting ambient context consent.
+         * Default value in @string/config_defaultAmbientContextConsentComponent.
+         * No VALIDATOR as this setting will not be backed up.
+         * @hide
+         */
+        public static final String AMBIENT_CONTEXT_CONSENT_COMPONENT =
+                "ambient_context_consent_component";
+
+        /**
+         * Current provider of the intent extra key for the caller's package name while
+         * requesting ambient context consent.
+         * No VALIDATOR as this setting will not be backed up.
+         * @hide
+         */
+        public static final String AMBIENT_CONTEXT_PACKAGE_NAME_EXTRA_KEY =
+                "ambient_context_package_name_key";
+
+        /**
+         * Current provider of the intent extra key for the event code int array while
+         * requesting ambient context consent.
+         * Default value in @string/config_ambientContextEventArrayExtraKey.
+         * No VALIDATOR as this setting will not be backed up.
+         * @hide
+         */
+        public static final String AMBIENT_CONTEXT_EVENT_ARRAY_EXTRA_KEY =
+                "ambient_context_event_array_key";
+
+        /**
          * Controls whether aware is enabled.
          * @hide
          */
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 3ff0161..5ff9263 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -2216,651 +2216,6 @@
     }
 
     /**
-     * Columns for the "rcs_*" tables used by {@link android.telephony.ims.RcsMessageStore} classes.
-     *
-     * @hide - not meant for public use
-     */
-    public interface RcsColumns {
-        // TODO(sahinc): Turn this to true once the schema finalizes, so that people can update
-        //  their messaging databases. NOTE: move the switch/case update in MmsSmsDatabaseHelper to
-        //  the latest version of the database before turning this flag to true.
-        boolean IS_RCS_TABLE_SCHEMA_CODE_COMPLETE = false;
-
-        /**
-         * The authority for the content provider
-         */
-        String AUTHORITY = "rcs";
-
-        /**
-         * The URI to start building upon to use {@link com.android.providers.telephony.RcsProvider}
-         */
-        Uri CONTENT_AND_AUTHORITY = Uri.parse("content://" + AUTHORITY);
-
-        /**
-         * The value to be used whenever a transaction that expects an integer to be returned
-         * failed.
-         */
-        int TRANSACTION_FAILED = Integer.MIN_VALUE;
-
-        /**
-         * The value that denotes a timestamp was not set before (e.g. a message that is not
-         * delivered yet will not have a DELIVERED_TIMESTAMP)
-         */
-        long TIMESTAMP_NOT_SET = 0;
-
-        /**
-         * The table that {@link android.telephony.ims.RcsThread} gets persisted to
-         */
-        interface RcsThreadColumns {
-            /**
-             * The path that should be used for referring to
-             * {@link android.telephony.ims.RcsThread}s in
-             * {@link com.android.providers.telephony.RcsProvider} URIs.
-             */
-            String RCS_THREAD_URI_PART = "thread";
-
-            /**
-             * The URI to query or modify {@link android.telephony.ims.RcsThread} via the content
-             * provider.
-             */
-            Uri RCS_THREAD_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY, RCS_THREAD_URI_PART);
-
-            /**
-             * The unique identifier of an {@link android.telephony.ims.RcsThread}
-             */
-            String RCS_THREAD_ID_COLUMN = "rcs_thread_id";
-        }
-
-        /**
-         * The table that {@link android.telephony.ims.Rcs1To1Thread} gets persisted to
-         */
-        interface Rcs1To1ThreadColumns extends RcsThreadColumns {
-            /**
-             * The path that should be used for referring to
-             * {@link android.telephony.ims.Rcs1To1Thread}s in
-             * {@link com.android.providers.telephony.RcsProvider} URIs.
-             */
-            String RCS_1_TO_1_THREAD_URI_PART = "p2p_thread";
-
-            /**
-             * The URI to query or modify {@link android.telephony.ims.Rcs1To1Thread}s via the
-             * content provider. Can also insert to this URI to create a new 1-to-1 thread. When
-             * performing an insert, ensure that the provided content values contain the other
-             * participant's ID under the key
-             * {@link RcsParticipantColumns.RCS_PARTICIPANT_ID_COLUMN}
-             */
-            Uri RCS_1_TO_1_THREAD_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
-                    RCS_1_TO_1_THREAD_URI_PART);
-
-            /**
-             * The SMS/MMS thread to fallback to in case of an RCS outage
-             */
-            String FALLBACK_THREAD_ID_COLUMN = "rcs_fallback_thread_id";
-        }
-
-        /**
-         * The table that {@link android.telephony.ims.RcsGroupThread} gets persisted to
-         */
-        interface RcsGroupThreadColumns extends RcsThreadColumns {
-            /**
-             * The path that should be used for referring to
-             * {@link android.telephony.ims.RcsGroupThread}s in
-             * {@link com.android.providers.telephony.RcsProvider} URIs.
-             */
-            String RCS_GROUP_THREAD_URI_PART = "group_thread";
-
-            /**
-             * The URI to query or modify {@link android.telephony.ims.RcsGroupThread}s via the
-             * content provider
-             */
-            Uri RCS_GROUP_THREAD_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
-                    RCS_GROUP_THREAD_URI_PART);
-
-            /**
-             * The owner/admin of the {@link android.telephony.ims.RcsGroupThread}
-             */
-            String OWNER_PARTICIPANT_COLUMN = "owner_participant";
-
-            /**
-             * The user visible name of the group
-             */
-            String GROUP_NAME_COLUMN = "group_name";
-
-            /**
-             * The user visible icon of the group
-             */
-            String GROUP_ICON_COLUMN = "group_icon";
-
-            /**
-             * The RCS conference URI for this group
-             */
-            String CONFERENCE_URI_COLUMN = "conference_uri";
-        }
-
-        /**
-         * The view that enables polling from all types of RCS threads at once
-         */
-        interface RcsUnifiedThreadColumns extends RcsThreadColumns, Rcs1To1ThreadColumns,
-                RcsGroupThreadColumns {
-            /**
-             * The type of this {@link android.telephony.ims.RcsThread}
-             */
-            String THREAD_TYPE_COLUMN = "thread_type";
-
-            /**
-             * Integer returned as a result from a database query that denotes the thread is 1 to 1
-             */
-            int THREAD_TYPE_1_TO_1 = 0;
-
-            /**
-             * Integer returned as a result from a database query that denotes the thread is 1 to 1
-             */
-            int THREAD_TYPE_GROUP = 1;
-        }
-
-        /**
-         * The table that {@link android.telephony.ims.RcsParticipant} gets persisted to
-         */
-        interface RcsParticipantColumns {
-            /**
-             * The path that should be used for referring to
-             * {@link android.telephony.ims.RcsParticipant}s in
-             * {@link com.android.providers.telephony.RcsProvider} URIs.
-             */
-            String RCS_PARTICIPANT_URI_PART = "participant";
-
-            /**
-             * The URI to query or modify {@link android.telephony.ims.RcsParticipant}s via the
-             * content provider
-             */
-            Uri RCS_PARTICIPANT_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
-                    RCS_PARTICIPANT_URI_PART);
-
-            /**
-             * The unique identifier of the entry in the database
-             */
-            String RCS_PARTICIPANT_ID_COLUMN = "rcs_participant_id";
-
-            /**
-             * A foreign key on canonical_address table, also used by SMS/MMS
-             */
-            String CANONICAL_ADDRESS_ID_COLUMN = "canonical_address_id";
-
-            /**
-             * The user visible RCS alias for this participant.
-             */
-            String RCS_ALIAS_COLUMN = "rcs_alias";
-        }
-
-        /**
-         * Additional constants to enable access to {@link android.telephony.ims.RcsParticipant}
-         * related data
-         */
-        interface RcsParticipantHelpers extends RcsParticipantColumns {
-            /**
-             * The view that unifies "rcs_participant" and "canonical_addresses" tables for easy
-             * access to participant address.
-             */
-            String RCS_PARTICIPANT_WITH_ADDRESS_VIEW = "rcs_participant_with_address_view";
-
-            /**
-             * The view that unifies "rcs_participant", "canonical_addresses" and
-             * "rcs_thread_participant" junction table to get full information on participants that
-             * contribute to threads.
-             */
-            String RCS_PARTICIPANT_WITH_THREAD_VIEW = "rcs_participant_with_thread_view";
-        }
-
-        /**
-         * The table that {@link android.telephony.ims.RcsMessage} gets persisted to
-         */
-        interface RcsMessageColumns {
-            /**
-             * Denotes the type of this message (i.e.
-             * {@link android.telephony.ims.RcsIncomingMessage} or
-             * {@link android.telephony.ims.RcsOutgoingMessage}
-             */
-            String MESSAGE_TYPE_COLUMN = "rcs_message_type";
-
-            /**
-             * The unique identifier for the message in the database - i.e. the primary key.
-             */
-            String MESSAGE_ID_COLUMN = "rcs_message_row_id";
-
-            /**
-             * The globally unique RCS identifier for the message. Please see 4.4.5.2 - GSMA
-             * RCC.53 (RCS Device API 1.6 Specification)
-             */
-            String GLOBAL_ID_COLUMN = "rcs_message_global_id";
-
-            /**
-             * The subscription where this message was sent from/to.
-             */
-            String SUB_ID_COLUMN = "sub_id";
-
-            /**
-             * The sending status of the message.
-             * @see android.telephony.ims.RcsMessage.RcsMessageStatus
-             */
-            String STATUS_COLUMN = "status";
-
-            /**
-             * The creation timestamp of the message.
-             */
-            String ORIGINATION_TIMESTAMP_COLUMN = "origination_timestamp";
-
-            /**
-             * The text content of the message.
-             */
-            String MESSAGE_TEXT_COLUMN = "rcs_text";
-
-            /**
-             * The latitude content of the message, if it contains a location.
-             */
-            String LATITUDE_COLUMN = "latitude";
-
-            /**
-             * The longitude content of the message, if it contains a location.
-             */
-            String LONGITUDE_COLUMN = "longitude";
-        }
-
-        /**
-         * The table that additional information of {@link android.telephony.ims.RcsIncomingMessage}
-         * gets persisted to.
-         */
-        interface RcsIncomingMessageColumns extends RcsMessageColumns {
-            /**
-             The path that should be used for referring to
-             * {@link android.telephony.ims.RcsIncomingMessage}s in
-             * {@link com.android.providers.telephony.RcsProvider} URIs.
-             */
-            String INCOMING_MESSAGE_URI_PART = "incoming_message";
-
-            /**
-             * The URI to query incoming messages through
-             * {@link com.android.providers.telephony.RcsProvider}
-             */
-            Uri INCOMING_MESSAGE_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
-                    INCOMING_MESSAGE_URI_PART);
-
-            /**
-             * The ID of the {@link android.telephony.ims.RcsParticipant} that sent this message
-             */
-            String SENDER_PARTICIPANT_ID_COLUMN = "sender_participant";
-
-            /**
-             * The timestamp of arrival for this message.
-             */
-            String ARRIVAL_TIMESTAMP_COLUMN = "arrival_timestamp";
-
-            /**
-             * The time when the recipient has read this message.
-             */
-            String SEEN_TIMESTAMP_COLUMN = "seen_timestamp";
-        }
-
-        /**
-         * The table that additional information of {@link android.telephony.ims.RcsOutgoingMessage}
-         * gets persisted to.
-         */
-        interface RcsOutgoingMessageColumns extends RcsMessageColumns {
-            /**
-             * The path that should be used for referring to
-             * {@link android.telephony.ims.RcsOutgoingMessage}s in
-             * {@link com.android.providers.telephony.RcsProvider} URIs.
-             */
-            String OUTGOING_MESSAGE_URI_PART = "outgoing_message";
-
-            /**
-             * The URI to query or modify {@link android.telephony.ims.RcsOutgoingMessage}s via the
-             * content provider
-             */
-            Uri OUTGOING_MESSAGE_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
-                    OUTGOING_MESSAGE_URI_PART);
-        }
-
-        /**
-         * The delivery information of an {@link android.telephony.ims.RcsOutgoingMessage}
-         */
-        interface RcsMessageDeliveryColumns extends RcsOutgoingMessageColumns {
-            /**
-             * The path that should be used for referring to
-             * {@link android.telephony.ims.RcsOutgoingMessageDelivery}s in
-             * {@link com.android.providers.telephony.RcsProvider} URIs.
-             */
-            String DELIVERY_URI_PART = "delivery";
-
-            /**
-             * The timestamp of delivery of this message.
-             */
-            String DELIVERED_TIMESTAMP_COLUMN = "delivered_timestamp";
-
-            /**
-             * The time when the recipient has read this message.
-             */
-            String SEEN_TIMESTAMP_COLUMN = "seen_timestamp";
-        }
-
-        /**
-         * The views that allow querying {@link android.telephony.ims.RcsIncomingMessage} and
-         * {@link android.telephony.ims.RcsOutgoingMessage} at the same time.
-         */
-        interface RcsUnifiedMessageColumns extends RcsIncomingMessageColumns,
-                RcsOutgoingMessageColumns {
-            /**
-             * The path that is used to query all {@link android.telephony.ims.RcsMessage} in
-             * {@link com.android.providers.telephony.RcsProvider} URIs.
-             */
-            String UNIFIED_MESSAGE_URI_PART = "message";
-
-            /**
-             * The URI to query all types of {@link android.telephony.ims.RcsMessage}s
-             */
-            Uri UNIFIED_MESSAGE_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
-                    UNIFIED_MESSAGE_URI_PART);
-
-            /**
-             * The name of the view that unites rcs_message and rcs_incoming_message tables.
-             */
-            String UNIFIED_INCOMING_MESSAGE_VIEW = "unified_incoming_message_view";
-
-            /**
-             * The name of the view that unites rcs_message and rcs_outgoing_message tables.
-             */
-            String UNIFIED_OUTGOING_MESSAGE_VIEW = "unified_outgoing_message_view";
-
-            /**
-             * The column that shows from which table the message entry came from.
-             */
-            String MESSAGE_TYPE_COLUMN = "message_type";
-
-            /**
-             * Integer returned as a result from a database query that denotes that the message is
-             * an incoming message
-             */
-            int MESSAGE_TYPE_INCOMING = 1;
-
-            /**
-             * Integer returned as a result from a database query that denotes that the message is
-             * an outgoing message
-             */
-            int MESSAGE_TYPE_OUTGOING = 0;
-        }
-
-        /**
-         * The table that {@link android.telephony.ims.RcsFileTransferPart} gets persisted to.
-         */
-        interface RcsFileTransferColumns {
-            /**
-             * The path that should be used for referring to
-             * {@link android.telephony.ims.RcsFileTransferPart}s in
-             * {@link com.android.providers.telephony.RcsProvider} URIs.
-             */
-            String FILE_TRANSFER_URI_PART = "file_transfer";
-
-            /**
-             * The URI to query or modify {@link android.telephony.ims.RcsFileTransferPart}s via the
-             * content provider
-             */
-            Uri FILE_TRANSFER_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
-                    FILE_TRANSFER_URI_PART);
-
-            /**
-             * The globally unique file transfer ID for this RCS file transfer.
-             */
-            String FILE_TRANSFER_ID_COLUMN = "rcs_file_transfer_id";
-
-            /**
-             * The RCS session ID for this file transfer. The ID is implementation dependent but
-             * should be unique.
-             */
-            String SESSION_ID_COLUMN = "session_id";
-
-            /**
-             * The URI that points to the content of this file transfer
-             */
-            String CONTENT_URI_COLUMN = "content_uri";
-
-            /**
-             * The file type of this file transfer in bytes. The validity of types is not enforced
-             * in {@link android.telephony.ims.RcsMessageStore} APIs.
-             */
-            String CONTENT_TYPE_COLUMN = "content_type";
-
-            /**
-             * The size of the file transfer in bytes.
-             */
-            String FILE_SIZE_COLUMN = "file_size";
-
-            /**
-             * Number of bytes that was successfully transmitted for this file transfer
-             */
-            String SUCCESSFULLY_TRANSFERRED_BYTES = "transfer_offset";
-
-            /**
-             * The status of this file transfer
-             * @see android.telephony.ims.RcsFileTransferPart.RcsFileTransferStatus
-             */
-            String TRANSFER_STATUS_COLUMN = "transfer_status";
-
-            /**
-             * The on-screen width of the file transfer, if it contains multi-media
-             */
-            String WIDTH_COLUMN = "width";
-
-            /**
-             * The on-screen height of the file transfer, if it contains multi-media
-             */
-            String HEIGHT_COLUMN = "height";
-
-            /**
-             * The duration of the content in milliseconds if this file transfer contains
-             * multi-media
-             */
-            String DURATION_MILLIS_COLUMN = "duration";
-
-            /**
-             * The URI to the preview of the content of this file transfer
-             */
-            String PREVIEW_URI_COLUMN = "preview_uri";
-
-            /**
-             * The type of the preview of the content of this file transfer. The validity of types
-             * is not enforced in {@link android.telephony.ims.RcsMessageStore} APIs.
-             */
-            String PREVIEW_TYPE_COLUMN = "preview_type";
-        }
-
-        /**
-         * The table that holds the information for
-         * {@link android.telephony.ims.RcsGroupThreadEvent} and its subclasses.
-         */
-        interface RcsThreadEventColumns {
-            /**
-             * The string used in the {@link com.android.providers.telephony.RcsProvider} URI to
-             * refer to participant joined events (example URI:
-             * {@code content://rcs/group_thread/3/participant_joined_event})
-             */
-            String PARTICIPANT_JOINED_URI_PART = "participant_joined_event";
-
-            /**
-             * The string used in the {@link com.android.providers.telephony.RcsProvider} URI to
-             * refer to participant left events. (example URI:
-             * {@code content://rcs/group_thread/3/participant_left_event/4})
-             */
-            String PARTICIPANT_LEFT_URI_PART = "participant_left_event";
-
-            /**
-             * The string used in the {@link com.android.providers.telephony.RcsProvider} URI to
-             * refer to name changed events. (example URI:
-             * {@code content://rcs/group_thread/3/name_changed_event})
-             */
-            String NAME_CHANGED_URI_PART = "name_changed_event";
-
-            /**
-             * The string used in the {@link com.android.providers.telephony.RcsProvider} URI to
-             * refer to icon changed events. (example URI:
-             * {@code content://rcs/group_thread/3/icon_changed_event})
-             */
-            String ICON_CHANGED_URI_PART = "icon_changed_event";
-
-            /**
-             * The unique ID of this event in the database, i.e. the primary key
-             */
-            String EVENT_ID_COLUMN = "event_id";
-
-            /**
-             * The type of this event
-             *
-             * @see RcsEventTypes
-             */
-            String EVENT_TYPE_COLUMN = "event_type";
-
-            /**
-             * The timestamp in milliseconds of when this event happened
-             */
-            String TIMESTAMP_COLUMN = "origination_timestamp";
-
-            /**
-             * The participant that generated this event
-             */
-            String SOURCE_PARTICIPANT_ID_COLUMN = "source_participant";
-
-            /**
-             * The receiving participant of this event if this was an
-             * {@link android.telephony.ims.RcsGroupThreadParticipantJoinedEvent} or
-             * {@link android.telephony.ims.RcsGroupThreadParticipantLeftEvent}
-             */
-            String DESTINATION_PARTICIPANT_ID_COLUMN = "destination_participant";
-
-            /**
-             * The URI for the new icon of the group thread if this was an
-             * {@link android.telephony.ims.RcsGroupThreadIconChangedEvent}
-             */
-            String NEW_ICON_URI_COLUMN = "new_icon_uri";
-
-            /**
-             * The URI for the new name of the group thread if this was an
-             * {@link android.telephony.ims.RcsGroupThreadNameChangedEvent}
-             */
-            String NEW_NAME_COLUMN = "new_name";
-        }
-
-        /**
-         * The table that {@link android.telephony.ims.RcsParticipantAliasChangedEvent} gets
-         * persisted to
-         */
-        interface RcsParticipantEventColumns {
-            /**
-             * The path that should be used for referring to
-             * {@link android.telephony.ims.RcsParticipantAliasChangedEvent}s in
-             * {@link com.android.providers.telephony.RcsProvider} URIs.
-             */
-            String ALIAS_CHANGE_EVENT_URI_PART = "alias_change_event";
-
-            /**
-             * The new alias of the participant
-             */
-            String NEW_ALIAS_COLUMN = "new_alias";
-        }
-
-        /**
-         * These values are used in {@link com.android.providers.telephony.RcsProvider} to determine
-         * what kind of event is present in the storage.
-         */
-        interface RcsEventTypes {
-            /**
-             * Integer constant that is stored in the
-             * {@link com.android.providers.telephony.RcsProvider} database that denotes the event
-             * is of type {@link android.telephony.ims.RcsParticipantAliasChangedEvent}
-             */
-            int PARTICIPANT_ALIAS_CHANGED_EVENT_TYPE = 1;
-
-            /**
-             * Integer constant that is stored in the
-             * {@link com.android.providers.telephony.RcsProvider} database that denotes the event
-             * is of type {@link android.telephony.ims.RcsGroupThreadParticipantJoinedEvent}
-             */
-            int PARTICIPANT_JOINED_EVENT_TYPE = 2;
-
-            /**
-             * Integer constant that is stored in the
-             * {@link com.android.providers.telephony.RcsProvider} database that denotes the event
-             * is of type {@link android.telephony.ims.RcsGroupThreadParticipantLeftEvent}
-             */
-            int PARTICIPANT_LEFT_EVENT_TYPE = 4;
-
-            /**
-             * Integer constant that is stored in the
-             * {@link com.android.providers.telephony.RcsProvider} database that denotes the event
-             * is of type {@link android.telephony.ims.RcsGroupThreadIconChangedEvent}
-             */
-            int ICON_CHANGED_EVENT_TYPE = 8;
-
-            /**
-             * Integer constant that is stored in the
-             * {@link com.android.providers.telephony.RcsProvider} database that denotes the event
-             * is of type {@link android.telephony.ims.RcsGroupThreadNameChangedEvent}
-             */
-            int NAME_CHANGED_EVENT_TYPE = 16;
-        }
-
-        /**
-         * The view that allows unified querying across all events
-         */
-        interface RcsUnifiedEventHelper extends RcsParticipantEventColumns, RcsThreadEventColumns {
-            /**
-             * The path that should be used for referring to
-             * {@link android.telephony.ims.RcsEvent}s in
-             * {@link com.android.providers.telephony.RcsProvider} URIs.
-             */
-            String RCS_EVENT_QUERY_URI_PATH = "event";
-
-            /**
-             * The URI to query {@link android.telephony.ims.RcsEvent}s via the content provider.
-             */
-            Uri RCS_EVENT_QUERY_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
-                    RCS_EVENT_QUERY_URI_PATH);
-        }
-
-        /**
-         * Allows RCS specific canonical address handling.
-         */
-        interface RcsCanonicalAddressHelper {
-            /**
-             * Returns the canonical address ID for a canonical address, if now row exists, this
-             * will add a row and return its ID. This helper works against the same table used by
-             * the SMS and MMS threads, but is accessible only by the phone process for use by RCS
-             * message storage.
-             *
-             * @throws IllegalArgumentException if unable to retrieve or create the canonical
-             *                                  address entry.
-             */
-            static long getOrCreateCanonicalAddressId(
-                    ContentResolver contentResolver, String canonicalAddress) {
-
-                Uri.Builder uriBuilder = CONTENT_AND_AUTHORITY.buildUpon();
-                uriBuilder.appendPath("canonical-address");
-                uriBuilder.appendQueryParameter("address", canonicalAddress);
-                Uri uri = uriBuilder.build();
-
-                try (Cursor cursor = contentResolver.query(uri, null, null, null)) {
-                    if (cursor != null && cursor.moveToFirst()) {
-                        return cursor.getLong(cursor.getColumnIndex(CanonicalAddressesColumns._ID));
-                    } else {
-                        Rlog.e(TAG, "getOrCreateCanonicalAddressId returned no rows");
-                    }
-                }
-
-                Rlog.e(TAG, "getOrCreateCanonicalAddressId failed");
-                throw new IllegalArgumentException(
-                        "Unable to find or allocate a canonical address ID");
-            }
-        }
-    }
-
-    /**
      * Contains all MMS messages.
      */
     public static final class Mms implements BaseMmsColumns {
diff --git a/core/java/android/app/ambientcontext/AmbientContextEventResponse.aidl b/core/java/android/service/ambientcontext/AmbientContextDetectionResult.aidl
similarity index 80%
rename from core/java/android/app/ambientcontext/AmbientContextEventResponse.aidl
rename to core/java/android/service/ambientcontext/AmbientContextDetectionResult.aidl
index 4dc6466..4bb29b2 100644
--- a/core/java/android/app/ambientcontext/AmbientContextEventResponse.aidl
+++ b/core/java/android/service/ambientcontext/AmbientContextDetectionResult.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 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.
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.app.ambientcontext;
+package android.service.ambientcontext;
 
-parcelable AmbientContextEventResponse;
\ No newline at end of file
+parcelable AmbientContextDetectionResult;
\ No newline at end of file
diff --git a/core/java/android/service/ambientcontext/AmbientContextDetectionResult.java b/core/java/android/service/ambientcontext/AmbientContextDetectionResult.java
new file mode 100644
index 0000000..227194e
--- /dev/null
+++ b/core/java/android/service/ambientcontext/AmbientContextDetectionResult.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2022 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.service.ambientcontext;
+
+import android.annotation.NonNull;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.app.ambientcontext.AmbientContextEvent;
+import android.os.Parcelable;
+
+import com.android.internal.util.AnnotationValidations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a {@code AmbientContextEvent} detection result reported by the detection service.
+ *
+ * @hide
+ */
+@SystemApi
+public final class AmbientContextDetectionResult implements Parcelable {
+
+    /**
+     * The bundle key for this class of object, used in {@code RemoteCallback#sendResult}.
+     *
+     * @hide
+     */
+    public static final String RESULT_RESPONSE_BUNDLE_KEY =
+            "android.app.ambientcontext.AmbientContextDetectionResultBundleKey";
+    @NonNull private final List<AmbientContextEvent> mEvents;
+    @NonNull private final String mPackageName;
+
+    AmbientContextDetectionResult(
+            @NonNull List<AmbientContextEvent> events,
+            @NonNull String packageName) {
+        this.mEvents = events;
+        AnnotationValidations.validate(NonNull.class, null, mEvents);
+        this.mPackageName = packageName;
+        AnnotationValidations.validate(NonNull.class, null, mPackageName);
+    }
+
+    /**
+     * A list of detected event.
+     */
+    @SuppressLint("ConcreteCollection")
+    public @NonNull List<AmbientContextEvent> getEvents() {
+        return mEvents;
+    }
+
+    /**
+     * The package to deliver the response to.
+     */
+    public @NonNull String getPackageName() {
+        return mPackageName;
+    }
+
+    @Override
+    public String toString() {
+        return "AmbientContextEventResponse { "
+                + "events = " + mEvents + ", " + "packageName = " + mPackageName + " }";
+    }
+
+    @Override
+    public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+        byte flg = 0;
+        dest.writeByte(flg);
+        dest.writeParcelableList(mEvents, flags);
+        dest.writeString(mPackageName);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    AmbientContextDetectionResult(@NonNull android.os.Parcel in) {
+        byte flg = in.readByte();
+        ArrayList<AmbientContextEvent> events = new ArrayList<>();
+        in.readParcelableList(events, AmbientContextEvent.class.getClassLoader(),
+                AmbientContextEvent.class);
+        String packageName = in.readString();
+
+        this.mEvents = events;
+        AnnotationValidations.validate(
+                NonNull.class, null, mEvents);
+        this.mPackageName = packageName;
+        AnnotationValidations.validate(
+                NonNull.class, null, mPackageName);
+    }
+
+    public static final @NonNull Creator<AmbientContextDetectionResult> CREATOR =
+            new Creator<AmbientContextDetectionResult>() {
+        @Override
+        public AmbientContextDetectionResult[] newArray(int size) {
+            return new AmbientContextDetectionResult[size];
+        }
+
+        @Override
+        public AmbientContextDetectionResult createFromParcel(@NonNull android.os.Parcel in) {
+            return new AmbientContextDetectionResult(in);
+        }
+    };
+
+    /**
+     * A builder for {@link AmbientContextDetectionResult}
+     */
+    @SuppressWarnings("WeakerAccess")
+    public static final class Builder {
+        private @NonNull ArrayList<AmbientContextEvent> mEvents;
+        private @NonNull String mPackageName;
+        private long mBuilderFieldsSet = 0L;
+
+        public Builder() {
+        }
+
+        /**
+         * Adds an event to the builder.
+         */
+        public @NonNull Builder addEvent(@NonNull AmbientContextEvent value) {
+            checkNotUsed();
+            if (mEvents == null) {
+                mBuilderFieldsSet |= 0x1;
+                mEvents = new ArrayList<>();
+            }
+            mEvents.add(value);
+            return this;
+        }
+
+        /**
+         * The package to deliver the response to.
+         */
+        public @NonNull Builder setPackageName(@NonNull String value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x2;
+            mPackageName = value;
+            return this;
+        }
+
+        /** Builds the instance. This builder should not be touched after calling this! */
+        public @NonNull AmbientContextDetectionResult build() {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x4; // Mark builder used
+
+            if ((mBuilderFieldsSet & 0x1) == 0) {
+                mEvents = new ArrayList<>();
+            }
+            if ((mBuilderFieldsSet & 0x2) == 0) {
+                mPackageName = "";
+            }
+            AmbientContextDetectionResult o = new AmbientContextDetectionResult(
+                    mEvents,
+                    mPackageName);
+            return o;
+        }
+
+        private void checkNotUsed() {
+            if ((mBuilderFieldsSet & 0x4) != 0) {
+                throw new IllegalStateException(
+                        "This Builder should not be reused. Use a new Builder instance instead");
+            }
+        }
+    }
+}
diff --git a/core/java/android/service/ambientcontext/AmbientContextDetectionService.java b/core/java/android/service/ambientcontext/AmbientContextDetectionService.java
index dccfe36..6224aa1 100644
--- a/core/java/android/service/ambientcontext/AmbientContextDetectionService.java
+++ b/core/java/android/service/ambientcontext/AmbientContextDetectionService.java
@@ -16,13 +16,13 @@
 
 package android.service.ambientcontext;
 
+import android.annotation.BinderThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.app.Service;
 import android.app.ambientcontext.AmbientContextEvent;
 import android.app.ambientcontext.AmbientContextEventRequest;
-import android.app.ambientcontext.AmbientContextEventResponse;
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -64,15 +64,6 @@
     public static final String SERVICE_INTERFACE =
             "android.service.ambientcontext.AmbientContextDetectionService";
 
-    /**
-     * The key for the bundle the parameter of {@code RemoteCallback#sendResult}. Implementation
-     * should set bundle result with this key.
-     *
-     * @hide
-     */
-    public static final String RESPONSE_BUNDLE_KEY =
-            "android.service.ambientcontext.EventResponseKey";
-
     @Nullable
     @Override
     public final IBinder onBind(@NonNull Intent intent) {
@@ -82,19 +73,30 @@
                 @Override
                 public void startDetection(
                         @NonNull AmbientContextEventRequest request, String packageName,
-                        RemoteCallback callback) {
+                        RemoteCallback detectionResultCallback, RemoteCallback statusCallback) {
                     Objects.requireNonNull(request);
-                    Objects.requireNonNull(callback);
-                    Consumer<AmbientContextEventResponse> consumer =
-                            response -> {
+                    Objects.requireNonNull(packageName);
+                    Objects.requireNonNull(detectionResultCallback);
+                    Objects.requireNonNull(statusCallback);
+                    Consumer<AmbientContextDetectionResult> detectionResultConsumer =
+                            result -> {
                                 Bundle bundle = new Bundle();
                                 bundle.putParcelable(
-                                        AmbientContextDetectionService.RESPONSE_BUNDLE_KEY,
-                                        response);
-                                callback.sendResult(bundle);
+                                        AmbientContextDetectionResult.RESULT_RESPONSE_BUNDLE_KEY,
+                                        result);
+                                detectionResultCallback.sendResult(bundle);
+                            };
+                    Consumer<AmbientContextDetectionServiceStatus> statusConsumer =
+                            status -> {
+                                Bundle bundle = new Bundle();
+                                bundle.putParcelable(
+                                        AmbientContextDetectionServiceStatus
+                                                .STATUS_RESPONSE_BUNDLE_KEY,
+                                        status);
+                                statusCallback.sendResult(bundle);
                             };
                     AmbientContextDetectionService.this.onStartDetection(
-                            request, packageName, consumer);
+                            request, packageName, detectionResultConsumer, statusConsumer);
                     Slog.d(TAG, "startDetection " + request);
                 }
 
@@ -104,29 +106,52 @@
                     Objects.requireNonNull(packageName);
                     AmbientContextDetectionService.this.onStopDetection(packageName);
                 }
+
+                /** {@inheritDoc} */
+                @Override
+                public void queryServiceStatus(
+                        @AmbientContextEvent.EventCode int[] eventTypes,
+                        String packageName,
+                        RemoteCallback callback) {
+                    Objects.requireNonNull(eventTypes);
+                    Objects.requireNonNull(packageName);
+                    Objects.requireNonNull(callback);
+                    Consumer<AmbientContextDetectionServiceStatus> consumer =
+                            response -> {
+                                Bundle bundle = new Bundle();
+                                bundle.putParcelable(
+                                        AmbientContextDetectionServiceStatus
+                                                .STATUS_RESPONSE_BUNDLE_KEY,
+                                        response);
+                                callback.sendResult(bundle);
+                            };
+                    AmbientContextDetectionService.this.onQueryServiceStatus(
+                            eventTypes, packageName, consumer);
+                }
             };
         }
         return null;
     }
 
     /**
-     * Starts detection and provides detected events to the consumer. The ongoing detection will
-     * keep running, until onStopDetection is called. If there were previously requested
+     * Starts detection and provides detected events to the statusConsumer. The ongoing detection
+     * will keep running, until onStopDetection is called. If there were previously requested
      * detection from the same package, the previous request will be replaced with the new request.
      * The implementation should keep track of whether the user consented each requested
-     * AmbientContextEvent for the app. If not consented, the response should set status
-     * STATUS_ACCESS_DENIED and include an action PendingIntent for the app to redirect the user
-     * to the consent screen.
+     * AmbientContextEvent for the app. If not consented, the statusConsumer should get a response
+     * with STATUS_ACCESS_DENIED.
      *
-     * @param request The request with events to detect, optional detection window and other
-     *                options.
+     * @param request The request with events to detect.
      * @param packageName the requesting app's package name
-     * @param consumer the consumer for the detected event
+     * @param detectionResultConsumer the consumer for the detected event
+     * @param statusConsumer the consumer for the service status.
      */
+    @BinderThread
     public abstract void onStartDetection(
             @NonNull AmbientContextEventRequest request,
             @NonNull String packageName,
-            @NonNull Consumer<AmbientContextEventResponse> consumer);
+            @NonNull Consumer<AmbientContextDetectionResult> detectionResultConsumer,
+            @NonNull Consumer<AmbientContextDetectionServiceStatus> statusConsumer);
 
     /**
      * Stops detection of the events. Events that are not being detected will be ignored.
@@ -134,4 +159,19 @@
      * @param packageName stops detection for the given package.
      */
     public abstract void onStopDetection(@NonNull String packageName);
+
+    /**
+     * Called when a query for the detection status occurs. The implementation should check
+     * the detection status of the requested events for the package, and provide results in a
+     * {@link AmbientContextDetectionServiceStatus} for the consumer.
+     *
+     * @param eventTypes The events to check for status.
+     * @param packageName the requesting app's package name
+     * @param consumer the consumer for the query results
+     */
+    @BinderThread
+    public abstract void onQueryServiceStatus(
+            @NonNull int[] eventTypes,
+            @NonNull String packageName,
+            @NonNull Consumer<AmbientContextDetectionServiceStatus> consumer);
 }
diff --git a/core/java/android/app/ambientcontext/AmbientContextEventResponse.aidl b/core/java/android/service/ambientcontext/AmbientContextDetectionServiceStatus.aidl
similarity index 79%
copy from core/java/android/app/ambientcontext/AmbientContextEventResponse.aidl
copy to core/java/android/service/ambientcontext/AmbientContextDetectionServiceStatus.aidl
index 4dc6466..979cf7b 100644
--- a/core/java/android/app/ambientcontext/AmbientContextEventResponse.aidl
+++ b/core/java/android/service/ambientcontext/AmbientContextDetectionServiceStatus.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 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.
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.app.ambientcontext;
+package android.service.ambientcontext;
 
-parcelable AmbientContextEventResponse;
\ No newline at end of file
+parcelable AmbientContextDetectionServiceStatus;
\ No newline at end of file
diff --git a/core/java/android/service/ambientcontext/AmbientContextDetectionServiceStatus.java b/core/java/android/service/ambientcontext/AmbientContextDetectionServiceStatus.java
new file mode 100644
index 0000000..3e92f39
--- /dev/null
+++ b/core/java/android/service/ambientcontext/AmbientContextDetectionServiceStatus.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2022 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.service.ambientcontext;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.app.ambientcontext.AmbientContextManager;
+import android.app.ambientcontext.AmbientContextManager.StatusCode;
+import android.os.Parcelable;
+
+import com.android.internal.util.AnnotationValidations;
+
+/**
+ * Represents a status for the {@code AmbientContextDetectionService}.
+ *
+ * @hide
+ */
+@SystemApi
+public final class AmbientContextDetectionServiceStatus implements Parcelable {
+    /**
+     * The bundle key for this class of object, used in {@code RemoteCallback#sendResult}.
+     *
+     * @hide
+     */
+    public static final String STATUS_RESPONSE_BUNDLE_KEY =
+            "android.app.ambientcontext.AmbientContextServiceStatusBundleKey";
+
+    @StatusCode private final int mStatusCode;
+    @NonNull private final String mPackageName;
+
+    AmbientContextDetectionServiceStatus(
+            @StatusCode int statusCode,
+            @NonNull String packageName) {
+        this.mStatusCode = statusCode;
+        AnnotationValidations.validate(StatusCode.class, null, mStatusCode);
+        this.mPackageName = packageName;
+    }
+
+    /**
+     * The status of the service.
+     */
+    public @StatusCode int getStatusCode() {
+        return mStatusCode;
+    }
+
+    /**
+     * The package to deliver the response to.
+     */
+    public @NonNull String getPackageName() {
+        return mPackageName;
+    }
+
+    @Override
+    public String toString() {
+        return "AmbientContextDetectionServiceStatus { " + "statusCode = " + mStatusCode + ", "
+                + "packageName = " + mPackageName + " }";
+    }
+
+    @Override
+    public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+        byte flg = 0;
+        dest.writeByte(flg);
+        dest.writeInt(mStatusCode);
+        dest.writeString(mPackageName);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    AmbientContextDetectionServiceStatus(@NonNull android.os.Parcel in) {
+        byte flg = in.readByte();
+        int statusCode = in.readInt();
+        String packageName = in.readString();
+
+        this.mStatusCode = statusCode;
+        AnnotationValidations.validate(
+                StatusCode.class, null, mStatusCode);
+        this.mPackageName = packageName;
+        AnnotationValidations.validate(
+                NonNull.class, null, mPackageName);
+    }
+
+    public static final @NonNull Creator<AmbientContextDetectionServiceStatus> CREATOR =
+            new Creator<AmbientContextDetectionServiceStatus>() {
+        @Override
+        public AmbientContextDetectionServiceStatus[] newArray(int size) {
+            return new AmbientContextDetectionServiceStatus[size];
+        }
+
+        @Override
+        public AmbientContextDetectionServiceStatus createFromParcel(
+                @NonNull android.os.Parcel in) {
+            return new AmbientContextDetectionServiceStatus(in);
+        }
+    };
+
+    /**
+     * A builder for {@link AmbientContextDetectionServiceStatus}
+     */
+    @SuppressWarnings("WeakerAccess")
+    public static final class Builder {
+        private @StatusCode int mStatusCode;
+        private @NonNull String mPackageName;
+        private long mBuilderFieldsSet = 0L;
+
+        public Builder() {
+        }
+
+        /**
+         * Sets the status of the service.
+         */
+        public @NonNull Builder setStatusCode(@StatusCode int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x1;
+            mStatusCode = value;
+            return this;
+        }
+
+        /**
+         * The package to deliver the response to.
+         */
+        public @NonNull Builder setPackageName(@NonNull String value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x2;
+            mPackageName = value;
+            return this;
+        }
+
+        /** Builds the instance. This builder should not be touched after calling this! */
+        public @NonNull AmbientContextDetectionServiceStatus build() {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x4; // Mark builder used
+
+            if ((mBuilderFieldsSet & 0x1) == 0) {
+                mStatusCode = AmbientContextManager.STATUS_UNKNOWN;
+            }
+            if ((mBuilderFieldsSet & 0x2) == 0) {
+                mPackageName = "";
+            }
+            AmbientContextDetectionServiceStatus o = new AmbientContextDetectionServiceStatus(
+                    mStatusCode,
+                    mPackageName);
+            return o;
+        }
+
+        private void checkNotUsed() {
+            if ((mBuilderFieldsSet & 0x4) != 0) {
+                throw new IllegalStateException(
+                        "This Builder should not be reused. Use a new Builder instance instead");
+            }
+        }
+    }
+}
diff --git a/core/java/android/service/ambientcontext/IAmbientContextDetectionService.aidl b/core/java/android/service/ambientcontext/IAmbientContextDetectionService.aidl
index 1c6e25e..50c89c0 100644
--- a/core/java/android/service/ambientcontext/IAmbientContextDetectionService.aidl
+++ b/core/java/android/service/ambientcontext/IAmbientContextDetectionService.aidl
@@ -26,6 +26,8 @@
  */
 oneway interface IAmbientContextDetectionService {
     void startDetection(in AmbientContextEventRequest request, in String packageName,
-        in RemoteCallback callback);
+        in RemoteCallback detectionResultCallback, in RemoteCallback statusCallback);
     void stopDetection(in String packageName);
+    void queryServiceStatus(in int[] eventTypes, in String packageName,
+        in RemoteCallback callback);
 }
\ No newline at end of file
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index ae39d3d..b9e60a1 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -256,6 +256,8 @@
     public static final int REASON_CHANNEL_REMOVED = 20;
     /** Notification was canceled due to the app's storage being cleared */
     public static final int REASON_CLEAR_DATA = 21;
+    /** Notification was canceled due to an assistant adjustment update. */
+    public static final int REASON_ASSISTANT_CANCEL = 22;
 
     /**
      * @hide
@@ -279,7 +281,10 @@
             REASON_UNAUTOBUNDLED,
             REASON_CHANNEL_BANNED,
             REASON_SNOOZED,
-            REASON_TIMEOUT
+            REASON_TIMEOUT,
+            REASON_CHANNEL_REMOVED,
+            REASON_CLEAR_DATA,
+            REASON_ASSISTANT_CANCEL,
     })
     public @interface NotificationCancelReason{};
 
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index c5ccc18..36baa04 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -941,4 +941,14 @@
      * @hide
      */
     void unregisterTaskFpsCallback(in IOnFpsCallbackListener listener);
+
+    /**
+     * Take a snapshot using the same path that's used for Recents. This is used for Testing only.
+     *
+     * @param taskId to take the snapshot of
+     *
+     * Returns a bitmap of the screenshot or {@code null} if it was unable to screenshot.
+     * @hide
+     */
+    Bitmap snapshotTaskForRecents(int taskId);
 }
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 7f115fa..d3061e2 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -2779,9 +2779,13 @@
          * is allowed as a convenience.
          */
         public Transaction() {
-            mNativeObject = nativeCreateTransaction();
-            mFreeNativeResources
-                = sRegistry.registerNativeAllocation(this, mNativeObject);
+            this(nativeCreateTransaction());
+        }
+
+        private Transaction(long nativeObject) {
+            mNativeObject = nativeObject;
+            mFreeNativeResources =
+                    sRegistry.registerNativeAllocation(this, mNativeObject);
         }
 
         private Transaction(Parcel in) {
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 83a59e7..a2fcf80 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -527,20 +527,12 @@
         mRequestedVisible = false;
 
         updateSurface();
-        tryReleaseSurfaces();
 
         // We don't release this as part of releaseSurfaces as
         // that is also called on transient visibility changes. We can't
         // recreate this Surface, so only release it when we are fully
         // detached.
-        if (mSurfacePackage != null) {
-            final SurfaceControl sc = mSurfacePackage.getSurfaceControl();
-            if (sc != null && sc.isValid()) {
-                mTmpTransaction.reparent(sc, null).apply();
-            }
-            mSurfacePackage.release();
-            mSurfacePackage = null;
-        }
+        tryReleaseSurfaces(true /* releaseSurfacePackage*/);
 
         mHaveFrame = false;
         super.onDetachedFromWindow();
@@ -871,7 +863,7 @@
         return t;
     }
 
-    private void tryReleaseSurfaces() {
+    private void tryReleaseSurfaces(boolean releaseSurfacePackage) {
         mSurfaceAlpha = 1f;
 
         synchronized (mSurfaceControlLock) {
@@ -881,9 +873,26 @@
                 mBlastBufferQueue = null;
             }
 
-            ViewRootImpl viewRoot = getViewRootImpl();
             Transaction transaction = new Transaction();
-            releaseSurfaces(transaction);
+            if (mSurfaceControl != null) {
+                transaction.remove(mSurfaceControl);
+                mSurfaceControl = null;
+            }
+            if (mBackgroundControl != null) {
+                transaction.remove(mBackgroundControl);
+                mBackgroundControl = null;
+            }
+            if (mBlastSurfaceControl != null) {
+                transaction.remove(mBlastSurfaceControl);
+                mBlastSurfaceControl = null;
+            }
+
+            if (releaseSurfacePackage && mSurfacePackage != null) {
+                mSurfacePackage.release();
+                mSurfacePackage = null;
+            }
+
+            ViewRootImpl viewRoot = getViewRootImpl();
             if (viewRoot != null) {
                 viewRoot.applyTransactionOnDraw(transaction);
             } else {
@@ -892,22 +901,6 @@
         }
     }
 
-    private void releaseSurfaces(Transaction transaction) {
-        if (mSurfaceControl != null) {
-            transaction.remove(mSurfaceControl);
-            mSurfaceControl = null;
-        }
-        if (mBackgroundControl != null) {
-            transaction.remove(mBackgroundControl);
-            mBackgroundControl = null;
-        }
-        if (mBlastSurfaceControl != null) {
-            transaction.remove(mBlastSurfaceControl);
-            mBlastSurfaceControl = null;
-        }
-    }
-
-
     // The position update listener is used to safely share the surface size between render thread
     // workers and the UI thread. Both threads need to know the surface size to determine the scale.
     // The parent layer scales the surface size to view size. The child (BBQ) layer scales
@@ -1048,7 +1041,7 @@
 
         if (viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) {
             notifySurfaceDestroyed();
-            tryReleaseSurfaces();
+            tryReleaseSurfaces(false /* releaseSurfacePackage*/);
             return;
         }
 
@@ -1189,7 +1182,7 @@
                 } finally {
                     mIsCreating = false;
                     if (mSurfaceControl != null && !mSurfaceCreated) {
-                        tryReleaseSurfaces();
+                        tryReleaseSurfaces(false /* releaseSurfacePackage*/);
                     }
                 }
             } catch (Exception ex) {
@@ -1835,43 +1828,24 @@
      * @param p The SurfacePackage to embed.
      */
     public void setChildSurfacePackage(@NonNull SurfaceControlViewHost.SurfacePackage p) {
-        setChildSurfacePackage(p, false /* applyTransactionOnDraw */);
-    }
-
-    /**
-     * Similar to setChildSurfacePackage, but using the BLAST queue so the transaction can be
-     * synchronized with the ViewRootImpl frame.
-     * @hide
-     */
-    public void setChildSurfacePackageOnDraw(
-            @NonNull SurfaceControlViewHost.SurfacePackage p) {
-        setChildSurfacePackage(p, true /* applyTransactionOnDraw */);
-    }
-
-    /**
-     * @param applyTransactionOnDraw Whether to apply transaction at onDraw or immediately.
-     */
-    private void setChildSurfacePackage(
-            @NonNull SurfaceControlViewHost.SurfacePackage p, boolean applyTransactionOnDraw) {
         final SurfaceControl lastSc = mSurfacePackage != null ?
                 mSurfacePackage.getSurfaceControl() : null;
+        final SurfaceControl.Transaction transaction = new Transaction();
         if (mSurfaceControl != null) {
             if (lastSc != null) {
-                mTmpTransaction.reparent(lastSc, null);
+                transaction.reparent(lastSc, null);
                 mSurfacePackage.release();
             }
-            reparentSurfacePackage(mTmpTransaction, p);
-            applyTransaction(applyTransactionOnDraw);
+            reparentSurfacePackage(transaction, p);
+            final ViewRootImpl viewRoot = getViewRootImpl();
+            if (viewRoot != null) {
+                viewRoot.applyTransactionOnDraw(transaction);
+            } else {
+                transaction.apply();
+            }
         }
         mSurfacePackage = p;
-    }
-
-    private void applyTransaction(boolean applyTransactionOnDraw) {
-        if (applyTransactionOnDraw) {
-            getViewRootImpl().applyTransactionOnDraw(mTmpTransaction);
-        } else {
-            mTmpTransaction.apply();
-        }
+        invalidate();
     }
 
     private void reparentSurfacePackage(SurfaceControl.Transaction t,
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 777e89d..39fc2c0 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -4169,19 +4169,22 @@
                         + " didProduceBuffer=" + didProduceBuffer);
             }
 
+            Transaction tmpTransaction = new Transaction();
+            tmpTransaction.merge(mRtBLASTSyncTransaction);
+
             // If frame wasn't drawn, clear out the next transaction so it doesn't affect the next
             // draw attempt. The next transaction and transaction complete callback were only set
             // for the current draw attempt.
             if (!didProduceBuffer) {
                 mBlastBufferQueue.setSyncTransaction(null);
-                // Apply the transactions that were sent to mergeWithNextTransaction since the
+                // Get the transactions that were sent to mergeWithNextTransaction since the
                 // frame didn't draw on this vsync. It's possible the frame will draw later, but
                 // it's better to not be sync than to block on a frame that may never come.
-                mBlastBufferQueue.applyPendingTransactions(mRtLastAttemptedDrawFrameNum);
+                Transaction pendingTransactions = mBlastBufferQueue.gatherPendingTransactions(
+                        mRtLastAttemptedDrawFrameNum);
+                tmpTransaction.merge(pendingTransactions);
             }
 
-            Transaction tmpTransaction = new Transaction();
-            tmpTransaction.merge(mRtBLASTSyncTransaction);
             // Post at front of queue so the buffer can be processed immediately and allow RT
             // to continue processing new buffers. If RT tries to process buffers before the sync
             // buffer is applied, the new buffers will not get acquired and could result in a
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index ca7f900..771d40b 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -97,6 +97,7 @@
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
+import android.graphics.Bitmap;
 import android.graphics.Insets;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
@@ -4886,4 +4887,21 @@
      */
     @SystemApi
     default void unregisterTaskFpsCallback(@NonNull TaskFpsCallback callback) {}
+
+    /**
+     * Take a snapshot using the same path that's used for Recents. This is used for Testing only.
+     *
+     * @param taskId to take the snapshot of
+     *
+     * @return a bitmap of the screenshot or {@code null} if it was unable to screenshot. The
+     * screenshot can fail if the taskId is invalid or if there's no SurfaceControl associated with
+     * that task.
+     *
+     * @hide
+     */
+    @TestApi
+    @Nullable
+    default Bitmap snapshotTaskForRecents(@IntRange(from = 0) int taskId) {
+        return null;
+    }
 }
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index c16703ef..f4353eb 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -32,6 +32,7 @@
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Configuration;
+import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.os.Bundle;
@@ -439,4 +440,14 @@
         } catch (RemoteException e) {
         }
     }
+
+    @Override
+    public Bitmap snapshotTaskForRecents(int taskId) {
+        try {
+            return WindowManagerGlobal.getWindowManagerService().snapshotTaskForRecents(taskId);
+        } catch (RemoteException e) {
+            e.rethrowAsRuntimeException();
+        }
+        return null;
+    }
 }
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index e54ed18..c6cd2e8 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -1773,8 +1773,7 @@
      * @param userId The user Id.
      * @hide
      */
-    @RequiresPermission(Manifest.permission.SET_SYSTEM_AUDIO_CAPTION)
-    public void setSystemAudioCaptioningRequested(boolean isEnabled, int userId) {
+    public void setSystemAudioCaptioningEnabled(boolean isEnabled, int userId) {
         final IAccessibilityManager service;
         synchronized (mLock) {
             service = getServiceLocked();
@@ -1783,7 +1782,7 @@
             }
         }
         try {
-            service.setSystemAudioCaptioningRequested(isEnabled, userId);
+            service.setSystemAudioCaptioningEnabled(isEnabled, userId);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
@@ -1796,7 +1795,7 @@
      * @return the system audio caption UI enabled state.
      * @hide
      */
-    public boolean isSystemAudioCaptioningUiRequested(int userId) {
+    public boolean isSystemAudioCaptioningUiEnabled(int userId) {
         final IAccessibilityManager service;
         synchronized (mLock) {
             service = getServiceLocked();
@@ -1805,7 +1804,7 @@
             }
         }
         try {
-            return service.isSystemAudioCaptioningUiRequested(userId);
+            return service.isSystemAudioCaptioningUiEnabled(userId);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
@@ -1818,8 +1817,7 @@
      * @param userId The user Id.
      * @hide
      */
-    @RequiresPermission(Manifest.permission.SET_SYSTEM_AUDIO_CAPTION)
-    public void setSystemAudioCaptioningUiRequested(boolean isEnabled, int userId) {
+    public void setSystemAudioCaptioningUiEnabled(boolean isEnabled, int userId) {
         final IAccessibilityManager service;
         synchronized (mLock) {
             service = getServiceLocked();
@@ -1828,7 +1826,7 @@
             }
         }
         try {
-            service.setSystemAudioCaptioningUiRequested(isEnabled, userId);
+            service.setSystemAudioCaptioningUiEnabled(isEnabled, userId);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
diff --git a/core/java/android/view/accessibility/CaptioningManager.java b/core/java/android/view/accessibility/CaptioningManager.java
index 4f9781b..e960bec 100644
--- a/core/java/android/view/accessibility/CaptioningManager.java
+++ b/core/java/android/view/accessibility/CaptioningManager.java
@@ -152,7 +152,7 @@
     /**
      * @return the system audio caption enabled state.
      */
-    public final boolean isSystemAudioCaptioningRequested() {
+    public final boolean isSystemAudioCaptioningEnabled() {
         return Secure.getIntForUser(mContentResolver, Secure.ODI_CAPTIONS_ENABLED,
                 SYSTEM_AUDIO_CAPTIONING_DEFAULT_ENABLED ? 1 : 0, mContext.getUserId()) == 1;
     }
@@ -169,9 +169,9 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.SET_SYSTEM_AUDIO_CAPTION)
-    public final void setSystemAudioCaptioningRequested(boolean isEnabled) {
+    public final void setSystemAudioCaptioningEnabled(boolean isEnabled) {
         if (mAccessibilityManager != null) {
-            mAccessibilityManager.setSystemAudioCaptioningRequested(isEnabled,
+            mAccessibilityManager.setSystemAudioCaptioningEnabled(isEnabled,
                     mContext.getUserId());
         }
     }
@@ -179,9 +179,9 @@
     /**
      * @return the system audio caption UI enabled state.
      */
-    public final boolean isSystemAudioCaptioningUiRequested() {
+    public final boolean isSystemAudioCaptioningUiEnabled() {
         return mAccessibilityManager != null
-                && mAccessibilityManager.isSystemAudioCaptioningUiRequested(mContext.getUserId());
+                && mAccessibilityManager.isSystemAudioCaptioningUiEnabled(mContext.getUserId());
     }
 
     /**
@@ -196,9 +196,9 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.SET_SYSTEM_AUDIO_CAPTION)
-    public final void setSystemAudioCaptioningUiRequested(boolean isEnabled) {
+    public final void setSystemAudioCaptioningUiEnabled(boolean isEnabled) {
         if (mAccessibilityManager != null) {
-            mAccessibilityManager.setSystemAudioCaptioningUiRequested(isEnabled,
+            mAccessibilityManager.setSystemAudioCaptioningUiEnabled(isEnabled,
                     mContext.getUserId());
         }
     }
@@ -300,7 +300,7 @@
     }
 
     private void notifySystemAudioCaptionChanged() {
-        final boolean enabled = isSystemAudioCaptioningRequested();
+        final boolean enabled = isSystemAudioCaptioningEnabled();
         synchronized (mListeners) {
             for (CaptioningChangeListener listener : mListeners) {
                 listener.onSystemAudioCaptioningChanged(enabled);
@@ -309,7 +309,7 @@
     }
 
     private void notifySystemAudioCaptionUiChanged() {
-        final boolean enabled = isSystemAudioCaptioningUiRequested();
+        final boolean enabled = isSystemAudioCaptioningUiEnabled();
         synchronized (mListeners) {
             for (CaptioningChangeListener listener : mListeners) {
                 listener.onSystemAudioCaptioningUiChanged(enabled);
@@ -686,7 +686,7 @@
          * @param isEnabled The system audio captioning enabled state.
          * @param userId The user Id.
          */
-        void setSystemAudioCaptioningRequested(boolean isEnabled, int userId);
+        void setSystemAudioCaptioningEnabled(boolean isEnabled, int userId);
 
         /**
          * Gets the system audio caption UI enabled state.
@@ -694,7 +694,7 @@
          * @param userId The user Id.
          * @return the system audio caption UI enabled state.
          */
-        boolean isSystemAudioCaptioningUiRequested(int userId);
+        boolean isSystemAudioCaptioningUiEnabled(int userId);
 
         /**
          * Sets the system audio caption UI enabled state.
@@ -702,6 +702,6 @@
          * @param isEnabled The system audio captioning UI enabled state.
          * @param userId The user Id.
          */
-        void setSystemAudioCaptioningUiRequested(boolean isEnabled, int userId);
+        void setSystemAudioCaptioningUiEnabled(boolean isEnabled, int userId);
     }
 }
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 645ddf5..418132a 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -101,13 +101,11 @@
 
     boolean isAudioDescriptionByDefaultEnabled();
 
-    // Requires Manifest.permission.SET_SYSTEM_AUDIO_CAPTION
-    // System process only
-    void setSystemAudioCaptioningRequested(boolean isEnabled, int userId);
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.SET_SYSTEM_AUDIO_CAPTION)")
+    void setSystemAudioCaptioningEnabled(boolean isEnabled, int userId);
 
-    boolean isSystemAudioCaptioningUiRequested(int userId);
+    boolean isSystemAudioCaptioningUiEnabled(int userId);
 
-    // Requires Manifest.permission.SET_SYSTEM_AUDIO_CAPTION
-    // System process only
-    void setSystemAudioCaptioningUiRequested(boolean isEnabled, int userId);
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.SET_SYSTEM_AUDIO_CAPTION)")
+    void setSystemAudioCaptioningUiEnabled(boolean isEnabled, int userId);
 }
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index f480b24..c713a54 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -115,6 +115,7 @@
 import java.util.Objects;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
 
 /**
  * Central system API to the overall input method framework (IMF) architecture,
@@ -426,6 +427,8 @@
     int mCursorSelEnd;
     int mCursorCandStart;
     int mCursorCandEnd;
+    int mInitialSelStart;
+    int mInitialSelEnd;
 
     /**
      * The instance that has previously been sent to the input method.
@@ -468,6 +471,13 @@
     @Nullable
     @GuardedBy("mH")
     private InputMethodSessionWrapper mCurrentInputMethodSession = null;
+    /**
+     * Encapsulates IPCs to the currently connected AccessibilityServices.
+     */
+    @Nullable
+    @GuardedBy("mH")
+    private final SparseArray<InputMethodSessionWrapper> mAccessibilityInputMethodSession =
+            new SparseArray<>();
 
     InputChannel mCurChannel;
     ImeInputEventSender mCurSender;
@@ -499,6 +509,8 @@
     static final int MSG_TIMEOUT_INPUT_EVENT = 6;
     static final int MSG_FLUSH_INPUT_EVENT = 7;
     static final int MSG_REPORT_FULLSCREEN_MODE = 10;
+    static final int MSG_BIND_ACCESSIBILITY_SERVICE = 11;
+    static final int MSG_UNBIND_ACCESSIBILITY_SERVICE = 12;
 
     private static boolean isAutofillUIShowing(View servedView) {
         AutofillManager afm = servedView.getContext().getSystemService(AutofillManager.class);
@@ -626,6 +638,7 @@
                 if (mCurrentInputMethodSession != null) {
                     mCurrentInputMethodSession.finishInput();
                 }
+                forAccessibilitySessions(InputMethodSessionWrapper::finishInput);
             }
         }
 
@@ -881,6 +894,7 @@
                         if (mBindSequence != sequence) {
                             return;
                         }
+                        clearAllAccessibilityBindingLocked();
                         clearBindingLocked();
                         // If we were actively using the last input method, then
                         // we would like to re-connect to the next input method.
@@ -896,6 +910,73 @@
                     }
                     return;
                 }
+                case MSG_BIND_ACCESSIBILITY_SERVICE: {
+                    final int id = msg.arg1;
+                    final InputBindResult res = (InputBindResult) msg.obj;
+                    if (DEBUG) {
+                        Log.i(TAG, "handleMessage: MSG_BIND_ACCESSIBILITY " + res.sequence
+                                + "," + res.id);
+                    }
+                    synchronized (mH) {
+                        if (mBindSequence < 0 || mBindSequence != res.sequence) {
+                            Log.w(TAG, "Ignoring onBind: cur seq=" + mBindSequence
+                                    + ", given seq=" + res.sequence);
+                            if (res.channel != null && res.channel != mCurChannel) {
+                                res.channel.dispose();
+                            }
+                            return;
+                        }
+
+                        // Since IMM can start inputting text before a11y sessions are back,
+                        // we send a notification so that the a11y service knows the session is
+                        // registered and update the a11y service with the current cursor positions.
+                        if (res.accessibilitySessions != null) {
+                            InputMethodSessionWrapper wrapper =
+                                    InputMethodSessionWrapper.createOrNull(
+                                            res.accessibilitySessions.get(id));
+                            if (wrapper != null) {
+                                mAccessibilityInputMethodSession.put(id, wrapper);
+                                if (mServedInputConnection != null) {
+                                    wrapper.updateSelection(mInitialSelStart, mInitialSelEnd,
+                                            mCursorSelStart, mCursorSelEnd, mCursorCandStart,
+                                            mCursorCandEnd);
+                                } else {
+                                    // If an a11y service binds before input starts, we should still
+                                    // send a notification because the a11y service doesn't know it
+                                    // binds before or after input starts, it may wonder if it binds
+                                    // after input starts, why it doesn't receive a notification of
+                                    // the current cursor positions.
+                                    wrapper.updateSelection(-1, -1,
+                                            -1, -1, -1,
+                                            -1);
+                                }
+                            }
+                        }
+                        mBindSequence = res.sequence;
+                    }
+                    startInputInner(StartInputReason.BOUND_ACCESSIBILITY_SESSION_TO_IMMS, null,
+                            0, 0, 0);
+                    return;
+                }
+                case MSG_UNBIND_ACCESSIBILITY_SERVICE: {
+                    final int sequence = msg.arg1;
+                    final int id = msg.arg2;
+                    if (DEBUG) {
+                        Log.i(TAG, "handleMessage: MSG_UNBIND_ACCESSIBILITY_SERVICE "
+                                + sequence + " id=" + id);
+                    }
+                    synchronized (mH) {
+                        if (mBindSequence != sequence) {
+                            if (DEBUG) {
+                                Log.i(TAG, "mBindSequence =" + mBindSequence + " sequence ="
+                                        + sequence + " id=" + id);
+                            }
+                            return;
+                        }
+                        clearAccessibilityBindingLocked(id);
+                    }
+                    return;
+                }
                 case MSG_SET_ACTIVE: {
                     final boolean active = msg.arg1 != 0;
                     final boolean fullscreen = msg.arg2 != 0;
@@ -996,11 +1077,21 @@
         }
 
         @Override
+        public void onBindAccessibilityService(InputBindResult res, int id) {
+            mH.obtainMessage(MSG_BIND_ACCESSIBILITY_SERVICE, id, 0, res).sendToTarget();
+        }
+
+        @Override
         public void onUnbindMethod(int sequence, @UnbindReason int unbindReason) {
             mH.obtainMessage(MSG_UNBIND, sequence, unbindReason).sendToTarget();
         }
 
         @Override
+        public void onUnbindAccessibilityService(int sequence, int id) {
+            mH.obtainMessage(MSG_UNBIND_ACCESSIBILITY_SERVICE, sequence, id).sendToTarget();
+        }
+
+        @Override
         public void setActive(boolean active, boolean fullscreen, boolean reportToImeController) {
             mH.obtainMessage(MSG_SET_ACTIVE, active ? 1 : 0, fullscreen ? 1 : 0,
                     reportToImeController).sendToTarget();
@@ -1420,16 +1511,36 @@
     /**
      * Reset all of the state associated with being bound to an input method.
      */
+    @GuardedBy("mH")
     void clearBindingLocked() {
         if (DEBUG) Log.v(TAG, "Clearing binding!");
         clearConnectionLocked();
         setInputChannelLocked(null);
+        // We only reset sequence number for input method, but not accessibility.
         mBindSequence = -1;
         mCurId = null;
         mCurMethod = null; // for @UnsupportedAppUsage
         mCurrentInputMethodSession = null;
     }
 
+    /**
+     * Reset all of the state associated with being bound to an accessibility service.
+     */
+    @GuardedBy("mH")
+    void clearAccessibilityBindingLocked(int id) {
+        if (DEBUG) Log.v(TAG, "Clearing accessibility binding " + id);
+        mAccessibilityInputMethodSession.remove(id);
+    }
+
+    /**
+     * Reset all of the state associated with being bound to all ccessibility services.
+     */
+    @GuardedBy("mH")
+    void clearAllAccessibilityBindingLocked() {
+        if (DEBUG) Log.v(TAG, "Clearing all accessibility bindings");
+        mAccessibilityInputMethodSession.clear();
+    }
+
     void setInputChannelLocked(InputChannel channel) {
         if (mCurChannel == channel) {
             return;
@@ -1938,6 +2049,8 @@
             editorInfo.setInitialSurroundingTextInternal(textSnapshot.getSurroundingText());
             mCurrentInputMethodSession.invalidateInput(editorInfo, mServedInputConnection,
                     sessionId);
+            forAccessibilitySessions(wrapper -> wrapper.invalidateInput(editorInfo,
+                    mServedInputConnection, sessionId));
         }
     }
 
@@ -2080,6 +2193,8 @@
             if (ic != null) {
                 mCursorSelStart = tba.initialSelStart;
                 mCursorSelEnd = tba.initialSelEnd;
+                mInitialSelStart = mCursorSelStart;
+                mInitialSelEnd = mCursorSelEnd;
                 mCursorCandStart = -1;
                 mCursorCandEnd = -1;
                 mCursorRect.setEmpty();
@@ -2128,6 +2243,17 @@
                 mBindSequence = res.sequence;
                 mCurMethod = res.method; // for @UnsupportedAppUsage
                 mCurrentInputMethodSession = InputMethodSessionWrapper.createOrNull(res.method);
+                mAccessibilityInputMethodSession.clear();
+                if (res.accessibilitySessions != null) {
+                    for (int i = 0; i < res.accessibilitySessions.size(); i++) {
+                        InputMethodSessionWrapper wrapper = InputMethodSessionWrapper.createOrNull(
+                                res.accessibilitySessions.valueAt(i));
+                        if (wrapper != null) {
+                            mAccessibilityInputMethodSession.append(
+                                    res.accessibilitySessions.keyAt(i), wrapper);
+                        }
+                    }
+                }
                 mCurId = res.id;
             } else if (res.channel != null && res.channel != mCurChannel) {
                 res.channel.dispose();
@@ -2137,8 +2263,10 @@
                     mRestartOnNextWindowFocus = true;
                     break;
             }
-            if (mCurrentInputMethodSession != null && mCompletions != null) {
-                mCurrentInputMethodSession.displayCompletions(mCompletions);
+            if (mCompletions != null) {
+                if (mCurrentInputMethodSession != null) {
+                    mCurrentInputMethodSession.displayCompletions(mCompletions);
+                }
             }
         }
 
@@ -2369,6 +2497,8 @@
                 mCursorCandEnd = candidatesEnd;
                 mCurrentInputMethodSession.updateSelection(
                         oldSelStart, oldSelEnd, selStart, selEnd, candidatesStart, candidatesEnd);
+                forAccessibilitySessions(wrapper -> wrapper.updateSelection(oldSelStart,
+                        oldSelEnd, selStart, selEnd, candidatesStart, candidatesEnd));
             }
         }
     }
@@ -3233,6 +3363,11 @@
         } else {
             p.println("  mCurMethod= null");
         }
+        for (int i = 0; i < mAccessibilityInputMethodSession.size(); i++) {
+            p.println("  mAccessibilityInputMethodSession("
+                    + mAccessibilityInputMethodSession.keyAt(i) + ")="
+                    + mAccessibilityInputMethodSession.valueAt(i));
+        }
         p.println("  mCurRootView=" + mCurRootView);
         p.println("  mServedView=" + getServedViewLocked());
         p.println("  mNextServedView=" + getNextServedViewLocked());
@@ -3377,4 +3512,10 @@
             }
         }
     }
+
+    private void forAccessibilitySessions(Consumer<InputMethodSessionWrapper> consumer) {
+        for (int i = 0; i < mAccessibilityInputMethodSession.size(); i++) {
+            consumer.accept(mAccessibilityInputMethodSession.valueAt(i));
+        }
+    }
 }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 9efa583..c0c7641 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -12295,7 +12295,7 @@
                     EXTRA_DATA_RENDERING_INFO_KEY,
                     EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY
             ));
-            info.setTextSelectable(isTextSelectable());
+            info.setTextSelectable(isTextSelectable() || isTextEditable());
         } else {
             info.setAvailableExtraData(Arrays.asList(
                     EXTRA_DATA_RENDERING_INFO_KEY
diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java
index b90e628..34a3418 100644
--- a/core/java/android/window/SplashScreenView.java
+++ b/core/java/android/window/SplashScreenView.java
@@ -493,7 +493,7 @@
             Log.d(TAG, "Transferring surface " + mSurfaceView.toString());
         }
 
-        mSurfaceView.setChildSurfacePackageOnDraw(mSurfacePackage);
+        mSurfaceView.setChildSurfacePackage(mSurfacePackage);
     }
 
     void initIconAnimation(Drawable iconDrawable, long duration) {
diff --git a/core/java/com/android/internal/inputmethod/InputBindResult.java b/core/java/com/android/internal/inputmethod/InputBindResult.java
index 1357bac..e838401 100644
--- a/core/java/com/android/internal/inputmethod/InputBindResult.java
+++ b/core/java/com/android/internal/inputmethod/InputBindResult.java
@@ -25,6 +25,7 @@
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.SparseArray;
 import android.view.InputChannel;
 
 import com.android.internal.view.IInputMethodSession;
@@ -53,7 +54,8 @@
             ResultCode.ERROR_NOT_IME_TARGET_WINDOW,
             ResultCode.ERROR_NO_EDITOR,
             ResultCode.ERROR_DISPLAY_ID_MISMATCH,
-            ResultCode.ERROR_INVALID_DISPLAY_ID
+            ResultCode.ERROR_INVALID_DISPLAY_ID,
+            ResultCode.SUCCESS_WITH_ACCESSIBILITY_SESSION
     })
     public @interface ResultCode {
         /**
@@ -168,6 +170,7 @@
          * display.
          */
         int ERROR_INVALID_DISPLAY_ID = 15;
+        int SUCCESS_WITH_ACCESSIBILITY_SESSION = 16;
     }
 
     @ResultCode
@@ -179,6 +182,11 @@
     public final IInputMethodSession method;
 
     /**
+     * The accessibility services.
+     */
+    public SparseArray<IInputMethodSession> accessibilitySessions;
+
+    /**
      * The input channel used to send input events to this IME.
      */
     public final InputChannel channel;
@@ -204,6 +212,8 @@
      *
      * @param result A result code defined in {@link ResultCode}.
      * @param method {@link IInputMethodSession} to interact with the IME.
+     * @param accessibilitySessions {@link IInputMethodSession} to interact with accessibility
+     *                              services.
      * @param channel {@link InputChannel} to forward input events to the IME.
      * @param id The {@link String} representations of the IME, which is the same as
      *           {@link android.view.inputmethod.InputMethodInfo#getId()} and
@@ -213,10 +223,12 @@
      *                                             {@code suppressesSpellChecker="true"}.
      */
     public InputBindResult(@ResultCode int result,
-            IInputMethodSession method, InputChannel channel, String id, int sequence,
+            IInputMethodSession method, SparseArray<IInputMethodSession> accessibilitySessions,
+            InputChannel channel, String id, int sequence,
             boolean isInputMethodSuppressingSpellChecker) {
         this.result = result;
         this.method = method;
+        this.accessibilitySessions = accessibilitySessions;
         this.channel = channel;
         this.id = id;
         this.sequence = sequence;
@@ -226,6 +238,19 @@
     private InputBindResult(Parcel source) {
         result = source.readInt();
         method = IInputMethodSession.Stub.asInterface(source.readStrongBinder());
+        int n = source.readInt();
+        if (n < 0) {
+            accessibilitySessions = null;
+        } else {
+            accessibilitySessions = new SparseArray<>(n);
+            while (n > 0) {
+                int key = source.readInt();
+                IInputMethodSession value =
+                        IInputMethodSession.Stub.asInterface(source.readStrongBinder());
+                accessibilitySessions.append(key, value);
+                n--;
+            }
+        }
         if (source.readInt() != 0) {
             channel = InputChannel.CREATOR.createFromParcel(source);
         } else {
@@ -254,6 +279,18 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(result);
         dest.writeStrongInterface(method);
+        if (accessibilitySessions == null) {
+            dest.writeInt(-1);
+        } else {
+            int n = accessibilitySessions.size();
+            dest.writeInt(n);
+            int i = 0;
+            while (i < n) {
+                dest.writeInt(accessibilitySessions.keyAt(i));
+                dest.writeStrongInterface(accessibilitySessions.valueAt(i));
+                i++;
+            }
+        }
         if (channel != null) {
             dest.writeInt(1);
             channel.writeToParcel(dest, flags);
@@ -329,7 +366,7 @@
     }
 
     private static InputBindResult error(@ResultCode int result) {
-        return new InputBindResult(result, null, null, null, -1, false);
+        return new InputBindResult(result, null, null, null, null, -1, false);
     }
 
     /**
diff --git a/core/java/com/android/internal/inputmethod/InputMethodDebug.java b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
index bf094db..d669768 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodDebug.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
@@ -64,6 +64,8 @@
                 return "DEACTIVATED_BY_IMMS";
             case StartInputReason.SESSION_CREATED_BY_IME:
                 return "SESSION_CREATED_BY_IME";
+            case StartInputReason.BOUND_ACCESSIBILITY_SESSION_TO_IMMS:
+                return "BOUND_ACCESSIBILITY_SESSION_TO_IMMS";
             default:
                 return "Unknown=" + reason;
         }
@@ -91,6 +93,8 @@
                 return "SWITCH_IME_FAILED";
             case UnbindReason.SWITCH_USER:
                 return "SWITCH_USER";
+            case UnbindReason.ACCESSIBILITY_SERVICE_DISABLED:
+                return "ACCESSIBILITY_SERVICE_DISABLED";
             default:
                 return "Unknown=" + reason;
         }
diff --git a/core/java/com/android/internal/inputmethod/StartInputReason.java b/core/java/com/android/internal/inputmethod/StartInputReason.java
index 2ba708d..1263466 100644
--- a/core/java/com/android/internal/inputmethod/StartInputReason.java
+++ b/core/java/com/android/internal/inputmethod/StartInputReason.java
@@ -38,7 +38,9 @@
         StartInputReason.UNBOUND_FROM_IMMS,
         StartInputReason.ACTIVATED_BY_IMMS,
         StartInputReason.DEACTIVATED_BY_IMMS,
-        StartInputReason.SESSION_CREATED_BY_IME})
+        StartInputReason.SESSION_CREATED_BY_IME,
+        StartInputReason.SESSION_CREATED_BY_ACCESSIBILITY,
+        StartInputReason.BOUND_ACCESSIBILITY_SESSION_TO_IMMS})
 public @interface StartInputReason {
     /**
      * Reason is not specified.
@@ -96,4 +98,14 @@
      * {@link com.android.internal.view.IInputSessionCallback#sessionCreated}.
      */
     int SESSION_CREATED_BY_IME = 10;
+    /**
+     * {@link android.accessibilityservice.AccessibilityService} is responding to
+     * {@link com.android.internal.view.IInputSessionWithIdCallback#sessionCreated}.
+     */
+    int SESSION_CREATED_BY_ACCESSIBILITY = 11;
+    /**
+     * {@link android.view.inputmethod.InputMethodManager} is responding to
+     * {@link com.android.internal.view.IInputMethodClient#onBindAccessibilityService(InputBindResult, int)}.
+     */
+    int BOUND_ACCESSIBILITY_SESSION_TO_IMMS = 12;
 }
diff --git a/core/java/com/android/internal/inputmethod/UnbindReason.java b/core/java/com/android/internal/inputmethod/UnbindReason.java
index f0f18f1..e926625 100644
--- a/core/java/com/android/internal/inputmethod/UnbindReason.java
+++ b/core/java/com/android/internal/inputmethod/UnbindReason.java
@@ -34,7 +34,9 @@
         UnbindReason.DISCONNECT_IME,
         UnbindReason.NO_IME,
         UnbindReason.SWITCH_IME_FAILED,
-        UnbindReason.SWITCH_USER})
+        UnbindReason.SWITCH_USER,
+        UnbindReason.ACCESSIBILITY_SERVICE_DISABLED
+})
 public @interface UnbindReason {
     /**
      * Reason is not specified.
@@ -66,4 +68,5 @@
      * user's active IME.
      */
     int SWITCH_USER = 6;
+    int ACCESSIBILITY_SERVICE_DISABLED = 7;
 }
diff --git a/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java
index d8e89b4..888f830 100644
--- a/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java
+++ b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java
@@ -22,10 +22,6 @@
 import android.os.BatteryStats;
 import android.os.BatteryUsageStats;
 import android.os.BatteryUsageStatsQuery;
-import android.os.UserHandle;
-import android.util.SparseArray;
-
-import java.util.List;
 
 /**
  * Estimates power consumed by the ambient display
@@ -67,29 +63,6 @@
                         powerMah, powerModel);
     }
 
-    /**
-     * Ambient display power is the additional power the screen takes while in ambient display/
-     * screen doze/ always-on display (interchangeable terms) mode. Ambient display power should
-     * be hidden {@link BatteryStatsHelper#shouldHideSipper(BatterySipper)}, but should not be
-     * included in smearing {@link BatteryStatsHelper#removeHiddenBatterySippers(List)}.
-     */
-    @Override
-    public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
-            long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
-        final long measuredEnergyUC = batteryStats.getScreenDozeMeasuredBatteryConsumptionUC();
-        final long durationMs = calculateDuration(batteryStats, rawRealtimeUs, statsType);
-        final int powerModel = getPowerModel(measuredEnergyUC);
-        final double powerMah = calculateTotalPower(powerModel, batteryStats, rawRealtimeUs,
-                measuredEnergyUC);
-        if (powerMah > 0) {
-            BatterySipper bs = new BatterySipper(BatterySipper.DrainType.AMBIENT_DISPLAY, null, 0);
-            bs.usagePowerMah = powerMah;
-            bs.usageTimeMs = durationMs;
-            bs.sumPower();
-            sippers.add(bs);
-        }
-    }
-
     private long calculateDuration(BatteryStats batteryStats, long rawRealtimeUs, int statsType) {
         return batteryStats.getScreenDozeTime(rawRealtimeUs, statsType) / 1000;
     }
diff --git a/core/java/com/android/internal/os/BatteryChargeCalculator.java b/core/java/com/android/internal/os/BatteryChargeCalculator.java
index 71a1463..912ec8f 100644
--- a/core/java/com/android/internal/os/BatteryChargeCalculator.java
+++ b/core/java/com/android/internal/os/BatteryChargeCalculator.java
@@ -20,10 +20,6 @@
 import android.os.BatteryStats;
 import android.os.BatteryUsageStats;
 import android.os.BatteryUsageStatsQuery;
-import android.os.UserHandle;
-import android.util.SparseArray;
-
-import java.util.List;
 
 /**
  * Estimates the battery discharge amounts.
@@ -81,10 +77,4 @@
                 BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE)
                 .setConsumedPower(dischargeMah);
     }
-
-    @Override
-    public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
-            long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
-        // Not implemented. The computation is done by BatteryStatsHelper
-    }
 }
diff --git a/core/java/com/android/internal/os/BatterySipper.java b/core/java/com/android/internal/os/BatterySipper.java
deleted file mode 100644
index dfd561a..0000000
--- a/core/java/com/android/internal/os/BatterySipper.java
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.os;
-
-import android.compat.annotation.UnsupportedAppUsage;
-import android.os.BatteryStats.Uid;
-import android.os.Build;
-
-import java.util.List;
-
-/**
- * Contains power usage of an application, system service, or hardware type.
- *
- * @deprecated Please use BatteryStatsManager.getBatteryUsageStats instead.
- */
-@Deprecated
-public class BatterySipper implements Comparable<BatterySipper> {
-    @UnsupportedAppUsage
-    public int userId;
-    @UnsupportedAppUsage
-    public Uid uidObj;
-    @UnsupportedAppUsage
-    public DrainType drainType;
-
-    /**
-     * Smeared power from screen usage.
-     * We split the screen usage power and smear them among apps, based on activity time.
-     * The actual screen usage power may be measured or estimated, affecting the granularity and
-     * accuracy of the smearing, but the smearing algorithm is essentially the same.
-     */
-    public double screenPowerMah;
-
-    /**
-     * Smeared power using proportional method.
-     *
-     * we smear power usage from hidden sippers to all apps proportionally.(except for screen usage)
-     *
-     * @see BatteryStatsHelper#shouldHideSipper(BatterySipper)
-     * @see BatteryStatsHelper#removeHiddenBatterySippers(List)
-     */
-    public double proportionalSmearMah;
-
-    /**
-     * Total power that adding the smeared power.
-     *
-     * @see #sumPower()
-     */
-    public double totalSmearedPowerMah;
-
-    /**
-     * Total power before smearing
-     */
-    @UnsupportedAppUsage
-    public double totalPowerMah;
-
-    /**
-     * Whether we should hide this sipper
-     *
-     * @see BatteryStatsHelper#shouldHideSipper(BatterySipper)
-     */
-    public boolean shouldHide;
-
-    /**
-     * Generic usage time in milliseconds.
-     */
-    @UnsupportedAppUsage
-    public long usageTimeMs;
-
-    /**
-     * Generic power usage in mAh.
-     */
-    public double usagePowerMah;
-
-    // Subsystem usage times.
-    public long audioTimeMs;
-    public long bluetoothRunningTimeMs;
-    public long cameraTimeMs;
-    @UnsupportedAppUsage
-    public long cpuFgTimeMs;
-    @UnsupportedAppUsage
-    public long cpuTimeMs;
-    public long flashlightTimeMs;
-    @UnsupportedAppUsage
-    public long gpsTimeMs;
-    public long videoTimeMs;
-    @UnsupportedAppUsage
-    public long wakeLockTimeMs;
-    @UnsupportedAppUsage
-    public long wifiRunningTimeMs;
-
-    public long mobileRxPackets;
-    public long mobileTxPackets;
-    public long mobileActive;
-    public int mobileActiveCount;
-    public double mobilemspp;         // milliseconds per packet
-    public long wifiRxPackets;
-    public long wifiTxPackets;
-    public long mobileRxBytes;
-    public long mobileTxBytes;
-    public long wifiRxBytes;
-    public long wifiTxBytes;
-    public long btRxBytes;
-    public long btTxBytes;
-    public double percent;
-    public double noCoveragePercent;
-    @UnsupportedAppUsage
-    public String[] mPackages;
-    @UnsupportedAppUsage
-    public String packageWithHighestDrain;
-
-    // Measured in mAh (milli-ampere per hour).
-    // These are included when summed.
-    public double audioPowerMah;
-    public double bluetoothPowerMah;
-    public double cameraPowerMah;
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public double cpuPowerMah;
-    public double flashlightPowerMah;
-    public double gpsPowerMah;
-    public double mobileRadioPowerMah;
-    public double sensorPowerMah;
-    public double videoPowerMah;
-    public double wakeLockPowerMah;
-    public double wifiPowerMah;
-    public double systemServiceCpuPowerMah;
-    public double[] customMeasuredPowerMah;
-
-    // Power that is re-attributed to other sippers. For example, for System Server
-    // this represents the power attributed to apps requesting system services.
-    // The value should be negative or zero.
-    public double powerReattributedToOtherSippersMah;
-
-    // Do not include this sipper in results because it is included
-    // in an aggregate sipper.
-    public boolean isAggregated;
-
-    //                           ****************
-    // This list must be kept current with atoms.proto (frameworks/base/cmds/statsd/src/atoms.proto)
-    // so the ordinal values (and therefore the order) must never change.
-    //                           ****************
-    @UnsupportedAppUsage(implicitMember =
-            "values()[Lcom/android/internal/os/BatterySipper$DrainType;")
-    public enum DrainType {
-        AMBIENT_DISPLAY,
-        @UnsupportedAppUsage
-        APP,
-        BLUETOOTH,
-        CAMERA,
-        CELL,
-        FLASHLIGHT,
-        IDLE,
-        MEMORY,
-        OVERCOUNTED,
-        PHONE,
-        SCREEN,
-        UNACCOUNTED,
-        USER,
-        WIFI,
-    }
-
-    @UnsupportedAppUsage
-    public BatterySipper(DrainType drainType, Uid uid, double value) {
-        this.totalPowerMah = value;
-        this.drainType = drainType;
-        uidObj = uid;
-    }
-
-    public void computeMobilemspp() {
-        long packets = mobileRxPackets + mobileTxPackets;
-        mobilemspp = packets > 0 ? (mobileActive / (double) packets) : 0;
-    }
-
-    @Override
-    public int compareTo(BatterySipper other) {
-        // Over-counted always goes to the bottom.
-        if (drainType != other.drainType) {
-            if (drainType == DrainType.OVERCOUNTED) {
-                // This is "larger"
-                return 1;
-            } else if (other.drainType == DrainType.OVERCOUNTED) {
-                return -1;
-            }
-        }
-        // Return the flipped value because we want the items in descending order
-        return Double.compare(other.totalPowerMah, totalPowerMah);
-    }
-
-    /**
-     * Gets a list of packages associated with the current user
-     */
-    @UnsupportedAppUsage
-    public String[] getPackages() {
-        return mPackages;
-    }
-
-    @UnsupportedAppUsage
-    public int getUid() {
-        // Bail out if the current sipper is not an App sipper.
-        if (uidObj == null) {
-            return 0;
-        }
-        return uidObj.getUid();
-    }
-
-    /**
-     * Add stats from other to this BatterySipper.
-     */
-    @UnsupportedAppUsage
-    public void add(BatterySipper other) {
-        totalPowerMah += other.totalPowerMah;
-        usageTimeMs += other.usageTimeMs;
-        usagePowerMah += other.usagePowerMah;
-        audioTimeMs += other.audioTimeMs;
-        cpuTimeMs += other.cpuTimeMs;
-        gpsTimeMs += other.gpsTimeMs;
-        wifiRunningTimeMs += other.wifiRunningTimeMs;
-        cpuFgTimeMs += other.cpuFgTimeMs;
-        videoTimeMs += other.videoTimeMs;
-        wakeLockTimeMs += other.wakeLockTimeMs;
-        cameraTimeMs += other.cameraTimeMs;
-        flashlightTimeMs += other.flashlightTimeMs;
-        bluetoothRunningTimeMs += other.bluetoothRunningTimeMs;
-        mobileRxPackets += other.mobileRxPackets;
-        mobileTxPackets += other.mobileTxPackets;
-        mobileActive += other.mobileActive;
-        mobileActiveCount += other.mobileActiveCount;
-        wifiRxPackets += other.wifiRxPackets;
-        wifiTxPackets += other.wifiTxPackets;
-        mobileRxBytes += other.mobileRxBytes;
-        mobileTxBytes += other.mobileTxBytes;
-        wifiRxBytes += other.wifiRxBytes;
-        wifiTxBytes += other.wifiTxBytes;
-        btRxBytes += other.btRxBytes;
-        btTxBytes += other.btTxBytes;
-        audioPowerMah += other.audioPowerMah;
-        wifiPowerMah += other.wifiPowerMah;
-        gpsPowerMah += other.gpsPowerMah;
-        cpuPowerMah += other.cpuPowerMah;
-        sensorPowerMah += other.sensorPowerMah;
-        mobileRadioPowerMah += other.mobileRadioPowerMah;
-        wakeLockPowerMah += other.wakeLockPowerMah;
-        cameraPowerMah += other.cameraPowerMah;
-        flashlightPowerMah += other.flashlightPowerMah;
-        bluetoothPowerMah += other.bluetoothPowerMah;
-        screenPowerMah += other.screenPowerMah;
-        videoPowerMah += other.videoPowerMah;
-        proportionalSmearMah += other.proportionalSmearMah;
-        totalSmearedPowerMah += other.totalSmearedPowerMah;
-        systemServiceCpuPowerMah += other.systemServiceCpuPowerMah;
-        if (other.customMeasuredPowerMah != null) {
-            if (customMeasuredPowerMah == null) {
-                customMeasuredPowerMah = new double[other.customMeasuredPowerMah.length];
-            }
-            if (customMeasuredPowerMah.length == other.customMeasuredPowerMah.length) {
-                // This should always be true.
-                for (int idx = 0; idx < other.customMeasuredPowerMah.length; idx++) {
-                    customMeasuredPowerMah[idx] += other.customMeasuredPowerMah[idx];
-                }
-            }
-        }
-        powerReattributedToOtherSippersMah += other.powerReattributedToOtherSippersMah;
-    }
-
-    /**
-     * Sum all the powers and store the value into `value`.
-     * Also sum the {@code smearedTotalPowerMah} by adding smeared powerMah.
-     *
-     * @return the sum of all the power in this BatterySipper.
-     */
-    public double sumPower() {
-        totalPowerMah = usagePowerMah + wifiPowerMah + gpsPowerMah + cpuPowerMah +
-                sensorPowerMah + mobileRadioPowerMah + wakeLockPowerMah + cameraPowerMah +
-                flashlightPowerMah + bluetoothPowerMah + audioPowerMah + videoPowerMah
-                + systemServiceCpuPowerMah;
-        if (customMeasuredPowerMah != null) {
-            for (int idx = 0; idx < customMeasuredPowerMah.length; idx++) {
-                totalPowerMah += customMeasuredPowerMah[idx];
-            }
-        }
-
-        // powerAttributedToOtherSippersMah is negative or zero
-        totalPowerMah = totalPowerMah + powerReattributedToOtherSippersMah;
-
-        totalSmearedPowerMah = totalPowerMah + screenPowerMah + proportionalSmearMah;
-
-        return totalPowerMah;
-    }
-}
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
deleted file mode 100644
index 4515a09..0000000
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ /dev/null
@@ -1,703 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.os;
-
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.hardware.SensorManager;
-import android.os.BatteryStats;
-import android.os.BatteryStats.Uid;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.MemoryFile;
-import android.os.Parcel;
-import android.os.ParcelFileDescriptor;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.SELinux;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.telephony.TelephonyManager;
-import android.util.ArrayMap;
-import android.util.Log;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.app.IBatteryStats;
-import com.android.internal.os.BatterySipper.DrainType;
-import com.android.internal.util.ArrayUtils;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * A helper class for retrieving the power usage information for all applications and services.
- *
- * The caller must initialize this class as soon as activity object is ready to use (for example, in
- * onAttach() for Fragment), call create() in onCreate() and call destroy() in onDestroy().
- *
- * @deprecated Please use BatteryStatsManager.getBatteryUsageStats instead.
- */
-@Deprecated
-public class BatteryStatsHelper {
-    private static final boolean DEBUG = false;
-
-    private static final String TAG = BatteryStatsHelper.class.getSimpleName();
-
-    private static BatteryStats sStatsXfer;
-    private static Intent sBatteryBroadcastXfer;
-    private static ArrayMap<File, BatteryStats> sFileXfer = new ArrayMap<>();
-
-    final private Context mContext;
-    final private boolean mCollectBatteryBroadcast;
-    final private boolean mWifiOnly;
-
-    private List<PowerCalculator> mPowerCalculators;
-
-    @UnsupportedAppUsage
-    private IBatteryStats mBatteryInfo;
-    private BatteryStats mStats;
-    private Intent mBatteryBroadcast;
-    @UnsupportedAppUsage
-    private PowerProfile mPowerProfile;
-
-    private String[] mSystemPackageArray;
-    private String[] mServicepackageArray;
-    private PackageManager mPackageManager;
-
-    /**
-     * List of apps using power.
-     */
-    @UnsupportedAppUsage
-    private final List<BatterySipper> mUsageList = new ArrayList<>();
-
-    private final List<BatterySipper> mMobilemsppList = new ArrayList<>();
-
-    private int mStatsType = BatteryStats.STATS_SINCE_CHARGED;
-
-    long mRawRealtimeUs;
-    long mRawUptimeUs;
-    long mBatteryRealtimeUs;
-    long mBatteryUptimeUs;
-    long mBatteryTimeRemainingUs;
-    long mChargeTimeRemainingUs;
-
-    private long mStatsPeriod = 0;
-
-    // The largest entry by power.
-    private double mMaxPower = 1;
-
-    // The largest real entry by power (not undercounted or overcounted).
-    private double mMaxRealPower = 1;
-
-    // Total computed power.
-    private double mComputedPower;
-    private double mTotalPower;
-    private double mMinDrainedPower;
-    private double mMaxDrainedPower;
-
-    public static boolean checkWifiOnly(Context context) {
-        final TelephonyManager tm = context.getSystemService(TelephonyManager.class);
-        if (tm == null) {
-            return false;
-        }
-        return !tm.isDataCapable();
-    }
-
-    @UnsupportedAppUsage
-    public BatteryStatsHelper(Context context) {
-        this(context, true);
-    }
-
-    @UnsupportedAppUsage
-    public BatteryStatsHelper(Context context, boolean collectBatteryBroadcast) {
-        this(context, collectBatteryBroadcast, checkWifiOnly(context));
-    }
-
-    @UnsupportedAppUsage
-    public BatteryStatsHelper(Context context, boolean collectBatteryBroadcast, boolean wifiOnly) {
-        mContext = context;
-        mCollectBatteryBroadcast = collectBatteryBroadcast;
-        mWifiOnly = wifiOnly;
-        mPackageManager = context.getPackageManager();
-
-        final Resources resources = context.getResources();
-        mSystemPackageArray = resources.getStringArray(
-                com.android.internal.R.array.config_batteryPackageTypeSystem);
-        mServicepackageArray = resources.getStringArray(
-                com.android.internal.R.array.config_batteryPackageTypeService);
-    }
-
-    public void storeStatsHistoryInFile(String fname) {
-        synchronized (sFileXfer) {
-            File path = makeFilePath(mContext, fname);
-            sFileXfer.put(path, this.getStats());
-            FileOutputStream fout = null;
-            try {
-                fout = new FileOutputStream(path);
-                Parcel hist = Parcel.obtain();
-                getStats().writeToParcelWithoutUids(hist, 0);
-                byte[] histData = hist.marshall();
-                fout.write(histData);
-            } catch (IOException e) {
-                Log.w(TAG, "Unable to write history to file", e);
-            } finally {
-                if (fout != null) {
-                    try {
-                        fout.close();
-                    } catch (IOException e) {
-                    }
-                }
-            }
-        }
-    }
-
-    public static BatteryStats statsFromFile(Context context, String fname) {
-        synchronized (sFileXfer) {
-            File path = makeFilePath(context, fname);
-            BatteryStats stats = sFileXfer.get(path);
-            if (stats != null) {
-                return stats;
-            }
-            FileInputStream fin = null;
-            try {
-                fin = new FileInputStream(path);
-                byte[] data = readFully(fin);
-                Parcel parcel = Parcel.obtain();
-                parcel.unmarshall(data, 0, data.length);
-                parcel.setDataPosition(0);
-                return com.android.internal.os.BatteryStatsImpl.CREATOR.createFromParcel(parcel);
-            } catch (IOException e) {
-                Log.w(TAG, "Unable to read history to file", e);
-            } finally {
-                if (fin != null) {
-                    try {
-                        fin.close();
-                    } catch (IOException e) {
-                    }
-                }
-            }
-        }
-        return getStats(IBatteryStats.Stub.asInterface(
-                ServiceManager.getService(BatteryStats.SERVICE_NAME)), true);
-    }
-
-    @UnsupportedAppUsage
-    public static void dropFile(Context context, String fname) {
-        makeFilePath(context, fname).delete();
-    }
-
-    private static File makeFilePath(Context context, String fname) {
-        return new File(context.getFilesDir(), fname);
-    }
-
-    /** Clears the current stats and forces recreating for future use. */
-    @UnsupportedAppUsage
-    public void clearStats() {
-        mStats = null;
-    }
-
-    @UnsupportedAppUsage
-    public BatteryStats getStats() {
-        return getStats(true /* updateAll */);
-    }
-
-    /** Retrieves stats from BatteryService, optionally getting updated numbers */
-    public BatteryStats getStats(boolean updateAll) {
-        if (mStats == null) {
-            load(updateAll);
-        }
-        return mStats;
-    }
-
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public Intent getBatteryBroadcast() {
-        if (mBatteryBroadcast == null && mCollectBatteryBroadcast) {
-            load();
-        }
-        return mBatteryBroadcast;
-    }
-
-    public PowerProfile getPowerProfile() {
-        return mPowerProfile;
-    }
-
-    public void create(BatteryStats stats) {
-        mPowerProfile = new PowerProfile(mContext);
-        mStats = stats;
-    }
-
-    @UnsupportedAppUsage
-    public void create(Bundle icicle) {
-        if (icicle != null) {
-            mStats = sStatsXfer;
-            mBatteryBroadcast = sBatteryBroadcastXfer;
-        }
-        mBatteryInfo = IBatteryStats.Stub.asInterface(
-                ServiceManager.getService(BatteryStats.SERVICE_NAME));
-        mPowerProfile = new PowerProfile(mContext);
-    }
-
-    @UnsupportedAppUsage
-    public void storeState() {
-        sStatsXfer = mStats;
-        sBatteryBroadcastXfer = mBatteryBroadcast;
-    }
-
-    /**
-     * Refreshes the power usage list.
-     */
-    @UnsupportedAppUsage
-    public void refreshStats(int statsType, int asUser) {
-        SparseArray<UserHandle> users = new SparseArray<>(1);
-        users.put(asUser, new UserHandle(asUser));
-        refreshStats(statsType, users);
-    }
-
-    /**
-     * Refreshes the power usage list.
-     */
-    @UnsupportedAppUsage
-    public void refreshStats(int statsType, List<UserHandle> asUsers) {
-        final int n = asUsers.size();
-        SparseArray<UserHandle> users = new SparseArray<>(n);
-        for (int i = 0; i < n; ++i) {
-            UserHandle userHandle = asUsers.get(i);
-            users.put(userHandle.getIdentifier(), userHandle);
-        }
-        refreshStats(statsType, users);
-    }
-
-    /**
-     * Refreshes the power usage list.
-     */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public void refreshStats(int statsType, SparseArray<UserHandle> asUsers) {
-        refreshStats(statsType, asUsers, SystemClock.elapsedRealtime() * 1000,
-                SystemClock.uptimeMillis() * 1000);
-    }
-
-    public void refreshStats(int statsType, SparseArray<UserHandle> asUsers, long rawRealtimeUs,
-            long rawUptimeUs) {
-        if (statsType != BatteryStats.STATS_SINCE_CHARGED) {
-            Log.w(TAG, "refreshStats called for statsType " + statsType + " but only "
-                    + "STATS_SINCE_CHARGED is supported. Using STATS_SINCE_CHARGED instead.");
-        }
-
-        // Initialize mStats if necessary.
-        getStats();
-
-        mMaxPower = 0;
-        mMaxRealPower = 0;
-        mComputedPower = 0;
-        mTotalPower = 0;
-
-        mUsageList.clear();
-        mMobilemsppList.clear();
-
-        if (mStats == null) {
-            return;
-        }
-
-        if (mPowerCalculators == null) {
-            mPowerCalculators = new ArrayList<>();
-
-            // Power calculators are applied in the order of registration
-            mPowerCalculators.add(new CpuPowerCalculator(mPowerProfile));
-            mPowerCalculators.add(new MemoryPowerCalculator(mPowerProfile));
-            mPowerCalculators.add(new WakelockPowerCalculator(mPowerProfile));
-            if (!mWifiOnly) {
-                mPowerCalculators.add(new MobileRadioPowerCalculator(mPowerProfile));
-            }
-            mPowerCalculators.add(new WifiPowerCalculator(mPowerProfile));
-            mPowerCalculators.add(new BluetoothPowerCalculator(mPowerProfile));
-            mPowerCalculators.add(new SensorPowerCalculator(
-                    mContext.getSystemService(SensorManager.class)));
-            mPowerCalculators.add(new GnssPowerCalculator(mPowerProfile));
-            mPowerCalculators.add(new CameraPowerCalculator(mPowerProfile));
-            mPowerCalculators.add(new FlashlightPowerCalculator(mPowerProfile));
-            mPowerCalculators.add(new MediaPowerCalculator(mPowerProfile));
-            mPowerCalculators.add(new PhonePowerCalculator(mPowerProfile));
-            mPowerCalculators.add(new ScreenPowerCalculator(mPowerProfile));
-            mPowerCalculators.add(new AmbientDisplayPowerCalculator(mPowerProfile));
-            mPowerCalculators.add(new SystemServicePowerCalculator(mPowerProfile));
-            mPowerCalculators.add(new IdlePowerCalculator(mPowerProfile));
-            mPowerCalculators.add(new CustomMeasuredPowerCalculator(mPowerProfile));
-
-            mPowerCalculators.add(new UserPowerCalculator());
-        }
-
-        for (int i = 0, size = mPowerCalculators.size(); i < size; i++) {
-            mPowerCalculators.get(i).reset();
-        }
-
-        mStatsType = statsType;
-        mRawUptimeUs = rawUptimeUs;
-        mRawRealtimeUs = rawRealtimeUs;
-        mBatteryUptimeUs = mStats.getBatteryUptime(rawUptimeUs);
-        mBatteryRealtimeUs = mStats.getBatteryRealtime(rawRealtimeUs);
-        mBatteryTimeRemainingUs = mStats.computeBatteryTimeRemaining(rawRealtimeUs);
-        mChargeTimeRemainingUs = mStats.computeChargeTimeRemaining(rawRealtimeUs);
-        mStatsPeriod = mStats.computeBatteryRealtime(rawRealtimeUs, mStatsType);
-
-        if (DEBUG) {
-            Log.d(TAG, "Raw time: realtime=" + (rawRealtimeUs / 1000) + " uptime="
-                    + (rawUptimeUs / 1000));
-            Log.d(TAG, "Battery time: realtime=" + (mBatteryRealtimeUs / 1000) + " uptime="
-                    + (mBatteryUptimeUs / 1000));
-            Log.d(TAG, "Battery type time: realtime=" + (mStatsPeriod / 1000) + " uptime="
-                    + (mStats.computeBatteryUptime(rawRealtimeUs, mStatsType) / 1000));
-        }
-        mMinDrainedPower = (mStats.getLowDischargeAmountSinceCharge()
-                * mPowerProfile.getBatteryCapacity()) / 100;
-        mMaxDrainedPower = (mStats.getHighDischargeAmountSinceCharge()
-                * mPowerProfile.getBatteryCapacity()) / 100;
-
-        // Create list of (almost all) sippers, calculate their usage, and put them in mUsageList.
-        processAppUsage(asUsers);
-
-        Collections.sort(mUsageList);
-
-        Collections.sort(mMobilemsppList,
-                (lhs, rhs) -> Double.compare(rhs.mobilemspp, lhs.mobilemspp));
-
-        // At this point, we've sorted the list so we are guaranteed the max values are at the top.
-        // We have only added real powers so far.
-        if (!mUsageList.isEmpty()) {
-            mMaxRealPower = mMaxPower = mUsageList.get(0).totalPowerMah;
-            final int usageListCount = mUsageList.size();
-            for (int i = 0; i < usageListCount; i++) {
-                mComputedPower += mUsageList.get(i).totalPowerMah;
-            }
-        }
-
-        if (DEBUG) {
-            Log.d(TAG, "Accuracy: total computed=" + PowerCalculator.formatCharge(mComputedPower)
-                    + ", min discharge=" + PowerCalculator.formatCharge(mMinDrainedPower)
-                    + ", max discharge=" + PowerCalculator.formatCharge(mMaxDrainedPower));
-        }
-
-        mTotalPower = mComputedPower;
-        if (mStats.getLowDischargeAmountSinceCharge() > 1) {
-            if (mMinDrainedPower > mComputedPower) {
-                double amount = mMinDrainedPower - mComputedPower;
-                mTotalPower = mMinDrainedPower;
-                BatterySipper bs = new BatterySipper(DrainType.UNACCOUNTED, null, amount);
-
-                // Insert the BatterySipper in its sorted position.
-                int index = Collections.binarySearch(mUsageList, bs);
-                if (index < 0) {
-                    index = -(index + 1);
-                }
-                mUsageList.add(index, bs);
-                mMaxPower = Math.max(mMaxPower, amount);
-            } else if (mMaxDrainedPower < mComputedPower) {
-                double amount = mComputedPower - mMaxDrainedPower;
-
-                // Insert the BatterySipper in its sorted position.
-                BatterySipper bs = new BatterySipper(DrainType.OVERCOUNTED, null, amount);
-                int index = Collections.binarySearch(mUsageList, bs);
-                if (index < 0) {
-                    index = -(index + 1);
-                }
-                mUsageList.add(index, bs);
-                mMaxPower = Math.max(mMaxPower, amount);
-            }
-        }
-
-        // Smear it!
-        final double hiddenPowerMah = removeHiddenBatterySippers(mUsageList);
-        final double totalRemainingPower = getTotalPower() - hiddenPowerMah;
-        if (Math.abs(totalRemainingPower) > 1e-3) {
-            for (int i = 0, size = mUsageList.size(); i < size; i++) {
-                final BatterySipper sipper = mUsageList.get(i);
-                if (!sipper.shouldHide) {
-                    sipper.proportionalSmearMah = hiddenPowerMah
-                            * ((sipper.totalPowerMah + sipper.screenPowerMah)
-                            / totalRemainingPower);
-                    sipper.sumPower();
-                }
-            }
-        }
-    }
-
-    private void processAppUsage(SparseArray<UserHandle> asUsers) {
-        final SparseArray<? extends Uid> uidStats = mStats.getUidStats();
-
-        final ArrayList<BatterySipper> sippers = new ArrayList<>(uidStats.size());
-
-        for (int iu = 0, size = uidStats.size(); iu < size; iu++) {
-            final Uid u = uidStats.valueAt(iu);
-            sippers.add(new BatterySipper(DrainType.APP, u, 0));
-        }
-
-        for (int i = 0, size = mPowerCalculators.size(); i < size; i++) {
-            final PowerCalculator calculator = mPowerCalculators.get(i);
-            calculator.calculate(sippers, mStats, mRawRealtimeUs, mRawUptimeUs, mStatsType,
-                    asUsers);
-        }
-
-        for (int i = sippers.size() - 1; i >= 0; i--) {
-            final BatterySipper sipper = sippers.get(i);
-            final double totalPower = sipper.sumPower();
-            if (DEBUG && totalPower != 0) {
-                Log.d(TAG, String.format("UID %d: total power=%s", sipper.getUid(),
-                        PowerCalculator.formatCharge(totalPower)));
-            }
-
-            // Add the sipper to the list if it is consuming power.
-            if (totalPower != 0 || sipper.getUid() == 0) {
-                if (sipper.drainType == DrainType.APP) {
-                    sipper.computeMobilemspp();
-                    if (sipper.mobilemspp != 0) {
-                        mMobilemsppList.add(sipper);
-                    }
-                }
-
-                if (!sipper.isAggregated) {
-                    mUsageList.add(sipper);
-                }
-            }
-        }
-    }
-
-    @UnsupportedAppUsage
-    public List<BatterySipper> getUsageList() {
-        return mUsageList;
-    }
-
-    public List<BatterySipper> getMobilemsppList() {
-        return mMobilemsppList;
-    }
-
-    public long getStatsPeriod() {
-        return mStatsPeriod;
-    }
-
-    public int getStatsType() {
-        return mStatsType;
-    }
-
-    @UnsupportedAppUsage
-    public double getMaxPower() {
-        return mMaxPower;
-    }
-
-    public double getMaxRealPower() {
-        return mMaxRealPower;
-    }
-
-    @UnsupportedAppUsage
-    public double getTotalPower() {
-        return mTotalPower;
-    }
-
-    public double getComputedPower() {
-        return mComputedPower;
-    }
-
-    public double getMinDrainedPower() {
-        return mMinDrainedPower;
-    }
-
-    public double getMaxDrainedPower() {
-        return mMaxDrainedPower;
-    }
-
-    public static byte[] readFully(FileInputStream stream) throws java.io.IOException {
-        return readFully(stream, stream.available());
-    }
-
-    public static byte[] readFully(FileInputStream stream, int avail) throws java.io.IOException {
-        int pos = 0;
-        byte[] data = new byte[avail];
-        while (true) {
-            int amt = stream.read(data, pos, data.length - pos);
-            //Log.i("foo", "Read " + amt + " bytes at " + pos
-            //        + " of avail " + data.length);
-            if (amt <= 0) {
-                //Log.i("foo", "**** FINISHED READING: pos=" + pos
-                //        + " len=" + data.length);
-                return data;
-            }
-            pos += amt;
-            avail = stream.available();
-            if (avail > data.length - pos) {
-                byte[] newData = new byte[pos + avail];
-                System.arraycopy(data, 0, newData, 0, pos);
-                data = newData;
-            }
-        }
-    }
-
-    /**
-     * Mark the {@link BatterySipper} that we should hide.
-     *
-     * @param sippers sipper list that need to check and remove
-     * @return the total power of the hidden items of {@link BatterySipper}
-     * for proportional smearing
-     */
-    public double removeHiddenBatterySippers(List<BatterySipper> sippers) {
-        double proportionalSmearPowerMah = 0;
-        for (int i = sippers.size() - 1; i >= 0; i--) {
-            final BatterySipper sipper = sippers.get(i);
-            sipper.shouldHide = shouldHideSipper(sipper);
-            if (sipper.shouldHide) {
-                if (sipper.drainType != DrainType.OVERCOUNTED
-                        && sipper.drainType != DrainType.SCREEN
-                        && sipper.drainType != DrainType.AMBIENT_DISPLAY
-                        && sipper.drainType != DrainType.UNACCOUNTED
-                        && sipper.drainType != DrainType.BLUETOOTH
-                        && sipper.drainType != DrainType.WIFI
-                        && sipper.drainType != DrainType.IDLE) {
-                    // Don't add it if it is overcounted, unaccounted or screen
-                    proportionalSmearPowerMah += sipper.totalPowerMah;
-                }
-            }
-        }
-        return proportionalSmearPowerMah;
-    }
-
-    /**
-     * Check whether we should hide the battery sipper.
-     */
-    public boolean shouldHideSipper(BatterySipper sipper) {
-        final DrainType drainType = sipper.drainType;
-
-        return drainType == DrainType.IDLE
-                || drainType == DrainType.CELL
-                || drainType == DrainType.SCREEN
-                || drainType == DrainType.AMBIENT_DISPLAY
-                || drainType == DrainType.UNACCOUNTED
-                || drainType == DrainType.OVERCOUNTED
-                || isTypeService(sipper)
-                || isTypeSystem(sipper);
-    }
-
-    /**
-     * Check whether {@code sipper} is type service
-     */
-    public boolean isTypeService(BatterySipper sipper) {
-        final String[] packages = mPackageManager.getPackagesForUid(sipper.getUid());
-        if (packages == null) {
-            return false;
-        }
-
-        for (String packageName : packages) {
-            if (ArrayUtils.contains(mServicepackageArray, packageName)) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    /**
-     * Check whether {@code sipper} is type system
-     */
-    public boolean isTypeSystem(BatterySipper sipper) {
-        final int uid = sipper.uidObj == null ? -1 : sipper.getUid();
-        sipper.mPackages = mPackageManager.getPackagesForUid(uid);
-        // Classify all the sippers to type system if the range of uid is 0...FIRST_APPLICATION_UID
-        if (uid >= Process.ROOT_UID && uid < Process.FIRST_APPLICATION_UID) {
-            return true;
-        } else if (sipper.mPackages != null) {
-            for (final String packageName : sipper.mPackages) {
-                if (ArrayUtils.contains(mSystemPackageArray, packageName)) {
-                    return true;
-                }
-            }
-        }
-
-        return false;
-    }
-
-    public long convertUsToMs(long timeUs) {
-        return timeUs / 1000;
-    }
-
-    public long convertMsToUs(long timeMs) {
-        return timeMs * 1000;
-    }
-
-    @VisibleForTesting
-    public void setPackageManager(PackageManager packageManager) {
-        mPackageManager = packageManager;
-    }
-
-    @VisibleForTesting
-    public void setSystemPackageArray(String[] array) {
-        mSystemPackageArray = array;
-    }
-
-    @VisibleForTesting
-    public void setServicePackageArray(String[] array) {
-        mServicepackageArray = array;
-    }
-
-    @UnsupportedAppUsage
-    private void load() {
-        load(true);
-    }
-
-    private void load(boolean updateAll) {
-        if (mBatteryInfo == null) {
-            return;
-        }
-        mStats = getStats(mBatteryInfo, updateAll);
-        if (mCollectBatteryBroadcast) {
-            mBatteryBroadcast = mContext.registerReceiver(null,
-                    new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
-        }
-    }
-
-    private static BatteryStatsImpl getStats(IBatteryStats service, boolean updateAll) {
-        try {
-            ParcelFileDescriptor pfd = service.getStatisticsStream(updateAll);
-            if (pfd != null) {
-                if (false) {
-                    Log.d(TAG, "selinux context: "
-                            + SELinux.getFileContext(pfd.getFileDescriptor()));
-                }
-                try (FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
-                    byte[] data = readFully(fis, MemoryFile.getSize(pfd.getFileDescriptor()));
-                    Parcel parcel = Parcel.obtain();
-                    parcel.unmarshall(data, 0, data.length);
-                    parcel.setDataPosition(0);
-                    BatteryStatsImpl stats = com.android.internal.os.BatteryStatsImpl.CREATOR
-                            .createFromParcel(parcel);
-                    return stats;
-                } catch (IOException e) {
-                    Log.w(TAG, "Unable to read statistics stream", e);
-                }
-            }
-        } catch (RemoteException e) {
-            Log.w(TAG, "RemoteException:", e);
-        }
-        return new BatteryStatsImpl();
-    }
-}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 5ba45c9..70b9639 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -9211,7 +9211,7 @@
          * Gets the minimum of the uid's foreground activity time and its PROCESS_STATE_TOP time
          * since last marked. Also sets the mark time for both these timers.
          *
-         * @see BatteryStatsHelper#getProcessForegroundTimeMs
+         * @see CpuPowerCalculator
          *
          * @param doCalc if true, then calculate the minimum; else don't bother and return 0. Either
          *               way, the mark is set.
diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
index e4d5fb7..a1c1917 100644
--- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
+++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
@@ -73,7 +73,7 @@
                 mPowerCalculators.add(new CpuPowerCalculator(mPowerProfile));
                 mPowerCalculators.add(new MemoryPowerCalculator(mPowerProfile));
                 mPowerCalculators.add(new WakelockPowerCalculator(mPowerProfile));
-                if (!BatteryStatsHelper.checkWifiOnly(mContext)) {
+                if (!BatteryStats.checkWifiOnly(mContext)) {
                     mPowerCalculators.add(new MobileRadioPowerCalculator(mPowerProfile));
                 }
                 mPowerCalculators.add(new WifiPowerCalculator(mPowerProfile));
diff --git a/core/java/com/android/internal/os/BluetoothPowerCalculator.java b/core/java/com/android/internal/os/BluetoothPowerCalculator.java
index afa41a7..2ebf689 100644
--- a/core/java/com/android/internal/os/BluetoothPowerCalculator.java
+++ b/core/java/com/android/internal/os/BluetoothPowerCalculator.java
@@ -21,14 +21,11 @@
 import android.os.BatteryStats.ControllerActivityCounter;
 import android.os.BatteryUsageStats;
 import android.os.BatteryUsageStatsQuery;
-import android.os.Process;
 import android.os.UidBatteryConsumer;
-import android.os.UserHandle;
 import android.util.Log;
 import android.util.SparseArray;
 
 import java.util.Arrays;
-import java.util.List;
 
 public class BluetoothPowerCalculator extends PowerCalculator {
     private static final String TAG = "BluetoothPowerCalc";
@@ -106,7 +103,7 @@
                 powerAndDuration.durationMs - powerAndDuration.totalDurationMs);
         if (DEBUG) {
             Log.d(TAG, "Bluetooth active: time=" + (systemComponentDurationMs)
-                    + " power=" + formatCharge(powerAndDuration.powerMah));
+                    + " power=" + BatteryStats.formatCharge(powerAndDuration.powerMah));
         }
 
         builder.getAggregateBatteryConsumerBuilder(
@@ -159,73 +156,6 @@
         }
     }
 
-    @Override
-    public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
-            long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
-        if (!mHasBluetoothPowerController || !batteryStats.hasBluetoothActivityReporting()) {
-            return;
-        }
-
-        PowerAndDuration powerAndDuration = new PowerAndDuration();
-
-        for (int i = sippers.size() - 1; i >= 0; i--) {
-            final BatterySipper app = sippers.get(i);
-            if (app.drainType == BatterySipper.DrainType.APP) {
-                calculateApp(app, app.uidObj, statsType, powerAndDuration);
-            }
-        }
-
-        BatterySipper bs = new BatterySipper(BatterySipper.DrainType.BLUETOOTH, null, 0);
-        final long measuredChargeUC = batteryStats.getBluetoothMeasuredBatteryConsumptionUC();
-        final int powerModel = getPowerModel(measuredChargeUC);
-        final ControllerActivityCounter activityCounter =
-                batteryStats.getBluetoothControllerActivity();
-        calculatePowerAndDuration(null, powerModel, measuredChargeUC, activityCounter, false,
-                powerAndDuration);
-
-        // Subtract what the apps used, but clamp to 0.
-        final double powerMah = Math.max(0,
-                powerAndDuration.powerMah - powerAndDuration.totalPowerMah);
-        final long durationMs = Math.max(0,
-                powerAndDuration.durationMs - powerAndDuration.totalDurationMs);
-        if (DEBUG && powerMah != 0) {
-            Log.d(TAG, "Bluetooth active: time=" + (durationMs)
-                    + " power=" + formatCharge(powerMah));
-        }
-
-        bs.bluetoothPowerMah = powerMah;
-        bs.bluetoothRunningTimeMs = durationMs;
-
-        for (int i = sippers.size() - 1; i >= 0; i--) {
-            BatterySipper app = sippers.get(i);
-            if (app.getUid() == Process.BLUETOOTH_UID) {
-                if (DEBUG) Log.d(TAG, "Bluetooth adding sipper " + app + ": cpu=" + app.cpuTimeMs);
-                app.isAggregated = true;
-                bs.add(app);
-            }
-        }
-        if (bs.sumPower() > 0) {
-            sippers.add(bs);
-        }
-    }
-
-    private void calculateApp(BatterySipper app, BatteryStats.Uid u, int statsType,
-            PowerAndDuration powerAndDuration) {
-        final long measuredChargeUC = u.getBluetoothMeasuredBatteryConsumptionUC();
-        final int powerModel = getPowerModel(measuredChargeUC);
-        final ControllerActivityCounter activityCounter = u.getBluetoothControllerActivity();
-        calculatePowerAndDuration(u, powerModel, measuredChargeUC, activityCounter,
-                false, powerAndDuration);
-
-        app.bluetoothRunningTimeMs = powerAndDuration.durationMs;
-        app.bluetoothPowerMah = powerAndDuration.powerMah;
-        app.btRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_BT_RX_DATA, statsType);
-        app.btTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_BT_TX_DATA, statsType);
-
-        powerAndDuration.totalDurationMs += powerAndDuration.durationMs;
-        powerAndDuration.totalPowerMah += powerAndDuration.powerMah;
-    }
-
     /** Returns bluetooth power usage based on the best data available. */
     private void calculatePowerAndDuration(@Nullable BatteryStats.Uid uid,
             @BatteryConsumer.PowerModel int powerModel,
diff --git a/core/java/com/android/internal/os/CameraPowerCalculator.java b/core/java/com/android/internal/os/CameraPowerCalculator.java
index 7bccab5..d0749e0 100644
--- a/core/java/com/android/internal/os/CameraPowerCalculator.java
+++ b/core/java/com/android/internal/os/CameraPowerCalculator.java
@@ -69,14 +69,4 @@
         app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA, durationMs)
                 .setConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA, powerMah);
     }
-
-    @Override
-    protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
-            long rawUptimeUs, int statsType) {
-        final long durationMs = mPowerEstimator.calculateDuration(u.getCameraTurnedOnTimer(),
-                rawRealtimeUs, statsType);
-        final double powerMah = mPowerEstimator.calculatePower(durationMs);
-        app.cameraTimeMs = durationMs;
-        app.cameraPowerMah = powerMah;
-    }
 }
diff --git a/core/java/com/android/internal/os/CpuPowerCalculator.java b/core/java/com/android/internal/os/CpuPowerCalculator.java
index 9940a0a..1fc2baf 100644
--- a/core/java/com/android/internal/os/CpuPowerCalculator.java
+++ b/core/java/com/android/internal/os/CpuPowerCalculator.java
@@ -20,13 +20,11 @@
 import android.os.BatteryUsageStats;
 import android.os.BatteryUsageStatsQuery;
 import android.os.UidBatteryConsumer;
-import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.SparseArray;
 
 import java.util.Arrays;
-import java.util.List;
 
 public class CpuPowerCalculator extends PowerCalculator {
     private static final String TAG = "CpuPowerCalculator";
@@ -217,29 +215,6 @@
         }
     }
 
-    @Override
-    public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
-            long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
-        Result result = new Result();
-        for (int i = sippers.size() - 1; i >= 0; i--) {
-            final BatterySipper app = sippers.get(i);
-            if (app.drainType == BatterySipper.DrainType.APP) {
-                calculateApp(app, app.uidObj, statsType, result);
-            }
-        }
-    }
-
-    private void calculateApp(BatterySipper app, BatteryStats.Uid u, int statsType, Result result) {
-        final long consumptionUC = u.getCpuMeasuredBatteryConsumptionUC();
-        final int powerModel = getPowerModel(consumptionUC);
-        calculatePowerAndDuration(u, powerModel, consumptionUC, statsType, result);
-
-        app.cpuPowerMah = result.powerMah;
-        app.cpuTimeMs = result.durationMs;
-        app.cpuFgTimeMs = result.durationFgMs;
-        app.packageWithHighestDrain = result.packageWithHighestDrain;
-    }
-
     private void calculatePowerAndDuration(BatteryStats.Uid u,
             @BatteryConsumer.PowerModel int powerModel, long consumptionUC, int statsType,
             Result result) {
@@ -258,7 +233,7 @@
 
         if (DEBUG && (durationMs != 0 || powerMah != 0)) {
             Log.d(TAG, "UID " + u.getUid() + ": CPU time=" + durationMs + " ms power="
-                    + formatCharge(powerMah));
+                    + BatteryStats.formatCharge(powerMah));
         }
 
         // Keep track of the package with highest drain.
@@ -325,7 +300,7 @@
                     if (DEBUG) {
                         Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + cluster
                                 + " clusterTimeMs=" + cpuClusterTimes[cluster]
-                                + " power=" + formatCharge(power));
+                                + " power=" + BatteryStats.formatCharge(power));
                     }
                 }
             } else {
diff --git a/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java b/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java
index 4cb7ef1..cbbb526 100644
--- a/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java
+++ b/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java
@@ -102,16 +102,6 @@
         return newTotalPowerMah;
     }
 
-    @Override
-    protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
-            long rawUptimeUs, int statsType) {
-        updateCustomMeasuredPowerMah(app, u.getCustomConsumerMeasuredBatteryConsumptionUC());
-    }
-
-    private void updateCustomMeasuredPowerMah(BatterySipper sipper, long[] measuredChargeUC) {
-        sipper.customMeasuredPowerMah = calculateMeasuredEnergiesMah(measuredChargeUC);
-    }
-
     private double[] calculateMeasuredEnergiesMah(long[] measuredChargeUC) {
         if (measuredChargeUC == null) {
             return null;
diff --git a/core/java/com/android/internal/os/FlashlightPowerCalculator.java b/core/java/com/android/internal/os/FlashlightPowerCalculator.java
index 7d3f962..ce3e7b9 100644
--- a/core/java/com/android/internal/os/FlashlightPowerCalculator.java
+++ b/core/java/com/android/internal/os/FlashlightPowerCalculator.java
@@ -66,14 +66,4 @@
         app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT, durationMs)
                 .setConsumedPower(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT, powerMah);
     }
-
-    @Override
-    protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
-            long rawUptimeUs, int statsType) {
-        final long durationMs = mPowerEstimator.calculateDuration(u.getFlashlightTurnedOnTimer(),
-                rawRealtimeUs, statsType);
-        final double powerMah = mPowerEstimator.calculatePower(durationMs);
-        app.flashlightTimeMs = durationMs;
-        app.flashlightPowerMah = powerMah;
-    }
 }
diff --git a/core/java/com/android/internal/os/GnssPowerCalculator.java b/core/java/com/android/internal/os/GnssPowerCalculator.java
index a836ddb..0f78306 100644
--- a/core/java/com/android/internal/os/GnssPowerCalculator.java
+++ b/core/java/com/android/internal/os/GnssPowerCalculator.java
@@ -21,11 +21,8 @@
 import android.os.BatteryUsageStats;
 import android.os.BatteryUsageStatsQuery;
 import android.os.UidBatteryConsumer;
-import android.os.UserHandle;
 import android.util.SparseArray;
 
-import java.util.List;
-
 /**
  * Estimates the amount of power consumed by the GNSS (e.g. GPS).
  */
@@ -100,41 +97,6 @@
         return powerMah;
     }
 
-    @Override
-    public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
-            long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
-        double averageGnssPowerMa = getAverageGnssPower(batteryStats, rawRealtimeUs, statsType);
-        for (int i = sippers.size() - 1; i >= 0; i--) {
-            final BatterySipper app = sippers.get(i);
-            if (app.drainType == BatterySipper.DrainType.APP) {
-                final long consumptionUC =
-                        app.uidObj.getGnssMeasuredBatteryConsumptionUC();
-                final int powerModel = getPowerModel(consumptionUC);
-                calculateApp(app, app.uidObj, powerModel, rawRealtimeUs, averageGnssPowerMa,
-                        consumptionUC);
-            }
-        }
-    }
-
-    private void calculateApp(BatterySipper app, BatteryStats.Uid u,
-            @BatteryConsumer.PowerModel int powerModel, long rawRealtimeUs,
-            double averageGnssPowerMa, long measuredChargeUC) {
-        final long durationMs = computeDuration(u, rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED);
-
-        final double powerMah;
-        switch (powerModel) {
-            case BatteryConsumer.POWER_MODEL_MEASURED_ENERGY:
-                powerMah = uCtoMah(measuredChargeUC);
-                break;
-            case BatteryConsumer.POWER_MODEL_POWER_PROFILE:
-            default:
-                powerMah = computePower(durationMs, averageGnssPowerMa);
-        }
-
-        app.gpsTimeMs = durationMs;
-        app.gpsPowerMah = powerMah;
-    }
-
     private long computeDuration(BatteryStats.Uid u, long rawRealtimeUs, int statsType) {
         final SparseArray<? extends BatteryStats.Uid.Sensor> sensorStats = u.getSensorStats();
         final BatteryStats.Uid.Sensor sensor = sensorStats.get(BatteryStats.Uid.Sensor.GPS);
diff --git a/core/java/com/android/internal/os/IdlePowerCalculator.java b/core/java/com/android/internal/os/IdlePowerCalculator.java
index 9491b3b..5b2052e 100644
--- a/core/java/com/android/internal/os/IdlePowerCalculator.java
+++ b/core/java/com/android/internal/os/IdlePowerCalculator.java
@@ -20,11 +20,7 @@
 import android.os.BatteryStats;
 import android.os.BatteryUsageStats;
 import android.os.BatteryUsageStatsQuery;
-import android.os.UserHandle;
 import android.util.Log;
-import android.util.SparseArray;
-
-import java.util.List;
 
 /**
  * Estimates the amount of power consumed when the device is idle.
@@ -64,20 +60,6 @@
         }
     }
 
-    @Override
-    public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
-            long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
-        calculatePowerAndDuration(batteryStats, rawRealtimeUs, rawUptimeUs, statsType);
-
-        if (mPowerMah != 0) {
-            BatterySipper bs = new BatterySipper(BatterySipper.DrainType.IDLE, null, 0);
-            bs.usagePowerMah = mPowerMah;
-            bs.usageTimeMs = mDurationMs;
-            bs.sumPower();
-            sippers.add(bs);
-        }
-    }
-
     /**
      * Calculates the baseline power usage for the device when it is in suspend and idle.
      * The device is drawing POWER_CPU_SUSPEND power at its lowest power state.
@@ -97,9 +79,9 @@
         mPowerMah = suspendPowerMah + idlePowerMah;
         if (DEBUG && mPowerMah != 0) {
             Log.d(TAG, "Suspend: time=" + (batteryRealtimeUs / 1000)
-                    + " power=" + formatCharge(suspendPowerMah));
+                    + " power=" + BatteryStats.formatCharge(suspendPowerMah));
             Log.d(TAG, "Idle: time=" + (batteryUptimeUs / 1000)
-                    + " power=" + formatCharge(idlePowerMah));
+                    + " power=" + BatteryStats.formatCharge(idlePowerMah));
         }
         mDurationMs = batteryRealtimeUs / 1000;
     }
diff --git a/core/java/com/android/internal/os/MediaPowerCalculator.java b/core/java/com/android/internal/os/MediaPowerCalculator.java
deleted file mode 100644
index fff96da..0000000
--- a/core/java/com/android/internal/os/MediaPowerCalculator.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.os;
-
-import android.os.BatteryConsumer;
-import android.os.BatteryStats;
-
-/**
- * A {@link PowerCalculator} to calculate power consumed by audio and video hardware.
- *
- * Also see {@link PowerProfile#POWER_AUDIO} and {@link PowerProfile#POWER_VIDEO}.
- */
-public class MediaPowerCalculator extends PowerCalculator {
-    private static final int MS_IN_HR = 1000 * 60 * 60;
-    private final double mAudioAveragePowerMa;
-    private final double mVideoAveragePowerMa;
-
-    public MediaPowerCalculator(PowerProfile profile) {
-        mAudioAveragePowerMa = profile.getAveragePower(PowerProfile.POWER_AUDIO);
-        mVideoAveragePowerMa = profile.getAveragePower(PowerProfile.POWER_VIDEO);
-    }
-
-    @Override
-    public boolean isPowerComponentSupported(@BatteryConsumer.PowerComponent int powerComponent) {
-        return powerComponent == BatteryConsumer.POWER_COMPONENT_VIDEO
-                || powerComponent == BatteryConsumer.POWER_COMPONENT_AUDIO;
-    }
-
-    @Override
-    protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
-            long rawUptimeUs, int statsType) {
-        // Calculate audio power usage, an estimate based on the average power routed to different
-        // components like speaker, bluetooth, usb-c, earphone, etc.
-        final BatteryStats.Timer audioTimer = u.getAudioTurnedOnTimer();
-        if (audioTimer == null) {
-            app.audioTimeMs = 0;
-            app.audioPowerMah = 0;
-        } else {
-            final long totalTime = audioTimer.getTotalTimeLocked(rawRealtimeUs, statsType) / 1000;
-            app.audioTimeMs = totalTime;
-            app.audioPowerMah = (totalTime * mAudioAveragePowerMa) / MS_IN_HR;
-        }
-
-        // Calculate video power usage.
-        final BatteryStats.Timer videoTimer = u.getVideoTurnedOnTimer();
-        if (videoTimer == null) {
-            app.videoTimeMs = 0;
-            app.videoPowerMah = 0;
-        } else {
-            final long totalTime = videoTimer.getTotalTimeLocked(rawRealtimeUs, statsType) / 1000;
-            app.videoTimeMs = totalTime;
-            app.videoPowerMah = (totalTime * mVideoAveragePowerMa) / MS_IN_HR;
-        }
-    }
-}
diff --git a/core/java/com/android/internal/os/MemoryPowerCalculator.java b/core/java/com/android/internal/os/MemoryPowerCalculator.java
index 0440a58..0d3040c 100644
--- a/core/java/com/android/internal/os/MemoryPowerCalculator.java
+++ b/core/java/com/android/internal/os/MemoryPowerCalculator.java
@@ -4,11 +4,7 @@
 import android.os.BatteryStats;
 import android.os.BatteryUsageStats;
 import android.os.BatteryUsageStatsQuery;
-import android.os.UserHandle;
 import android.util.LongSparseArray;
-import android.util.SparseArray;
-
-import java.util.List;
 
 public class MemoryPowerCalculator extends PowerCalculator {
     public static final String TAG = "MemoryPowerCalculator";
@@ -41,20 +37,6 @@
                 .setConsumedPower(BatteryConsumer.POWER_COMPONENT_MEMORY, powerMah);
     }
 
-    @Override
-    public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
-            long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
-        final long durationMs = calculateDuration(batteryStats, rawRealtimeUs, statsType);
-        final double powerMah = calculatePower(batteryStats, rawRealtimeUs, statsType);
-        BatterySipper memory = new BatterySipper(BatterySipper.DrainType.MEMORY, null, 0);
-        memory.usageTimeMs = durationMs;
-        memory.usagePowerMah = powerMah;
-        memory.sumPower();
-        if (memory.totalPowerMah > 0) {
-            sippers.add(memory);
-        }
-    }
-
     private long calculateDuration(BatteryStats batteryStats, long rawRealtimeUs, int statsType) {
         long usageDurationMs = 0;
         LongSparseArray<? extends BatteryStats.Timer> timers = batteryStats.getKernelMemoryStats();
diff --git a/core/java/com/android/internal/os/MobileRadioPowerCalculator.java b/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
index 3a50b73..f4624de 100644
--- a/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
+++ b/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
@@ -20,13 +20,10 @@
 import android.os.BatteryUsageStats;
 import android.os.BatteryUsageStatsQuery;
 import android.os.UidBatteryConsumer;
-import android.os.UserHandle;
 import android.telephony.CellSignalStrength;
 import android.util.Log;
 import android.util.SparseArray;
 
-import java.util.List;
-
 public class MobileRadioPowerCalculator extends PowerCalculator {
     private static final String TAG = "MobRadioPowerCalculator";
     private static final boolean DEBUG = PowerCalculator.DEBUG;
@@ -170,65 +167,6 @@
         }
     }
 
-    @Override
-    public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
-            long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
-        PowerAndDuration total = new PowerAndDuration();
-        for (int i = sippers.size() - 1; i >= 0; i--) {
-            final BatterySipper app = sippers.get(i);
-            if (app.drainType == BatterySipper.DrainType.APP) {
-                final BatteryStats.Uid u = app.uidObj;
-                calculateApp(app, u, statsType, total);
-            }
-        }
-
-        BatterySipper radio = new BatterySipper(BatterySipper.DrainType.CELL, null, 0);
-        final long consumptionUC = batteryStats.getMobileRadioMeasuredBatteryConsumptionUC();
-        final int powerModel = getPowerModel(consumptionUC);
-        calculateRemaining(total, powerModel, batteryStats, rawRealtimeUs, consumptionUC);
-        if (total.remainingPowerMah != 0) {
-            if (total.signalDurationMs != 0) {
-                radio.noCoveragePercent =
-                        total.noCoverageDurationMs * 100.0 / total.signalDurationMs;
-            }
-            radio.mobileActive = total.durationMs;
-            radio.mobileActiveCount = batteryStats.getMobileRadioActiveUnknownCount(statsType);
-            radio.mobileRadioPowerMah = total.remainingPowerMah;
-            radio.sumPower();
-        }
-        if (radio.totalPowerMah > 0) {
-            sippers.add(radio);
-        }
-    }
-
-    private void calculateApp(BatterySipper app, BatteryStats.Uid u, int statsType,
-            PowerAndDuration total) {
-        app.mobileActive = calculateDuration(u, statsType);
-
-        final long consumptionUC =  u.getMobileRadioMeasuredBatteryConsumptionUC();
-        final int powerModel = getPowerModel(consumptionUC);
-        app.mobileRadioPowerMah = calculatePower(u, powerModel, app.mobileActive, consumptionUC);
-        total.totalAppDurationMs += app.mobileActive;
-
-        // Add cost of mobile traffic.
-        app.mobileRxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_RX_DATA,
-                statsType);
-        app.mobileTxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_TX_DATA,
-                statsType);
-        app.mobileActiveCount = u.getMobileRadioActiveCount(statsType);
-        app.mobileRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_MOBILE_RX_DATA,
-                statsType);
-        app.mobileTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_MOBILE_TX_DATA,
-                statsType);
-
-        if (DEBUG && app.mobileRadioPowerMah != 0) {
-            Log.d(TAG, "UID " + u.getUid() + ": mobile packets "
-                    + (app.mobileRxPackets + app.mobileTxPackets)
-                    + " active time " + app.mobileActive
-                    + " power=" + formatCharge(app.mobileRadioPowerMah));
-        }
-    }
-
     private long calculateDuration(BatteryStats.Uid u, int statsType) {
         return u.getMobileRadioActiveTime(statsType) / 1000;
     }
@@ -262,7 +200,7 @@
                 final double p = calcIdlePowerAtSignalStrengthMah(strengthTimeMs, i);
                 if (DEBUG && p != 0) {
                     Log.d(TAG, "Cell strength #" + i + ": time=" + strengthTimeMs + " power="
-                            + formatCharge(p));
+                            + BatteryStats.formatCharge(p));
                 }
                 powerMah += p;
             }
@@ -281,8 +219,8 @@
         if (powerModel == BatteryConsumer.POWER_MODEL_POWER_PROFILE) {
             final double p = calcScanTimePowerMah(scanningTimeMs);
             if (DEBUG && p != 0) {
-                Log.d(TAG, "Cell radio scanning: time=" + scanningTimeMs + " power=" + formatCharge(
-                        p));
+                Log.d(TAG, "Cell radio scanning: time=" + scanningTimeMs
+                        + " power=" + BatteryStats.formatCharge(p));
             }
             powerMah += p;
 
diff --git a/core/java/com/android/internal/os/PhonePowerCalculator.java b/core/java/com/android/internal/os/PhonePowerCalculator.java
index 7310314..cb893de 100644
--- a/core/java/com/android/internal/os/PhonePowerCalculator.java
+++ b/core/java/com/android/internal/os/PhonePowerCalculator.java
@@ -20,10 +20,6 @@
 import android.os.BatteryStats;
 import android.os.BatteryUsageStats;
 import android.os.BatteryUsageStatsQuery;
-import android.os.UserHandle;
-import android.util.SparseArray;
-
-import java.util.List;
 
 /**
  * Estimates power consumed by telephony.
@@ -54,18 +50,4 @@
                     .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnTimeMs);
         }
     }
-
-    @Override
-    public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
-            long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
-        final long phoneOnTimeMs = batteryStats.getPhoneOnTime(rawRealtimeUs, statsType) / 1000;
-        final double phoneOnPower = mPowerEstimator.calculatePower(phoneOnTimeMs);
-        if (phoneOnPower != 0) {
-            BatterySipper bs = new BatterySipper(BatterySipper.DrainType.PHONE, null, 0);
-            bs.usagePowerMah = phoneOnPower;
-            bs.usageTimeMs = phoneOnTimeMs;
-            bs.sumPower();
-            sippers.add(bs);
-        }
-    }
 }
diff --git a/core/java/com/android/internal/os/PowerCalculator.java b/core/java/com/android/internal/os/PowerCalculator.java
index 28c0f5a..ec785b8 100644
--- a/core/java/com/android/internal/os/PowerCalculator.java
+++ b/core/java/com/android/internal/os/PowerCalculator.java
@@ -21,12 +21,9 @@
 import android.os.BatteryUsageStats;
 import android.os.BatteryUsageStatsQuery;
 import android.os.UidBatteryConsumer;
-import android.os.UserHandle;
 import android.util.SparseArray;
 
 import java.io.PrintWriter;
-import java.util.List;
-import java.util.Locale;
 
 /**
  * Calculates power use of a device subsystem for an app.
@@ -43,34 +40,6 @@
     public abstract boolean isPowerComponentSupported(
             @BatteryConsumer.PowerComponent int powerComponent);
 
-
-    /**
-     * Attributes the total amount of power used by this subsystem to various consumers such
-     * as apps.
-     *
-     * @param sippers       A list of battery sippers that contains battery attribution data.
-     *                      The calculator may modify the list.
-     * @param batteryStats  The recorded battery stats.
-     * @param rawRealtimeUs The raw system realtime in microseconds.
-     * @param rawUptimeUs   The raw system uptime in microseconds.
-     * @param statsType     The type of stats. As of {@link android.os.Build.VERSION_CODES#Q}, this
-     *                      can only be {@link BatteryStats#STATS_SINCE_CHARGED}, since
-     *                      {@link BatteryStats#STATS_CURRENT} and
-     *                      {@link BatteryStats#STATS_SINCE_UNPLUGGED} are deprecated.
-     * @param asUsers       An array of users for which the attribution is requested.  It may
-     *                      contain {@link UserHandle#USER_ALL} to indicate that the attribution
-     *                      should be performed for all users.
-     */
-    public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
-            long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
-        for (int i = sippers.size() - 1; i >= 0; i--) {
-            final BatterySipper app = sippers.get(i);
-            if (app.drainType == BatterySipper.DrainType.APP) {
-                calculateApp(app, app.uidObj, rawRealtimeUs, rawUptimeUs, statsType);
-            }
-        }
-    }
-
     /**
      * Attributes the total amount of power used by this subsystem to various consumers such
      * as apps.
@@ -95,21 +64,6 @@
 
     /**
      * Calculate the amount of power an app used for this subsystem.
-     * @param app The BatterySipper that represents the power use of an app.
-     * @param u The recorded stats for the app.
-     * @param rawRealtimeUs The raw system realtime in microseconds.
-     * @param rawUptimeUs The raw system uptime in microseconds.
-     * @param statsType The type of stats. As of {@link android.os.Build.VERSION_CODES#Q}, this can
-     *                  only be {@link BatteryStats#STATS_SINCE_CHARGED}, since
-     *                  {@link BatteryStats#STATS_CURRENT} and
-     *                  {@link BatteryStats#STATS_SINCE_UNPLUGGED} are deprecated.
-     */
-    protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
-                                      long rawUptimeUs, int statsType) {
-    }
-
-    /**
-     * Calculate the amount of power an app used for this subsystem.
      * @param app The UidBatteryConsumer.Builder that represents the power use of an app.
      * @param u The recorded stats for the app.
      * @param rawRealtimeUs The raw system realtime in microseconds.
@@ -145,38 +99,7 @@
      * Prints formatted amount of power in milli-amp-hours.
      */
     public static void printPowerMah(PrintWriter pw, double powerMah) {
-        pw.print(formatCharge(powerMah));
-    }
-
-    /**
-     * Converts charge in mAh to string.
-     */
-    public static String formatCharge(double power) {
-        if (power == 0) return "0";
-
-        final String format;
-        if (power < .00001) {
-            format = "%.8f";
-        } else if (power < .0001) {
-            format = "%.7f";
-        } else if (power < .001) {
-            format = "%.6f";
-        } else if (power < .01) {
-            format = "%.5f";
-        } else if (power < .1) {
-            format = "%.4f";
-        } else if (power < 1) {
-            format = "%.3f";
-        } else if (power < 10) {
-            format = "%.2f";
-        } else if (power < 100) {
-            format = "%.1f";
-        } else {
-            format = "%.0f";
-        }
-
-        // Use English locale because this is never used in UI (only in checkin and dump).
-        return String.format(Locale.ENGLISH, format, power);
+        pw.print(BatteryStats.formatCharge(powerMah));
     }
 
     static double uCtoMah(long chargeUC) {
diff --git a/core/java/com/android/internal/os/ScreenPowerCalculator.java b/core/java/com/android/internal/os/ScreenPowerCalculator.java
index 110b6b6..67d3d6e 100644
--- a/core/java/com/android/internal/os/ScreenPowerCalculator.java
+++ b/core/java/com/android/internal/os/ScreenPowerCalculator.java
@@ -24,7 +24,6 @@
 import android.os.BatteryUsageStats;
 import android.os.BatteryUsageStatsQuery;
 import android.os.UidBatteryConsumer;
-import android.os.UserHandle;
 import android.text.format.DateUtils;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -32,8 +31,6 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 
-import java.util.List;
-
 /**
  * Estimates power consumed by the screen(s)
  */
@@ -125,48 +122,6 @@
     }
 
     /**
-     * Screen power is the additional power the screen takes while the device is running.
-     */
-    @Override
-    public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
-            long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
-        final PowerAndDuration totalPowerAndDuration = new PowerAndDuration();
-        final long consumptionUC = batteryStats.getScreenOnMeasuredBatteryConsumptionUC();
-        final int powerModel = getPowerModel(consumptionUC);
-        calculateTotalDurationAndPower(totalPowerAndDuration, powerModel, batteryStats,
-                rawRealtimeUs, statsType, consumptionUC);
-        if (totalPowerAndDuration.powerMah == 0) {
-            return;
-        }
-
-        // First deal with the SCREEN BatterySipper (since we need this for smearing over apps).
-        final BatterySipper bs = new BatterySipper(BatterySipper.DrainType.SCREEN, null, 0);
-        bs.usagePowerMah = totalPowerAndDuration.powerMah;
-        bs.usageTimeMs = totalPowerAndDuration.durationMs;
-        bs.sumPower();
-        sippers.add(bs);
-
-        // Now deal with each app's BatterySipper. The results are stored in the screenPowerMah
-        // field, which is considered smeared, but the method depends on the data source.
-        switch (powerModel) {
-            case BatteryConsumer.POWER_MODEL_MEASURED_ENERGY:
-                final PowerAndDuration appPowerAndDuration = new PowerAndDuration();
-                for (int i = sippers.size() - 1; i >= 0; i--) {
-                    final BatterySipper app = sippers.get(i);
-                    if (app.drainType == BatterySipper.DrainType.APP) {
-                        calculateAppUsingMeasuredEnergy(appPowerAndDuration, app.uidObj,
-                                rawRealtimeUs);
-                        app.screenPowerMah = appPowerAndDuration.powerMah;
-                    }
-                }
-                break;
-            case BatteryConsumer.POWER_MODEL_POWER_PROFILE:
-            default:
-                smearScreenBatterySipper(sippers, bs, rawRealtimeUs);
-        }
-    }
-
-    /**
      * Stores duration and power information in totalPowerAndDuration.
      */
     private void calculateTotalDurationAndPower(PowerAndDuration totalPowerAndDuration,
@@ -219,7 +174,7 @@
                         brightnessTime) * (bin + 0.5f) / BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS;
                 if (DEBUG && binPowerMah != 0) {
                     Slog.d(TAG, "Screen bin #" + bin + ": time=" + brightnessTime
-                            + " power=" + formatCharge(binPowerMah));
+                            + " power=" + BatteryStats.formatCharge(binPowerMah));
                 }
                 power += binPowerMah;
             }
@@ -228,37 +183,8 @@
     }
 
     /**
-     * Smear the screen on power usage among {@code sippers}, based on ratio of foreground activity
-     * time, and store this in the {@link BatterySipper#screenPowerMah} field.
-     */
-    @VisibleForTesting
-    public void smearScreenBatterySipper(List<BatterySipper> sippers, BatterySipper screenSipper,
-            long rawRealtimeUs) {
-        long totalActivityTimeMs = 0;
-        final SparseLongArray activityTimeArray = new SparseLongArray();
-        for (int i = sippers.size() - 1; i >= 0; i--) {
-            final BatteryStats.Uid uid = sippers.get(i).uidObj;
-            if (uid != null) {
-                final long timeMs = getProcessForegroundTimeMs(uid, rawRealtimeUs);
-                activityTimeArray.put(uid.getUid(), timeMs);
-                totalActivityTimeMs += timeMs;
-            }
-        }
-
-        if (screenSipper != null && totalActivityTimeMs >= MIN_ACTIVE_TIME_FOR_SMEARING) {
-            final double totalScreenPowerMah = screenSipper.totalPowerMah;
-            for (int i = sippers.size() - 1; i >= 0; i--) {
-                final BatterySipper sipper = sippers.get(i);
-                sipper.screenPowerMah = totalScreenPowerMah
-                        * activityTimeArray.get(sipper.getUid(), 0)
-                        / totalActivityTimeMs;
-            }
-        }
-    }
-
-    /**
-     * Smear the screen on power usage among {@code sippers}, based on ratio of foreground activity
-     * time, and store this in the {@link BatterySipper#screenPowerMah} field.
+     * Smear the screen on power usage among {@code UidBatteryConsumers}, based on ratio of
+     * foreground activity time.
      */
     private void smearScreenBatteryDrain(
             SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders,
diff --git a/core/java/com/android/internal/os/SensorPowerCalculator.java b/core/java/com/android/internal/os/SensorPowerCalculator.java
index 495a6d9..4a9c91d 100644
--- a/core/java/com/android/internal/os/SensorPowerCalculator.java
+++ b/core/java/com/android/internal/os/SensorPowerCalculator.java
@@ -72,12 +72,6 @@
         return powerMah;
     }
 
-    @Override
-    protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
-            long rawUptimeUs, int statsType) {
-        app.sensorPowerMah = calculatePowerMah(u, rawRealtimeUs, statsType);
-    }
-
     private long calculateDuration(BatteryStats.Uid u, long rawRealtimeUs, int statsType) {
         long durationMs = 0;
         final SparseArray<? extends BatteryStats.Uid.Sensor> sensorStats = u.getSensorStats();
diff --git a/core/java/com/android/internal/os/SystemServicePowerCalculator.java b/core/java/com/android/internal/os/SystemServicePowerCalculator.java
index d7872ba..3a3df87 100644
--- a/core/java/com/android/internal/os/SystemServicePowerCalculator.java
+++ b/core/java/com/android/internal/os/SystemServicePowerCalculator.java
@@ -22,12 +22,9 @@
 import android.os.BatteryUsageStatsQuery;
 import android.os.Process;
 import android.os.UidBatteryConsumer;
-import android.os.UserHandle;
 import android.util.Log;
 import android.util.SparseArray;
 
-import java.util.List;
-
 /**
  * Estimates the amount of power consumed by the System Server handling requests from
  * a given app.
@@ -121,55 +118,6 @@
                         systemServicePowerMah);
     }
 
-    @Override
-    public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
-            long rawRealtimeUs, long rawUptimeUs, int statsType,
-            SparseArray<UserHandle> asUsers) {
-        final BatteryStats.Uid systemUid = batteryStats.getUidStats().get(Process.SYSTEM_UID);
-        if (systemUid == null) {
-            return;
-        }
-
-        final long consumptionUC = systemUid.getCpuMeasuredBatteryConsumptionUC();
-        double systemServicePowerMah;
-        if (getPowerModel(consumptionUC) == BatteryConsumer.POWER_MODEL_MEASURED_ENERGY) {
-            systemServicePowerMah = calculatePowerUsingMeasuredConsumption(batteryStats,
-                    systemUid, consumptionUC);
-        } else {
-            systemServicePowerMah = calculatePowerUsingPowerProfile(batteryStats);
-        }
-
-        BatterySipper systemServerSipper = null;
-        for (int i = sippers.size() - 1; i >= 0; i--) {
-            final BatterySipper app = sippers.get(i);
-            if (app.drainType == BatterySipper.DrainType.APP) {
-                if (app.getUid() == Process.SYSTEM_UID) {
-                    systemServerSipper = app;
-                    break;
-                }
-            }
-        }
-
-        if (systemServerSipper != null) {
-            systemServicePowerMah = Math.min(systemServicePowerMah, systemServerSipper.sumPower());
-
-            // The system server power needs to be adjusted because part of it got
-            // distributed to applications
-            systemServerSipper.powerReattributedToOtherSippersMah = -systemServicePowerMah;
-        }
-
-        for (int i = sippers.size() - 1; i >= 0; i--) {
-            final BatterySipper app = sippers.get(i);
-            if (app.drainType == BatterySipper.DrainType.APP) {
-                if (app != systemServerSipper) {
-                    final BatteryStats.Uid uid = app.uidObj;
-                    app.systemServiceCpuPowerMah =
-                            systemServicePowerMah * uid.getProportionalSystemServiceUsage();
-                }
-            }
-        }
-    }
-
     private double calculatePowerUsingMeasuredConsumption(BatteryStats batteryStats,
             BatteryStats.Uid systemUid, long consumptionUC) {
         // Use the PowerProfile based model to estimate the ratio between the power consumed
diff --git a/core/java/com/android/internal/os/UserPowerCalculator.java b/core/java/com/android/internal/os/UserPowerCalculator.java
index b590bf7..22cff6e 100644
--- a/core/java/com/android/internal/os/UserPowerCalculator.java
+++ b/core/java/com/android/internal/os/UserPowerCalculator.java
@@ -27,8 +27,6 @@
 
 import com.android.internal.util.ArrayUtils;
 
-import java.util.List;
-
 /**
  * Computes power consumed by Users
  */
@@ -65,40 +63,4 @@
             }
         }
     }
-
-    @Override
-    public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
-            long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
-        final boolean forAllUsers = (asUsers.get(UserHandle.USER_ALL) != null);
-        if (forAllUsers) {
-            return;
-        }
-
-        SparseArray<BatterySipper> userSippers = new SparseArray<>();
-
-        for (int i = sippers.size() - 1; i >= 0; i--) {
-            BatterySipper sipper = sippers.get(i);
-            final int uid = sipper.getUid();
-            final int userId = UserHandle.getUserId(uid);
-            if (asUsers.get(userId) == null
-                    && UserHandle.getAppId(uid) >= Process.FIRST_APPLICATION_UID) {
-                // We are told to just report this user's apps as one accumulated entry.
-                BatterySipper userSipper = userSippers.get(userId);
-                if (userSipper == null) {
-                    userSipper = new BatterySipper(BatterySipper.DrainType.USER, null, 0);
-                    userSipper.userId = userId;
-                    userSippers.put(userId, userSipper);
-                }
-                userSipper.add(sipper);
-                sipper.isAggregated = true;
-            }
-        }
-
-        for (int i = 0; i < userSippers.size(); i++) {
-            BatterySipper sipper = userSippers.valueAt(i);
-            if (sipper.sumPower() > 0) {
-                sippers.add(sipper);
-            }
-        }
-    }
 }
diff --git a/core/java/com/android/internal/os/WakelockPowerCalculator.java b/core/java/com/android/internal/os/WakelockPowerCalculator.java
index bceb209..0251e1c 100644
--- a/core/java/com/android/internal/os/WakelockPowerCalculator.java
+++ b/core/java/com/android/internal/os/WakelockPowerCalculator.java
@@ -21,13 +21,10 @@
 import android.os.BatteryUsageStatsQuery;
 import android.os.Process;
 import android.os.UidBatteryConsumer;
-import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.SparseArray;
 
-import java.util.List;
-
 public class WakelockPowerCalculator extends PowerCalculator {
     private static final String TAG = "WakelockPowerCalculator";
     private static final boolean DEBUG = PowerCalculator.DEBUG;
@@ -105,42 +102,6 @@
                         appPowerMah);
     }
 
-    @Override
-    public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
-            long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
-        final PowerAndDuration result = new PowerAndDuration();
-        BatterySipper osSipper = null;
-        double osPowerMah = 0;
-        long osDurationMs = 0;
-        long totalAppDurationMs = 0;
-        for (int i = sippers.size() - 1; i >= 0; i--) {
-            final BatterySipper app = sippers.get(i);
-            if (app.drainType == BatterySipper.DrainType.APP) {
-                calculateApp(result, app.uidObj, rawRealtimeUs, statsType);
-                app.wakeLockTimeMs = result.durationMs;
-                app.wakeLockPowerMah = result.powerMah;
-                totalAppDurationMs += result.durationMs;
-
-                if (app.getUid() == Process.ROOT_UID) {
-                    osSipper = app;
-                    osPowerMah = result.powerMah;
-                    osDurationMs = result.durationMs;
-                }
-            }
-        }
-
-        // The device has probably been awake for longer than the screen on
-        // time and application wake lock time would account for.  Assign
-        // this remainder to the OS, if possible.
-        if (osSipper != null) {
-            calculateRemaining(result, batteryStats, rawRealtimeUs, rawUptimeUs, statsType,
-                    osPowerMah, osDurationMs, totalAppDurationMs);
-            osSipper.wakeLockTimeMs = result.durationMs;
-            osSipper.wakeLockPowerMah = result.powerMah;
-            osSipper.sumPower();
-        }
-    }
-
     private void calculateApp(PowerAndDuration result, BatteryStats.Uid u, long rawRealtimeUs,
             int statsType) {
         long wakeLockTimeUs = 0;
@@ -163,7 +124,7 @@
         result.powerMah = mPowerEstimator.calculatePower(result.durationMs);
         if (DEBUG && result.powerMah != 0) {
             Log.d(TAG, "UID " + u.getUid() + ": wake " + result.durationMs
-                    + " power=" + formatCharge(result.powerMah));
+                    + " power=" + BatteryStats.formatCharge(result.powerMah));
         }
     }
 
@@ -175,7 +136,8 @@
         if (wakeTimeMillis > 0) {
             final double power = mPowerEstimator.calculatePower(wakeTimeMillis);
             if (DEBUG) {
-                Log.d(TAG, "OS wakeLockTime " + wakeTimeMillis + " power " + formatCharge(power));
+                Log.d(TAG, "OS wakeLockTime " + wakeTimeMillis
+                        + " power " + BatteryStats.formatCharge(power));
             }
             result.durationMs = osDurationMs + wakeTimeMillis;
             result.powerMah = osPowerMah + power;
diff --git a/core/java/com/android/internal/os/WifiPowerCalculator.java b/core/java/com/android/internal/os/WifiPowerCalculator.java
index ad291a4..8c3fb86 100644
--- a/core/java/com/android/internal/os/WifiPowerCalculator.java
+++ b/core/java/com/android/internal/os/WifiPowerCalculator.java
@@ -19,14 +19,11 @@
 import android.os.BatteryStats;
 import android.os.BatteryUsageStats;
 import android.os.BatteryUsageStatsQuery;
-import android.os.Process;
 import android.os.UidBatteryConsumer;
-import android.os.UserHandle;
 import android.util.Log;
 import android.util.SparseArray;
 
 import java.util.Arrays;
-import java.util.List;
 
 /**
  * WiFi power calculator for when BatteryStats supports energy reporting
@@ -156,62 +153,6 @@
                         totalAppPowerMah, powerModel);
     }
 
-    /**
-     * We do per-app blaming of WiFi activity. If energy info is reported from the controller,
-     * then only the WiFi process gets blamed here since we normalize power calculations and
-     * assign all the power drain to apps. If energy info is not reported, we attribute the
-     * difference between total running time of WiFi for all apps and the actual running time
-     * of WiFi to the WiFi subsystem.
-     */
-    @Override
-    public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
-            long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
-
-        final BatterySipper bs = new BatterySipper(BatterySipper.DrainType.WIFI, null, 0);
-
-        long totalAppDurationMs = 0;
-        double totalAppPowerMah = 0;
-        final PowerDurationAndTraffic powerDurationAndTraffic = new PowerDurationAndTraffic();
-        for (int i = sippers.size() - 1; i >= 0; i--) {
-            final BatterySipper app = sippers.get(i);
-            if (app.drainType == BatterySipper.DrainType.APP) {
-                final long consumptionUC =
-                        app.uidObj.getWifiMeasuredBatteryConsumptionUC();
-                final int powerModel = getPowerModel(consumptionUC);
-                calculateApp(powerDurationAndTraffic, app.uidObj, powerModel, rawRealtimeUs,
-                        statsType, batteryStats.hasWifiActivityReporting(), consumptionUC);
-
-                totalAppDurationMs += powerDurationAndTraffic.durationMs;
-                totalAppPowerMah += powerDurationAndTraffic.powerMah;
-
-                app.wifiPowerMah = powerDurationAndTraffic.powerMah;
-                app.wifiRunningTimeMs = powerDurationAndTraffic.durationMs;
-                app.wifiRxBytes = powerDurationAndTraffic.wifiRxBytes;
-                app.wifiRxPackets = powerDurationAndTraffic.wifiRxPackets;
-                app.wifiTxBytes = powerDurationAndTraffic.wifiTxBytes;
-                app.wifiTxPackets = powerDurationAndTraffic.wifiTxPackets;
-                if (app.getUid() == Process.WIFI_UID) {
-                    if (DEBUG) Log.d(TAG, "WiFi adding sipper " + app + ": cpu=" + app.cpuTimeMs);
-                    app.isAggregated = true;
-                    bs.add(app);
-                }
-            }
-        }
-
-        final long consumptionUC = batteryStats.getWifiMeasuredBatteryConsumptionUC();
-        final int powerModel = getPowerModel(consumptionUC);
-        calculateRemaining(powerDurationAndTraffic, powerModel, batteryStats, rawRealtimeUs,
-                statsType, batteryStats.hasWifiActivityReporting(), totalAppDurationMs,
-                totalAppPowerMah, consumptionUC);
-
-        bs.wifiRunningTimeMs += powerDurationAndTraffic.durationMs;
-        bs.wifiPowerMah += powerDurationAndTraffic.powerMah;
-
-        if (bs.sumPower() > 0) {
-            sippers.add(bs);
-        }
-    }
-
     private void calculateApp(PowerDurationAndTraffic powerDurationAndTraffic,
             BatteryStats.Uid u, @BatteryConsumer.PowerModel int powerModel,
             long rawRealtimeUs, int statsType, boolean hasWifiActivityReporting,
@@ -251,7 +192,7 @@
 
                 if (DEBUG && powerDurationAndTraffic.powerMah != 0) {
                     Log.d(TAG, "UID " + u.getUid() + ": idle=" + idleTime + "ms rx=" + rxTime
-                            + "ms tx=" + txTime + "ms power=" + formatCharge(
+                            + "ms tx=" + txTime + "ms power=" + BatteryStats.formatCharge(
                             powerDurationAndTraffic.powerMah));
                 }
 
@@ -306,7 +247,7 @@
             }
 
             if (DEBUG && powerDurationAndTraffic.powerMah != 0) {
-                Log.d(TAG, "UID " + u.getUid() + ": power=" + formatCharge(
+                Log.d(TAG, "UID " + u.getUid() + ": power=" + BatteryStats.formatCharge(
                         powerDurationAndTraffic.powerMah));
             }
         }
@@ -353,7 +294,8 @@
         powerDurationAndTraffic.powerMah = Math.max(0, totalPowerMah - totalAppPowerMah);
 
         if (DEBUG) {
-            Log.d(TAG, "left over WiFi power: " + formatCharge(powerDurationAndTraffic.powerMah));
+            Log.d(TAG, "left over WiFi power: " + BatteryStats.formatCharge(
+                    powerDurationAndTraffic.powerMah));
         }
     }
 
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index f258f84..3d24aa2d 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -736,10 +736,13 @@
             Zygote.applyInvokeWithSystemProperty(parsedArgs);
 
             if (Zygote.nativeSupportsMemoryTagging()) {
-                /* The system server has ASYNC MTE by default, in order to allow
-                 * system services to specify their own MTE level later, as you
-                 * can't re-enable MTE once it's disabled. */
-                String mode = SystemProperties.get("arm64.memtag.process.system_server", "async");
+                String mode = SystemProperties.get("arm64.memtag.process.system_server", "");
+                if (mode.isEmpty()) {
+                  /* The system server has ASYNC MTE by default, in order to allow
+                   * system services to specify their own MTE level later, as you
+                   * can't re-enable MTE once it's disabled. */
+                  mode = SystemProperties.get("persist.arm64.memtag.default", "async");
+                }
                 if (mode.equals("async")) {
                     parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_ASYNC;
                 } else if (mode.equals("sync")) {
diff --git a/core/java/com/android/internal/view/IInputMethodClient.aidl b/core/java/com/android/internal/view/IInputMethodClient.aidl
index e72afdd..8430c08 100644
--- a/core/java/com/android/internal/view/IInputMethodClient.aidl
+++ b/core/java/com/android/internal/view/IInputMethodClient.aidl
@@ -24,7 +24,9 @@
  */
 oneway interface IInputMethodClient {
     void onBindMethod(in InputBindResult res);
+    void onBindAccessibilityService(in InputBindResult res, int id);
     void onUnbindMethod(int sequence, int unbindReason);
+    void onUnbindAccessibilityService(int sequence, int id);
     void setActive(boolean active, boolean fullscreen, boolean reportToImeController);
     void scheduleStartInputIfNecessary(boolean fullscreen);
     void reportFullscreenMode(boolean fullscreen);
diff --git a/core/java/com/android/internal/view/IInputSessionWithIdCallback.aidl b/core/java/com/android/internal/view/IInputSessionWithIdCallback.aidl
new file mode 100644
index 0000000..8fbdefe
--- /dev/null
+++ b/core/java/com/android/internal/view/IInputSessionWithIdCallback.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+ package com.android.internal.view;
+
+ import com.android.internal.view.IInputMethodSession;
+
+/**
+ * Helper interface for IInputMethod to allow the input method to notify the client when a new
+ * session has been created.
+ */
+oneway interface IInputSessionWithIdCallback {
+    void sessionCreated(IInputMethodSession session, int id);
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index c9dc6b6..1e11c6d 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -26,6 +26,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.PropertyInvalidatedCache;
 import android.app.admin.DevicePolicyManager;
 import android.app.admin.PasswordMetrics;
 import android.app.trust.IStrongAuthTracker;
@@ -941,17 +942,53 @@
     }
 
     /**
+     * Retrieve the credential type of a user.
+     */
+    private final PropertyInvalidatedCache.QueryHandler<Integer, Integer> mCredentialTypeQuery =
+            new PropertyInvalidatedCache.QueryHandler<>() {
+                @Override
+                public Integer apply(Integer userHandle) {
+                    try {
+                        return getLockSettings().getCredentialType(userHandle);
+                    } catch (RemoteException re) {
+                        Log.e(TAG, "failed to get credential type", re);
+                        return CREDENTIAL_TYPE_NONE;
+                    }
+                }
+                @Override
+                public boolean shouldBypassCache(Integer userHandle) {
+                    return userHandle == USER_FRP;
+                }
+            };
+
+    /**
+     * The API that is cached.
+     */
+    private final static String CREDENTIAL_TYPE_API = "getCredentialType";
+
+    /**
+     * Cache the credential type of a user.
+     */
+    private final PropertyInvalidatedCache<Integer, Integer> mCredentialTypeCache =
+            new PropertyInvalidatedCache<>(4, PropertyInvalidatedCache.MODULE_SYSTEM,
+                    CREDENTIAL_TYPE_API, CREDENTIAL_TYPE_API, mCredentialTypeQuery);
+
+    /**
+     * Invalidate the credential cache
+     * @hide
+     */
+    public final static void invalidateCredentialTypeCache() {
+        PropertyInvalidatedCache.invalidateCache(PropertyInvalidatedCache.MODULE_SYSTEM,
+                CREDENTIAL_TYPE_API);
+    }
+
+    /**
      * Returns the credential type of the user, can be one of {@link #CREDENTIAL_TYPE_NONE},
      * {@link #CREDENTIAL_TYPE_PATTERN}, {@link #CREDENTIAL_TYPE_PIN} and
      * {@link #CREDENTIAL_TYPE_PASSWORD}
      */
     public @CredentialType int getCredentialTypeForUser(int userHandle) {
-        try {
-            return getLockSettings().getCredentialType(userHandle);
-        } catch (RemoteException re) {
-            Log.e(TAG, "failed to get credential type", re);
-            return CREDENTIAL_TYPE_NONE;
-        }
+        return mCredentialTypeCache.query(userHandle);
     }
 
     /**
diff --git a/core/jni/android_graphics_BLASTBufferQueue.cpp b/core/jni/android_graphics_BLASTBufferQueue.cpp
index 55f1369..4f13a9c 100644
--- a/core/jni/android_graphics_BLASTBufferQueue.cpp
+++ b/core/jni/android_graphics_BLASTBufferQueue.cpp
@@ -30,6 +30,11 @@
 
 namespace android {
 
+static struct {
+    jclass clazz;
+    jmethodID ctor;
+} gTransactionClassInfo;
+
 static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring jName) {
     ScopedUtfChars name(env, jName);
     sp<BLASTBufferQueue> queue = new BLASTBufferQueue(name.c_str());
@@ -86,6 +91,14 @@
     return queue->isSameSurfaceControl(reinterpret_cast<SurfaceControl*>(surfaceControl));
 }
 
+static jobject nativeGatherPendingTransactions(JNIEnv* env, jclass clazz, jlong ptr,
+                                               jlong frameNum) {
+    sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
+    SurfaceComposerClient::Transaction* transaction = queue->gatherPendingTransactions(frameNum);
+    return env->NewObject(gTransactionClassInfo.clazz, gTransactionClassInfo.ctor,
+                          reinterpret_cast<jlong>(transaction));
+}
+
 static const JNINativeMethod gMethods[] = {
         /* name, signature, funcPtr */
         // clang-format off
@@ -98,6 +111,7 @@
         {"nativeGetLastAcquiredFrameNum", "(J)J", (void*)nativeGetLastAcquiredFrameNum},
         {"nativeApplyPendingTransactions", "(JJ)V", (void*)nativeApplyPendingTransactions},
         {"nativeIsSameSurfaceControl", "(JJ)Z", (void*)nativeIsSameSurfaceControl},
+        {"nativeGatherPendingTransactions", "(JJ)Landroid/view/SurfaceControl$Transaction;", (void*)nativeGatherPendingTransactions}
         // clang-format on
 };
 
@@ -105,6 +119,11 @@
     int res = jniRegisterNativeMethods(env, "android/graphics/BLASTBufferQueue",
             gMethods, NELEM(gMethods));
     LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
+
+    jclass transactionClazz = FindClassOrDie(env, "android/view/SurfaceControl$Transaction");
+    gTransactionClassInfo.clazz = MakeGlobalRefOrDie(env, transactionClazz);
+    gTransactionClassInfo.ctor =
+            GetMethodIDOrDie(env, gTransactionClassInfo.clazz, "<init>", "(J)V");
     return 0;
 }
 
diff --git a/core/jni/android_os_HwRemoteBinder.cpp b/core/jni/android_os_HwRemoteBinder.cpp
index 3af55fe..d2d7213 100644
--- a/core/jni/android_os_HwRemoteBinder.cpp
+++ b/core/jni/android_os_HwRemoteBinder.cpp
@@ -81,27 +81,37 @@
 
     void binderDied(const wp<hardware::IBinder>& who)
     {
-        if (mObject != NULL) {
-            JNIEnv* env = javavm_to_jnienv(mVM);
+        JNIEnv* env = javavm_to_jnienv(mVM);
 
-            env->CallStaticVoidMethod(gProxyOffsets.proxy_class, gProxyOffsets.sendDeathNotice, mObject, mCookie);
+        // Serialize with our containing HwBinderDeathRecipientList so that we can't
+        // delete the global ref on object while the list is being iterated.
+        sp<HwBinderDeathRecipientList> list = mList.promote();
+        if (list == nullptr) return;
+
+        jobject object;
+        {
+            AutoMutex _l(list->lock());
+
+            // this function now owns the global ref - to the rest of the code, it looks like
+            // this binder already died, but we won't actually delete the reference until
+            // the Java code has processed the death
+            object = mObject;
+
+            // Demote from strong ref to weak for after binderDied() has been delivered,
+            // to allow the DeathRecipient and BinderProxy to be GC'd if no longer needed.
+            mObjectWeak = env->NewWeakGlobalRef(mObject);
+            mObject = nullptr;
+        }
+
+        if (object != nullptr) {
+            env->CallStaticVoidMethod(gProxyOffsets.proxy_class, gProxyOffsets.sendDeathNotice,
+                                      object, mCookie);
             if (env->ExceptionCheck()) {
                 ALOGE("Uncaught exception returned from death notification.");
                 env->ExceptionClear();
             }
 
-            // Serialize with our containing HwBinderDeathRecipientList so that we can't
-            // delete the global ref on mObject while the list is being iterated.
-            sp<HwBinderDeathRecipientList> list = mList.promote();
-            if (list != NULL) {
-                AutoMutex _l(list->lock());
-
-                // Demote from strong ref to weak after binderDied() has been delivered,
-                // to allow the DeathRecipient and BinderProxy to be GC'd if no longer needed.
-                mObjectWeak = env->NewWeakGlobalRef(mObject);
-                env->DeleteGlobalRef(mObject);
-                mObject = NULL;
-            }
+            env->DeleteGlobalRef(object);
         }
     }
 
@@ -115,7 +125,7 @@
         }
     }
 
-    bool matches(jobject obj) {
+    bool matchesLocked(jobject obj) {
         bool result;
         JNIEnv* env = javavm_to_jnienv(mVM);
 
@@ -129,7 +139,7 @@
         return result;
     }
 
-    void warnIfStillLive() {
+    void warnIfStillLiveLocked() {
         if (mObject != NULL) {
             // Okay, something is wrong -- we have a hard reference to a live death
             // recipient on the VM side, but the list is being torn down.
@@ -176,7 +186,7 @@
     AutoMutex _l(mLock);
 
     for (const sp<HwBinderDeathRecipient>& deathRecipient : mList) {
-        deathRecipient->warnIfStillLive();
+        deathRecipient->warnIfStillLiveLocked();
     }
 }
 
@@ -201,7 +211,7 @@
     AutoMutex _l(mLock);
 
     for(auto iter = mList.rbegin(); iter != mList.rend(); iter++) {
-        if ((*iter)->matches(recipient)) {
+        if ((*iter)->matchesLocked(recipient)) {
             return (*iter);
         }
     }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 2736ba63..f29de56 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -199,6 +199,8 @@
     <protected-broadcast
         android:name="android.bluetooth.headsetclient.profile.action.LAST_VTAG" />
     <protected-broadcast
+        android:name="android.bluetooth.headsetclient.profile.action.NETWORK_SERVICE_STATE_CHANGED" />
+    <protected-broadcast
         android:name="android.bluetooth.hearingaid.profile.action.CONNECTION_STATE_CHANGED" />
     <protected-broadcast
         android:name="android.bluetooth.hearingaid.profile.action.PLAYING_STATE_CHANGED" />
@@ -721,6 +723,7 @@
     <protected-broadcast android:name="android.app.action.DEVICE_POLICY_RESOURCE_UPDATED" />
     <protected-broadcast android:name="android.intent.action.SHOW_FOREGROUND_SERVICE_MANAGER" />
     <protected-broadcast android:name="android.service.autofill.action.DELAYED_FILL" />
+    <protected-broadcast android:name="android.app.action.PROVISIONING_COMPLETED" />
 
     <!-- ====================================================================== -->
     <!--                          RUNTIME PERMISSIONS                           -->
@@ -1895,7 +1898,7 @@
         android:label="@string/permlab_changeWifiState"
         android:protectionLevel="normal" />
 
-    <!-- @SystemApi @hide Allows applications to enable/disable wifi auto join. This permission
+    <!-- Allows applications to enable/disable wifi auto join. This permission
          is used to let OEMs grant their trusted app access to a subset of privileged wifi APIs
          to improve wifi performance.
          <p>Not for use by third-party applications. -->
@@ -1933,7 +1936,7 @@
     <permission android:name="android.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE"
         android:protectionLevel="signature|privileged" />
 
-    <!-- @SystemApi @hide Allows an application to modify any wifi configuration, even if created
+    <!-- Allows an application to modify any wifi configuration, even if created
      by another application. Once reconfigured the original creator cannot make any further
      modifications.
      <p>Not for use by third-party applications. -->
@@ -6616,14 +6619,6 @@
                   android:exported="false">
         </activity>
 
-        <activity android:name="com.android.server.logcat.LogAccessConfirmationActivity"
-                  android:theme="@style/Theme.Dialog.Confirmation"
-                  android:excludeFromRecents="true"
-                  android:process=":ui"
-                  android:label="@string/log_access_confirmation_title"
-                  android:exported="false">
-        </activity>
-
         <activity android:name="com.android.server.notification.NASLearnMoreActivity"
                   android:theme="@style/Theme.Dialog.Confirmation"
                   android:excludeFromRecents="true"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 8df5871..090b1c52 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3910,6 +3910,8 @@
             <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_MULTI_FINGER_GESTURES}. -->
             <flag name="flagRequestMultiFingerGestures" value="0x00001000" />
             <flag name="flagSendMotionEvents" value="0x0004000" />
+            <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_INPUT_METHOD_EDITOR}. -->
+            <flag name="flagInputMethodEditor" value="0x0008000" />
         </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/res/res/values/config.xml b/core/res/res/values/config.xml
index 6a86b1c..775527d 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4082,6 +4082,16 @@
    -->
     <string name="config_defaultAmbientContextDetectionService" translatable="false"></string>
 
+    <!-- Component name that accepts ACTION_SEND intents for requesting ambient context consent. -->
+    <string translatable="false" name="config_defaultAmbientContextConsentComponent"></string>
+
+    <!-- Intent extra key for the caller's package name while requesting ambient context consent.
+     -->
+    <string translatable="false" name="config_ambientContextPackageNameExtraKey"></string>
+
+    <!-- Intent extra key for the event code int array while requesting ambient context consent. -->
+    <string translatable="false" name="config_ambientContextEventArrayExtraKey"></string>
+
     <!-- The component name for the system-wide captions service.
          This service must be trusted, as it controls part of the UI of the volume bar.
          Example: "com.android.captions/.SystemCaptionsService"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 70ca8fc..6297ed9 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5719,20 +5719,6 @@
     <!-- Title for the harmful app warning dialog. [CHAR LIMIT=40] -->
     <string name="harmful_app_warning_title">Harmful app detected</string>
 
-    <!-- Title for the log access confirmation dialog. [CHAR LIMIT=40] -->
-    <string name="log_access_confirmation_title">System log access request</string>
-    <!-- Label for the allow button on the log access confirmation dialog. [CHAR LIMIT=20] -->
-    <string name="log_access_confirmation_allow">Only this time</string>
-    <!-- Label for the deny button on the log access confirmation dialog. [CHAR LIMIT=20] -->
-    <string name="log_access_confirmation_deny">Don\u2019t allow</string>
-
-    <!-- Content for the log access confirmation dialog. [CHAR LIMIT=NONE]-->
-    <string name="log_access_confirmation_body"><xliff:g id="log_access_app_name" example="Example App">%s</xliff:g> requests system logs for functional debugging.
-        These logs might contain information that apps and services on your device have written.</string>
-
-    <!-- Privacy notice do not show [CHAR LIMIT=20] -->
-    <string name="log_access_do_not_show_again">Don\u2019t show again</string>
-
     <!-- Text describing a permission request for one app to show another app's
          slices [CHAR LIMIT=NONE] -->
     <string name="slices_permission_request"><xliff:g id="app" example="Example App">%1$s</xliff:g> wants to show <xliff:g id="app_2" example="Other Example App">%2$s</xliff:g> slices</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a79eec2..d731180 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3868,11 +3868,6 @@
   <java-symbol type="string" name="harmful_app_warning_title" />
   <java-symbol type="layout" name="harmful_app_warning_dialog" />
 
-  <java-symbol type="string" name="log_access_confirmation_allow" />
-  <java-symbol type="string" name="log_access_confirmation_deny" />
-  <java-symbol type="string" name="log_access_confirmation_title" />
-  <java-symbol type="string" name="log_access_confirmation_body" />
-
   <java-symbol type="string" name="config_defaultAssistantAccessComponent" />
 
   <java-symbol type="string" name="slices_permission_request" />
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java
deleted file mode 100644
index 260b65a..0000000
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- *
- */
-
-package com.android.internal.os;
-
-import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.BatteryStats;
-import android.os.Process;
-import android.text.format.DateUtils;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import junit.framework.TestCase;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class BatteryStatsHelperTest extends TestCase {
-    private static final long TIME_FOREGROUND_ACTIVITY_ZERO = 0;
-    private static final long TIME_FOREGROUND_ACTIVITY = 100 * DateUtils.MINUTE_IN_MILLIS * 1000;
-    private static final long TIME_STATE_FOREGROUND_MS = 10 * DateUtils.MINUTE_IN_MILLIS;
-    private static final long TIME_STATE_FOREGROUND_US = TIME_STATE_FOREGROUND_MS * 1000;
-
-    private static final int UID = 123456;
-    private static final double BATTERY_SCREEN_USAGE = 300;
-    private static final double BATTERY_SYSTEM_USAGE = 600;
-    private static final double BATTERY_WIFI_USAGE = 200;
-    private static final double BATTERY_IDLE_USAGE = 600;
-    private static final double BATTERY_BLUETOOTH_USAGE = 300;
-    private static final double BATTERY_OVERACCOUNTED_USAGE = 500;
-    private static final double BATTERY_UNACCOUNTED_USAGE = 700;
-    private static final double BATTERY_APP_USAGE = 100;
-    private static final double TOTAL_BATTERY_USAGE = 1000;
-    private static final double PRECISION = 0.001;
-
-    @Mock
-    private BatteryStats.Uid mUid;
-    @Mock
-    private BatterySipper mWifiBatterySipper;
-    @Mock
-    private BatterySipper mBluetoothBatterySipper;
-    @Mock
-    private BatterySipper mIdleBatterySipper;
-    @Mock
-    private BatterySipper mNormalBatterySipper;
-    @Mock
-    private BatterySipper mScreenBatterySipper;
-    @Mock
-    private BatterySipper mOvercountedBatterySipper;
-    @Mock
-    private BatterySipper mUnaccountedBatterySipper;
-    @Mock
-    private BatterySipper mSystemBatterySipper;
-    @Mock
-    private BatterySipper mCellBatterySipper;
-    @Mock
-    private PackageManager mPackageManager;
-
-    private BatteryStatsHelper mBatteryStatsHelper;
-    private Context mContext;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-
-        mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
-        mNormalBatterySipper.totalPowerMah = TOTAL_BATTERY_USAGE;
-        when(mNormalBatterySipper.getUid()).thenReturn(UID);
-        mNormalBatterySipper.uidObj = mUid;
-
-
-        mScreenBatterySipper.drainType = BatterySipper.DrainType.SCREEN;
-        mScreenBatterySipper.totalPowerMah = BATTERY_SCREEN_USAGE;
-
-        mSystemBatterySipper.drainType = BatterySipper.DrainType.APP;
-        mSystemBatterySipper.totalPowerMah = BATTERY_SYSTEM_USAGE;
-        mSystemBatterySipper.uidObj = mUid;
-        when(mSystemBatterySipper.getUid()).thenReturn(Process.SYSTEM_UID);
-
-        mOvercountedBatterySipper.drainType = BatterySipper.DrainType.OVERCOUNTED;
-        mOvercountedBatterySipper.totalPowerMah = BATTERY_OVERACCOUNTED_USAGE;
-
-        mUnaccountedBatterySipper.drainType = BatterySipper.DrainType.UNACCOUNTED;
-        mUnaccountedBatterySipper.totalPowerMah = BATTERY_UNACCOUNTED_USAGE;
-
-        mWifiBatterySipper.drainType = BatterySipper.DrainType.WIFI;
-        mWifiBatterySipper.totalPowerMah = BATTERY_WIFI_USAGE;
-
-        mBluetoothBatterySipper.drainType = BatterySipper.DrainType.BLUETOOTH;
-        mBluetoothBatterySipper.totalPowerMah = BATTERY_BLUETOOTH_USAGE;
-
-        mIdleBatterySipper.drainType = BatterySipper.DrainType.IDLE;
-        mIdleBatterySipper.totalPowerMah = BATTERY_IDLE_USAGE;
-
-        mContext = InstrumentationRegistry.getContext();
-        mBatteryStatsHelper = spy(new BatteryStatsHelper(mContext));
-        mBatteryStatsHelper.setPackageManager(mPackageManager);
-    }
-
-    @Test
-    public void testShouldHideSipper_TypeUnAccounted_ReturnTrue() {
-        mNormalBatterySipper.drainType = BatterySipper.DrainType.UNACCOUNTED;
-        assertThat(mBatteryStatsHelper.shouldHideSipper(mNormalBatterySipper)).isTrue();
-    }
-
-    @Test
-    public void testShouldHideSipper_TypeOverAccounted_ReturnTrue() {
-        mNormalBatterySipper.drainType = BatterySipper.DrainType.OVERCOUNTED;
-        assertThat(mBatteryStatsHelper.shouldHideSipper(mNormalBatterySipper)).isTrue();
-    }
-
-    @Test
-    public void testShouldHideSipper_TypeIdle_ReturnTrue() {
-        mNormalBatterySipper.drainType = BatterySipper.DrainType.IDLE;
-        assertThat(mBatteryStatsHelper.shouldHideSipper(mNormalBatterySipper)).isTrue();
-    }
-
-    @Test
-    public void testShouldHideSipper_TypeCell_ReturnTrue() {
-        mNormalBatterySipper.drainType = BatterySipper.DrainType.CELL;
-        assertThat(mBatteryStatsHelper.shouldHideSipper(mNormalBatterySipper)).isTrue();
-    }
-
-    @Test
-    public void testShouldHideSipper_TypeScreen_ReturnTrue() {
-        mNormalBatterySipper.drainType = BatterySipper.DrainType.SCREEN;
-        assertThat(mBatteryStatsHelper.shouldHideSipper(mNormalBatterySipper)).isTrue();
-    }
-
-    @Test
-    public void testShouldHideSipper_TypeSystem_ReturnTrue() {
-        mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
-        when(mNormalBatterySipper.getUid()).thenReturn(Process.ROOT_UID);
-        assertThat(mBatteryStatsHelper.shouldHideSipper(mNormalBatterySipper)).isTrue();
-    }
-
-    @Test
-    public void testShouldHideSipper_UidNormal_ReturnFalse() {
-        mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
-        assertThat(mBatteryStatsHelper.shouldHideSipper(mNormalBatterySipper)).isFalse();
-    }
-
-    @Test
-    public void testRemoveHiddenBatterySippers_ContainsHiddenSippers_RemoveAndReturnValue() {
-        final List<BatterySipper> sippers = new ArrayList<>();
-        sippers.add(mNormalBatterySipper);
-        sippers.add(mScreenBatterySipper);
-        sippers.add(mSystemBatterySipper);
-        sippers.add(mOvercountedBatterySipper);
-        sippers.add(mUnaccountedBatterySipper);
-        sippers.add(mWifiBatterySipper);
-        sippers.add(mBluetoothBatterySipper);
-        sippers.add(mIdleBatterySipper);
-        doReturn(true).when(mBatteryStatsHelper).isTypeSystem(mSystemBatterySipper);
-
-        final double totalUsage = mBatteryStatsHelper.removeHiddenBatterySippers(sippers);
-
-        assertThat(mNormalBatterySipper.shouldHide).isFalse();
-        assertThat(mScreenBatterySipper.shouldHide).isTrue();
-        assertThat(mSystemBatterySipper.shouldHide).isTrue();
-        assertThat(mOvercountedBatterySipper.shouldHide).isTrue();
-        assertThat(mUnaccountedBatterySipper.shouldHide).isTrue();
-        assertThat(totalUsage).isWithin(PRECISION).of(BATTERY_SYSTEM_USAGE);
-    }
-
-    @Test
-    public void testSmearScreenBatterySipper() {
-        final ScreenPowerCalculator spc = spy(ScreenPowerCalculator.class);
-        final BatterySipper sipperNull = createTestSmearBatterySipper(TIME_FOREGROUND_ACTIVITY_ZERO,
-                BATTERY_APP_USAGE, 0 /* uid */, true /* isUidNull */, spc);
-        final BatterySipper sipperBg = createTestSmearBatterySipper(TIME_FOREGROUND_ACTIVITY_ZERO,
-                BATTERY_APP_USAGE, 1 /* uid */, false /* isUidNull */, spc);
-        final BatterySipper sipperFg = createTestSmearBatterySipper(TIME_FOREGROUND_ACTIVITY,
-                BATTERY_APP_USAGE, 2 /* uid */, false /* isUidNull */, spc);
-
-        final List<BatterySipper> sippers = new ArrayList<>();
-        sippers.add(sipperNull);
-        sippers.add(sipperBg);
-        sippers.add(sipperFg);
-
-        spc.smearScreenBatterySipper(sippers, mScreenBatterySipper, 0);
-
-        assertThat(sipperNull.screenPowerMah).isWithin(PRECISION).of(0);
-        assertThat(sipperBg.screenPowerMah).isWithin(PRECISION).of(0);
-        assertThat(sipperFg.screenPowerMah).isWithin(PRECISION).of(BATTERY_SCREEN_USAGE);
-    }
-
-    @Test
-    public void testIsTypeSystem_systemPackage_returnTrue() {
-        final String[] systemPackages = {"com.android.system"};
-        mBatteryStatsHelper.setSystemPackageArray(systemPackages);
-        doReturn(UID).when(mNormalBatterySipper).getUid();
-        doReturn(systemPackages).when(mPackageManager).getPackagesForUid(UID);
-
-        assertThat(mBatteryStatsHelper.isTypeSystem(mNormalBatterySipper)).isTrue();
-    }
-
-    @Test
-    public void testIsTypeService_servicePackage_returnTrue() {
-        final String[] servicePackages = {"com.android.service"};
-        mBatteryStatsHelper.setServicePackageArray(servicePackages);
-        doReturn(UID).when(mNormalBatterySipper).getUid();
-        doReturn(servicePackages).when(mPackageManager).getPackagesForUid(UID);
-
-        assertThat(mBatteryStatsHelper.isTypeService(mNormalBatterySipper)).isTrue();
-    }
-
-    @Test
-    public void testGetProcessForegroundTimeMs_largerActivityTime_returnMinTime() {
-        final ScreenPowerCalculator spc = spy(ScreenPowerCalculator.class);
-        doReturn(TIME_STATE_FOREGROUND_US + 500).when(spc)
-                .getForegroundActivityTotalTimeUs(eq(mUid), anyLong());
-        doReturn(TIME_STATE_FOREGROUND_US).when(mUid).getProcessStateTime(eq(PROCESS_STATE_TOP),
-                anyLong(), anyInt());
-
-        final long time = spc.getProcessForegroundTimeMs(mUid, 1000);
-
-        assertThat(time).isEqualTo(TIME_STATE_FOREGROUND_MS);
-    }
-
-    private BatterySipper createTestSmearBatterySipper(long activityTime, double totalPowerMah,
-            int uidCode, boolean isUidNull, ScreenPowerCalculator spc) {
-        final BatterySipper sipper = mock(BatterySipper.class);
-        sipper.drainType = BatterySipper.DrainType.APP;
-        sipper.totalPowerMah = totalPowerMah;
-        doReturn(uidCode).when(sipper).getUid();
-        if (!isUidNull) {
-            final BatteryStats.Uid uid = mock(BatteryStats.Uid.class, RETURNS_DEEP_STUBS);
-            doReturn(activityTime).when(spc).getProcessForegroundTimeMs(eq(uid), anyLong());
-            doReturn(uidCode).when(uid).getUid();
-            sipper.uidObj = uid;
-        }
-
-        return sipper;
-    }
-
-}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
index be8045d..d9b98a5 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
@@ -41,6 +41,7 @@
 import android.bluetooth.UidTraffic;
 import android.os.BatteryStats;
 import android.os.BluetoothBatteryStats;
+import android.os.Parcel;
 import android.os.WakeLockStats;
 import android.os.WorkSource;
 import android.util.SparseArray;
@@ -583,11 +584,42 @@
         mBatteryStatsImpl.noteBluetoothScanStoppedFromSourceLocked(ws, true, 9000, 9000);
         mBatteryStatsImpl.noteBluetoothScanResultsFromSourceLocked(ws, 42, 9000, 9000);
 
-        BluetoothActivityEnergyInfo info = new BluetoothActivityEnergyInfo(1000,
-                BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE, 9000, 8000, 12000, 0);
-        info.setUidTraffic(ImmutableList.of(
-                new UidTraffic(10042, 3000, 4000),
-                new UidTraffic(10043, 5000, 8000)));
+
+
+        final Parcel uidTrafficParcel1 = Parcel.obtain();
+        final Parcel uidTrafficParcel2 = Parcel.obtain();
+
+        uidTrafficParcel1.writeInt(10042);
+        uidTrafficParcel1.writeLong(3000);
+        uidTrafficParcel1.writeLong(4000);
+        uidTrafficParcel1.setDataPosition(0);
+        uidTrafficParcel2.writeInt(10043);
+        uidTrafficParcel2.writeLong(5000);
+        uidTrafficParcel2.writeLong(8000);
+        uidTrafficParcel2.setDataPosition(0);
+
+        List<UidTraffic> uidTrafficList = ImmutableList.of(
+                UidTraffic.CREATOR.createFromParcel(uidTrafficParcel1),
+                UidTraffic.CREATOR.createFromParcel(uidTrafficParcel2));
+
+        final Parcel btActivityEnergyInfoParcel = Parcel.obtain();
+        btActivityEnergyInfoParcel.writeLong(1000);
+        btActivityEnergyInfoParcel.writeInt(
+                BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE);
+        btActivityEnergyInfoParcel.writeLong(9000);
+        btActivityEnergyInfoParcel.writeLong(8000);
+        btActivityEnergyInfoParcel.writeLong(12000);
+        btActivityEnergyInfoParcel.writeLong(0);
+        btActivityEnergyInfoParcel.writeTypedList(uidTrafficList);
+        btActivityEnergyInfoParcel.setDataPosition(0);
+
+        BluetoothActivityEnergyInfo info = BluetoothActivityEnergyInfo.CREATOR
+                .createFromParcel(btActivityEnergyInfoParcel);
+
+        uidTrafficParcel1.recycle();
+        uidTrafficParcel2.recycle();
+        btActivityEnergyInfoParcel.recycle();
+
         mBatteryStatsImpl.updateBluetoothStateLocked(info, -1, 1000, 1000);
 
         BluetoothBatteryStats stats =
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
index 92c2d43..ace39fb 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
@@ -30,7 +30,6 @@
         BatteryStatsCounterTest.class,
         BatteryStatsDualTimerTest.class,
         BatteryStatsDurationTimerTest.class,
-        BatteryStatsHelperTest.class,
         BatteryStatsHistoryIteratorTest.class,
         BatteryStatsHistoryTest.class,
         BatteryStatsImplTest.class,
@@ -69,7 +68,6 @@
         LongSamplingCounterTest.class,
         LongSamplingCounterArrayTest.class,
         MobileRadioPowerCalculatorTest.class,
-        PowerCalculatorTest.class,
         PowerProfileTest.class,
         ScreenPowerCalculatorTest.class,
         SensorPowerCalculatorTest.class,
diff --git a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
index ed035e5..448f666 100644
--- a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
@@ -24,6 +24,7 @@
 import android.os.BatteryConsumer;
 import android.os.BatteryStats;
 import android.os.BatteryUsageStatsQuery;
+import android.os.Parcel;
 import android.os.Process;
 import android.os.UidBatteryConsumer;
 import android.os.WorkSource;
@@ -37,6 +38,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.List;
+
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 @SuppressWarnings("GuardedBy")
@@ -90,11 +93,13 @@
         uid.setProcessStateForTest(
                 BatteryStats.Uid.PROCESS_STATE_FOREGROUND, 1000);
 
-        BluetoothActivityEnergyInfo info1 = new BluetoothActivityEnergyInfo(2000,
-                BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE, 1000, 2000, 3000, 4000);
-        info1.setUidTraffic(ImmutableList.of(
-                new UidTraffic(Process.BLUETOOTH_UID, 1000, 2000),
-                new UidTraffic(APP_UID, 3000, 4000)));
+
+        List<UidTraffic> trafficList1 = ImmutableList.of(
+                createUidTraffic(Process.BLUETOOTH_UID, 1000, 2000),
+                createUidTraffic(APP_UID, 3000, 4000));
+        BluetoothActivityEnergyInfo info1 = createBtEnergyInfo(2000,
+                BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE, 1000, 2000, 3000, 4000,
+                trafficList1);
 
         batteryStats.updateBluetoothStateLocked(info1,
                 0/*1_000_000*/, 2000, 2000);
@@ -102,11 +107,14 @@
         uid.setProcessStateForTest(
                 BatteryStats.Uid.PROCESS_STATE_BACKGROUND, 3000);
 
-        BluetoothActivityEnergyInfo info2 = new BluetoothActivityEnergyInfo(4000,
-                BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE, 5000, 6000, 7000, 8000);
-        info2.setUidTraffic(ImmutableList.of(
-                new UidTraffic(Process.BLUETOOTH_UID, 5000, 6000),
-                new UidTraffic(APP_UID, 7000, 8000)));
+
+        List<UidTraffic> trafficList2 = ImmutableList.of(
+                createUidTraffic(Process.BLUETOOTH_UID, 5000, 6000),
+                createUidTraffic(APP_UID, 7000, 8000));
+        BluetoothActivityEnergyInfo info2 = createBtEnergyInfo(4000,
+                BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE, 5000, 6000, 7000, 8000,
+                trafficList2);
+
 
         batteryStats.updateBluetoothStateLocked(info2,
                 0 /*5_000_000 */, 4000, 4000);
@@ -202,11 +210,14 @@
         uid.setProcessStateForTest(
                 BatteryStats.Uid.PROCESS_STATE_FOREGROUND, 1000);
 
-        BluetoothActivityEnergyInfo info1 = new BluetoothActivityEnergyInfo(2000,
-                BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE, 1000, 2000, 3000, 4000);
-        info1.setUidTraffic(ImmutableList.of(
-                new UidTraffic(Process.BLUETOOTH_UID, 1000, 2000),
-                new UidTraffic(APP_UID, 3000, 4000)));
+
+        List<UidTraffic> trafficList1 = ImmutableList.of(
+                createUidTraffic(Process.BLUETOOTH_UID, 1000, 2000),
+                createUidTraffic(APP_UID, 3000, 4000));
+        BluetoothActivityEnergyInfo info1 = createBtEnergyInfo(2000,
+                BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE, 1000, 2000, 3000, 4000,
+                trafficList1);
+
 
         batteryStats.updateBluetoothStateLocked(info1,
                 1_000_000, 2000, 2000);
@@ -214,11 +225,13 @@
         uid.setProcessStateForTest(
                 BatteryStats.Uid.PROCESS_STATE_BACKGROUND, 3000);
 
-        BluetoothActivityEnergyInfo info2 = new BluetoothActivityEnergyInfo(4000,
-                BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE, 5000, 6000, 7000, 8000);
-        info2.setUidTraffic(ImmutableList.of(
-                new UidTraffic(Process.BLUETOOTH_UID, 5000, 6000),
-                new UidTraffic(APP_UID, 7000, 8000)));
+        List<UidTraffic> trafficList2 = ImmutableList.of(
+                createUidTraffic(Process.BLUETOOTH_UID, 5000, 6000),
+                createUidTraffic(APP_UID, 7000, 8000));
+        BluetoothActivityEnergyInfo info2 = createBtEnergyInfo(4000,
+                BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE, 5000, 6000, 7000, 8000,
+                trafficList2);
+
 
         batteryStats.updateBluetoothStateLocked(info2,
                 5_000_000, 4000, 4000);
@@ -280,12 +293,15 @@
     }
 
     private void setupBluetoothEnergyInfo(long reportedEnergyUc, long consumedEnergyUc) {
-        final BluetoothActivityEnergyInfo info = new BluetoothActivityEnergyInfo(1000,
+        List<UidTraffic> trafficList = ImmutableList.of(
+                createUidTraffic(Process.BLUETOOTH_UID, 1000, 2000),
+                createUidTraffic(APP_UID, 3000, 4000));
+
+
+        final BluetoothActivityEnergyInfo info = createBtEnergyInfo(1000,
                 BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE, 7000, 5000, 0,
-                reportedEnergyUc);
-        info.setUidTraffic(ImmutableList.of(
-                new UidTraffic(Process.BLUETOOTH_UID, 1000, 2000),
-                new UidTraffic(APP_UID, 3000, 4000)));
+                reportedEnergyUc, trafficList);
+
         mStatsRule.getBatteryStats().updateBluetoothStateLocked(info,
                 consumedEnergyUc, 1000, 1000);
     }
@@ -304,4 +320,34 @@
                 BatteryConsumer.POWER_COMPONENT_BLUETOOTH);
         assertThat(usageDurationMillis).isEqualTo(durationMs);
     }
+
+    private UidTraffic createUidTraffic(int uid, long traffic1, long traffic2) {
+        final Parcel uidTrafficParcel = Parcel.obtain();
+        uidTrafficParcel.writeInt(uid);
+        uidTrafficParcel.writeLong(traffic1);
+        uidTrafficParcel.writeLong(traffic2);
+        uidTrafficParcel.setDataPosition(0);
+
+        UidTraffic traffic = UidTraffic.CREATOR.createFromParcel(uidTrafficParcel);
+        uidTrafficParcel.recycle();
+        return traffic;
+    }
+
+    private BluetoothActivityEnergyInfo createBtEnergyInfo(long timestamp, int stackState,
+            long txTime, long rxTime, long idleTime, long energyUsed, List<UidTraffic> traffic) {
+        final Parcel btActivityEnergyInfoParcel = Parcel.obtain();
+        btActivityEnergyInfoParcel.writeLong(timestamp);
+        btActivityEnergyInfoParcel.writeInt(stackState);
+        btActivityEnergyInfoParcel.writeLong(txTime);
+        btActivityEnergyInfoParcel.writeLong(rxTime);
+        btActivityEnergyInfoParcel.writeLong(idleTime);
+        btActivityEnergyInfoParcel.writeLong(energyUsed);
+        btActivityEnergyInfoParcel.writeTypedList(traffic);
+        btActivityEnergyInfoParcel.setDataPosition(0);
+
+        BluetoothActivityEnergyInfo info = BluetoothActivityEnergyInfo.CREATOR
+                .createFromParcel(btActivityEnergyInfoParcel);
+        btActivityEnergyInfoParcel.recycle();
+        return info;
+    }
 }
diff --git a/core/tests/coretests/src/com/android/internal/os/PowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/PowerCalculatorTest.java
deleted file mode 100644
index 4bd5724..0000000
--- a/core/tests/coretests/src/com/android/internal/os/PowerCalculatorTest.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- *
- */
-
-package com.android.internal.os;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import android.os.BatteryStats;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import junit.framework.TestCase;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class PowerCalculatorTest extends TestCase {
-    private static final long US_IN_HR = 1000L * 1000L * 60L * 60L;
-
-    @Mock
-    private PowerProfile mPowerProfile;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-    }
-
-    /** Test {@link MediaPowerCalculator#calculateApp} */
-    @Test
-    public void testMediaPowerCalculator() {
-        when(mPowerProfile.getAveragePower(PowerProfile.POWER_AUDIO)).thenReturn(12.0);
-        when(mPowerProfile.getAveragePower(PowerProfile.POWER_VIDEO)).thenReturn(25.0);
-
-        BatteryStats.Uid u = mock(BatteryStats.Uid.class);
-        BatteryStats.Timer audioTimer = mock(BatteryStats.Timer.class);
-        when(u.getAudioTurnedOnTimer()).thenReturn(audioTimer);
-        when(audioTimer.getTotalTimeLocked(2L * US_IN_HR, 0)).thenReturn(2L * US_IN_HR);
-        BatteryStats.Timer videoTimer = mock(BatteryStats.Timer.class);
-        when(u.getVideoTurnedOnTimer()).thenReturn(videoTimer);
-        when(videoTimer.getTotalTimeLocked(2L * US_IN_HR, 0)).thenReturn(1L * US_IN_HR);
-
-        MediaPowerCalculator mediaPowerCalculator = new MediaPowerCalculator(mPowerProfile);
-        BatterySipper app = new BatterySipper(BatterySipper.DrainType.APP, u, 0);
-
-        mediaPowerCalculator.calculate(List.of(app), null, 2L * US_IN_HR, 2L * US_IN_HR, 0, null);
-        assertEquals(49.0, app.sumPower());
-    }
-}
diff --git a/graphics/java/android/graphics/BLASTBufferQueue.java b/graphics/java/android/graphics/BLASTBufferQueue.java
index a9e730d..2678c79d 100644
--- a/graphics/java/android/graphics/BLASTBufferQueue.java
+++ b/graphics/java/android/graphics/BLASTBufferQueue.java
@@ -39,6 +39,8 @@
     private static native long nativeGetLastAcquiredFrameNum(long ptr);
     private static native void nativeApplyPendingTransactions(long ptr, long frameNumber);
     private static native boolean nativeIsSameSurfaceControl(long ptr, long surfaceControlPtr);
+    private static native SurfaceControl.Transaction nativeGatherPendingTransactions(long ptr,
+            long frameNumber);
 
     /** Create a new connection with the surface flinger. */
     public BLASTBufferQueue(String name, SurfaceControl sc, int width, int height,
@@ -159,4 +161,17 @@
     public boolean isSameSurfaceControl(SurfaceControl sc) {
         return nativeIsSameSurfaceControl(mNativeObject, sc.mNativeObject);
     }
+
+    /**
+     * Get any transactions that were passed to {@link #mergeWithNextTransaction} with the
+     * specified frameNumber. This is intended to ensure transactions don't get stuck as pending
+     * if the specified frameNumber is never drawn.
+     *
+     * @param frameNumber The frameNumber used to determine which transactions to apply.
+     * @return a Transaction that contains the merge of all the transactions that were sent to
+     *         mergeWithNextTransaction
+     */
+    public SurfaceControl.Transaction gatherPendingTransactions(long frameNumber) {
+        return nativeGatherPendingTransactions(mNativeObject, frameNumber);
+    }
 }
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index ee41148..ee0d647 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -290,7 +290,7 @@
      * context at a time.
      *
      * @param texName The name of the OpenGL ES texture that will be created.  This texture name
-     * must be unusued in the OpenGL ES context that is current on the calling thread.
+     * must be unused in the OpenGL ES context that is current on the calling thread.
      */
     public void attachToGLContext(int texName) {
         int err = nativeAttachToGLContext(texName);
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 13c1498..7d57734 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -60,21 +60,21 @@
 import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
- * MediaRouter allows applications to control the routing of media channels
+ * This API is not recommended for new applications. Use the
+ * <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/mediarouter/media/package-summary.html">Media Router
+ * Library</a> for consistent behavior across all devices.
+ *
+ * <p>MediaRouter allows applications to control the routing of media channels
  * and streams from the current device to external speakers and destination devices.
  *
  * <p>A MediaRouter is retrieved through {@link Context#getSystemService(String)
  * Context.getSystemService()} of a {@link Context#MEDIA_ROUTER_SERVICE
  * Context.MEDIA_ROUTER_SERVICE}.
  *
- * <p>The media router API is not thread-safe; all interactions with it must be
- * done from the main thread of the process.</p>
- *
- * <p>
- * We recommend using {@link android.media.MediaRouter2} APIs for new applications.
- * </p>
+ * <p>This API is not thread-safe; all interactions with it must be done from the main thread of the
+ * process.
  */
-//TODO: Link androidx.media2.MediaRouter when we are ready.
 @SystemService(Context.MEDIA_ROUTER_SERVICE)
 public class MediaRouter {
     private static final String TAG = "MediaRouter";
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index f8c47e8..311476c 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -52,13 +52,13 @@
 import java.util.stream.Collectors;
 
 /**
- * This API is not generally intended for third party application developers.
- * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
-  <a href="{@docRoot}reference/androidx/mediarouter/media/package-summary.html">Media Router
+ * This API is not generally intended for third party application developers. Use the
+ * <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/mediarouter/media/package-summary.html">Media Router
  * Library</a> for consistent behavior across all devices.
  *
- * Media Router 2 allows applications to control the routing of media channels
- * and streams from the current device to remote speakers and devices.
+ * <p>MediaRouter2 allows applications to control the routing of media channels and streams from
+ * the current device to remote speakers and devices.
  */
 // TODO(b/157873330): Add method names at the beginning of log messages. (e.g. selectRoute)
 //       Not only MediaRouter2, but also to service / manager / provider.
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 955ae3c..37050df 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -407,7 +407,7 @@
     /**
      * Get the session owner's package name.
      *
-     * @return The package name of of the session owner.
+     * @return The package name of the session owner.
      */
     public String getPackageName() {
         if (mPackageName == null) {
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 73e96a2..96809bd 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -1877,6 +1877,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(android.Manifest.permission.TUNER_RESOURCE_ACCESS)
     public int getClientPriority(@TvInputService.PriorityHintUseCaseType int useCase,
             @Nullable String sessionId) {
         return getClientPriorityInternal(useCase, sessionId);
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 4d6739e..31e1817 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -623,7 +623,7 @@
     Image_setBufferItem(env, image, buffer);
     env->SetLongField(image, gSurfaceImageClassInfo.mTimestamp,
             static_cast<jlong>(buffer->mTimestamp));
-    env->SetLongField(image, gSurfaceImageClassInfo.mDataSpace,
+    env->SetIntField(image, gSurfaceImageClassInfo.mDataSpace,
             static_cast<jint>(buffer->mDataSpace));
     auto transform = buffer->mTransform;
     if (buffer->mTransformToDisplayInverse) {
diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp
index 0f88afb..6c6fccb 100644
--- a/media/jni/android_media_ImageWriter.cpp
+++ b/media/jni/android_media_ImageWriter.cpp
@@ -901,7 +901,7 @@
 
     env->SetIntField(thiz, gSurfaceImageClassInfo.mNativeFenceFd, reinterpret_cast<jint>(fenceFd));
 
-    env->SetLongField(thiz, gSurfaceImageClassInfo.mDataSpace, dataSpace);
+    env->SetIntField(thiz, gSurfaceImageClassInfo.mDataSpace, dataSpace);
 }
 
 static void Image_unlockIfLocked(JNIEnv* env, jobject thiz) {
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index b7beb6e..3009a36 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -205,6 +205,7 @@
     ASensorManager_destroyEventQueue;
     ASensorManager_getDefaultSensor;
     ASensorManager_getDefaultSensorEx; # introduced=21
+    ASensorManager_getDynamicSensorList; # introduced=33
     ASensorManager_getInstance;
     ASensorManager_getInstanceForPackage; # introduced=26
     ASensorManager_getSensorList;
diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp
index 63082fd..968de34 100644
--- a/native/android/sensor.cpp
+++ b/native/android/sensor.cpp
@@ -83,6 +83,16 @@
     return c;
 }
 
+ssize_t ASensorManager_getDynamicSensorList(ASensorManager* manager, ASensorList* list) {
+    RETURN_IF_MANAGER_IS_NULL(android::BAD_VALUE);
+    Sensor const* const* l;
+    ssize_t c = static_cast<SensorManager*>(manager)->getDynamicSensorList(&l);
+    if (list) {
+        *list = reinterpret_cast<ASensorList>(l);
+    }
+    return c;
+}
+
 ASensor const* ASensorManager_getDefaultSensor(ASensorManager* manager, int type) {
     RETURN_IF_MANAGER_IS_NULL(nullptr);
     return static_cast<SensorManager*>(manager)->getDefaultSensor(type);
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java
index a423783..9cb0947 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java
@@ -61,7 +61,7 @@
  *     Internet Protocol</a>
  */
 @SystemService(Context.IPSEC_SERVICE)
-public final class IpSecManager {
+public class IpSecManager {
     private static final String TAG = "IpSecManager";
 
     /**
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/RecentAppOpsAccess.java b/packages/SettingsLib/src/com/android/settingslib/applications/RecentAppOpsAccess.java
index 2e7cfcb..9a29f22 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/RecentAppOpsAccess.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/RecentAppOpsAccess.java
@@ -51,6 +51,9 @@
     private static final int[] MICROPHONE_OPS = new int[]{
             AppOpsManager.OP_RECORD_AUDIO,
     };
+    private static final int[] CAMERA_OPS = new int[]{
+            AppOpsManager.OP_CAMERA,
+    };
 
 
     private static final String TAG = RecentAppOpsAccess.class.getSimpleName();
@@ -99,6 +102,13 @@
     }
 
     /**
+     * Creates an instance of {@link RecentAppOpsAccess} for camera access.
+     */
+    public static RecentAppOpsAccess createForCamera(Context context) {
+        return new RecentAppOpsAccess(context, CAMERA_OPS);
+    }
+
+    /**
      * Fills a list of applications which queried for access recently within specified time.
      * Apps are sorted by recency. Apps with more recent accesses are in the front.
      */
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java b/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java
index dee6894..6a1cee3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java
@@ -16,6 +16,7 @@
 
 package com.android.settingslib.notification;
 
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.AlarmManager;
 import android.app.AlertDialog;
@@ -42,8 +43,6 @@
 import android.widget.TextView;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto;
 import com.android.internal.policy.PhoneWindow;
 import com.android.settingslib.R;
 
@@ -72,6 +71,9 @@
     private static final int SECONDS_MS = 1000;
     private static final int MINUTES_MS = 60 * SECONDS_MS;
 
+    @Nullable
+    private final ZenModeDialogMetricsLogger mMetricsLogger;
+
     @VisibleForTesting
     protected Uri mForeverId;
     private int mBucketIndex = -1;
@@ -102,13 +104,16 @@
     }
 
     public EnableZenModeDialog(Context context, int themeResId) {
-        this(context, themeResId, false /* cancelIsNeutral */);
+        this(context, themeResId, false /* cancelIsNeutral */,
+                new ZenModeDialogMetricsLogger(context));
     }
 
-    public EnableZenModeDialog(Context context, int themeResId, boolean cancelIsNeutral) {
+    public EnableZenModeDialog(Context context, int themeResId, boolean cancelIsNeutral,
+            ZenModeDialogMetricsLogger metricsLogger) {
         mContext = context;
         mThemeResId = themeResId;
         mCancelIsNeutral = cancelIsNeutral;
+        mMetricsLogger = metricsLogger;
     }
 
     public AlertDialog createDialog() {
@@ -129,17 +134,11 @@
                                 ConditionTag tag = getConditionTagAt(checkedId);
 
                                 if (isForever(tag.condition)) {
-                                    MetricsLogger.action(mContext,
-                                            MetricsProto.MetricsEvent.
-                                                    NOTIFICATION_ZEN_MODE_TOGGLE_ON_FOREVER);
+                                    mMetricsLogger.logOnEnableZenModeForever();
                                 } else if (isAlarm(tag.condition)) {
-                                    MetricsLogger.action(mContext,
-                                            MetricsProto.MetricsEvent.
-                                                    NOTIFICATION_ZEN_MODE_TOGGLE_ON_ALARM);
+                                    mMetricsLogger.logOnEnableZenModeUntilAlarm();
                                 } else if (isCountdown(tag.condition)) {
-                                    MetricsLogger.action(mContext,
-                                            MetricsProto.MetricsEvent.
-                                                    NOTIFICATION_ZEN_MODE_TOGGLE_ON_COUNTDOWN);
+                                    mMetricsLogger.logOnEnableZenModeUntilCountdown();
                                 } else {
                                     Slog.d(TAG, "Invalid manual condition: " + tag.condition);
                                 }
@@ -222,8 +221,7 @@
                 if (isChecked) {
                     tag.rb.setChecked(true);
                     if (DEBUG) Log.d(TAG, "onCheckedChanged " + conditionId);
-                    MetricsLogger.action(mContext,
-                            MetricsProto.MetricsEvent.QS_DND_CONDITION_SELECT);
+                    mMetricsLogger.logOnConditionSelected();
                     updateAlarmWarningText(tag.condition);
                 }
             }
@@ -435,7 +433,7 @@
     }
 
     private void onClickTimeButton(View row, ConditionTag tag, boolean up, int rowId) {
-        MetricsLogger.action(mContext, MetricsProto.MetricsEvent.QS_DND_TIME, up);
+        mMetricsLogger.logOnClickTimeButton(up);
         Condition newCondition = null;
         final int N = MINUTE_BUCKETS.length;
         if (mBucketIndex == -1) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/ZenModeDialogMetricsLogger.java b/packages/SettingsLib/src/com/android/settingslib/notification/ZenModeDialogMetricsLogger.java
new file mode 100644
index 0000000..088a37d
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/ZenModeDialogMetricsLogger.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2022 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.settingslib.notification;
+
+import android.content.Context;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
+
+/**
+ * Logs ui events for {@link EnableZenModeDialog}.
+ */
+public class ZenModeDialogMetricsLogger {
+    private final Context mContext;
+
+    public ZenModeDialogMetricsLogger(Context context) {
+        mContext = context;
+    }
+
+    /**
+     * User enabled DND from the QS DND dialog to last until manually turned off
+     */
+    public void logOnEnableZenModeForever() {
+        MetricsLogger.action(
+                mContext,
+                MetricsProto.MetricsEvent.NOTIFICATION_ZEN_MODE_TOGGLE_ON_FOREVER);
+    }
+
+    /**
+     * User enabled DND from the QS DND dialog to last until the next alarm goes off
+     */
+    public void logOnEnableZenModeUntilAlarm() {
+        MetricsLogger.action(
+                mContext,
+                MetricsProto.MetricsEvent.NOTIFICATION_ZEN_MODE_TOGGLE_ON_ALARM);
+    }
+
+    /**
+     * User enabled DND from the QS DND dialog to last until countdown is done
+     */
+    public void logOnEnableZenModeUntilCountdown() {
+        MetricsLogger.action(
+                mContext,
+                MetricsProto.MetricsEvent.NOTIFICATION_ZEN_MODE_TOGGLE_ON_COUNTDOWN);
+    }
+
+    /**
+     * User selected an option on the DND dialog
+     */
+    public void logOnConditionSelected() {
+        MetricsLogger.action(
+                mContext,
+                MetricsProto.MetricsEvent.QS_DND_CONDITION_SELECT);
+    }
+
+    /**
+     * User increased or decreased countdown duration of DND from the DND dialog
+     */
+    public void logOnClickTimeButton(boolean up) {
+        MetricsLogger.action(mContext, MetricsProto.MetricsEvent.QS_DND_TIME, up);
+    }
+}
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
index a6bfc408b..716ee84 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
@@ -43,6 +43,7 @@
         Settings.System.FONT_SCALE,
         Settings.System.DIM_SCREEN,
         Settings.System.SCREEN_OFF_TIMEOUT,
+        Settings.System.SCREEN_OFF_TIMEOUT_DOCKED,
         Settings.System.SCREEN_BRIGHTNESS_MODE,
         Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ,
         Settings.System.SCREEN_BRIGHTNESS_FOR_VR,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
index 06712cc..d430296 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -111,6 +111,7 @@
                 });
         VALIDATORS.put(System.DISPLAY_COLOR_MODE_VENDOR_HINT, ANY_STRING_VALIDATOR);
         VALIDATORS.put(System.SCREEN_OFF_TIMEOUT, NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(System.SCREEN_OFF_TIMEOUT_DOCKED, NON_NEGATIVE_INTEGER_VALIDATOR);
         VALIDATORS.put(System.SCREEN_BRIGHTNESS_FOR_VR, new InclusiveIntegerRangeValidator(0, 255));
         VALIDATORS.put(System.SCREEN_BRIGHTNESS_MODE, BOOLEAN_VALIDATOR);
         VALIDATORS.put(System.ADAPTIVE_SLEEP, BOOLEAN_VALIDATOR);
diff --git a/packages/SystemUI/res/values-sw720dp-land/dimens.xml b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
index ae557c4..e897f75 100644
--- a/packages/SystemUI/res/values-sw720dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
@@ -20,4 +20,6 @@
     <dimen name="controls_padding_horizontal">205dp</dimen>
     <dimen name="split_shade_notifications_scrim_margin_bottom">16dp</dimen>
     <dimen name="notification_panel_margin_bottom">56dp</dimen>
+
+    <dimen name="keyguard_split_shade_top_margin">72dp</dimen>
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java
index 54664f2..72b40d4 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java
@@ -48,7 +48,7 @@
     @Override
     public void start() {
         if (DeviceConfig.getBoolean(
-                DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_ENABLED, true)) {
+                DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_ENABLED, false)) {
             mClipboardManager = requireNonNull(mContext.getSystemService(ClipboardManager.class));
             mClipboardManager.addPrimaryClipChangedListener(this);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 552f188..51101da 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -139,7 +139,7 @@
 
     /***************************************/
     // 900 - media
-    public static final BooleanFlag MEDIA_TAP_TO_TRANSFER = new BooleanFlag(900, false);
+    public static final BooleanFlag MEDIA_TAP_TO_TRANSFER = new BooleanFlag(900, true);
     public static final BooleanFlag MEDIA_SESSION_ACTIONS = new BooleanFlag(901, true);
     public static final BooleanFlag MEDIA_SESSION_LAYOUT = new BooleanFlag(902, false);
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
index adae07b..2ed2f4f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
@@ -47,7 +47,7 @@
         gravity = Gravity.TOP.or(Gravity.CENTER_HORIZONTAL)
         type = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY
         flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
-        title = "Media Tap-To-Transfer Chip View"
+        title = WINDOW_TITLE
         format = PixelFormat.TRANSLUCENT
         setTrustedOverlay()
     }
@@ -106,3 +106,7 @@
         }
     }
 }
+
+// Used in CTS tests UpdateMediaTapToTransferSenderDisplayTest and
+// UpdateMediaTapToTransferReceiverDisplayTest
+private const val WINDOW_TITLE = "Media Transfer Chip View"
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSEvents.kt b/packages/SystemUI/src/com/android/systemui/qs/QSEvents.kt
index cc5a771..26adf46 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSEvents.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSEvents.kt
@@ -94,15 +94,28 @@
     override fun getId() = _id
 }
 
+/**
+ * Events from the QS DND tile dialog. {@see QSZenModeDialogMetricsLogger}
+ * Other names for DND (Do Not Disturb) include "Zen" and "Priority mode".
+ */
 enum class QSDndEvent(private val _id: Int) : UiEventLogger.UiEventEnum {
-    @UiEvent(doc = "TODO(beverlyt)")
+    @UiEvent(doc = "User selected an option on the DND dialog")
     QS_DND_CONDITION_SELECT(420),
 
-    @UiEvent(doc = "TODO(beverlyt)")
+    @UiEvent(doc = "User increased countdown duration of DND from the DND dialog")
     QS_DND_TIME_UP(422),
 
-    @UiEvent(doc = "TODO(beverlyt)")
-    QS_DND_TIME_DOWN(423);
+    @UiEvent(doc = "User decreased countdown duration of DND from the DND dialog")
+    QS_DND_TIME_DOWN(423),
+
+    @UiEvent(doc = "User enabled DND from the QS DND dialog to last until manually turned off")
+    QS_DND_DIALOG_ENABLE_FOREVER(946),
+
+    @UiEvent(doc = "User enabled DND from the QS DND dialog to last until the next alarm goes off")
+    QS_DND_DIALOG_ENABLE_UNTIL_ALARM(947),
+
+    @UiEvent(doc = "User enabled DND from the QS DND dialog to last until countdown is done")
+    QS_DND_DIALOG_ENABLE_UNTIL_COUNTDOWN(948);
 
     override fun getId() = _id
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index a06dc8b..a33650c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -65,6 +65,7 @@
 import com.android.systemui.qs.SettingObserver;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.qs.tiles.dialog.QSZenModeDialogMetricsLogger;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.util.settings.SecureSettings;
@@ -86,6 +87,7 @@
     private final SharedPreferences mSharedPreferences;
     private final SettingObserver mSettingZenDuration;
     private final DialogLaunchAnimator mDialogLaunchAnimator;
+    private final QSZenModeDialogMetricsLogger mQSZenDialogMetricsLogger;
 
     private boolean mListening;
     private boolean mShowingDetail;
@@ -119,6 +121,7 @@
                 refreshState();
             }
         };
+        mQSZenDialogMetricsLogger = new QSZenModeDialogMetricsLogger(mContext);
     }
 
     public static void setVisible(Context context, boolean visible) {
@@ -211,7 +214,8 @@
 
     private Dialog makeZenModeDialog() {
         AlertDialog dialog = new EnableZenModeDialog(mContext, R.style.Theme_SystemUI_Dialog,
-                true /* cancelIsNeutral */).createDialog();
+                true /* cancelIsNeutral */,
+                mQSZenDialogMetricsLogger).createDialog();
         SystemUIDialog.applyFlags(dialog);
         SystemUIDialog.setShowForAllUsers(dialog, true);
         SystemUIDialog.registerDismissListener(dialog);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/QSZenModeDialogMetricsLogger.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/QSZenModeDialogMetricsLogger.java
new file mode 100644
index 0000000..1b81a99
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/QSZenModeDialogMetricsLogger.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2022 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.qs.tiles.dialog;
+
+import android.content.Context;
+
+import com.android.internal.logging.UiEventLogger;
+import com.android.settingslib.notification.ZenModeDialogMetricsLogger;
+import com.android.systemui.qs.QSDndEvent;
+import com.android.systemui.qs.QSEvents;
+
+/**
+ * Logs ui events for the DND dialog that may appear from tapping the QS DND tile.
+ * To see the dialog from QS:
+ *     Settings > Notifications > Do Not Disturb > Duration for Quick Settings >  Ask every time
+ *
+ * Other names for DND (Do Not Disturb) include "Zen" and "Priority only".
+ */
+public class QSZenModeDialogMetricsLogger extends ZenModeDialogMetricsLogger {
+    private final UiEventLogger mUiEventLogger = QSEvents.INSTANCE.getQsUiEventsLogger();
+
+    public QSZenModeDialogMetricsLogger(Context context) {
+        super(context);
+    }
+
+    @Override
+    public void logOnEnableZenModeForever() {
+        super.logOnEnableZenModeForever();
+        mUiEventLogger.log(QSDndEvent.QS_DND_DIALOG_ENABLE_FOREVER);
+    }
+
+    @Override
+    public void logOnEnableZenModeUntilAlarm() {
+        super.logOnEnableZenModeUntilAlarm();
+        mUiEventLogger.log(QSDndEvent.QS_DND_DIALOG_ENABLE_UNTIL_ALARM);
+    }
+
+    @Override
+    public void logOnEnableZenModeUntilCountdown() {
+        super.logOnEnableZenModeUntilCountdown();
+        mUiEventLogger.log(QSDndEvent.QS_DND_DIALOG_ENABLE_UNTIL_COUNTDOWN);
+    }
+
+    @Override
+    public void logOnConditionSelected() {
+        super.logOnConditionSelected();
+        mUiEventLogger.log(QSDndEvent.QS_DND_CONDITION_SELECT);
+    }
+
+    @Override
+    public void logOnClickTimeButton(boolean up) {
+        super.logOnClickTimeButton(up);
+        mUiEventLogger.log(up
+                ? QSDndEvent.QS_DND_TIME_UP : QSDndEvent.QS_DND_TIME_DOWN);
+    }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index eccf27e..0509a7c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -73,6 +73,7 @@
 import com.android.systemui.R;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.keyguard.KeyguardIndication;
@@ -132,6 +133,7 @@
     private final DevicePolicyManager mDevicePolicyManager;
     private final UserManager mUserManager;
     protected final @Main DelayableExecutor mExecutor;
+    protected final @Background DelayableExecutor mBackgroundExecutor;
     private final LockPatternUtils mLockPatternUtils;
     private final IActivityManager mIActivityManager;
     private final FalsingManager mFalsingManager;
@@ -203,6 +205,7 @@
             IBatteryStats iBatteryStats,
             UserManager userManager,
             @Main DelayableExecutor executor,
+            @Background DelayableExecutor bgExecutor,
             FalsingManager falsingManager,
             LockPatternUtils lockPatternUtils,
             ScreenLifecycle screenLifecycle,
@@ -220,6 +223,7 @@
         mBatteryInfo = iBatteryStats;
         mUserManager = userManager;
         mExecutor = executor;
+        mBackgroundExecutor = bgExecutor;
         mLockPatternUtils = lockPatternUtils;
         mIActivityManager = iActivityManager;
         mFalsingManager = falsingManager;
@@ -328,15 +332,22 @@
 
     private void updateDisclosure() {
         if (mOrganizationOwnedDevice) {
-            final CharSequence organizationName = getOrganizationOwnedDeviceOrganizationName();
-            final CharSequence disclosure = getDisclosureText(organizationName);
-            mRotateTextViewController.updateIndication(
-                    INDICATION_TYPE_DISCLOSURE,
-                    new KeyguardIndication.Builder()
-                            .setMessage(disclosure)
-                            .setTextColor(mInitialTextColorState)
-                            .build(),
-                    /* updateImmediately */ false);
+            mBackgroundExecutor.execute(() -> {
+                final CharSequence organizationName = getOrganizationOwnedDeviceOrganizationName();
+                final CharSequence disclosure = getDisclosureText(organizationName);
+
+                mExecutor.execute(() -> {
+                    if (mKeyguardStateController.isShowing()) {
+                        mRotateTextViewController.updateIndication(
+                              INDICATION_TYPE_DISCLOSURE,
+                              new KeyguardIndication.Builder()
+                                      .setMessage(disclosure)
+                                      .setTextColor(mInitialTextColorState)
+                                      .build(),
+                              /* updateImmediately */ false);
+                    }
+                });
+            });
         } else {
             mRotateTextViewController.hideIndication(INDICATION_TYPE_DISCLOSURE);
         }
@@ -364,26 +375,35 @@
     }
 
     private void updateOwnerInfo() {
-        String info = mLockPatternUtils.getDeviceOwnerInfo();
-        if (info == null) {
-            // Use the current user owner information if enabled.
-            final boolean ownerInfoEnabled = mLockPatternUtils.isOwnerInfoEnabled(
-                    KeyguardUpdateMonitor.getCurrentUser());
-            if (ownerInfoEnabled) {
-                info = mLockPatternUtils.getOwnerInfo(KeyguardUpdateMonitor.getCurrentUser());
+        // Check device owner info on a bg thread.
+        // It makes multiple IPCs that could block the thread it's run on.
+        mBackgroundExecutor.execute(() -> {
+            String info = mLockPatternUtils.getDeviceOwnerInfo();
+            if (info == null) {
+                // Use the current user owner information if enabled.
+                final boolean ownerInfoEnabled = mLockPatternUtils.isOwnerInfoEnabled(
+                        KeyguardUpdateMonitor.getCurrentUser());
+                if (ownerInfoEnabled) {
+                    info = mLockPatternUtils.getOwnerInfo(KeyguardUpdateMonitor.getCurrentUser());
+                }
             }
-        }
-        if (!TextUtils.isEmpty(info)) {
-            mRotateTextViewController.updateIndication(
-                    INDICATION_TYPE_OWNER_INFO,
-                    new KeyguardIndication.Builder()
-                            .setMessage(info)
-                            .setTextColor(mInitialTextColorState)
-                            .build(),
-                    false);
-        } else {
-            mRotateTextViewController.hideIndication(INDICATION_TYPE_OWNER_INFO);
-        }
+
+            // Update the UI on the main thread.
+            final String finalInfo = info;
+            mExecutor.execute(() -> {
+                if (!TextUtils.isEmpty(finalInfo) && mKeyguardStateController.isShowing()) {
+                    mRotateTextViewController.updateIndication(
+                            INDICATION_TYPE_OWNER_INFO,
+                            new KeyguardIndication.Builder()
+                                    .setMessage(finalInfo)
+                                    .setTextColor(mInitialTextColorState)
+                                    .build(),
+                            false);
+                } else {
+                    mRotateTextViewController.hideIndication(INDICATION_TYPE_OWNER_INFO);
+                }
+            });
+        });
     }
 
     private void updateBattery(boolean animate) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index ee12cc5..7811401 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -336,6 +336,9 @@
     }
 
     private void setDozeAmountInternal(float dozeAmount) {
+        if (Float.compare(dozeAmount, mDozeAmount) == 0) {
+            return;
+        }
         mDozeAmount = dozeAmount;
         float interpolatedAmount = mDozeInterpolator.getInterpolation(dozeAmount);
         synchronized (mListeners) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index e1116f8..d1c63e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -290,11 +290,11 @@
 
         @Override
         public void onThemeChanged() {
-            updateShowEmptyShadeView();
             mView.updateCornerRadius();
             mView.updateBgColor();
             mView.updateDecorViews();
             mView.reinflateViews();
+            updateShowEmptyShadeView();
             updateFooter();
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index e24cd3e..3a3f581 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -376,6 +376,11 @@
 
         final float stackHeight = ambientState.getStackHeight()  - shelfHeight - scrimPadding;
         final float stackEndHeight = ambientState.getStackEndHeight() - shelfHeight - scrimPadding;
+        if (stackEndHeight == 0f) {
+            // This should not happen, since even when the shade is empty we show EmptyShadeView
+            // but check just in case, so we don't return infinity or NaN.
+            return 0f;
+        }
         return stackHeight / stackEndHeight;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index 0cd4fb9..7bb987c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -56,12 +56,9 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.UiEventLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
-import com.android.systemui.qs.QSDndEvent;
-import com.android.systemui.qs.QSEvents;
 import com.android.systemui.statusbar.policy.ZenModeController;
 
 import java.io.FileDescriptor;
@@ -106,7 +103,6 @@
     private final TransitionHelper mTransitionHelper = new TransitionHelper();
     private final Uri mForeverId;
     private final ConfigurableTexts mConfigurableTexts;
-    private final UiEventLogger mUiEventLogger = QSEvents.INSTANCE.getQsUiEventsLogger();
 
     private String mTag = TAG + "/" + Integer.toHexString(System.identityHashCode(this));
 
@@ -666,7 +662,6 @@
                     tag.rb.setChecked(true);
                     if (DEBUG) Log.d(mTag, "onCheckedChanged " + conditionId);
                     MetricsLogger.action(mContext, MetricsEvent.QS_DND_CONDITION_SELECT);
-                    mUiEventLogger.log(QSDndEvent.QS_DND_CONDITION_SELECT);
                     select(tag.condition);
                     announceConditionSelection(tag);
                 }
@@ -772,7 +767,6 @@
 
     private void onClickTimeButton(View row, ConditionTag tag, boolean up, int rowId) {
         MetricsLogger.action(mContext, MetricsEvent.QS_DND_TIME, up);
-        mUiEventLogger.log(up ? QSDndEvent.QS_DND_TIME_UP : QSDndEvent.QS_DND_TIME_DOWN);
         Condition newCondition = null;
         final int N = MINUTE_BUCKETS.length;
         if (mBucketIndex == -1) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 98e2857..5924329 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -229,8 +229,8 @@
         mController = new KeyguardIndicationController(mContext, mWakeLockBuilder,
                 mKeyguardStateController, mStatusBarStateController, mKeyguardUpdateMonitor,
                 mDockManager, mBroadcastDispatcher, mDevicePolicyManager, mIBatteryStats,
-                mUserManager, mExecutor, mFalsingManager, mLockPatternUtils, mScreenLifecycle,
-                mIActivityManager, mKeyguardBypassController);
+                mUserManager, mExecutor, mExecutor,  mFalsingManager, mLockPatternUtils,
+                mScreenLifecycle, mIActivityManager, mKeyguardBypassController);
         mController.init();
         mController.setIndicationArea(mIndicationArea);
         verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture());
@@ -331,6 +331,7 @@
         when(mDevicePolicyManager.isDeviceManaged()).thenReturn(false);
         when(mDevicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile()).thenReturn(false);
         sendUpdateDisclosureBroadcast();
+        mExecutor.runAllReady();
 
         verifyHideIndication(INDICATION_TYPE_DISCLOSURE);
     }
@@ -341,6 +342,7 @@
         when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
         when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(null);
         sendUpdateDisclosureBroadcast();
+        mExecutor.runAllReady();
 
         verifyIndicationMessage(INDICATION_TYPE_DISCLOSURE, mDisclosureGeneric);
     }
@@ -353,6 +355,7 @@
                 new UserInfo(10, /* name */ null, /* flags */ FLAG_MANAGED_PROFILE)));
         when(mDevicePolicyManager.getOrganizationNameForUser(eq(10))).thenReturn(null);
         sendUpdateDisclosureBroadcast();
+        mExecutor.runAllReady();
 
         verifyIndicationMessage(INDICATION_TYPE_DISCLOSURE, mDisclosureGeneric);
     }
@@ -363,6 +366,7 @@
         when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
         when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(ORGANIZATION_NAME);
         sendUpdateDisclosureBroadcast();
+        mExecutor.runAllReady();
 
         verifyIndicationMessage(INDICATION_TYPE_DISCLOSURE, mDisclosureWithOrganization);
     }
@@ -375,6 +379,7 @@
                 new UserInfo(10, /* name */ null, FLAG_MANAGED_PROFILE)));
         when(mDevicePolicyManager.getOrganizationNameForUser(eq(10))).thenReturn(ORGANIZATION_NAME);
         sendUpdateDisclosureBroadcast();
+        mExecutor.runAllReady();
 
         verifyIndicationMessage(INDICATION_TYPE_DISCLOSURE, mDisclosureWithOrganization);
     }
@@ -387,6 +392,7 @@
         when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
         when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(null);
         sendUpdateDisclosureBroadcast();
+        mExecutor.runAllReady();
 
         verifyIndicationMessage(INDICATION_TYPE_DISCLOSURE, mDisclosureGeneric);
         reset(mRotateTextViewController);
@@ -394,12 +400,14 @@
         when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
         when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(ORGANIZATION_NAME);
         sendUpdateDisclosureBroadcast();
+        mExecutor.runAllReady();
 
         verifyIndicationMessage(INDICATION_TYPE_DISCLOSURE, mDisclosureWithOrganization);
         reset(mRotateTextViewController);
 
         when(mDevicePolicyManager.isDeviceManaged()).thenReturn(false);
         sendUpdateDisclosureBroadcast();
+        mExecutor.runAllReady();
 
         verifyHideIndication(INDICATION_TYPE_DISCLOSURE);
     }
@@ -413,6 +421,7 @@
         when(mDevicePolicyManager.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
                 .thenReturn(DEVICE_OWNER_TYPE_FINANCED);
         sendUpdateDisclosureBroadcast();
+        mExecutor.runAllReady();
 
         verifyIndicationMessage(INDICATION_TYPE_DISCLOSURE, mFinancedDisclosureWithOrganization);
     }
@@ -734,6 +743,7 @@
 
         // WHEN asked to update the indication area
         mController.setVisible(true);
+        mExecutor.runAllReady();
 
         // THEN the owner info should be hidden
         verifyHideIndication(INDICATION_TYPE_OWNER_INFO);
@@ -763,6 +773,7 @@
 
         // WHEN keyguard showing changed called
         mKeyguardStateControllerCallback.onKeyguardShowingChanged();
+        mExecutor.runAllReady();
 
         // THEN persistent messages are updated (in this case, most messages are hidden since
         // no info is provided) - verify that this happens
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
index a5ea897..6abdea5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
@@ -23,14 +23,18 @@
 import com.android.internal.logging.testing.UiEventLoggerFake
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
+import com.android.systemui.plugins.statusbar.StatusBarStateController
 import org.junit.Assert.assertEquals
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyFloat
 import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.eq
 import org.mockito.Mock
 import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 import org.mockito.Mockito.`when` as whenever
 
@@ -73,4 +77,14 @@
         assertEquals(StatusBarStateEvent.STATUS_BAR_STATE_SHADE.id, ids[1])
         assertEquals(StatusBarStateEvent.STATUS_BAR_STATE_SHADE_LOCKED.id, ids[2])
     }
+
+    @Test
+    fun testSetDozeAmountInternal_onlySetsOnce() {
+        val listener = mock(StatusBarStateController.StateListener::class.java)
+        controller.addCallback(listener)
+
+        controller.setDozeAmount(0.5f, false /* animated */)
+        controller.setDozeAmount(0.5f, false /* animated */)
+        verify(listener).onDozeAmountChanged(eq(0.5f), anyFloat())
+    }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 8b62a64..7f10314 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -25,6 +25,7 @@
 import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_SERVICE_CLIENT;
 import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_SERVICE_CONNECTION;
 import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAGER_INTERNAL;
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
 import static android.view.accessibility.AccessibilityInteractionClient.CALL_STACK;
 import static android.view.accessibility.AccessibilityInteractionClient.IGNORE_CALL_STACK;
@@ -66,6 +67,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.os.Trace;
 import android.provider.Settings;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -80,15 +82,21 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityWindowInfo;
 import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputBinding;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.compat.IPlatformCompat;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.internal.view.IInputContext;
+import com.android.internal.view.IInputMethodSession;
+import com.android.internal.view.IInputSessionWithIdCallback;
 import com.android.server.LocalServices;
 import com.android.server.accessibility.AccessibilityWindowManager.RemoteAccessibilityConnection;
 import com.android.server.accessibility.magnification.MagnificationProcessor;
+import com.android.server.inputmethod.InputMethodManagerInternal;
 import com.android.server.wm.ActivityTaskManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
 
@@ -180,6 +188,8 @@
 
     boolean mLastAccessibilityButtonCallbackState;
 
+    boolean mRequestImeApis;
+
     int mFetchFlags;
 
     long mNotificationTimeout;
@@ -271,6 +281,9 @@
 
         void onDoubleTapAndHold(int displayId);
 
+        void requestImeLocked(AccessibilityServiceConnection connection);
+
+        void unbindImeLocked(AccessibilityServiceConnection connection);
     }
 
     public AbstractAccessibilityServiceConnection(Context context, ComponentName componentName,
@@ -374,6 +387,9 @@
                 & AccessibilityServiceInfo.FLAG_REQUEST_FINGERPRINT_GESTURES) != 0;
         mRequestAccessibilityButton = (info.flags
                 & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
+        // TODO(b/218193835): request ime when ime flag is set and clean up when ime flag is unset
+        mRequestImeApis = (info.flags
+                & AccessibilityServiceInfo.FLAG_INPUT_METHOD_EDITOR) != 0;
     }
 
     protected boolean supportsFlagForNotImportantViews(AccessibilityServiceInfo info) {
@@ -1610,6 +1626,27 @@
         mInvocationHandler.notifyAccessibilityButtonAvailabilityChangedLocked(available);
     }
 
+    public void createImeSessionLocked() {
+        mInvocationHandler.createImeSessionLocked();
+    }
+
+    public void setImeSessionEnabledLocked(IInputMethodSession session, boolean enabled) {
+        mInvocationHandler.setImeSessionEnabledLocked(session, enabled);
+    }
+
+    public void bindInputLocked(InputBinding binding) {
+        mInvocationHandler.bindInputLocked(binding);
+    }
+
+    public  void unbindInputLocked() {
+        mInvocationHandler.unbindInputLocked();
+    }
+
+    public void startInputLocked(IBinder startInputToken, IInputContext inputContext,
+            EditorInfo editorInfo, boolean restarting) {
+        mInvocationHandler.startInputLocked(startInputToken, inputContext, editorInfo, restarting);
+    }
+
     /**
      * Called by the invocation handler to notify the service that the
      * state of magnification has changed.
@@ -1732,6 +1769,84 @@
         }
     }
 
+    private void createImeSessionInternal() {
+        final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
+        if (listener != null) {
+            try {
+                if (svcClientTracingEnabled()) {
+                    logTraceSvcClient("createImeSession", "");
+                }
+                AccessibilityCallback callback = new AccessibilityCallback();
+                listener.createImeSession(callback);
+            } catch (RemoteException re) {
+                Slog.e(LOG_TAG,
+                        "Error requesting IME session from " + mService, re);
+            }
+        }
+    }
+
+    private void setImeSessionEnabledInternal(IInputMethodSession session, boolean enabled) {
+        final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
+        if (listener != null && session != null) {
+            try {
+                if (svcClientTracingEnabled()) {
+                    logTraceSvcClient("createImeSession", "");
+                }
+                listener.setImeSessionEnabled(session, enabled);
+            } catch (RemoteException re) {
+                Slog.e(LOG_TAG,
+                        "Error requesting IME session from " + mService, re);
+            }
+        }
+    }
+
+    private void bindInputInternal(InputBinding binding) {
+        final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
+        if (listener != null) {
+            try {
+                if (svcClientTracingEnabled()) {
+                    logTraceSvcClient("bindInput", binding.toString());
+                }
+                listener.bindInput(binding);
+            } catch (RemoteException re) {
+                Slog.e(LOG_TAG,
+                        "Error binding input to " + mService, re);
+            }
+        }
+    }
+
+    private void unbindInputInternal() {
+        final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
+        if (listener != null) {
+            try {
+                if (svcClientTracingEnabled()) {
+                    logTraceSvcClient("unbindInput", "");
+                }
+                listener.unbindInput();
+            } catch (RemoteException re) {
+                Slog.e(LOG_TAG,
+                        "Error unbinding input to " + mService, re);
+            }
+        }
+    }
+
+    private void startInputInternal(IBinder startInputToken, IInputContext inputContext,
+            EditorInfo editorInfo, boolean restarting) {
+        final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
+        if (listener != null) {
+            try {
+                if (svcClientTracingEnabled()) {
+                    logTraceSvcClient("startInput", startInputToken + " "
+                            + inputContext + " " + editorInfo + restarting);
+                }
+                listener.startInput(startInputToken, inputContext, editorInfo, restarting);
+            } catch (RemoteException re) {
+                Slog.e(LOG_TAG,
+                        "Error starting input to " + mService, re);
+            }
+        }
+    }
+
     protected IAccessibilityServiceClient getServiceInterfaceSafely() {
         synchronized (mLock) {
             return mServiceInterface;
@@ -1925,6 +2040,11 @@
         private static final int MSG_ON_ACCESSIBILITY_BUTTON_CLICKED = 7;
         private static final int MSG_ON_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED = 8;
         private static final int MSG_ON_SYSTEM_ACTIONS_CHANGED = 9;
+        private static final int MSG_CREATE_IME_SESSION = 10;
+        private static final int MSG_SET_IME_SESSION_ENABLED = 11;
+        private static final int MSG_BIND_INPUT = 12;
+        private static final int MSG_UNBIND_INPUT = 13;
+        private static final int MSG_START_INPUT = 14;
 
         /** List of magnification callback states, mapping from displayId -> Boolean */
         @GuardedBy("mlock")
@@ -1974,6 +2094,29 @@
                     notifySystemActionsChangedInternal();
                     break;
                 }
+                case MSG_CREATE_IME_SESSION:
+                    createImeSessionInternal();
+                    break;
+                case MSG_SET_IME_SESSION_ENABLED:
+                    final boolean enabled = (message.arg1 != 0);
+                    final IInputMethodSession session = (IInputMethodSession) message.obj;
+                    setImeSessionEnabledInternal(session, enabled);
+                    break;
+                case MSG_BIND_INPUT:
+                    final InputBinding binding = (InputBinding) message.obj;
+                    bindInputInternal(binding);
+                    break;
+                case MSG_UNBIND_INPUT:
+                    unbindInputInternal();
+                    break;
+                case MSG_START_INPUT:
+                    final boolean restarting = (message.arg1 != 0);
+                    final SomeArgs args = (SomeArgs) message.obj;
+                    final IBinder startInputToken = (IBinder) args.arg1;
+                    final IInputContext inputContext = (IInputContext) args.arg2;
+                    final EditorInfo editorInfo = (EditorInfo) args.arg3;
+                    startInputInternal(startInputToken, inputContext, editorInfo, restarting);
+                    break;
                 default: {
                     throw new IllegalArgumentException("Unknown message: " + type);
                 }
@@ -2036,6 +2179,37 @@
                     (available ? 1 : 0), 0);
             msg.sendToTarget();
         }
+
+        public void createImeSessionLocked() {
+            final Message msg = obtainMessage(MSG_CREATE_IME_SESSION);
+            msg.sendToTarget();
+        }
+
+        public void setImeSessionEnabledLocked(IInputMethodSession session, boolean enabled) {
+            final Message msg = obtainMessage(MSG_SET_IME_SESSION_ENABLED, (enabled ? 1 : 0),
+                    0, session);
+            msg.sendToTarget();
+        }
+
+        public void bindInputLocked(InputBinding binding) {
+            final Message msg = obtainMessage(MSG_BIND_INPUT, binding);
+            msg.sendToTarget();
+        }
+
+        public void unbindInputLocked() {
+            final Message msg = obtainMessage(MSG_UNBIND_INPUT);
+            msg.sendToTarget();
+        }
+
+        public void startInputLocked(IBinder startInputToken, IInputContext inputContext,
+                EditorInfo editorInfo, boolean restarting) {
+            final SomeArgs args = SomeArgs.obtain();
+            args.arg1 = startInputToken;
+            args.arg2 = inputContext;
+            args.arg3 = editorInfo;
+            final Message msg = obtainMessage(MSG_START_INPUT, restarting ? 1 : 0, 0, args);
+            msg.sendToTarget();
+        }
     }
 
     public boolean isServiceHandlesDoubleTapEnabled() {
@@ -2185,4 +2359,18 @@
             Binder.restoreCallingIdentity(identity);
         }
     }
+
+    private static final class AccessibilityCallback extends IInputSessionWithIdCallback.Stub {
+        @Override
+        public void sessionCreated(IInputMethodSession session, int id) {
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.sessionCreated");
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                InputMethodManagerInternal.get().onSessionForAccessibilityCreated(id, session);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+        }
+    }
 }
\ No newline at end of file
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 5b580d9..62da981 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -115,6 +115,8 @@
 import android.view.accessibility.IAccessibilityManager;
 import android.view.accessibility.IAccessibilityManagerClient;
 import android.view.accessibility.IWindowMagnificationConnection;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputBinding;
 
 import com.android.internal.R;
 import com.android.internal.accessibility.AccessibilityShortcutController;
@@ -128,12 +130,16 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.IntPair;
+import com.android.internal.view.IInputContext;
+import com.android.internal.view.IInputMethodSession;
+import com.android.server.AccessibilityManagerInternal;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.accessibility.magnification.MagnificationController;
 import com.android.server.accessibility.magnification.MagnificationProcessor;
 import com.android.server.accessibility.magnification.MagnificationScaleProvider;
 import com.android.server.accessibility.magnification.WindowMagnificationManager;
+import com.android.server.inputmethod.InputMethodManagerInternal;
 import com.android.server.pm.UserManagerInternal;
 import com.android.server.wm.ActivityTaskManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
@@ -231,7 +237,7 @@
 
     private final MainHandler mMainHandler;
 
-    // Lazily initialized - access through getSystemActionPerfomer()
+    // Lazily initialized - access through getSystemActionPerformer()
     private SystemActionPerformer mSystemActionPerformer;
 
     private InteractionBridge mInteractionBridge;
@@ -273,6 +279,13 @@
     private Point mTempPoint = new Point();
     private boolean mIsAccessibilityButtonShown;
 
+    private InputBinding mInputBinding;
+    IBinder mStartInputToken;
+    IInputContext mInputContext;
+    EditorInfo mEditorInfo;
+    boolean mRestarting;
+    boolean mInputSessionRequested;
+
     private AccessibilityUserState getCurrentUserStateLocked() {
         return getUserStateLocked(mCurrentUserId);
     }
@@ -298,6 +311,42 @@
         }
     }
 
+    private static final class LocalServiceImpl extends AccessibilityManagerInternal {
+        @NonNull
+        private final AccessibilityManagerService mService;
+
+        LocalServiceImpl(@NonNull AccessibilityManagerService service) {
+            mService = service;
+        }
+
+        @Override
+        public void setImeSessionEnabled(SparseArray<IInputMethodSession> sessions,
+                boolean enabled) {
+            mService.setImeSessionEnabled(sessions, enabled);
+        }
+
+        @Override
+        public void unbindInput() {
+            mService.unbindInput();
+        }
+
+        @Override
+        public void bindInput(InputBinding binding) {
+            mService.bindInput(binding);
+        }
+
+        @Override
+        public void createImeSession(ArraySet<Integer> ignoreSet) {
+            mService.createImeSession(ignoreSet);
+        }
+
+        @Override
+        public void startInput(IBinder startInputToken, IInputContext inputContext,
+                EditorInfo editorInfo, boolean restarting) {
+            mService.startInput(startInputToken, inputContext, editorInfo, restarting);
+        }
+    }
+
     public static final class Lifecycle extends SystemService {
         private final AccessibilityManagerService mService;
 
@@ -308,6 +357,8 @@
 
         @Override
         public void onStart() {
+            LocalServices.addService(AccessibilityManagerInternal.class,
+                    new LocalServiceImpl(mService));
             publishBinderService(Context.ACCESSIBILITY_SERVICE, mService);
         }
 
@@ -3463,27 +3514,27 @@
 
     @Override
     @RequiresPermission(Manifest.permission.SET_SYSTEM_AUDIO_CAPTION)
-    public void setSystemAudioCaptioningRequested(boolean isEnabled, int userId) {
+    public void setSystemAudioCaptioningEnabled(boolean isEnabled, int userId) {
         mContext.enforceCallingOrSelfPermission(
                 Manifest.permission.SET_SYSTEM_AUDIO_CAPTION,
-                "setSystemAudioCaptioningRequested");
+                "setSystemAudioCaptioningEnabled");
 
-        mCaptioningManagerImpl.setSystemAudioCaptioningRequested(isEnabled, userId);
+        mCaptioningManagerImpl.setSystemAudioCaptioningEnabled(isEnabled, userId);
     }
 
     @Override
-    public boolean isSystemAudioCaptioningUiRequested(int userId) {
-        return mCaptioningManagerImpl.isSystemAudioCaptioningUiRequested(userId);
+    public boolean isSystemAudioCaptioningUiEnabled(int userId) {
+        return mCaptioningManagerImpl.isSystemAudioCaptioningUiEnabled(userId);
     }
 
     @Override
     @RequiresPermission(Manifest.permission.SET_SYSTEM_AUDIO_CAPTION)
-    public void setSystemAudioCaptioningUiRequested(boolean isEnabled, int userId) {
+    public void setSystemAudioCaptioningUiEnabled(boolean isEnabled, int userId) {
         mContext.enforceCallingOrSelfPermission(
                 Manifest.permission.SET_SYSTEM_AUDIO_CAPTION,
-                "setSystemAudioCaptioningUiRequested");
+                "setSystemAudioCaptioningUiEnabled");
 
-        mCaptioningManagerImpl.setSystemAudioCaptioningUiRequested(isEnabled, userId);
+        mCaptioningManagerImpl.setSystemAudioCaptioningUiEnabled(isEnabled, userId);
     }
 
     @Override
@@ -4240,6 +4291,45 @@
                         this, displayId));
     }
 
+    @Override
+    public void requestImeLocked(AccessibilityServiceConnection connection) {
+        mMainHandler.sendMessage(obtainMessage(
+                AccessibilityManagerService::createSessionForConnection, this, connection));
+        mMainHandler.sendMessage(obtainMessage(
+                AccessibilityManagerService::bindAndStartInputForConnection, this, connection));
+    }
+
+    @Override
+    public void unbindImeLocked(AccessibilityServiceConnection connection) {
+        mMainHandler.sendMessage(obtainMessage(
+                AccessibilityManagerService::unbindInputForConnection, this, connection));
+    }
+
+    private void createSessionForConnection(AccessibilityServiceConnection connection) {
+        synchronized (mLock) {
+            if (mInputSessionRequested) {
+                connection.createImeSessionLocked();
+            }
+        }
+    }
+
+    private void bindAndStartInputForConnection(AccessibilityServiceConnection connection) {
+        synchronized (mLock) {
+            if (mInputBinding != null) {
+                connection.bindInputLocked(mInputBinding);
+                connection.startInputLocked(mStartInputToken, mInputContext, mEditorInfo,
+                        mRestarting);
+            }
+        }
+    }
+
+    private void unbindInputForConnection(AccessibilityServiceConnection connection) {
+        InputMethodManagerInternal.get().unbindAccessibilityFromCurrentClient(connection.mId);
+        synchronized (mLock) {
+            connection.unbindInputLocked();
+        }
+    }
+
     private void onDoubleTapAndHoldInternal(int displayId) {
         synchronized (mLock) {
             if (mHasInputFilter && mInputFilter != null) {
@@ -4268,4 +4358,100 @@
     public AccessibilityTraceManager getTraceManager() {
         return mTraceManager;
     }
+
+    /**
+     * Bind input for accessibility services which request ime capabilities.
+     *
+     * @param binding Information given to an accessibility service about a client connecting to it.
+     */
+    public void bindInput(InputBinding binding) {
+        AccessibilityUserState userState;
+        synchronized (mLock) {
+            // Keep records of these in case new Accessibility Services are enabled.
+            mInputBinding = binding;
+            userState = getCurrentUserStateLocked();
+            for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
+                final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
+                if (service.requestImeApis()) {
+                    service.bindInputLocked(binding);
+                }
+            }
+        }
+    }
+
+    /**
+     * Unbind input for accessibility services which request ime capabilities.
+     */
+    public void unbindInput() {
+        AccessibilityUserState userState;
+        // TODO(b/218182733): Resolve the Imf lock and mLock possible deadlock
+        synchronized (mLock) {
+            userState = getCurrentUserStateLocked();
+            for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
+                final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
+                if (service.requestImeApis()) {
+                    service.unbindInputLocked();
+                }
+            }
+        }
+    }
+
+    /**
+     * Start input for accessibility services which request ime capabilities.
+     */
+    public void startInput(IBinder startInputToken, IInputContext inputContext,
+            EditorInfo editorInfo, boolean restarting) {
+        AccessibilityUserState userState;
+        synchronized (mLock) {
+            // Keep records of these in case new Accessibility Services are enabled.
+            mStartInputToken = startInputToken;
+            mInputContext = inputContext;
+            mEditorInfo = editorInfo;
+            mRestarting = restarting;
+            userState = getCurrentUserStateLocked();
+            for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
+                final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
+                if (service.requestImeApis()) {
+                    service.startInputLocked(startInputToken, inputContext, editorInfo, restarting);
+                }
+            }
+        }
+    }
+
+    /**
+     * Request input sessions from all accessibility services which request ime capabilities and
+     * whose id is not in the ignoreSet
+     */
+    public void createImeSession(ArraySet<Integer> ignoreSet) {
+        AccessibilityUserState userState;
+        synchronized (mLock) {
+            mInputSessionRequested = true;
+            userState = getCurrentUserStateLocked();
+            for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
+                final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
+                if ((!ignoreSet.contains(service.mId)) && service.requestImeApis()) {
+                    service.createImeSessionLocked();
+                }
+            }
+        }
+    }
+
+    /**
+     * Enable or disable the sessions.
+     *
+     * @param sessions Sessions to enable or disable.
+     * @param enabled True if enable the sessions or false if disable the sessions.
+     */
+    public void setImeSessionEnabled(SparseArray<IInputMethodSession> sessions, boolean enabled) {
+        AccessibilityUserState userState;
+        synchronized (mLock) {
+            userState = getCurrentUserStateLocked();
+            for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
+                final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
+                if (sessions.contains(service.mId) && service.requestImeApis()) {
+                    service.setImeSessionEnabledLocked(sessions.get(service.mId), enabled);
+                }
+            }
+        }
+    }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index 8f7260f..0631028 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -127,6 +127,9 @@
     }
 
     public void unbindLocked() {
+        if (requestImeApis()) {
+            mSystemSupport.unbindImeLocked(this);
+        }
         mContext.unbindService(this);
         AccessibilityUserState userState = mUserStateWeakReference.get();
         if (userState == null) return;
@@ -188,6 +191,9 @@
             // the new configuration (for example, initializing the input filter).
             mMainHandler.sendMessage(obtainMessage(
                     AccessibilityServiceConnection::initializeService, this));
+            if (requestImeApis()) {
+                mSystemSupport.requestImeLocked(this);
+            }
         }
     }
 
@@ -371,6 +377,9 @@
             if (!isConnectedLocked()) {
                 return;
             }
+            if (requestImeApis()) {
+                mSystemSupport.unbindImeLocked(this);
+            }
             mAccessibilityServiceInfo.crashed = true;
             AccessibilityUserState userState = mUserStateWeakReference.get();
             if (userState != null) {
@@ -512,6 +521,10 @@
         mMainHandler.sendMessage(msg);
     }
 
+    public boolean requestImeApis() {
+        return mRequestImeApis;
+    }
+
     private void notifyMotionEventInternal(MotionEvent event) {
         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
         if (listener != null) {
diff --git a/services/accessibility/java/com/android/server/accessibility/CaptioningManagerImpl.java b/services/accessibility/java/com/android/server/accessibility/CaptioningManagerImpl.java
index 39780d2..0fc6c8d 100644
--- a/services/accessibility/java/com/android/server/accessibility/CaptioningManagerImpl.java
+++ b/services/accessibility/java/com/android/server/accessibility/CaptioningManagerImpl.java
@@ -40,7 +40,7 @@
      * @param userId The user Id.
      */
     @Override
-    public void setSystemAudioCaptioningRequested(boolean isEnabled, int userId) {
+    public void setSystemAudioCaptioningEnabled(boolean isEnabled, int userId) {
         final long identity = Binder.clearCallingIdentity();
         try {
             Settings.Secure.putIntForUser(mContext.getContentResolver(),
@@ -57,7 +57,7 @@
      * @return the system audio caption UI enabled state.
      */
     @Override
-    public boolean isSystemAudioCaptioningUiRequested(int userId) {
+    public boolean isSystemAudioCaptioningUiEnabled(int userId) {
         final long identity = Binder.clearCallingIdentity();
         try {
             return Settings.Secure.getIntForUser(mContext.getContentResolver(),
@@ -75,7 +75,7 @@
      * @param userId The user Id.
      */
     @Override
-    public void setSystemAudioCaptioningUiRequested(boolean isEnabled, int userId) {
+    public void setSystemAudioCaptioningUiEnabled(boolean isEnabled, int userId) {
         final long identity = Binder.clearCallingIdentity();
         try {
             Settings.Secure.putIntForUser(mContext.getContentResolver(),
diff --git a/services/api/current.txt b/services/api/current.txt
index dcf7e64..e46c972 100644
--- a/services/api/current.txt
+++ b/services/api/current.txt
@@ -38,8 +38,8 @@
 package com.android.server.am {
 
   public interface ActivityManagerLocal {
+    method public boolean bindSupplementalProcessService(@NonNull android.content.Intent, @NonNull android.content.ServiceConnection, int, @NonNull String, int) throws android.os.RemoteException;
     method public boolean canStartForegroundService(int, int, @NonNull String);
-    method public boolean startAndBindSupplementalProcessService(@NonNull android.content.Intent, @NonNull android.content.ServiceConnection, int) throws android.os.TransactionTooLargeException;
   }
 
 }
diff --git a/services/core/java/com/android/server/AccessibilityManagerInternal.java b/services/core/java/com/android/server/AccessibilityManagerInternal.java
new file mode 100644
index 0000000..28f6db1
--- /dev/null
+++ b/services/core/java/com/android/server/AccessibilityManagerInternal.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.annotation.NonNull;
+import android.os.IBinder;
+import android.util.ArraySet;
+import android.util.SparseArray;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputBinding;
+
+import com.android.internal.view.IInputContext;
+import com.android.internal.view.IInputMethodSession;
+
+/**
+ * Accessibility manager local system service interface.
+ */
+public abstract class AccessibilityManagerInternal {
+    /** Enable or disable the sessions. */
+    public abstract void setImeSessionEnabled(SparseArray<IInputMethodSession> sessions,
+            boolean enabled);
+
+    /** Unbind input for all accessibility services which require ime capabilities. */
+    public abstract void unbindInput();
+
+    /** Bind input for all accessibility services which require ime capabilities. */
+    public abstract void bindInput(InputBinding binding);
+
+    /**
+     * Request input session from all accessibility services which require ime capabilities and
+     * whose id is not in the ignoreSet.
+     */
+    public abstract void createImeSession(ArraySet<Integer> ignoreSet);
+
+    /** Start input for all accessibility services which require ime capabilities. */
+    public abstract void startInput(IBinder startInputToken, IInputContext inputContext,
+            EditorInfo editorInfo, boolean restarting);
+
+    private static final AccessibilityManagerInternal NOP = new AccessibilityManagerInternal() {
+        @Override
+        public void setImeSessionEnabled(SparseArray<IInputMethodSession> sessions,
+                boolean enabled) {
+        }
+
+        @Override
+        public void unbindInput() {
+        }
+
+        @Override
+        public void bindInput(InputBinding binding) {
+        }
+
+        @Override
+        public void createImeSession(ArraySet<Integer> ignoreSet) {
+        }
+
+        @Override
+        public void startInput(IBinder startInputToken, IInputContext inputContext,
+                EditorInfo editorInfo, boolean restarting) {
+        }
+    };
+
+    /**
+     * @return Global instance if exists. Otherwise, a fallback no-op instance.
+     */
+    @NonNull
+    public static AccessibilityManagerInternal get() {
+        final AccessibilityManagerInternal instance =
+                LocalServices.getService(AccessibilityManagerInternal.class);
+        return instance != null ? instance : NOP;
+    }
+}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 9353dd8..dc64d80 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -3411,9 +3411,11 @@
                     final Intent.FilterComparison filter
                             = new Intent.FilterComparison(service.cloneFilter());
                     final ServiceRestarter res = new ServiceRestarter();
+                    String supplementalProcessName = isSupplementalProcessService ? instanceName
+                                                                                  : null;
                     r = new ServiceRecord(mAm, className, name, definingPackageName,
                             definingUid, filter, sInfo, callingFromFg, res,
-                            isSupplementalProcessService);
+                            supplementalProcessName);
                     res.setService(r);
                     smap.mServicesByInstanceName.put(name, r);
                     smap.mServicesByIntent.put(filter, r);
diff --git a/services/core/java/com/android/server/am/ActivityManagerLocal.java b/services/core/java/com/android/server/am/ActivityManagerLocal.java
index d9ee7d9..535340b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerLocal.java
+++ b/services/core/java/com/android/server/am/ActivityManagerLocal.java
@@ -17,10 +17,12 @@
 package com.android.server.am;
 
 import android.annotation.NonNull;
+import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
+import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
-import android.os.TransactionTooLargeException;
+import android.os.RemoteException;
 
 /**
  * Interface for in-process calls into
@@ -63,22 +65,28 @@
     void tempAllowWhileInUsePermissionInFgs(int uid, long durationMs);
 
     /**
-     * Starts a supplemental process service and binds to it. You can through the arguments here
-     * have the system bring up multiple concurrent processes hosting their own instance of that
-     * service. The <var>userAppUid</var> you provide here identifies the different instances - each
-     * unique uid is attributed to a supplemental process.
+     * Binds to a supplemental process service, creating it if needed. You can through the arguments
+     * here have the system bring up multiple concurrent processes hosting their own instance of
+     * that service. The {@code processName} you provide here identifies the different instances.
      *
      * @param service Identifies the supplemental process service to connect to. The Intent must
      *        specify an explicit component name. This value cannot be null.
      * @param conn Receives information as the service is started and stopped.
      *        This must be a valid ServiceConnection object; it must not be null.
      * @param userAppUid Uid of the app for which the supplemental process needs to be spawned.
+     * @param processName Unique identifier for the service instance. Each unique name here will
+     *        result in a different service instance being created. Identifiers must only contain
+     *        ASCII letters, digits, underscores, and periods.
+     * @param flags Operation options provided by Context class for the binding.
      * @return {@code true} if the system is in the process of bringing up a
      *         service that your client has permission to bind to; {@code false}
      *         if the system couldn't find the service or if your client doesn't
      *         have permission to bind to it.
+     * @throws RemoteException If the service could not be brought up.
+     * @see Context#bindService(Intent, ServiceConnection, int)
      */
-    boolean startAndBindSupplementalProcessService(@NonNull Intent service,
-            @NonNull ServiceConnection conn, int userAppUid) throws TransactionTooLargeException;
-
+    @SuppressLint("RethrowRemoteException")
+    boolean bindSupplementalProcessService(@NonNull Intent service, @NonNull ServiceConnection conn,
+            int userAppUid, @NonNull String processName, @Context.BindServiceFlags int flags)
+            throws RemoteException;
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5cc163d..7f64c00 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -458,7 +458,7 @@
      * broadcasts
      */
     private static final boolean ENFORCE_DYNAMIC_RECEIVER_EXPLICIT_EXPORT =
-            SystemProperties.getBoolean("fw.enforce_dynamic_receiver_explicit_export", false);
+            SystemProperties.getBoolean("fw.enforce_dynamic_receiver_explicit_export", true);
 
     static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityManagerService" : TAG_AM;
     static final String TAG_BACKUP = TAG + POSTFIX_BACKUP;
@@ -15951,14 +15951,17 @@
         }
 
         @Override
-        public boolean startAndBindSupplementalProcessService(Intent service,
-                ServiceConnection conn, int userAppUid) throws TransactionTooLargeException {
+        public boolean bindSupplementalProcessService(Intent service, ServiceConnection conn,
+                int userAppUid, String processName, int flags) throws RemoteException {
             if (service == null) {
                 throw new IllegalArgumentException("intent is null");
             }
             if (conn == null) {
                 throw new IllegalArgumentException("connection is null");
             }
+            if (processName == null) {
+                throw new IllegalArgumentException("processName is null");
+            }
             if (service.getComponent() == null) {
                 throw new IllegalArgumentException("service must specify explicit component");
             }
@@ -15967,15 +15970,14 @@
             }
 
             Handler handler = mContext.getMainThreadHandler();
-            int flags = Context.BIND_AUTO_CREATE;
 
             final IServiceConnection sd = mContext.getServiceDispatcher(conn, handler, flags);
             service.prepareToLeaveProcess(mContext);
             return ActivityManagerService.this.bindServiceInstance(
-                        mContext.getIApplicationThread(), mContext.getActivityToken(), service,
-                        service.resolveTypeIfNeeded(mContext.getContentResolver()), sd, flags,
-                        Integer.toString(userAppUid), /*isSupplementalProcessService*/ true,
-                        mContext.getOpPackageName(), UserHandle.getUserId(userAppUid)) != 0;
+                    mContext.getIApplicationThread(), mContext.getActivityToken(), service,
+                    service.resolveTypeIfNeeded(mContext.getContentResolver()), sd, flags,
+                    processName, /*isSupplementalProcessService*/ true, mContext.getOpPackageName(),
+                    UserHandle.getUserId(userAppUid)) != 0;
         }
 
         @Override
@@ -16119,23 +16121,6 @@
         }
 
         /**
-         * Returns package name by pid.
-         */
-        @Override
-        @Nullable
-        public String getPackageNameByPid(int pid) {
-            synchronized (mPidsSelfLocked) {
-                final ProcessRecord app = mPidsSelfLocked.get(pid);
-
-                if (app != null && app.info != null) {
-                    return app.info.packageName;
-                }
-
-                return null;
-            }
-        }
-
-        /**
          * Sets if the given pid has an overlay UI or not.
          *
          * @param pid The pid we are setting overlay UI for.
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 2f7249e..91822ac 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -79,7 +79,6 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.os.BackgroundThread;
-import com.android.internal.os.BatteryStatsHelper;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.internal.os.BatteryUsageStatsProvider;
 import com.android.internal.os.BatteryUsageStatsStore;
@@ -2488,7 +2487,7 @@
 
         final long ident = Binder.clearCallingIdentity();
         try {
-            if (BatteryStatsHelper.checkWifiOnly(mContext)) {
+            if (BatteryStats.checkWifiOnly(mContext)) {
                 flags |= BatteryStats.DUMP_DEVICE_WIFI_ONLY;
             }
             awaitCompletion();
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index bdfd02e..6c9187a 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -2491,6 +2491,7 @@
                 mCachedAppOptimizer.onOomAdjustChanged(state.getSetAdj(), state.getCurAdj(), app);
             } else if (mService.mWakefulness.get() != PowerManagerInternal.WAKEFULNESS_AWAKE
                     && state.getSetAdj() < ProcessList.FOREGROUND_APP_ADJ
+                    && !state.isRunningRemoteAnimation()
                     // Because these can fire independent of oom_adj/procstate changes, we need
                     // to throttle the actual dispatch of these requests in addition to the
                     // processing of the requests. As a result, there is throttling both here
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index da78e2d..d3b5752 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -571,13 +571,13 @@
             Intent.FilterComparison intent, ServiceInfo sInfo, boolean callerIsFg,
             Runnable restarter) {
         this(ams, name, instanceName, definingPackageName, definingUid, intent, sInfo, callerIsFg,
-                restarter, false);
+                restarter, null);
     }
 
     ServiceRecord(ActivityManagerService ams, ComponentName name,
             ComponentName instanceName, String definingPackageName, int definingUid,
             Intent.FilterComparison intent, ServiceInfo sInfo, boolean callerIsFg,
-            Runnable restarter, boolean isSupplementalProcessService) {
+            Runnable restarter, String supplementalProcessName) {
         this.ams = ams;
         this.name = name;
         this.instanceName = instanceName;
@@ -588,9 +588,10 @@
         serviceInfo = sInfo;
         appInfo = sInfo.applicationInfo;
         packageName = sInfo.applicationInfo.packageName;
-        if ((sInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0
-                || isSupplementalProcessService) {
+        if ((sInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0) {
             processName = sInfo.processName + ":" + instanceName.getClassName();
+        } else if (supplementalProcessName != null) {
+            processName = supplementalProcessName;
         } else {
             processName = sInfo.processName;
         }
diff --git a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java
index 6982513..ab4d856 100644
--- a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java
+++ b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java
@@ -20,22 +20,30 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.ActivityTaskManager;
 import android.app.AppGlobals;
 import android.app.BroadcastOptions;
 import android.app.PendingIntent;
 import android.app.ambientcontext.AmbientContextEvent;
 import android.app.ambientcontext.AmbientContextEventRequest;
-import android.app.ambientcontext.AmbientContextEventResponse;
 import android.app.ambientcontext.AmbientContextManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
 import android.content.pm.ServiceInfo;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.RemoteCallback;
 import android.os.RemoteException;
-import android.service.ambientcontext.AmbientContextDetectionService;
+import android.provider.Settings;
+import android.service.ambientcontext.AmbientContextDetectionResult;
+import android.service.ambientcontext.AmbientContextDetectionServiceStatus;
+import android.text.TextUtils;
+import android.util.ArraySet;
 import android.util.IndentingPrintWriter;
 import android.util.Slog;
 
@@ -44,7 +52,8 @@
 import com.android.server.infra.AbstractPerUserSystemService;
 
 import java.io.PrintWriter;
-import java.util.HashSet;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Set;
 
 /**
@@ -60,14 +69,12 @@
     RemoteAmbientContextDetectionService mRemoteService;
 
     private ComponentName mComponentName;
-    private Context mContext;
     private Set<PendingIntent> mExistingPendingIntents;
 
     AmbientContextManagerPerUserService(
             @NonNull AmbientContextManagerService master, Object lock, @UserIdInt int userId) {
         super(master, lock, userId);
-        mContext = master.getContext();
-        mExistingPendingIntents = new HashSet<>();
+        mExistingPendingIntents = new ArraySet<>();
     }
 
     void destroyLocked() {
@@ -154,12 +161,13 @@
      * package. A new registration from the same package will overwrite the previous registration.
      */
     public void onRegisterObserver(AmbientContextEventRequest request,
-            PendingIntent pendingIntent) {
+            PendingIntent pendingIntent, RemoteCallback clientStatusCallback) {
         synchronized (mLock) {
             if (!setUpServiceIfNeeded()) {
-                Slog.w(TAG, "Service is not available at this moment.");
-                sendStatusUpdateIntent(
-                        pendingIntent, AmbientContextEventResponse.STATUS_SERVICE_UNAVAILABLE);
+                Slog.w(TAG, "Detection service is not available at this moment.");
+                sendStatusCallback(
+                        clientStatusCallback,
+                        AmbientContextManager.STATUS_SERVICE_UNAVAILABLE);
                 return;
             }
 
@@ -173,29 +181,58 @@
             }
 
             // Register new package and add request to mExistingRequests
-            startDetection(request, callingPackage, createRemoteCallback());
+            startDetection(request, callingPackage, createDetectionResultRemoteCallback(),
+                    getServerStatusCallback(clientStatusCallback));
             mExistingPendingIntents.add(pendingIntent);
         }
     }
 
+    /**
+     * Returns a RemoteCallback that handles the status from the detection service, and
+     * sends results to the client callback.
+     */
+    private RemoteCallback getServerStatusCallback(RemoteCallback clientStatusCallback) {
+        return new RemoteCallback(result -> {
+            AmbientContextDetectionServiceStatus serviceStatus =
+                    (AmbientContextDetectionServiceStatus) result.get(
+                            AmbientContextDetectionServiceStatus.STATUS_RESPONSE_BUNDLE_KEY);
+            final long token = Binder.clearCallingIdentity();
+            try {
+                String packageName = serviceStatus.getPackageName();
+                Bundle bundle = new Bundle();
+                bundle.putInt(
+                        AmbientContextManager.STATUS_RESPONSE_BUNDLE_KEY,
+                        serviceStatus.getStatusCode());
+                clientStatusCallback.sendResult(bundle);
+                int statusCode = serviceStatus.getStatusCode();
+                Slog.i(TAG, "Got detection status of " + statusCode
+                        + " for " + packageName);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        });
+    }
+
     @VisibleForTesting
     void startDetection(AmbientContextEventRequest request, String callingPackage,
-            RemoteCallback callback) {
+            RemoteCallback detectionResultCallback, RemoteCallback statusCallback) {
         Slog.d(TAG, "Requested detection of " + request.getEventTypes());
         synchronized (mLock) {
             ensureRemoteServiceInitiated();
-            mRemoteService.startDetection(request, callingPackage, callback);
+            mRemoteService.startDetection(request, callingPackage, detectionResultCallback,
+                    statusCallback);
         }
     }
 
     /**
      * Sends an intent with a status code and empty events.
      */
-    void sendStatusUpdateIntent(PendingIntent pendingIntent, int statusCode) {
-        AmbientContextEventResponse response = new AmbientContextEventResponse.Builder()
-                .setStatusCode(statusCode)
-                .build();
-        sendResponseIntent(pendingIntent, response);
+    void sendStatusCallback(RemoteCallback statusCallback, int statusCode) {
+        Bundle bundle = new Bundle();
+        bundle.putInt(
+                AmbientContextManager.STATUS_RESPONSE_BUNDLE_KEY,
+                statusCode);
+        statusCallback.sendResult(bundle);
     }
 
     /**
@@ -217,6 +254,113 @@
         }
     }
 
+    public void onQueryServiceStatus(int[] eventTypes, String callingPackage,
+            RemoteCallback statusCallback) {
+        Slog.d(TAG, "Query event status of " + Arrays.toString(eventTypes)
+                + " for " + callingPackage);
+        synchronized (mLock) {
+            if (!setUpServiceIfNeeded()) {
+                Slog.w(TAG, "Detection service is not available at this moment.");
+                sendStatusToCallback(statusCallback,
+                        AmbientContextManager.STATUS_SERVICE_UNAVAILABLE);
+                return;
+            }
+            ensureRemoteServiceInitiated();
+            mRemoteService.queryServiceStatus(
+                    eventTypes,
+                    callingPackage,
+                    getServerStatusCallback(statusCallback));
+        }
+    }
+
+    public void onStartConsentActivity(int[] eventTypes, String callingPackage) {
+        Slog.d(TAG, "Opening consent activity of " + Arrays.toString(eventTypes)
+                + " for " + callingPackage);
+
+        // Look up the recent task from the callingPackage
+        ActivityManager.RecentTaskInfo task;
+        ParceledListSlice<ActivityManager.RecentTaskInfo> recentTasks;
+        int userId = getUserId();
+        try {
+            recentTasks = ActivityTaskManager.getService().getRecentTasks(/*maxNum*/1,
+                    /*flags*/ 0, userId);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Failed to query recent tasks!");
+            return;
+        }
+
+        if ((recentTasks != null) || recentTasks.getList().isEmpty()) {
+            Slog.e(TAG, "Recent task list is empty!");
+            return;
+        }
+
+        task = recentTasks.getList().get(0);
+        if (!callingPackage.equals(task.topActivityInfo.packageName)) {
+            Slog.e(TAG, "Recent task package name: " + task.topActivityInfo.packageName
+                    + " doesn't match with camera client package name: " + callingPackage);
+            return;
+        }
+
+        // Start activity as the same task from the callingPackage
+        Intent intent = new Intent();
+        ComponentName consentComponent = getConsentComponent();
+        if (consentComponent != null) {
+            Slog.e(TAG, "Starting consent activity for " + callingPackage);
+            Context context = getContext();
+            String packageNameExtraKey = Settings.Secure.getStringForUser(
+                    context.getContentResolver(),
+                    Settings.Secure.AMBIENT_CONTEXT_PACKAGE_NAME_EXTRA_KEY,
+                    userId);
+            String eventArrayExtraKey = Settings.Secure.getStringForUser(
+                    context.getContentResolver(),
+                    Settings.Secure.AMBIENT_CONTEXT_EVENT_ARRAY_EXTRA_KEY,
+                    userId);
+
+            // Create consent activity intent with the calling package name and requested events.
+            intent.setComponent(consentComponent);
+            if (packageNameExtraKey != null) {
+                intent.putExtra(packageNameExtraKey, callingPackage);
+            }
+            if (eventArrayExtraKey != null) {
+                intent.putExtra(eventArrayExtraKey, eventTypes);
+            }
+
+            // Set parent to the calling app's task
+            ActivityOptions options = ActivityOptions.makeBasic();
+            options.setLaunchTaskId(task.taskId);
+            context.startActivity(intent, options.toBundle());
+        } else {
+            Slog.e(TAG, "Consent component not found!");
+        }
+    }
+
+    /**
+     * Returns the consent activity component from config lookup.
+     */
+    private ComponentName getConsentComponent() {
+        Context context = getContext();
+        String consentComponent = Settings.Secure.getStringForUser(
+                context.getContentResolver(),
+                Settings.Secure.AMBIENT_CONTEXT_CONSENT_COMPONENT,
+                getUserId());
+        if (TextUtils.isEmpty(consentComponent)) {
+            return null;
+        }
+        return ComponentName.unflattenFromString(consentComponent);
+    }
+
+    /**
+     * Sends the result response with the specified status to the callback.
+     */
+    void sendStatusToCallback(RemoteCallback callback,
+                    @AmbientContextManager.StatusCode int status) {
+        Bundle bundle = new Bundle();
+        bundle.putInt(
+                AmbientContextManager.STATUS_RESPONSE_BUNDLE_KEY,
+                status);
+        callback.sendResult(bundle);
+    }
+
     @VisibleForTesting
     void stopDetection(String packageName) {
         Slog.d(TAG, "Stop detection for " + packageName);
@@ -240,12 +384,13 @@
      * Sends out the Intent to the client after the event is detected.
      *
      * @param pendingIntent Client's PendingIntent for callback
-     * @param response Response with status code and detection result
+     * @param result result from the detection service
      */
-    private void sendResponseIntent(PendingIntent pendingIntent,
-            AmbientContextEventResponse response) {
+    private void sendDetectionResultIntent(PendingIntent pendingIntent,
+            AmbientContextDetectionResult result) {
         Intent intent = new Intent();
-        intent.putExtra(AmbientContextManager.EXTRA_AMBIENT_CONTEXT_EVENT_RESPONSE, response);
+        intent.putExtra(AmbientContextManager.EXTRA_AMBIENT_CONTEXT_EVENTS,
+                new ArrayList(result.getEvents()));
         // Explicitly disallow the receiver from starting activities, to prevent apps from utilizing
         // the PendingIntent as a backdoor to do this.
         BroadcastOptions options = BroadcastOptions.makeBasic();
@@ -254,38 +399,29 @@
             pendingIntent.send(getContext(), 0, intent, null, null, null,
                     options.toBundle());
             Slog.i(TAG, "Sending PendingIntent to " + pendingIntent.getCreatorPackage() + ": "
-                    + response);
+                    + result);
         } catch (PendingIntent.CanceledException e) {
             Slog.w(TAG, "Couldn't deliver pendingIntent:" + pendingIntent);
         }
     }
 
     @NonNull
-    private RemoteCallback createRemoteCallback() {
+    private RemoteCallback createDetectionResultRemoteCallback() {
         return new RemoteCallback(result -> {
-            AmbientContextEventResponse response = (AmbientContextEventResponse) result.get(
-                            AmbientContextDetectionService.RESPONSE_BUNDLE_KEY);
+            AmbientContextDetectionResult detectionResult =
+                    (AmbientContextDetectionResult) result.get(
+                            AmbientContextDetectionResult.RESULT_RESPONSE_BUNDLE_KEY);
             final long token = Binder.clearCallingIdentity();
             try {
-                Set<PendingIntent> pendingIntentForFailedRequests = new HashSet<>();
                 for (PendingIntent pendingIntent : mExistingPendingIntents) {
-                    // Send PendingIntent if a requesting package matches the response packages.
-                    if (response.getPackageName().equals(pendingIntent.getCreatorPackage())) {
-                        sendResponseIntent(pendingIntent, response);
-
-                        int statusCode = response.getStatusCode();
-                        if (statusCode != AmbientContextEventResponse.STATUS_SUCCESS) {
-                            pendingIntentForFailedRequests.add(pendingIntent);
-                        }
-                        Slog.i(TAG, "Got response of " + response.getEvents() + " for "
-                                + pendingIntent.getCreatorPackage() + ". Status: " + statusCode);
+                    // Send PendingIntent to requesting packages
+                    String creatorPackage = pendingIntent.getCreatorPackage();
+                    if (detectionResult.getPackageName().equals(creatorPackage)) {
+                        sendDetectionResultIntent(pendingIntent, detectionResult);
+                        Slog.i(TAG, "Got detection result of " + detectionResult.getEvents()
+                                + " for " + creatorPackage);
                     }
                 }
-
-                // Removes the failed requests from the existing requests.
-                for (PendingIntent pendingIntent : pendingIntentForFailedRequests) {
-                    mExistingPendingIntents.remove(pendingIntent);
-                }
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
diff --git a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java
index 33905f2..2cdf7e7 100644
--- a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java
+++ b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java
@@ -24,8 +24,8 @@
 import android.app.PendingIntent;
 import android.app.ambientcontext.AmbientContextEvent;
 import android.app.ambientcontext.AmbientContextEventRequest;
-import android.app.ambientcontext.AmbientContextEventResponse;
-import android.app.ambientcontext.IAmbientContextEventObserver;
+import android.app.ambientcontext.AmbientContextManager;
+import android.app.ambientcontext.IAmbientContextManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManagerInternal;
@@ -76,7 +76,7 @@
 
     @Override
     public void onStart() {
-        publishBinderService(Context.AMBIENT_CONTEXT_SERVICE, new AmbientContextEventObserver());
+        publishBinderService(Context.AMBIENT_CONTEXT_SERVICE, new AmbientContextManagerInternal());
     }
 
     @Override
@@ -128,14 +128,16 @@
      * specified events. Intended for use by shell command for testing.
      * Requires ACCESS_AMBIENT_CONTEXT_EVENT permission.
      */
-    void startAmbientContextEvent(@UserIdInt int userId, AmbientContextEventRequest request,
-            String packageName, RemoteCallback callback) {
+    void startDetection(@UserIdInt int userId, AmbientContextEventRequest request,
+            String packageName, RemoteCallback detectionResultCallback,
+            RemoteCallback statusCallback) {
         mContext.enforceCallingOrSelfPermission(
                 Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT, TAG);
         synchronized (mLock) {
             final AmbientContextManagerPerUserService service = getServiceForUserLocked(userId);
             if (service != null) {
-                service.startDetection(request, packageName, callback);
+                service.startDetection(request, packageName, detectionResultCallback,
+                        statusCallback);
             } else {
                 Slog.i(TAG, "service not available for user_id: " + userId);
             }
@@ -161,6 +163,25 @@
     }
 
     /**
+     * Send request to the remote AmbientContextDetectionService impl to query the status of the
+     * specified events. Intended for use by shell command for testing.
+     * Requires ACCESS_AMBIENT_CONTEXT_EVENT permission.
+     */
+    void queryServiceStatus(@UserIdInt int userId, String packageName,
+            int[] eventTypes, RemoteCallback callback) {
+        mContext.enforceCallingOrSelfPermission(
+                Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT, TAG);
+        synchronized (mLock) {
+            final AmbientContextManagerPerUserService service = getServiceForUserLocked(userId);
+            if (service != null) {
+                service.onQueryServiceStatus(eventTypes, packageName, callback);
+            } else {
+                Slog.i(TAG, "query service not available for user_id: " + userId);
+            }
+        }
+    }
+
+    /**
      * Returns the AmbientContextManagerPerUserService component for this user.
      */
     public ComponentName getComponentName(@UserIdInt int userId) {
@@ -173,34 +194,65 @@
         return null;
     }
 
-    private final class AmbientContextEventObserver extends IAmbientContextEventObserver.Stub {
+    private final class AmbientContextManagerInternal extends IAmbientContextManager.Stub {
         final AmbientContextManagerPerUserService mService = getServiceForUserLocked(
                 UserHandle.getCallingUserId());
 
         @Override
         public void registerObserver(
-                AmbientContextEventRequest request, PendingIntent pendingIntent) {
+                AmbientContextEventRequest request, PendingIntent resultPendingIntent,
+                RemoteCallback statusCallback) {
             Objects.requireNonNull(request);
-            Objects.requireNonNull(pendingIntent);
+            Objects.requireNonNull(resultPendingIntent);
+            Objects.requireNonNull(statusCallback);
             mContext.enforceCallingOrSelfPermission(
                     Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT, TAG);
+            assertCalledByPackageOwner(resultPendingIntent.getCreatorPackage());
             if (!mIsServiceEnabled) {
                 Slog.w(TAG, "Service not available.");
-                mService.sendStatusUpdateIntent(pendingIntent,
-                        AmbientContextEventResponse.STATUS_SERVICE_UNAVAILABLE);
+                mService.sendStatusCallback(statusCallback,
+                        AmbientContextManager.STATUS_SERVICE_UNAVAILABLE);
                 return;
             }
-            mService.onRegisterObserver(request, pendingIntent);
+            mService.onRegisterObserver(request, resultPendingIntent, statusCallback);
         }
 
         @Override
         public void unregisterObserver(String callingPackage) {
             mContext.enforceCallingOrSelfPermission(
                     Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT, TAG);
+            assertCalledByPackageOwner(callingPackage);
             mService.onUnregisterObserver(callingPackage);
         }
 
         @Override
+        public void queryServiceStatus(int[] eventTypes, String callingPackage,
+                RemoteCallback statusCallback) {
+            Objects.requireNonNull(eventTypes);
+            Objects.requireNonNull(callingPackage);
+            Objects.requireNonNull(statusCallback);
+            mContext.enforceCallingOrSelfPermission(
+                    Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT, TAG);
+            assertCalledByPackageOwner(callingPackage);
+            if (!mIsServiceEnabled) {
+                Slog.w(TAG, "Detection service not available.");
+                mService.sendStatusToCallback(statusCallback,
+                        AmbientContextManager.STATUS_SERVICE_UNAVAILABLE);
+                return;
+            }
+            mService.onQueryServiceStatus(eventTypes, callingPackage,
+                    statusCallback);
+        }
+
+        @Override
+        public void startConsentActivity(int[] eventTypes, String callingPackage) {
+            Objects.requireNonNull(eventTypes);
+            Objects.requireNonNull(callingPackage);
+            assertCalledByPackageOwner(callingPackage);
+            mService.onStartConsentActivity(eventTypes, callingPackage);
+        }
+
+        @Override
         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) {
                 return;
diff --git a/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java b/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java
index b5cd985..010bf1b 100644
--- a/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java
+++ b/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java
@@ -21,12 +21,12 @@
 import android.annotation.NonNull;
 import android.app.ambientcontext.AmbientContextEvent;
 import android.app.ambientcontext.AmbientContextEventRequest;
-import android.app.ambientcontext.AmbientContextEventResponse;
 import android.content.ComponentName;
 import android.os.Binder;
 import android.os.RemoteCallback;
 import android.os.ShellCommand;
-import android.service.ambientcontext.AmbientContextDetectionService;
+import android.service.ambientcontext.AmbientContextDetectionResult;
+import android.service.ambientcontext.AmbientContextDetectionServiceStatus;
 
 import java.io.PrintWriter;
 
@@ -35,6 +35,12 @@
  */
 final class AmbientContextShellCommand extends ShellCommand {
 
+    private static final AmbientContextEventRequest REQUEST =
+            new AmbientContextEventRequest.Builder()
+                    .addEventType(AmbientContextEvent.EVENT_COUGH)
+                    .addEventType(AmbientContextEvent.EVENT_SNORE)
+                    .build();
+
     @NonNull
     private final AmbientContextManagerService mService;
 
@@ -44,22 +50,43 @@
 
     /** Callbacks for AmbientContextEventService results used internally for testing. */
     static class TestableCallbackInternal {
-        private AmbientContextEventResponse mLastResponse;
+        private AmbientContextDetectionResult mLastResult;
+        private AmbientContextDetectionServiceStatus mLastStatus;
 
-        public AmbientContextEventResponse getLastResponse() {
-            return mLastResponse;
+        public AmbientContextDetectionResult getLastResult() {
+            return mLastResult;
+        }
+
+        public AmbientContextDetectionServiceStatus getLastStatus() {
+            return mLastStatus;
         }
 
         @NonNull
-        private RemoteCallback createRemoteCallback() {
+        private RemoteCallback createRemoteDetectionResultCallback() {
             return new RemoteCallback(result -> {
-                AmbientContextEventResponse response =
-                        (AmbientContextEventResponse) result.get(
-                                AmbientContextDetectionService.RESPONSE_BUNDLE_KEY);
+                AmbientContextDetectionResult detectionResult =
+                        (AmbientContextDetectionResult) result.get(
+                                AmbientContextDetectionResult.RESULT_RESPONSE_BUNDLE_KEY);
                 final long token = Binder.clearCallingIdentity();
                 try {
-                    mLastResponse = response;
-                    out.println("Response available: " + response);
+                    mLastResult = detectionResult;
+                    out.println("Detection result available: " + detectionResult);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            });
+        }
+
+        @NonNull
+        private RemoteCallback createRemoteStatusCallback() {
+            return new RemoteCallback(result -> {
+                AmbientContextDetectionServiceStatus status =
+                        (AmbientContextDetectionServiceStatus) result.get(
+                                AmbientContextDetectionServiceStatus.STATUS_RESPONSE_BUNDLE_KEY);
+                final long token = Binder.clearCallingIdentity();
+                try {
+                    mLastStatus = status;
+                    out.println("Status available: " + status);
                 } finally {
                     Binder.restoreCallingIdentity(token);
                 }
@@ -83,6 +110,8 @@
                 return runStopDetection();
             case "get-last-status-code":
                 return getLastStatusCode();
+            case "query-service-status":
+                return runQueryServiceStatus();
             case "get-bound-package":
                 return getBoundPackageName();
             case "set-temporary-service":
@@ -95,13 +124,9 @@
     private int runStartDetection() {
         final int userId = Integer.parseInt(getNextArgRequired());
         final String packageName = getNextArgRequired();
-        AmbientContextEventRequest request = new AmbientContextEventRequest.Builder()
-                .addEventType(AmbientContextEvent.EVENT_COUGH)
-                .addEventType(AmbientContextEvent.EVENT_SNORE)
-                .build();
-
-        mService.startAmbientContextEvent(userId, request, packageName,
-                sTestableCallbackInternal.createRemoteCallback());
+        mService.startDetection(userId, REQUEST, packageName,
+                sTestableCallbackInternal.createRemoteDetectionResultCallback(),
+                sTestableCallbackInternal.createRemoteStatusCallback());
         return 0;
     }
 
@@ -112,8 +137,20 @@
         return 0;
     }
 
+    private int runQueryServiceStatus() {
+        final int userId = Integer.parseInt(getNextArgRequired());
+        final String packageName = getNextArgRequired();
+        int[] types = new int[] {
+                AmbientContextEvent.EVENT_COUGH,
+                AmbientContextEvent.EVENT_SNORE};
+        mService.queryServiceStatus(userId, packageName, types,
+                sTestableCallbackInternal.createRemoteStatusCallback());
+        return 0;
+    }
+
     private int getLastStatusCode() {
-        AmbientContextEventResponse lastResponse = sTestableCallbackInternal.getLastResponse();
+        AmbientContextDetectionServiceStatus lastResponse =
+                sTestableCallbackInternal.getLastStatus();
         if (lastResponse == null) {
             return -1;
         }
@@ -130,6 +167,7 @@
         pw.println("  start-detection USER_ID PACKAGE_NAME: Starts AmbientContextEvent detection.");
         pw.println("  stop-detection USER_ID: Stops AmbientContextEvent detection.");
         pw.println("  get-last-status-code: Prints the latest request status code.");
+        pw.println("  query-event-status USER_ID PACKAGE_NAME: Prints the event status code.");
         pw.println("  get-bound-package USER_ID:"
                 + "     Print the bound package that implements the service.");
         pw.println("  set-temporary-service USER_ID [COMPONENT_NAME DURATION]");
diff --git a/services/core/java/com/android/server/ambientcontext/RemoteAmbientContextDetectionService.java b/services/core/java/com/android/server/ambientcontext/RemoteAmbientContextDetectionService.java
index 5cc29b3..f42080d 100644
--- a/services/core/java/com/android/server/ambientcontext/RemoteAmbientContextDetectionService.java
+++ b/services/core/java/com/android/server/ambientcontext/RemoteAmbientContextDetectionService.java
@@ -20,6 +20,7 @@
 import static android.content.Context.BIND_INCLUDE_CAPABILITIES;
 
 import android.annotation.NonNull;
+import android.app.ambientcontext.AmbientContextEvent;
 import android.app.ambientcontext.AmbientContextEventRequest;
 import android.content.ComponentName;
 import android.content.Context;
@@ -53,13 +54,15 @@
      *
      * @param request The request with events to detect, and optional detection options.
      * @param packageName The app package that requested the detection
-     * @param callback callback for detection results
+     * @param detectionResultCallback callback for detection results
+     * @param statusCallback callback for service status
      */
     public void startDetection(
             @NonNull AmbientContextEventRequest request, String packageName,
-            RemoteCallback callback) {
+            RemoteCallback detectionResultCallback, RemoteCallback statusCallback) {
         Slog.i(TAG, "Start detection for " + request.getEventTypes());
-        post(service -> service.startDetection(request, packageName, callback));
+        post(service -> service.startDetection(request, packageName, detectionResultCallback,
+                statusCallback));
     }
 
     /**
@@ -71,4 +74,15 @@
         Slog.i(TAG, "Stop detection for " + packageName);
         post(service -> service.stopDetection(packageName));
     }
+
+    /**
+     * Asks the implementation to return the event status for the package.
+     */
+    public void queryServiceStatus(
+            @AmbientContextEvent.EventCode int[] eventTypes,
+            String packageName,
+            RemoteCallback callback) {
+        Slog.i(TAG, "Query status for " + packageName);
+        post(service -> service.queryServiceStatus(eventTypes, packageName, callback));
+    }
 }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index b814782..b2f500a 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -422,7 +422,7 @@
             addFreshWindowToken();
             return new InputBindResult(
                     InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
-                    null, null, mCurId, mCurSeq, false);
+                    null, null, null, mCurId, mCurSeq, false);
         }
 
         Slog.w(InputMethodManagerService.TAG,
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
index 80c83e9..29dcdfa 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
@@ -25,6 +25,7 @@
 
 import com.android.internal.inputmethod.SoftInputShowHideReason;
 import com.android.internal.view.IInlineSuggestionsRequestCallback;
+import com.android.internal.view.IInputMethodSession;
 import com.android.internal.view.InlineSuggestionsRequestInfo;
 import com.android.server.LocalServices;
 
@@ -149,6 +150,24 @@
     public abstract void updateImeWindowStatus(boolean disableImeIcon);
 
     /**
+     * Callback when the IInputMethodSession from the accessibility service with the specified
+     * accessibilityConnectionId is created.
+     *
+     * @param accessibilityConnectionId The connection id of the accessibility service.
+     * @param session The session passed back from the accessibility service.
+     */
+    public abstract void onSessionForAccessibilityCreated(int accessibilityConnectionId,
+            IInputMethodSession session);
+
+    /**
+     * Unbind the accessibility service with the specified accessibilityConnectionId from current
+     * client.
+     *
+     * @param accessibilityConnectionId The connection id of the accessibility service.
+     */
+    public abstract void unbindAccessibilityFromCurrentClient(int accessibilityConnectionId);
+
+    /**
      * Fake implementation of {@link InputMethodManagerInternal}.  All the methods do nothing.
      */
     private static final InputMethodManagerInternal NOP =
@@ -211,6 +230,15 @@
                 @Override
                 public void updateImeWindowStatus(boolean disableImeIcon) {
                 }
+
+                @Override
+                public void onSessionForAccessibilityCreated(int accessibilityConnectionId,
+                        IInputMethodSession session) {
+                }
+
+                @Override
+                public void unbindAccessibilityFromCurrentClient(int accessibilityConnectionId) {
+                }
             };
 
     /**
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index ba15a04..7068ed1 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -94,6 +94,7 @@
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.DeadObjectException;
 import android.os.Debug;
 import android.os.Handler;
 import android.os.IBinder;
@@ -120,6 +121,7 @@
 import android.util.PrintWriterPrinter;
 import android.util.Printer;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.proto.ProtoOutputStream;
 import android.view.IWindowManager;
 import android.view.InputChannel;
@@ -171,6 +173,7 @@
 import com.android.internal.view.IInputMethodSession;
 import com.android.internal.view.IInputSessionCallback;
 import com.android.internal.view.InlineSuggestionsRequestInfo;
+import com.android.server.AccessibilityManagerInternal;
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
 import com.android.server.ServiceThread;
@@ -228,7 +231,9 @@
     private static final int MSG_START_HANDWRITING = 1100;
 
     private static final int MSG_UNBIND_CLIENT = 3000;
+    private static final int MSG_UNBIND_ACCESSIBILITY_SERVICE = 3001;
     private static final int MSG_BIND_CLIENT = 3010;
+    private static final int MSG_BIND_ACCESSIBILITY_SERVICE = 3011;
     private static final int MSG_SET_ACTIVE = 3020;
     private static final int MSG_SET_INTERACTIVE = 3030;
     private static final int MSG_REPORT_FULLSCREEN_MODE = 3045;
@@ -351,6 +356,33 @@
         }
     }
 
+    /**
+     * Record session state for an accessibility service.
+     */
+    private static class AccessibilitySessionState {
+        final ClientState mClient;
+        // Id of the accessibility service.
+        final int mId;
+
+        public IInputMethodSession mSession;
+
+        @Override
+        public String toString() {
+            return "AccessibilitySessionState{uid " + mClient.uid + " pid " + mClient.pid
+                    + " id " + Integer.toHexString(mId)
+                    + " session " + Integer.toHexString(
+                    System.identityHashCode(mSession))
+                    + "}";
+        }
+
+        AccessibilitySessionState(ClientState client, int id,
+                IInputMethodSession session) {
+            mClient = client;
+            mId = id;
+            mSession = session;
+        }
+    }
+
     private static final class ClientDeathRecipient implements IBinder.DeathRecipient {
         private final InputMethodManagerService mImms;
         private final IInputMethodClient mClient;
@@ -376,7 +408,9 @@
         final ClientDeathRecipient clientDeathRecipient;
 
         boolean sessionRequested;
+        boolean mSessionRequestedForAccessibility;
         SessionState curSession;
+        SparseArray<AccessibilitySessionState> mAccessibilitySessions = new SparseArray<>();
 
         @Override
         public String toString() {
@@ -637,10 +671,16 @@
     boolean mBoundToMethod;
 
     /**
+     * Have we called bindInput() for accessibility services?
+     */
+    boolean mBoundToAccessibility;
+
+     /**
      * Currently enabled session.
      */
     @GuardedBy("ImfLock.class")
     SessionState mEnabledSession;
+    SparseArray<AccessibilitySessionState> mEnabledAccessibilitySessions = new SparseArray<>();
 
     /**
      * True if the device is currently interactive with user.  The value is true initially.
@@ -2188,6 +2228,7 @@
             if (cs != null) {
                 client.asBinder().unlinkToDeath(cs.clientDeathRecipient, 0);
                 clearClientSessionLocked(cs);
+                clearClientSessionForAccessibilityLocked(cs);
                 if (mCurClient == cs) {
                     hideCurrentInputLocked(
                             mCurFocusedWindow, 0, null, SoftInputShowHideReason.HIDE_REMOVE_CLIENT);
@@ -2195,9 +2236,13 @@
                         mBoundToMethod = false;
                         IInputMethodInvoker curMethod = getCurMethodLocked();
                         if (curMethod != null) {
+                            // When we unbind input, we are unbinding the client, so we always
+                            // unbind ime and a11y together.
                             curMethod.unbindInput();
+                            AccessibilityManagerInternal.get().unbindInput();
                         }
                     }
+                    mBoundToAccessibility = false;
                     mCurClient = null;
                 }
                 if (mCurFocusedWindowClient == cs) {
@@ -2216,6 +2261,24 @@
     }
 
     @NonNull
+    private Message obtainMessageOOO(int what, Object arg1, Object arg2, Object arg3) {
+        SomeArgs args = SomeArgs.obtain();
+        args.arg1 = arg1;
+        args.arg2 = arg2;
+        args.arg3 = arg3;
+        return mHandler.obtainMessage(what, 0, 0, args);
+    }
+
+    @NonNull
+    private Message obtainMessageIIOO(int what, int arg1, int arg2,
+            Object arg3, Object arg4) {
+        SomeArgs args = SomeArgs.obtain();
+        args.arg1 = arg3;
+        args.arg2 = arg4;
+        return mHandler.obtainMessage(what, arg1, arg2, args);
+    }
+
+    @NonNull
     private Message obtainMessageIIIO(int what, int argi1, int argi2, int argi3, Object arg1) {
         final SomeArgs args = SomeArgs.obtain();
         args.arg1 = arg1;
@@ -2252,13 +2315,18 @@
                     curMethod.unbindInput();
                 }
             }
+            mBoundToAccessibility = false;
 
+            // Since we set active false to current client and set mCurClient to null, let's unbind
+            // all accessibility too. That means, when input method get disconnected (including
+            // switching ime), we also unbind accessibility
             scheduleSetActiveToClient(mCurClient, false /* active */, false /* fullscreen */,
                     false /* reportToImeController */);
             executeOrSendMessage(mCurClient.client, mHandler.obtainMessage(
                     MSG_UNBIND_CLIENT, getSequenceNumberLocked(), unbindClientReason,
                     mCurClient.client));
             mCurClient.sessionRequested = false;
+            mCurClient.mSessionRequestedForAccessibility = false;
             mCurClient = null;
 
             mMenuController.hideInputMethodMenuLocked();
@@ -2340,11 +2408,63 @@
         final InputMethodInfo curInputMethodInfo = mMethodMap.get(curId);
         final boolean suppressesSpellChecker =
                 curInputMethodInfo != null && curInputMethodInfo.suppressesSpellChecker();
+        final SparseArray<IInputMethodSession> accessibilityInputMethodSessions =
+                createAccessibilityInputMethodSessions(mCurClient.mAccessibilitySessions);
         return new InputBindResult(InputBindResult.ResultCode.SUCCESS_WITH_IME_SESSION,
-                session.session, (session.channel != null ? session.channel.dup() : null),
+                session.session, accessibilityInputMethodSessions,
+                (session.channel != null ? session.channel.dup() : null),
                 curId, getSequenceNumberLocked(), suppressesSpellChecker);
     }
 
+    @GuardedBy("ImfLock.class")
+    @Nullable
+    InputBindResult attachNewAccessibilityLocked(@StartInputReason int startInputReason,
+            boolean initial, int id) {
+        if (!mBoundToAccessibility) {
+            AccessibilityManagerInternal.get().bindInput(mCurClient.binding);
+            mBoundToAccessibility = true;
+        }
+
+        // TODO(b/187453053): grantImplicitAccess to accessibility services access? if so, need to
+        //  record accessibility services uid.
+
+        final AccessibilitySessionState accessibilitySession =
+                mCurClient.mAccessibilitySessions.get(id);
+        // We don't start input when session for a11y is created. We start input when
+        // input method start input, a11y manager service is always on.
+        if (startInputReason != StartInputReason.SESSION_CREATED_BY_ACCESSIBILITY) {
+            final Binder startInputToken = new Binder();
+            setEnabledSessionForAccessibilityLocked(mCurClient.mAccessibilitySessions);
+            AccessibilityManagerInternal.get().startInput(startInputToken, mCurInputContext,
+                    mCurAttribute, !initial /* restarting */);
+        }
+
+        if (accessibilitySession != null) {
+            final SessionState session = mCurClient.curSession;
+            IInputMethodSession imeSession = session == null ? null : session.session;
+            final SparseArray<IInputMethodSession> accessibilityInputMethodSessions =
+                    createAccessibilityInputMethodSessions(mCurClient.mAccessibilitySessions);
+            return new InputBindResult(
+                    InputBindResult.ResultCode.SUCCESS_WITH_ACCESSIBILITY_SESSION,
+                    imeSession, accessibilityInputMethodSessions, null,
+                    getCurIdLocked(), getSequenceNumberLocked(), false);
+        }
+        return null;
+    }
+
+    private SparseArray<IInputMethodSession> createAccessibilityInputMethodSessions(
+            SparseArray<AccessibilitySessionState> accessibilitySessions) {
+        final SparseArray<IInputMethodSession> accessibilityInputMethodSessions =
+                new SparseArray<>();
+        if (accessibilitySessions != null) {
+            for (int i = 0; i < accessibilitySessions.size(); i++) {
+                accessibilityInputMethodSessions.append(accessibilitySessions.keyAt(i),
+                        accessibilitySessions.valueAt(i).mSession);
+            }
+        }
+        return accessibilityInputMethodSessions;
+    }
+
     /**
      * Called by {@link #startInputOrWindowGainedFocusInternalLocked} to bind/unbind/attach the
      * selected InputMethod to the given focused IME client.
@@ -2370,7 +2490,7 @@
             // party code.
             return new InputBindResult(
                     InputBindResult.ResultCode.ERROR_SYSTEM_NOT_READY,
-                    null, null, selectedMethodId, getSequenceNumberLocked(), false);
+                    null, null, null, selectedMethodId, getSequenceNumberLocked(), false);
         }
 
         if (!InputMethodUtils.checkIfPackageBelongsToUid(mAppOpsManager, cs.uid,
@@ -2422,6 +2542,17 @@
             if (cs.curSession != null) {
                 // Fast case: if we are already connected to the input method,
                 // then just return it.
+                // This doesn't mean a11y sessions are there. When a11y service is
+                // enabled while this client is switched out, this client doesn't have the session.
+                // A11yManagerService will only request missing sessions (will not request existing
+                // sessions again). Note when an a11y service is disabled, it will clear its
+                // session from all clients, so we don't need to worry about disabled a11y services.
+                cs.mSessionRequestedForAccessibility = false;
+                requestClientSessionForAccessibilityLocked(cs);
+                // we can always attach to accessibility because AccessibilityManagerService is
+                // always on.
+                attachNewAccessibilityLocked(startInputReason,
+                        (startInputFlags & StartInputFlags.INITIAL_CONNECTION) != 0, -1);
                 return attachNewInputLocked(startInputReason,
                         (startInputFlags & StartInputFlags.INITIAL_CONNECTION) != 0);
             }
@@ -2464,9 +2595,10 @@
                 // Return to client, and we will get back with it when
                 // we have had a session made for it.
                 requestClientSessionLocked(cs);
+                requestClientSessionForAccessibilityLocked(cs);
                 return new InputBindResult(
                         InputBindResult.ResultCode.SUCCESS_WAITING_IME_SESSION,
-                        null, null, getCurIdLocked(), getSequenceNumberLocked(), false);
+                        null, null, null, getCurIdLocked(), getSequenceNumberLocked(), false);
             } else {
                 long bindingDuration = SystemClock.uptimeMillis() - getLastBindTimeLocked();
                 if (bindingDuration < TIME_TO_RECONNECT) {
@@ -2479,7 +2611,7 @@
                     // to see if we can get back in touch with the service.
                     return new InputBindResult(
                             InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
-                            null, null, getCurIdLocked(), getSequenceNumberLocked(), false);
+                            null, null, null, getCurIdLocked(), getSequenceNumberLocked(), false);
                 } else {
                     EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME,
                             getSelectedMethodIdLocked(), bindingDuration, 0);
@@ -2565,6 +2697,8 @@
                                 method, session, channel);
                         InputBindResult res = attachNewInputLocked(
                                 StartInputReason.SESSION_CREATED_BY_IME, true);
+                        attachNewAccessibilityLocked(StartInputReason.SESSION_CREATED_BY_IME,
+                                true, -1);
                         if (res.method != null) {
                             executeOrSendMessage(mCurClient.client, obtainMessageOO(
                                     MSG_BIND_CLIENT, mCurClient.client, res));
@@ -2602,7 +2736,9 @@
     void reRequestCurrentClientSessionLocked() {
         if (mCurClient != null) {
             clearClientSessionLocked(mCurClient);
+            clearClientSessionForAccessibilityLocked(mCurClient);
             requestClientSessionLocked(mCurClient);
+            requestClientSessionForAccessibilityLocked(mCurClient);
         }
     }
 
@@ -2646,6 +2782,19 @@
     }
 
     @GuardedBy("ImfLock.class")
+    void requestClientSessionForAccessibilityLocked(ClientState cs) {
+        if (!cs.mSessionRequestedForAccessibility) {
+            if (DEBUG) Slog.v(TAG, "Creating new accessibility sessions for client " + cs);
+            cs.mSessionRequestedForAccessibility = true;
+            ArraySet<Integer> ignoreSet = new ArraySet<>();
+            for (int i = 0; i < cs.mAccessibilitySessions.size(); i++) {
+                ignoreSet.add(cs.mAccessibilitySessions.keyAt(i));
+            }
+            AccessibilityManagerInternal.get().createImeSession(ignoreSet);
+        }
+    }
+
+    @GuardedBy("ImfLock.class")
     void clearClientSessionLocked(ClientState cs) {
         finishSessionLocked(cs.curSession);
         cs.curSession = null;
@@ -2653,6 +2802,24 @@
     }
 
     @GuardedBy("ImfLock.class")
+    void clearClientSessionForAccessibilityLocked(ClientState cs) {
+        for (int i = 0; i < cs.mAccessibilitySessions.size(); i++) {
+            finishSessionForAccessibilityLocked(cs.mAccessibilitySessions.valueAt(i));
+        }
+        cs.mAccessibilitySessions.clear();
+        cs.mSessionRequestedForAccessibility = false;
+    }
+
+    @GuardedBy("ImfLock.class")
+    void clearClientSessionForAccessibilityLocked(ClientState cs, int id) {
+        AccessibilitySessionState session = cs.mAccessibilitySessions.get(id);
+        if (session != null) {
+            finishSessionForAccessibilityLocked(session);
+            cs.mAccessibilitySessions.remove(id);
+        }
+    }
+
+    @GuardedBy("ImfLock.class")
     private void finishSessionLocked(SessionState sessionState) {
         if (sessionState != null) {
             if (sessionState.session != null) {
@@ -2672,15 +2839,34 @@
     }
 
     @GuardedBy("ImfLock.class")
+    private void finishSessionForAccessibilityLocked(AccessibilitySessionState sessionState) {
+        if (sessionState != null) {
+            if (sessionState.mSession != null) {
+                try {
+                    sessionState.mSession.finishSession();
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Session failed to close due to remote exception", e);
+                }
+                sessionState.mSession = null;
+            }
+        }
+    }
+
+    @GuardedBy("ImfLock.class")
     void clearClientSessionsLocked() {
         if (getCurMethodLocked() != null) {
             final int numClients = mClients.size();
             for (int i = 0; i < numClients; ++i) {
                 clearClientSessionLocked(mClients.valueAt(i));
+                clearClientSessionForAccessibilityLocked(mClients.valueAt(i));
             }
 
             finishSessionLocked(mEnabledSession);
+            for (int i = 0; i < mEnabledAccessibilitySessions.size(); i++) {
+                finishSessionForAccessibilityLocked(mEnabledAccessibilitySessions.valueAt(i));
+            }
             mEnabledSession = null;
+            mEnabledAccessibilitySessions.clear();
             scheduleNotifyImeUidToAudioService(Process.INVALID_UID);
         }
         hideStatusBarIconLocked();
@@ -3455,7 +3641,7 @@
             }
             return new InputBindResult(
                     InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
-                    null, null, null, -1, false);
+                    null, null, null, null, -1, false);
         }
 
         mCurFocusedWindow = windowToken;
@@ -4250,6 +4436,41 @@
         }
     }
 
+    @GuardedBy("ImfLock.class")
+    void setEnabledSessionForAccessibilityLocked(
+            SparseArray<AccessibilitySessionState> accessibilitySessions) {
+        // mEnabledAccessibilitySessions could the same object as accessibilitySessions.
+        SparseArray<IInputMethodSession> disabledSessions = new SparseArray<>();
+        for (int i = 0; i < mEnabledAccessibilitySessions.size(); i++) {
+            if (!accessibilitySessions.contains(mEnabledAccessibilitySessions.keyAt(i))) {
+                AccessibilitySessionState sessionState  = mEnabledAccessibilitySessions.valueAt(i);
+                if (sessionState != null) {
+                    disabledSessions.append(mEnabledAccessibilitySessions.keyAt(i),
+                            sessionState.mSession);
+                }
+            }
+        }
+        if (disabledSessions.size() > 0) {
+            AccessibilityManagerInternal.get().setImeSessionEnabled(disabledSessions,
+                    false);
+        }
+        SparseArray<IInputMethodSession> enabledSessions = new SparseArray<>();
+        for (int i = 0; i < accessibilitySessions.size(); i++) {
+            if (!mEnabledAccessibilitySessions.contains(accessibilitySessions.keyAt(i))) {
+                AccessibilitySessionState sessionState = accessibilitySessions.valueAt(i);
+                if (sessionState != null) {
+                    enabledSessions.append(accessibilitySessions.keyAt(i), sessionState.mSession);
+                }
+            }
+        }
+        if (enabledSessions.size() > 0) {
+            AccessibilityManagerInternal.get().setImeSessionEnabled(enabledSessions,
+                    true);
+        }
+        mEnabledAccessibilitySessions = accessibilitySessions;
+    }
+
+    @SuppressWarnings("unchecked")
     @UiThread
     @Override
     public boolean handleMessage(Message msg) {
@@ -4319,13 +4540,34 @@
 
             // ---------------------------------------------------------
 
-            case MSG_UNBIND_CLIENT:
+            case MSG_UNBIND_CLIENT: {
                 try {
-                    ((IInputMethodClient)msg.obj).onUnbindMethod(msg.arg1, msg.arg2);
+                    // This unbinds all accessibility services too.
+                    ((IInputMethodClient) msg.obj).onUnbindMethod(msg.arg1, msg.arg2);
                 } catch (RemoteException e) {
                     // There is nothing interesting about the last client dying.
+                    if (!(e instanceof DeadObjectException)) {
+                        Slog.w(TAG, "RemoteException when unbinding input method service or"
+                                + "accessibility services");
+                    }
                 }
                 return true;
+            }
+            case MSG_UNBIND_ACCESSIBILITY_SERVICE: {
+                args = (SomeArgs) msg.obj;
+                IInputMethodClient client = (IInputMethodClient) args.arg1;
+                int id = (int) args.arg2;
+                try {
+                    client.onUnbindAccessibilityService(msg.arg1, id);
+                } catch (RemoteException e) {
+                    // There is nothing interesting about the last client dying.
+                    if (!(e instanceof DeadObjectException)) {
+                        Slog.w(TAG, "RemoteException when unbinding accessibility services");
+                    }
+                }
+                args.recycle();
+                return true;
+            }
             case MSG_BIND_CLIENT: {
                 args = (SomeArgs)msg.obj;
                 IInputMethodClient client = (IInputMethodClient)args.arg1;
@@ -4344,6 +4586,25 @@
                 args.recycle();
                 return true;
             }
+            case MSG_BIND_ACCESSIBILITY_SERVICE: {
+                args = (SomeArgs) msg.obj;
+                IInputMethodClient client = (IInputMethodClient) args.arg1;
+                InputBindResult res = (InputBindResult) args.arg2;
+                int id = (int) args.arg3;
+                try {
+                    client.onBindAccessibilityService(res, id);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Client died receiving input method " + args.arg2);
+                } finally {
+                    // Dispose the channel if the accessibility service is not local to this process
+                    // because the remote proxy will get its own copy when unparceled.
+                    if (res.channel != null && Binder.isProxy(client)) {
+                        res.channel.dispose();
+                    }
+                }
+                args.recycle();
+                return true;
+            }
             case MSG_SET_ACTIVE: {
                 args = (SomeArgs) msg.obj;
                 final ClientState clientState = (ClientState) args.arg1;
@@ -5025,6 +5286,59 @@
             mHandler.obtainMessage(MSG_UPDATE_IME_WINDOW_STATUS, disableImeIcon ? 1 : 0, 0)
                     .sendToTarget();
         }
+
+        @Override
+        public void onSessionForAccessibilityCreated(int accessibilityConnectionId,
+                IInputMethodSession session) {
+            synchronized (ImfLock.class) {
+                if (mCurClient != null) {
+                    clearClientSessionForAccessibilityLocked(mCurClient, accessibilityConnectionId);
+                    mCurClient.mAccessibilitySessions.put(accessibilityConnectionId,
+                            new AccessibilitySessionState(mCurClient, accessibilityConnectionId,
+                                    session));
+                    InputBindResult res = attachNewAccessibilityLocked(
+                            StartInputReason.SESSION_CREATED_BY_ACCESSIBILITY, true,
+                            accessibilityConnectionId);
+                    executeOrSendMessage(mCurClient.client, obtainMessageOOO(
+                            MSG_BIND_ACCESSIBILITY_SERVICE, mCurClient.client, res,
+                            accessibilityConnectionId));
+                }
+            }
+        }
+
+        @Override
+        public void unbindAccessibilityFromCurrentClient(int accessibilityConnectionId) {
+            synchronized (ImfLock.class) {
+                if (mCurClient != null) {
+                    if (DEBUG) {
+                        Slog.v(TAG, "unbindAccessibilityFromCurrentClientLocked: client="
+                                + mCurClient.client.asBinder());
+                    }
+                    // A11yManagerService unbinds the disabled accessibility service. We don't need
+                    // to do it here.
+                    @UnbindReason int unbindClientReason =
+                            UnbindReason.ACCESSIBILITY_SERVICE_DISABLED;
+                    executeOrSendMessage(mCurClient.client, obtainMessageIIOO(
+                            MSG_UNBIND_ACCESSIBILITY_SERVICE, getSequenceNumberLocked(),
+                            unbindClientReason, mCurClient.client, accessibilityConnectionId));
+                }
+                // We only have sessions when we bound to an input method. Remove this session
+                // from all clients.
+                if (getCurMethodLocked() != null) {
+                    final int numClients = mClients.size();
+                    for (int i = 0; i < numClients; ++i) {
+                        clearClientSessionForAccessibilityLocked(mClients.valueAt(i),
+                                accessibilityConnectionId);
+                    }
+                    AccessibilitySessionState session = mEnabledAccessibilitySessions.get(
+                            accessibilityConnectionId);
+                    if (session != null) {
+                        finishSessionForAccessibilityLocked(session);
+                        mEnabledAccessibilitySessions.remove(accessibilityConnectionId);
+                    }
+                }
+            }
+        }
     }
 
     @BinderThread
@@ -5184,6 +5498,8 @@
                 p.println("    client=" + ci.client);
                 p.println("    inputContext=" + ci.inputContext);
                 p.println("    sessionRequested=" + ci.sessionRequested);
+                p.println("    sessionRequestedForAccessibility="
+                        + ci.mSessionRequestedForAccessibility);
                 p.println("    curSession=" + ci.curSession);
             }
             p.println("  mCurMethodId=" + getSelectedMethodIdLocked());
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 3abe5e2..4d3e438 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -148,6 +148,8 @@
 import com.android.server.locksettings.SyntheticPasswordManager.TokenType;
 import com.android.server.locksettings.recoverablekeystore.RecoverableKeyStoreManager;
 import com.android.server.pm.UserManagerInternal;
+import com.android.server.utils.Watchable;
+import com.android.server.utils.Watcher;
 import com.android.server.wm.WindowManagerInternal;
 
 import libcore.util.HexEncoding;
@@ -230,6 +232,7 @@
     protected final Handler mHandler;
     @VisibleForTesting
     protected final LockSettingsStorage mStorage;
+    private final Watcher mStorageWatcher;
     private final LockSettingsStrongAuth mStrongAuth;
     private final SynchronizedStrongAuthTracker mStrongAuthTracker;
     private final BiometricDeferredQueue mBiometricDeferredQueue;
@@ -573,6 +576,12 @@
         }
     }
 
+    private class StorageWatcher extends Watcher {
+        public void onChange(Watchable what) {
+            LockSettingsService.this.onChange();
+        }
+    }
+
     public LockSettingsService(Context context) {
         this(new Injector(context));
     }
@@ -614,6 +623,16 @@
                 mStorage);
 
         LocalServices.addService(LockSettingsInternal.class, new LocalService());
+
+        mStorageWatcher = new StorageWatcher();
+        mStorage.registerObserver(mStorageWatcher);
+    }
+
+    /**
+     * Invalidate caches if the storage has changed.
+     */
+    private void onChange() {
+        LockPatternUtils.invalidateCredentialTypeCache();
     }
 
     /**
@@ -1278,6 +1297,11 @@
                 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userId);
     }
 
+    /**
+     * This API is cached; whenever the result would change,
+     * {@link com.android.internal.widget.LockPatternUtils#invalidateCredentialTypeCache}
+     * must be called.
+     */
     @Override
     public int getCredentialType(int userId) {
         checkPasswordHavePermission(userId);
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
index f69a3bd..f9db5cf 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
@@ -47,6 +47,7 @@
 import com.android.internal.widget.LockPatternUtils.CredentialType;
 import com.android.server.LocalServices;
 import com.android.server.PersistentDataBlockManagerInternal;
+import com.android.server.utils.WatchableImpl;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -66,7 +67,7 @@
 /**
  * Storage for the lock settings service.
  */
-class LockSettingsStorage {
+class LockSettingsStorage extends WatchableImpl {
 
     private static final String TAG = "LockSettingsStorage";
     private static final String TABLE = "locksettings";
@@ -173,7 +174,7 @@
         } finally {
             db.endTransaction();
         }
-
+        dispatchChange(this);
     }
 
     @VisibleForTesting
@@ -221,7 +222,7 @@
         } finally {
             db.endTransaction();
         }
-
+        dispatchChange(this);
     }
 
     public void prefetchUser(int userId) {
@@ -412,6 +413,7 @@
                 }
             }
             mCache.putFile(name, hash);
+            dispatchChange(this);
         }
     }
 
@@ -423,6 +425,7 @@
                 file.delete();
                 mCache.putFile(name, null);
             }
+            dispatchChange(this);
         }
     }
 
@@ -500,6 +503,7 @@
                 Slog.w(TAG, "Failed to zeroize " + path, e);
             } finally {
                 file.delete();
+                dispatchChange(this);
             }
             mCache.putFile(path, null);
         }
@@ -587,6 +591,7 @@
         } finally {
             db.endTransaction();
         }
+        dispatchChange(this);
     }
 
     private void deleteFilesAndRemoveCache(String... names) {
@@ -595,6 +600,7 @@
             if (file.exists()) {
                 file.delete();
                 mCache.putFile(name, null);
+                dispatchChange(this);
             }
         }
     }
@@ -675,6 +681,7 @@
         }
         persistentDataBlock.setFrpCredentialHandle(PersistentData.toBytes(
                 persistentType, userId, qualityForUi, payload));
+        dispatchChange(this);
     }
 
     public PersistentData readPersistentDataBlock() {
diff --git a/services/core/java/com/android/server/logcat/LogAccessConfirmationActivity.java b/services/core/java/com/android/server/logcat/LogAccessConfirmationActivity.java
deleted file mode 100644
index 6b442a6..0000000
--- a/services/core/java/com/android/server/logcat/LogAccessConfirmationActivity.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2022 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.logcat;
-
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentSender;
-import android.os.Bundle;
-import android.os.ServiceManager;
-import android.os.logcat.ILogcatManagerService;
-import android.util.Slog;
-import android.view.View;
-import android.widget.TextView;
-
-import com.android.internal.R;
-import com.android.internal.app.AlertActivity;
-import com.android.internal.app.AlertController;
-
-
-/**
- * This dialog is shown to the user before an activity in a harmful app is launched.
- *
- * See {@code PackageManager.setLogcatAppInfo} for more info.
- */
-public class LogAccessConfirmationActivity extends AlertActivity implements
-        DialogInterface.OnClickListener {
-    private static final String TAG = LogAccessConfirmationActivity.class.getSimpleName();
-
-    private String mPackageName;
-    private IntentSender mTarget;
-    private final ILogcatManagerService mLogcatManagerService =
-            ILogcatManagerService.Stub.asInterface(ServiceManager.getService("logcat"));
-
-    private int mUid;
-    private int mGid;
-    private int mPid;
-    private int mFd;
-
-    private static final String EXTRA_UID = "uid";
-    private static final String EXTRA_GID = "gid";
-    private static final String EXTRA_PID = "pid";
-    private static final String EXTRA_FD = "fd";
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        final Intent intent = getIntent();
-        mPackageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
-        mUid = intent.getIntExtra("uid", 0);
-        mGid = intent.getIntExtra("gid", 0);
-        mPid = intent.getIntExtra("pid", 0);
-        mFd = intent.getIntExtra("fd", 0);
-
-        final AlertController.AlertParams p = mAlertParams;
-        p.mTitle = getString(R.string.log_access_confirmation_title);
-        p.mView = createView();
-
-        p.mPositiveButtonText = getString(R.string.log_access_confirmation_allow);
-        p.mPositiveButtonListener = this;
-        p.mNegativeButtonText = getString(R.string.log_access_confirmation_deny);
-        p.mNegativeButtonListener = this;
-
-        mAlert.installContent(mAlertParams);
-    }
-
-    private View createView() {
-        final View view = getLayoutInflater().inflate(R.layout.harmful_app_warning_dialog,
-                null /*root*/);
-        ((TextView) view.findViewById(R.id.app_name_text))
-                .setText(mPackageName);
-        ((TextView) view.findViewById(R.id.message))
-                .setText(getIntent().getExtras().getString("body"));
-        return view;
-    }
-
-    @Override
-    public void onClick(DialogInterface dialog, int which) {
-        switch (which) {
-            case DialogInterface.BUTTON_POSITIVE:
-                try {
-                    mLogcatManagerService.approve(mUid, mGid, mPid, mFd);
-                } catch (Throwable t) {
-                    Slog.e(TAG, "Could not start the LogcatManagerService.", t);
-                }
-                finish();
-                break;
-            case DialogInterface.BUTTON_NEGATIVE:
-                try {
-                    mLogcatManagerService.decline(mUid, mGid, mPid, mFd);
-                } catch (Throwable t) {
-                    Slog.e(TAG, "Could not start the LogcatManagerService.", t);
-                }
-                finish();
-                break;
-        }
-    }
-
-    /**
-     * Create the Intent for a LogAccessConfirmationActivity.
-     */
-    public static Intent createIntent(Context context, String targetPackageName,
-            IntentSender target, int uid, int gid, int pid, int fd) {
-        final Intent intent = new Intent();
-        intent.setClass(context, LogAccessConfirmationActivity.class);
-        intent.putExtra(Intent.EXTRA_PACKAGE_NAME, targetPackageName);
-        intent.putExtra(EXTRA_UID, uid);
-        intent.putExtra(EXTRA_GID, gid);
-        intent.putExtra(EXTRA_PID, pid);
-        intent.putExtra(EXTRA_FD, fd);
-
-        return intent;
-    }
-
-}
diff --git a/services/core/java/com/android/server/logcat/LogcatManagerService.java b/services/core/java/com/android/server/logcat/LogcatManagerService.java
index 7832296..ff6372ae 100644
--- a/services/core/java/com/android/server/logcat/LogcatManagerService.java
+++ b/services/core/java/com/android/server/logcat/LogcatManagerService.java
@@ -16,36 +16,20 @@
 
 package com.android.server.logcat;
 
-import android.annotation.NonNull;
-import android.app.ActivityManager;
-import android.app.ActivityManager.RunningAppProcessInfo;
-import android.app.ActivityManagerInternal;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
 import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.ILogd;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.UserHandle;
 import android.os.logcat.ILogcatManagerService;
 import android.util.Slog;
 
-import com.android.internal.R;
-import com.android.internal.notification.SystemNotificationChannels;
-import com.android.internal.util.ArrayUtils;
-import com.android.server.LocalServices;
 import com.android.server.SystemService;
 
-import java.util.Arrays;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
 /**
- * Service responsible for managing the access to Logcat.
+ * Service responsible for manage the access to Logcat.
  */
 public final class LogcatManagerService extends SystemService {
 
@@ -54,43 +38,6 @@
     private final BinderService mBinderService;
     private final ExecutorService mThreadExecutor;
     private ILogd mLogdService;
-    private NotificationManager mNotificationManager;
-    private @NonNull ActivityManager mActivityManager;
-    private ActivityManagerInternal mActivityManagerInternal;
-    private static final int MAX_UID_IMPORTANCE_COUNT_LISTENER = 2;
-    private static int sUidImportanceListenerCount = 0;
-    private static final int AID_APP_UID = 10000;
-
-    // TODO This allowlist is just a temporary workaround for the tests:
-    //      FrameworksServicesTests
-    //      PlatformRuleTests
-    // After adapting the test suites, the allowlist will be removed in
-    // the upcoming bug fix patches.
-    private static final String[] ALLOWABLE_TESTING_PACKAGES = {
-            "android.platform.test.rule.tests",
-            "com.android.frameworks.servicestests"
-    };
-
-    // TODO Same as the above ALLOWABLE_TESTING_PACKAGES.
-    private boolean isAllowableTestingPackage(int uid) {
-        PackageManager pm = mContext.getPackageManager();
-
-        String[] packageNames = pm.getPackagesForUid(uid);
-
-        if (ArrayUtils.isEmpty(packageNames)) {
-            return false;
-        }
-
-        for (String name : packageNames) {
-            Slog.e(TAG, "isAllowableTestingPackage: " + name);
-
-            if (Arrays.asList(ALLOWABLE_TESTING_PACKAGES).contains(name)) {
-                return true;
-            }
-        }
-
-        return false;
-    };
 
     private final class BinderService extends ILogcatManagerService.Stub {
         @Override
@@ -104,197 +51,6 @@
             // the logd data access is finished.
             mThreadExecutor.execute(new LogdMonitor(uid, gid, pid, fd, false));
         }
-
-        @Override
-        public void approve(int uid, int gid, int pid, int fd) {
-            try {
-                getLogdService().approve(uid, gid, pid, fd);
-            } catch (RemoteException e) {
-                e.printStackTrace();
-            }
-        }
-
-        @Override
-        public void decline(int uid, int gid, int pid, int fd) {
-            try {
-                getLogdService().decline(uid, gid, pid, fd);
-            } catch (RemoteException e) {
-                e.printStackTrace();
-            }
-        }
-    }
-
-    private ILogd getLogdService() {
-        synchronized (LogcatManagerService.this) {
-            if (mLogdService == null) {
-                LogcatManagerService.this.addLogdService();
-            }
-            return mLogdService;
-        }
-    }
-
-    private String getBodyString(Context context, String callingPackage, int uid) {
-        PackageManager pm = context.getPackageManager();
-        try {
-            return context.getString(
-                com.android.internal.R.string.log_access_confirmation_body,
-                pm.getApplicationInfoAsUser(callingPackage, PackageManager.MATCH_DIRECT_BOOT_AUTO,
-                    UserHandle.getUserId(uid)).loadLabel(pm));
-        } catch (NameNotFoundException e) {
-            // App name is unknown.
-            return null;
-        }
-    }
-
-    private void sendNotification(int notificationId, String clientInfo, int uid, int gid, int pid,
-            int fd) {
-
-        final ActivityManagerInternal activityManagerInternal =
-                LocalServices.getService(ActivityManagerInternal.class);
-
-        PackageManager pm = mContext.getPackageManager();
-        String packageName = activityManagerInternal.getPackageNameByPid(pid);
-        if (packageName != null) {
-            String notificationBody = getBodyString(mContext, packageName, uid);
-
-            final Intent mIntent = LogAccessConfirmationActivity.createIntent(mContext,
-                    packageName, null, uid, gid, pid, fd);
-
-            if (notificationBody == null) {
-                // Decline the logd access if the nofitication body is unknown
-                Slog.e(TAG, "Unknown notification body, declining the logd access");
-                declineLogdAccess(uid, gid, pid, fd);
-                return;
-            }
-
-            // TODO Next version will replace notification with dialogue
-            // per UX guidance.
-            generateNotificationWithBodyContent(notificationId, clientInfo, notificationBody,
-                    mIntent);
-            return;
-
-        }
-
-        String[] packageNames = pm.getPackagesForUid(uid);
-
-        if (ArrayUtils.isEmpty(packageNames)) {
-            // Decline the logd access if the app name is unknown
-            Slog.e(TAG, "Unknown calling package name, declining the logd access");
-            declineLogdAccess(uid, gid, pid, fd);
-            return;
-        }
-
-        String firstPackageName = packageNames[0];
-
-        if (firstPackageName == null || firstPackageName.length() == 0) {
-            // Decline the logd access if the package name from uid is unknown
-            Slog.e(TAG, "Unknown calling package name, declining the logd access");
-            declineLogdAccess(uid, gid, pid, fd);
-            return;
-        }
-
-        String notificationBody = getBodyString(mContext, firstPackageName, uid);
-
-        final Intent mIntent = LogAccessConfirmationActivity.createIntent(mContext,
-                firstPackageName, null, uid, gid, pid, fd);
-
-        if (notificationBody == null) {
-            Slog.e(TAG, "Unknown notification body, declining the logd access");
-            declineLogdAccess(uid, gid, pid, fd);
-            return;
-        }
-
-        // TODO Next version will replace notification with dialogue
-        // per UX guidance.
-        generateNotificationWithBodyContent(notificationId, clientInfo,
-                notificationBody, mIntent);
-    }
-
-    private void declineLogdAccess(int uid, int gid, int pid, int fd) {
-        try {
-            getLogdService().decline(uid, gid, pid, fd);
-        } catch (RemoteException ex) {
-            Slog.e(TAG, "Fails to call remote functions ", ex);
-        }
-    }
-
-    private void generateNotificationWithBodyContent(int notificationId, String clientInfo,
-            String notificationBody, Intent intent) {
-        final Notification.Builder notificationBuilder = new Notification.Builder(
-                mContext,
-                SystemNotificationChannels.ACCESSIBILITY_SECURITY_POLICY);
-        intent.setFlags(
-                Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
-        intent.setIdentifier(String.valueOf(notificationId) + clientInfo);
-        intent.putExtra("body", notificationBody);
-
-        notificationBuilder
-            .setSmallIcon(R.drawable.ic_info)
-            .setContentTitle(
-                mContext.getString(R.string.log_access_confirmation_title))
-            .setContentText(notificationBody)
-            .setContentIntent(
-                PendingIntent.getActivity(mContext, 0, intent,
-                    PendingIntent.FLAG_IMMUTABLE))
-            .setTicker(mContext.getString(R.string.log_access_confirmation_title))
-            .setOnlyAlertOnce(true)
-            .setAutoCancel(true);
-        mNotificationManager.notify(notificationId, notificationBuilder.build());
-    }
-
-    /**
-     * A class which watches an uid for background access and notifies the logdMonitor when
-     * the package status becomes foreground (importance change)
-     */
-    private class UidImportanceListener implements ActivityManager.OnUidImportanceListener {
-        private final int mExpectedUid;
-        private final int mExpectedGid;
-        private final int mExpectedPid;
-        private final int mExpectedFd;
-        private int mExpectedImportance;
-        private int mCurrentImportance = RunningAppProcessInfo.IMPORTANCE_GONE;
-
-        UidImportanceListener(int uid, int gid, int pid, int fd, int importance) {
-            mExpectedUid = uid;
-            mExpectedGid = gid;
-            mExpectedPid = pid;
-            mExpectedFd = fd;
-            mExpectedImportance = importance;
-        }
-
-        @Override
-        public void onUidImportance(int uid, int importance) {
-            if (uid == mExpectedUid) {
-                mCurrentImportance = importance;
-
-                /**
-                 * 1) If the process status changes to foreground, send a notification
-                 * for user consent.
-                 * 2) If the process status remains background, we decline logd access request.
-                 **/
-                if (importance <= RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE) {
-                    String clientInfo = getClientInfo(uid, mExpectedGid, mExpectedPid, mExpectedFd);
-                    sendNotification(0, clientInfo, uid, mExpectedGid, mExpectedPid,
-                            mExpectedFd);
-                    mActivityManager.removeOnUidImportanceListener(this);
-
-                    synchronized (LogcatManagerService.this) {
-                        sUidImportanceListenerCount--;
-                    }
-                } else {
-                    try {
-                        getLogdService().decline(uid, mExpectedGid, mExpectedPid, mExpectedFd);
-                    } catch (RemoteException ex) {
-                        Slog.e(TAG, "Fails to call remote functions ", ex);
-                    }
-                }
-            }
-        }
-    }
-
-    private static String getClientInfo(int uid, int gid, int pid, int fd) {
-        return "UID=" + Integer.toString(uid) + " GID=" + Integer.toString(gid) + " PID="
-            + Integer.toString(pid) + " FD=" + Integer.toString(fd);
     }
 
     private class LogdMonitor implements Runnable {
@@ -318,7 +74,9 @@
         }
 
         /**
-         * LogdMonitor generates a prompt for users.
+         * The current version grant the permission by default.
+         * And track the logd access.
+         * The next version will generate a prompt for users.
          * The users decide whether the logd access is allowed.
          */
         @Override
@@ -328,63 +86,10 @@
             }
 
             if (mStart) {
-
-                // TODO See the comments of ALLOWABLE_TESTING_PACKAGES.
-                if (isAllowableTestingPackage(mUid)) {
-                    try {
-                        getLogdService().approve(mUid, mGid, mPid, mFd);
-                    } catch (RemoteException e) {
-                        e.printStackTrace();
-                    }
-                    return;
-                }
-
-                // If the access request is coming from native apps, approve the logd access
-                // TODO: This is needed to make tooling to work. However,
-                // we intend to be stricter with respect to native processes in a follow-up CL
-                if (mUid < AID_APP_UID) {
-                    try {
-                        getLogdService().approve(mUid, mGid, mPid, mFd);
-                    } catch (RemoteException e) {
-                        e.printStackTrace();
-                    }
-                    return;
-                }
-
-                final int procState = LocalServices.getService(ActivityManagerInternal.class)
-                        .getUidProcessState(mUid);
-                // If the process is foreground, send a notification for user consent
-                if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
-                    String clientInfo = getClientInfo(mUid, mGid, mPid, mFd);
-                    sendNotification(0, clientInfo, mUid, mGid, mPid, mFd);
-                } else {
-                    /**
-                     * If the process is background, add a background process change listener and
-                     * monitor if the process status changes.
-                     * To avoid clients registering multiple listeners, we limit the number of
-                     * maximum listeners to MAX_UID_IMPORTANCE_COUNT_LISTENER.
-                     **/
-                    if (mActivityManager == null) {
-                        return;
-                    }
-
-                    synchronized (LogcatManagerService.this) {
-                        if (sUidImportanceListenerCount < MAX_UID_IMPORTANCE_COUNT_LISTENER) {
-                            // Trigger addOnUidImportanceListener when there is an update from
-                            // the importance of the process
-                            mActivityManager.addOnUidImportanceListener(new UidImportanceListener(
-                                    mUid, mGid, mPid, mFd,
-                                    RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE),
-                                    RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE);
-                            sUidImportanceListenerCount++;
-                        } else {
-                            try {
-                                getLogdService().decline(mUid, mGid, mPid, mFd);
-                            } catch (RemoteException e) {
-                                e.printStackTrace();
-                            }
-                        }
-                    }
+                try {
+                    mLogdService.approve(mUid, mGid, mPid, mFd);
+                } catch (RemoteException ex) {
+                    Slog.e(TAG, "Fails to call remote functions ", ex);
                 }
             }
         }
@@ -395,8 +100,6 @@
         mContext = context;
         mBinderService = new BinderService();
         mThreadExecutor = Executors.newCachedThreadPool();
-        mActivityManager = context.getSystemService(ActivityManager.class);
-        mNotificationManager = mContext.getSystemService(NotificationManager.class);
     }
 
     @Override
@@ -411,4 +114,5 @@
     private void addLogdService() {
         mLogdService = ILogd.Stub.asInterface(ServiceManager.getService("logd"));
     }
+
 }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index aafcc58..2717f0c 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -83,6 +83,7 @@
 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
+import static android.service.notification.NotificationListenerService.REASON_ASSISTANT_CANCEL;
 import static android.service.notification.NotificationListenerService.REASON_CANCEL;
 import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
 import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
@@ -476,6 +477,14 @@
     @LoggingOnly
     private static final long RATE_LIMIT_TOASTS = 174840628L;
 
+    /**
+     * Whether listeners understand the more specific reason provided for notification
+     * cancellations from an assistant, rather than using the more general REASON_LISTENER_CANCEL.
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2)
+    private static final long NOTIFICATION_LOG_ASSISTANT_CANCEL = 195579280L;
+
     private IActivityManager mAm;
     private ActivityTaskManagerInternal mAtm;
     private ActivityManager mActivityManager;
@@ -4388,6 +4397,13 @@
                 synchronized (mNotificationLock) {
                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
 
+                    // Cancellation reason. If the token comes from assistant, label the
+                    // cancellation as coming from the assistant; default to LISTENER_CANCEL.
+                    int reason = REASON_LISTENER_CANCEL;
+                    if (mAssistants.isServiceTokenValidLocked(token)) {
+                        reason = REASON_ASSISTANT_CANCEL;
+                    }
+
                     if (keys != null) {
                         final int N = keys.length;
                         for (int i = 0; i < N; i++) {
@@ -4400,7 +4416,7 @@
                             }
                             cancelNotificationFromListenerLocked(info, callingUid, callingPid,
                                     r.getSbn().getPackageName(), r.getSbn().getTag(),
-                                    r.getSbn().getId(), userId);
+                                    r.getSbn().getId(), userId, reason);
                         }
                     } else {
                         cancelAllLocked(callingUid, callingPid, info.userid,
@@ -4494,12 +4510,13 @@
          */
         @GuardedBy("mNotificationLock")
         private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
-                int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
+                int callingUid, int callingPid, String pkg, String tag, int id, int userId,
+                int reason) {
             int mustNotHaveFlags = FLAG_ONGOING_EVENT;
             cancelNotification(callingUid, callingPid, pkg, tag, id, 0 /* mustHaveFlags */,
                     mustNotHaveFlags,
                     true,
-                    userId, REASON_LISTENER_CANCEL, info);
+                    userId, reason, info);
         }
 
         /**
@@ -4641,13 +4658,17 @@
             try {
                 synchronized (mNotificationLock) {
                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
+                    int cancelReason = REASON_LISTENER_CANCEL;
+                    if (mAssistants.isServiceTokenValidLocked(token)) {
+                        cancelReason = REASON_ASSISTANT_CANCEL;
+                    }
                     if (info.supportsProfiles()) {
                         Slog.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
                                 + "from " + info.component
                                 + " use cancelNotification(key) instead.");
                     } else {
                         cancelNotificationFromListenerLocked(info, callingUid, callingPid,
-                                pkg, tag, id, info.userid);
+                                pkg, tag, id, info.userid, cancelReason);
                     }
                 }
             } finally {
@@ -11049,6 +11070,12 @@
                         && (reason == REASON_CHANNEL_REMOVED || reason == REASON_CLEAR_DATA)) {
                     reason = REASON_CHANNEL_BANNED;
                 }
+                // apps before T don't know about REASON_ASSISTANT, so replace it with the
+                // previously-used case, REASON_LISTENER_CANCEL
+                if (!CompatChanges.isChangeEnabled(NOTIFICATION_LOG_ASSISTANT_CANCEL, info.uid)
+                        && reason == REASON_ASSISTANT_CANCEL) {
+                    reason = REASON_LISTENER_CANCEL;
+                }
                 listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason);
             } catch (RemoteException ex) {
                 Slog.e(TAG, "unable to notify listener (removed): " + info, ex);
diff --git a/services/core/java/com/android/server/notification/NotificationRecordLogger.java b/services/core/java/com/android/server/notification/NotificationRecordLogger.java
index f3dc2dd..9a89efa 100644
--- a/services/core/java/com/android/server/notification/NotificationRecordLogger.java
+++ b/services/core/java/com/android/server/notification/NotificationRecordLogger.java
@@ -16,6 +16,7 @@
 
 package com.android.server.notification;
 
+import static android.service.notification.NotificationListenerService.REASON_ASSISTANT_CANCEL;
 import static android.service.notification.NotificationListenerService.REASON_CANCEL;
 import static android.service.notification.NotificationListenerService.REASON_CLICK;
 import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
@@ -180,7 +181,9 @@
                 + " shade.")
         NOTIFICATION_CANCEL_USER_SHADE(192),
         @UiEvent(doc = "Notification was canceled due to user dismissal from the lockscreen")
-        NOTIFICATION_CANCEL_USER_LOCKSCREEN(193);
+        NOTIFICATION_CANCEL_USER_LOCKSCREEN(193),
+        @UiEvent(doc = "Notification was canceled due to an assistant adjustment update.")
+        NOTIFICATION_CANCEL_ASSISTANT(906);
 
         private final int mId;
         NotificationCancelledEvent(int id) {
@@ -206,6 +209,9 @@
                 if ((REASON_CLICK <= reason) && (reason <= REASON_TIMEOUT)) {
                     return NotificationCancelledEvent.values()[reason];
                 }
+                if (reason == REASON_ASSISTANT_CANCEL) {
+                    return NotificationCancelledEvent.NOTIFICATION_CANCEL_ASSISTANT;
+                }
                 if (NotificationManagerService.DBG) {
                     throw new IllegalArgumentException("Unexpected cancel reason " + reason);
                 }
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 2760578..1cf2dc5 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -735,6 +735,9 @@
         if (DEBUG || DEBUG_REBOOT) {
             Slog.d(TAG, "unloadUserLocked: user=" + userId);
         }
+        // Cancel any ongoing background tasks.
+        getUserShortcutsLocked(userId).cancelAllInFlightTasks();
+
         // Save all dirty information.
         saveDirtyInfo(false);
 
@@ -3736,6 +3739,7 @@
             synchronized (mLock) {
                 if (mHandler.hasCallbacks(mSaveDirtyInfoRunner)) {
                     mHandler.removeCallbacks(mSaveDirtyInfoRunner);
+                    forEachLoadedUserLocked(ShortcutUser::cancelAllInFlightTasks);
                     saveDirtyInfo(false);
                 }
                 mShutdown.set(true);
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index 408f045..4bb5dcf 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -33,6 +33,7 @@
 import android.util.TypedXmlPullParser;
 import android.util.TypedXmlSerializer;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.infra.AndroidFuture;
 import com.android.internal.logging.MetricsLogger;
@@ -50,7 +51,9 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 
@@ -138,6 +141,11 @@
     private String mLastAppScanOsFingerprint;
     private String mRestoreFromOsFingerprint;
 
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private final ArrayList<AndroidFuture<AppSearchSession>> mInFlightSessions = new ArrayList<>();
+
     public ShortcutUser(ShortcutService service, int userId) {
         mService = service;
         mUserId = userId;
@@ -718,6 +726,10 @@
     AndroidFuture<AppSearchSession> getAppSearch(
             @NonNull final AppSearchManager.SearchContext searchContext) {
         final AndroidFuture<AppSearchSession> future = new AndroidFuture<>();
+        synchronized (mLock) {
+            mInFlightSessions.removeIf(CompletableFuture::isDone);
+            mInFlightSessions.add(future);
+        }
         if (mAppSearchManager == null) {
             future.completeExceptionally(new RuntimeException("app search manager is null"));
             return future;
@@ -743,4 +755,13 @@
         }
         return future;
     }
+
+    void cancelAllInFlightTasks() {
+        synchronized (mLock) {
+            for (AndroidFuture<AppSearchSession> session : mInFlightSessions) {
+                session.cancel(true);
+            }
+            mInFlightSessions.clear();
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 3857072..e523153 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -521,6 +521,9 @@
     // The screen off timeout setting value in milliseconds.
     private long mScreenOffTimeoutSetting;
 
+    // The screen off timeout setting value in milliseconds to apply while device is docked.
+    private long mScreenOffTimeoutDockedSetting;
+
     // Default for attentive warning duration.
     private long mAttentiveWarningDurationConfig;
 
@@ -1272,6 +1275,9 @@
         resolver.registerContentObserver(Settings.System.getUriFor(
                 Settings.System.SCREEN_OFF_TIMEOUT),
                 false, mSettingsObserver, UserHandle.USER_ALL);
+        resolver.registerContentObserver(Settings.System.getUriFor(
+                Settings.System.SCREEN_OFF_TIMEOUT_DOCKED),
+                false, mSettingsObserver, UserHandle.USER_ALL);
         resolver.registerContentObserver(Settings.Secure.getUriFor(
                 Settings.Secure.SLEEP_TIMEOUT),
                 false, mSettingsObserver, UserHandle.USER_ALL);
@@ -1394,6 +1400,9 @@
         mScreenOffTimeoutSetting = Settings.System.getIntForUser(resolver,
                 Settings.System.SCREEN_OFF_TIMEOUT, DEFAULT_SCREEN_OFF_TIMEOUT,
                 UserHandle.USER_CURRENT);
+        mScreenOffTimeoutDockedSetting = Settings.System.getLongForUser(resolver,
+                Settings.System.SCREEN_OFF_TIMEOUT_DOCKED, mScreenOffTimeoutSetting,
+                UserHandle.USER_CURRENT);
         mSleepTimeoutSetting = Settings.Secure.getIntForUser(resolver,
                 Settings.Secure.SLEEP_TIMEOUT, DEFAULT_SLEEP_TIMEOUT,
                 UserHandle.USER_CURRENT);
@@ -2946,7 +2955,9 @@
 
     @GuardedBy("mLock")
     private long getScreenOffTimeoutLocked(long sleepTimeout, long attentiveTimeout) {
-        long timeout = mScreenOffTimeoutSetting;
+        long timeout = mDockState == Intent.EXTRA_DOCK_STATE_UNDOCKED
+                ? mScreenOffTimeoutSetting
+                : mScreenOffTimeoutDockedSetting;
         if (isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked()) {
             timeout = Math.min(timeout, mMaximumScreenOffTimeoutFromDeviceAdmin);
         }
@@ -4974,7 +4985,8 @@
         }
     }
 
-    private final class DockReceiver extends BroadcastReceiver {
+    @VisibleForTesting
+    final class DockReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
             synchronized (mLock) {
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index f15d2bb..e02fabd 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -2543,6 +2543,7 @@
 
         @Override
         public int getClientPriority(int useCase, String sessionId) {
+            ensureTunerResourceAccessPermission();
             final int callingPid = Binder.getCallingPid();
             final long identity = Binder.clearCallingIdentity();
             try {
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index ff96aeb..ec4c58f 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -1135,13 +1135,13 @@
     }
 
     @Override
-    public void setDisablePreviewScreenshots(IBinder token, boolean disable) {
+    public void setRecentsScreenshotEnabled(IBinder token, boolean enabled) {
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
                 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token);
                 if (r != null) {
-                    r.setDisablePreviewScreenshots(disable);
+                    r.setRecentsScreenshotEnabled(enabled);
                 }
             }
         } finally {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 0769286..9532a5c 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -766,7 +766,7 @@
     // Last visibility state we reported to the app token.
     boolean reportedVisible;
 
-    boolean mDisablePreviewScreenshots;
+    boolean mEnablePreviewScreenshots = true;
 
     // Information about an application starting window if displayed.
     // Note: these are de-referenced before the starting window animates away.
@@ -5116,22 +5116,22 @@
     }
 
     /**
-     * See {@link Activity#setDisablePreviewScreenshots}.
+     * See {@link Activity#setRecentsScreenshotEnabled}.
      */
-    void setDisablePreviewScreenshots(boolean disable) {
-        mDisablePreviewScreenshots = disable;
+    void setRecentsScreenshotEnabled(boolean enabled) {
+        mEnablePreviewScreenshots = enabled;
     }
 
     /**
      * Retrieves whether we'd like to generate a snapshot that's based solely on the theme. This is
-     * the case when preview screenshots are disabled {@link #setDisablePreviewScreenshots} or when
+     * the case when preview screenshots are disabled {@link #setRecentsScreenshotEnabled} or when
      * we can't take a snapshot for other reasons, for example, if we have a secure window.
      *
      * @return True if we need to generate an app theme snapshot, false if we'd like to take a real
      *         screenshot.
      */
     boolean shouldUseAppThemeSnapshot() {
-        return mDisablePreviewScreenshots || forAllWindows(WindowState::isSecureLocked,
+        return !mEnablePreviewScreenshots || forAllWindows(WindowState::isSecureLocked,
                 true /* topToBottom */);
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index ca4d717..580ab179 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -5267,6 +5267,18 @@
         }
     }
 
+    /**
+     * Returns {@code true} if the process represented by the pid passed as argument is
+     * instrumented.
+     */
+    boolean isInstrumenting(int pid) {
+        final WindowProcessController process;
+        synchronized (mGlobalLock) {
+            process = mProcessMap.getProcess(pid);
+        }
+        return process != null ? process.isInstrumenting() : false;
+    }
+
     final class H extends Handler {
         static final int REPORT_TIME_TRACKER_MSG = 1;
         static final int UPDATE_PROCESS_ANIMATING_STATE = 2;
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index bf11ebc..a9add59 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -196,15 +196,21 @@
         snapshotTasks(tasks, false /* allowSnapshotHome */);
     }
 
-    void recordTaskSnapshot(Task task, boolean allowSnapshotHome) {
+    /**
+     * This is different than {@link #recordTaskSnapshot(Task, boolean)} because it doesn't store
+     * the snapshot to the cache and returns the TaskSnapshot immediately.
+     *
+     * This is only used for testing so the snapshot content can be verified.
+     */
+    @VisibleForTesting
+    TaskSnapshot captureTaskSnapshot(Task task, boolean snapshotHome) {
         final TaskSnapshot snapshot;
-        final boolean snapshotHome = allowSnapshotHome && task.isActivityTypeHome();
         if (snapshotHome) {
             snapshot = snapshotTask(task);
         } else {
             switch (getSnapshotMode(task)) {
                 case SNAPSHOT_MODE_NONE:
-                    return;
+                    return null;
                 case SNAPSHOT_MODE_APP_THEME:
                     snapshot = drawAppThemeSnapshot(task);
                     break;
@@ -216,19 +222,27 @@
                     break;
             }
         }
-        if (snapshot != null) {
-            final HardwareBuffer buffer = snapshot.getHardwareBuffer();
-            if (buffer.getWidth() == 0 || buffer.getHeight() == 0) {
-                buffer.close();
-                Slog.e(TAG, "Invalid task snapshot dimensions " + buffer.getWidth() + "x"
-                        + buffer.getHeight());
-            } else {
-                mCache.putSnapshot(task, snapshot);
-                // Don't persist or notify the change for the temporal snapshot.
-                if (!snapshotHome) {
-                    mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot);
-                    task.onSnapshotChanged(snapshot);
-                }
+        return snapshot;
+    }
+
+    void recordTaskSnapshot(Task task, boolean allowSnapshotHome) {
+        final boolean snapshotHome = allowSnapshotHome && task.isActivityTypeHome();
+        final TaskSnapshot snapshot = captureTaskSnapshot(task, snapshotHome);
+        if (snapshot == null) {
+            return;
+        }
+
+        final HardwareBuffer buffer = snapshot.getHardwareBuffer();
+        if (buffer.getWidth() == 0 || buffer.getHeight() == 0) {
+            buffer.close();
+            Slog.e(TAG, "Invalid task snapshot dimensions " + buffer.getWidth() + "x"
+                    + buffer.getHeight());
+        } else {
+            mCache.putSnapshot(task, snapshot);
+            // Don't persist or notify the change for the temporal snapshot.
+            if (!snapshotHome) {
+                mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot);
+                task.onSnapshotChanged(snapshot);
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 71f4882..0f3b903 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -116,6 +116,7 @@
 import static com.android.server.wm.DisplayContent.IME_TARGET_CONTROL;
 import static com.android.server.wm.DisplayContent.IME_TARGET_INPUT;
 import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING;
+import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS;
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL;
 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
 import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
@@ -3682,7 +3683,8 @@
      * Sets the touch mode state.
      *
      * To be able to change touch mode state, the caller must either own the focused window, or must
-     * have the MODIFY_TOUCH_MODE_STATE permission.
+     * have the MODIFY_TOUCH_MODE_STATE permission. Instrumented processes are allowed to switch
+     * touch mode at any time.
      *
      * @param mode the touch mode to set
      */
@@ -3694,8 +3696,9 @@
             }
             final int pid = Binder.getCallingPid();
             final int uid = Binder.getCallingUid();
-            final boolean hasPermission = checkCallingPermission(MODIFY_TOUCH_MODE_STATE,
-                    "setInTouchMode()");
+
+            final boolean hasPermission = mAtmService.isInstrumenting(pid)
+                    || checkCallingPermission(MODIFY_TOUCH_MODE_STATE, "setInTouchMode()");
             final long token = Binder.clearCallingIdentity();
             try {
                 if (mInputManager.setInTouchMode(mode, pid, uid, hasPermission)) {
@@ -8908,4 +8911,27 @@
 
         mTaskFpsCallbackController.unregisterCallback(listener);
     }
+
+    @Override
+    public Bitmap snapshotTaskForRecents(int taskId) {
+        if (!checkCallingPermission(READ_FRAME_BUFFER, "snapshotTaskForRecents()")) {
+            throw new SecurityException("Requires READ_FRAME_BUFFER permission");
+        }
+
+        TaskSnapshot taskSnapshot;
+        synchronized (mGlobalLock) {
+            Task task = mRoot.anyTaskForId(taskId, MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
+            if (task == null) {
+                throw new IllegalArgumentException(
+                        "Failed to find matching task for taskId=" + taskId);
+            }
+            taskSnapshot = mTaskSnapshotController.captureTaskSnapshot(task, false);
+        }
+
+        if (taskSnapshot == null || taskSnapshot.getHardwareBuffer() == null) {
+            return null;
+        }
+        return Bitmap.wrapHardwareBuffer(taskSnapshot.getHardwareBuffer(),
+                taskSnapshot.getColorSpace());
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 27024ce..1d5c184 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -1146,7 +1146,11 @@
         final PendingTransaction pt = mPendingTransactions.remove(0);
         pt.startSync();
         // Post this so that the now-playing transition setup isn't interrupted.
-        mService.mH.post(pt::startTransaction);
+        mService.mH.post(() -> {
+            synchronized (mGlobalLock) {
+                pt.startTransaction();
+            }
+        });
     }
 
     @Override
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index ebfa2c6..80011d1 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -10982,13 +10982,12 @@
     }
 
     @Override
-    public void acknowledgeNewUserDisclaimer() {
+    public void acknowledgeNewUserDisclaimer(@UserIdInt int userId) {
         CallerIdentity callerIdentity = getCallerIdentity();
         Preconditions.checkCallAuthorization(canManageUsers(callerIdentity)
                 || hasCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS));
 
-        setShowNewUserDisclaimer(callerIdentity.getUserId(),
-                DevicePolicyData.NEW_USER_DISCLAIMER_ACKNOWLEDGED);
+        setShowNewUserDisclaimer(userId, DevicePolicyData.NEW_USER_DISCLAIMER_ACKNOWLEDGED);
     }
 
     private void setShowNewUserDisclaimer(@UserIdInt int userId, String value) {
@@ -11021,11 +11020,10 @@
     }
 
     @Override
-    public boolean isNewUserDisclaimerAcknowledged() {
+    public boolean isNewUserDisclaimerAcknowledged(@UserIdInt int userId) {
         CallerIdentity callerIdentity = getCallerIdentity();
         Preconditions.checkCallAuthorization(canManageUsers(callerIdentity)
                 || hasCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS));
-        int userId = callerIdentity.getUserId();
         synchronized (getLockObject()) {
             DevicePolicyData policyData = getUserData(userId);
             return policyData.isNewUserDisclaimerAcknowledged();
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index 62a16f7..c5f990d 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -60,6 +60,12 @@
     private static ProfcollectForwardingService sSelfService;
     private final Handler mHandler = new ProfcollectdHandler(IoThread.getHandler().getLooper());
 
+    private IProviderStatusCallback mProviderStatusCallback = new IProviderStatusCallback.Stub() {
+        public void onProviderReady() {
+            mHandler.sendEmptyMessage(ProfcollectdHandler.MESSAGE_REGISTER_SCHEDULERS);
+        }
+    };
+
     public ProfcollectForwardingService(Context context) {
         super(context);
 
@@ -93,13 +99,23 @@
             }
             BackgroundThread.get().getThreadHandler().post(() -> {
                 if (serviceHasSupportedTraceProvider()) {
-                    registerObservers();
-                    ProfcollectBGJobService.schedule(getContext());
+                    registerProviderStatusCallback();
                 }
             });
         }
     }
 
+    private void registerProviderStatusCallback() {
+        if (mIProfcollect == null) {
+            return;
+        }
+        try {
+            mIProfcollect.registerProviderStatusCallback(mProviderStatusCallback);
+        } catch (RemoteException e) {
+            Log.e(LOG_TAG, e.getMessage());
+        }
+    }
+
     private boolean serviceHasSupportedTraceProvider() {
         if (mIProfcollect == null) {
             return false;
@@ -141,6 +157,7 @@
         }
 
         public static final int MESSAGE_BINDER_CONNECT = 0;
+        public static final int MESSAGE_REGISTER_SCHEDULERS = 1;
 
         @Override
         public void handleMessage(android.os.Message message) {
@@ -148,6 +165,10 @@
                 case MESSAGE_BINDER_CONNECT:
                     connectNativeService();
                     break;
+                case MESSAGE_REGISTER_SCHEDULERS:
+                    registerObservers();
+                    ProfcollectBGJobService.schedule(getContext());
+                    break;
                 default:
                     throw new AssertionError("Unknown message: " + message);
             }
diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
index d710308..ac115a2 100644
--- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
@@ -30,7 +30,6 @@
 import static com.android.server.DeviceIdleController.LIGHT_STATE_IDLE_MAINTENANCE;
 import static com.android.server.DeviceIdleController.LIGHT_STATE_INACTIVE;
 import static com.android.server.DeviceIdleController.LIGHT_STATE_OVERRIDE;
-import static com.android.server.DeviceIdleController.LIGHT_STATE_PRE_IDLE;
 import static com.android.server.DeviceIdleController.LIGHT_STATE_WAITING_FOR_NETWORK;
 import static com.android.server.DeviceIdleController.MSG_REPORT_STATIONARY_STATUS;
 import static com.android.server.DeviceIdleController.MSG_RESET_PRE_IDLE_TIMEOUT_FACTOR;
@@ -112,6 +111,7 @@
 /**
  * Tests for {@link com.android.server.DeviceIdleController}.
  */
+@SuppressWarnings("GuardedBy")
 @RunWith(AndroidJUnit4.class)
 public class DeviceIdleControllerTest {
     private DeviceIdleController mDeviceIdleController;
@@ -875,7 +875,7 @@
     @Test
     public void testLightStepIdleStateLocked_InvalidStates() {
         mDeviceIdleController.becomeActiveLocked("testing", 0);
-        mDeviceIdleController.stepLightIdleStateLocked("testing");
+        mDeviceIdleController.stepLightIdleStateLocked("testing", true);
         // stepLightIdleStateLocked doesn't handle the ACTIVE case, so the state
         // should stay as ACTIVE.
         verifyLightStateConditions(LIGHT_STATE_ACTIVE);
@@ -888,7 +888,7 @@
     @Test
     public void testLightStepIdleStateLocked_Overriden() {
         enterLightState(LIGHT_STATE_OVERRIDE);
-        mDeviceIdleController.stepLightIdleStateLocked("testing");
+        mDeviceIdleController.stepLightIdleStateLocked("testing", true);
         verifyLightStateConditions(LIGHT_STATE_OVERRIDE);
     }
 
@@ -906,18 +906,18 @@
         verifyLightStateConditions(LIGHT_STATE_INACTIVE);
 
         // No active ops means INACTIVE should go straight to IDLE.
-        mDeviceIdleController.stepLightIdleStateLocked("testing");
+        mDeviceIdleController.stepLightIdleStateLocked("testing", true);
         verifyLightStateConditions(LIGHT_STATE_IDLE);
 
         // Should just alternate between IDLE and IDLE_MAINTENANCE now.
 
-        mDeviceIdleController.stepLightIdleStateLocked("testing");
+        mDeviceIdleController.stepLightIdleStateLocked("testing", true);
         verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
 
-        mDeviceIdleController.stepLightIdleStateLocked("testing");
+        mDeviceIdleController.stepLightIdleStateLocked("testing", true);
         verifyLightStateConditions(LIGHT_STATE_IDLE);
 
-        mDeviceIdleController.stepLightIdleStateLocked("testing");
+        mDeviceIdleController.stepLightIdleStateLocked("testing", true);
         verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
     }
 
@@ -930,26 +930,22 @@
         setScreenOn(false);
         verifyLightStateConditions(LIGHT_STATE_INACTIVE);
 
-        // Active ops means INACTIVE should go to PRE_IDLE to wait.
+        // After enough time, INACTIVE should go to IDLE regardless of any active ops.
         mDeviceIdleController.setJobsActive(true);
         mDeviceIdleController.setAlarmsActive(true);
         mDeviceIdleController.setActiveIdleOpsForTest(1);
-        mDeviceIdleController.stepLightIdleStateLocked("testing");
-        verifyLightStateConditions(LIGHT_STATE_PRE_IDLE);
-
-        // Even with active ops, PRE_IDLE should go to IDLE.
-        mDeviceIdleController.stepLightIdleStateLocked("testing");
+        mDeviceIdleController.stepLightIdleStateLocked("testing", true);
         verifyLightStateConditions(LIGHT_STATE_IDLE);
 
         // Should just alternate between IDLE and IDLE_MAINTENANCE now.
 
-        mDeviceIdleController.stepLightIdleStateLocked("testing");
+        mDeviceIdleController.stepLightIdleStateLocked("testing", true);
         verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
 
-        mDeviceIdleController.stepLightIdleStateLocked("testing");
+        mDeviceIdleController.stepLightIdleStateLocked("testing", true);
         verifyLightStateConditions(LIGHT_STATE_IDLE);
 
-        mDeviceIdleController.stepLightIdleStateLocked("testing");
+        mDeviceIdleController.stepLightIdleStateLocked("testing", true);
         verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
     }
 
@@ -967,24 +963,24 @@
         verifyLightStateConditions(LIGHT_STATE_INACTIVE);
 
         // No active ops means INACTIVE should go straight to IDLE.
-        mDeviceIdleController.stepLightIdleStateLocked("testing");
+        mDeviceIdleController.stepLightIdleStateLocked("testing", true);
         verifyLightStateConditions(LIGHT_STATE_IDLE);
 
         // Should cycle between IDLE, WAITING_FOR_NETWORK, and IDLE_MAINTENANCE now.
 
-        mDeviceIdleController.stepLightIdleStateLocked("testing");
+        mDeviceIdleController.stepLightIdleStateLocked("testing", true);
         verifyLightStateConditions(LIGHT_STATE_WAITING_FOR_NETWORK);
 
-        mDeviceIdleController.stepLightIdleStateLocked("testing");
+        mDeviceIdleController.stepLightIdleStateLocked("testing", true);
         verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
 
-        mDeviceIdleController.stepLightIdleStateLocked("testing");
+        mDeviceIdleController.stepLightIdleStateLocked("testing", true);
         verifyLightStateConditions(LIGHT_STATE_IDLE);
 
-        mDeviceIdleController.stepLightIdleStateLocked("testing");
+        mDeviceIdleController.stepLightIdleStateLocked("testing", true);
         verifyLightStateConditions(LIGHT_STATE_WAITING_FOR_NETWORK);
 
-        mDeviceIdleController.stepLightIdleStateLocked("testing");
+        mDeviceIdleController.stepLightIdleStateLocked("testing", true);
         verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
     }
 
@@ -997,36 +993,177 @@
         setScreenOn(false);
         verifyLightStateConditions(LIGHT_STATE_INACTIVE);
 
-        // Active ops means INACTIVE should go to PRE_IDLE to wait.
+        // After enough time, INACTIVE should go to IDLE regardless of any active ops.
         mDeviceIdleController.setJobsActive(true);
         mDeviceIdleController.setAlarmsActive(true);
         mDeviceIdleController.setActiveIdleOpsForTest(1);
-        mDeviceIdleController.stepLightIdleStateLocked("testing");
-        verifyLightStateConditions(LIGHT_STATE_PRE_IDLE);
-
-        // Even with active ops, PRE_IDLE should go to IDLE.
-        mDeviceIdleController.stepLightIdleStateLocked("testing");
+        mDeviceIdleController.stepLightIdleStateLocked("testing", true);
         verifyLightStateConditions(LIGHT_STATE_IDLE);
 
         // Should cycle between IDLE, WAITING_FOR_NETWORK, and IDLE_MAINTENANCE now.
 
-        mDeviceIdleController.stepLightIdleStateLocked("testing");
+        mDeviceIdleController.stepLightIdleStateLocked("testing", true);
         verifyLightStateConditions(LIGHT_STATE_WAITING_FOR_NETWORK);
 
-        mDeviceIdleController.stepLightIdleStateLocked("testing");
+        mDeviceIdleController.stepLightIdleStateLocked("testing", true);
         verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
 
-        mDeviceIdleController.stepLightIdleStateLocked("testing");
+        mDeviceIdleController.stepLightIdleStateLocked("testing", true);
         verifyLightStateConditions(LIGHT_STATE_IDLE);
 
-        mDeviceIdleController.stepLightIdleStateLocked("testing");
+        mDeviceIdleController.stepLightIdleStateLocked("testing", true);
         verifyLightStateConditions(LIGHT_STATE_WAITING_FOR_NETWORK);
 
-        mDeviceIdleController.stepLightIdleStateLocked("testing");
+        mDeviceIdleController.stepLightIdleStateLocked("testing", true);
         verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
     }
 
     @Test
+    public void testLightStepIdleStateSkippedAlarms() {
+        setNetworkConnected(true);
+        mDeviceIdleController.setJobsActive(false);
+        mDeviceIdleController.setAlarmsActive(false);
+        mDeviceIdleController.setActiveIdleOpsForTest(0);
+
+        final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListenerCaptor = ArgumentCaptor
+                .forClass(AlarmManager.OnAlarmListener.class);
+        doNothing().when(mAlarmManager).setWindow(anyInt(), anyLong(), anyLong(),
+                eq("DeviceIdleController.light"), alarmListenerCaptor.capture(), any());
+        doNothing().when(mAlarmManager).setWindow(anyInt(), anyLong(), anyLong(),
+                eq("DeviceIdleController.light"), alarmListenerCaptor.capture(), any());
+
+        // Set state to INACTIVE.
+        mDeviceIdleController.becomeActiveLocked("testing", 0);
+        setChargingOn(false);
+        setScreenOn(false);
+        verifyLightStateConditions(LIGHT_STATE_INACTIVE);
+
+        final AlarmManager.OnAlarmListener progressionListener =
+                alarmListenerCaptor.getAllValues().get(0);
+        final AlarmManager.OnAlarmListener maintenanceListener =
+                alarmListenerCaptor.getAllValues().get(1);
+
+        // Set things to make it look like the INACTIVE -> IDLE alarm didn't fire and the
+        // MAINTENANCE alarm just fired.
+        mInjector.nowElapsed = mDeviceIdleController.getNextLightMaintenanceAlarmTimeForTesting();
+        // If the non-wakeup alarm doesn't fire in a timely manner, we would see both fire at the
+        // same time.
+        progressionListener.onAlarm();
+        verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
+        maintenanceListener.onAlarm();
+        verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
+
+        assertTrue(mInjector.nowElapsed < mDeviceIdleController.getNextLightAlarmTimeForTesting());
+
+        // MAINTENANCE->IDLE alarm goes off at correct time.
+        mInjector.nowElapsed = mDeviceIdleController.getNextLightAlarmTimeForTesting();
+        progressionListener.onAlarm();
+        verifyLightStateConditions(LIGHT_STATE_IDLE);
+
+        // Go back to MAINTENANCE
+        mInjector.nowElapsed = mDeviceIdleController.getNextLightMaintenanceAlarmTimeForTesting();
+        maintenanceListener.onAlarm();
+        verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
+
+        assertTrue(mInjector.nowElapsed < mDeviceIdleController.getNextLightAlarmTimeForTesting());
+        assertTrue(mInjector.nowElapsed
+                < mDeviceIdleController.getNextLightMaintenanceAlarmTimeForTesting());
+
+        // MAINTENANCE->IDLE alarm is delayed until IDLE->MAINTENANCE alarm goes off.
+        mInjector.nowElapsed = mDeviceIdleController.getNextLightMaintenanceAlarmTimeForTesting();
+        progressionListener.onAlarm();
+        verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
+        maintenanceListener.onAlarm();
+        verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
+    }
+
+    @Test
+    public void testLightStepIdleStateIdlingTimeIncreases() {
+        final long maintenanceTimeMs = 60_000L;
+        mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET = maintenanceTimeMs;
+        mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET = maintenanceTimeMs;
+        mConstants.LIGHT_IDLE_TIMEOUT = 5 * 60_000L;
+        mConstants.LIGHT_MAX_IDLE_TIMEOUT = 20 * 60_000L;
+        mConstants.LIGHT_IDLE_FACTOR = 2f;
+
+        setNetworkConnected(true);
+        mDeviceIdleController.setJobsActive(false);
+        mDeviceIdleController.setAlarmsActive(false);
+        mDeviceIdleController.setActiveIdleOpsForTest(0);
+
+        InOrder alarmManagerInOrder = inOrder(mAlarmManager);
+
+        final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListenerCaptor = ArgumentCaptor
+                .forClass(AlarmManager.OnAlarmListener.class);
+        doNothing().when(mAlarmManager).setWindow(anyInt(), anyLong(), anyLong(),
+                eq("DeviceIdleController.light"), alarmListenerCaptor.capture(), any());
+        doNothing().when(mAlarmManager).setWindow(anyInt(), anyLong(), anyLong(),
+                eq("DeviceIdleController.light"), alarmListenerCaptor.capture(), any());
+
+        // Set state to INACTIVE.
+        mDeviceIdleController.becomeActiveLocked("testing", 0);
+        setChargingOn(false);
+        setScreenOn(false);
+        verifyLightStateConditions(LIGHT_STATE_INACTIVE);
+        long idlingTimeMs = mConstants.LIGHT_IDLE_TIMEOUT;
+        final long idleAfterInactiveExpiryTime =
+                mInjector.nowElapsed + mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT;
+        alarmManagerInOrder.verify(mAlarmManager).setWindow(
+                eq(AlarmManager.ELAPSED_REALTIME),
+                eq(idleAfterInactiveExpiryTime),
+                anyLong(), anyString(), any(), any());
+        // Maintenance alarm
+        alarmManagerInOrder.verify(mAlarmManager).setWindow(
+                eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
+                eq(idleAfterInactiveExpiryTime + idlingTimeMs),
+                anyLong(), anyString(), any(), any());
+
+        final AlarmManager.OnAlarmListener progressionListener =
+                alarmListenerCaptor.getAllValues().get(0);
+        final AlarmManager.OnAlarmListener maintenanceListener =
+                alarmListenerCaptor.getAllValues().get(1);
+
+        // INACTIVE -> IDLE alarm
+        mInjector.nowElapsed = mDeviceIdleController.getNextLightAlarmTimeForTesting();
+        progressionListener.onAlarm();
+        verifyLightStateConditions(LIGHT_STATE_IDLE);
+        alarmManagerInOrder.verify(mAlarmManager).setWindow(
+                eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
+                eq(mInjector.nowElapsed + idlingTimeMs),
+                anyLong(), anyString(), any(), any());
+
+        for (int i = 0; i < 2; ++i) {
+            // IDLE->MAINTENANCE alarm
+            mInjector.nowElapsed =
+                    mDeviceIdleController.getNextLightMaintenanceAlarmTimeForTesting();
+            maintenanceListener.onAlarm();
+            verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
+            long maintenanceExpiryTime = mInjector.nowElapsed + maintenanceTimeMs;
+            idlingTimeMs *= mConstants.LIGHT_IDLE_FACTOR;
+            // Set MAINTENANCE->IDLE
+            alarmManagerInOrder.verify(mAlarmManager).setWindow(
+                    eq(AlarmManager.ELAPSED_REALTIME),
+                    eq(maintenanceExpiryTime),
+                    anyLong(), anyString(), any(), any());
+            // Set IDLE->MAINTENANCE
+            alarmManagerInOrder.verify(mAlarmManager).setWindow(
+                    eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
+                    eq(maintenanceExpiryTime + idlingTimeMs),
+                    anyLong(), anyString(), any(), any());
+
+            // MAINTENANCE->IDLE alarm
+            mInjector.nowElapsed = mDeviceIdleController.getNextLightAlarmTimeForTesting();
+            progressionListener.onAlarm();
+            verifyLightStateConditions(LIGHT_STATE_IDLE);
+            // Set IDLE->MAINTENANCE again
+            alarmManagerInOrder.verify(mAlarmManager).setWindow(
+                    eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
+                    eq(mInjector.nowElapsed + idlingTimeMs),
+                    anyLong(), anyString(), any(), any());
+        }
+    }
+
+    @Test
     public void testLightIdleAlarmUnaffectedByMotion() {
         setNetworkConnected(true);
         mDeviceIdleController.setJobsActive(false);
@@ -1043,45 +1180,37 @@
         verifyLightStateConditions(LIGHT_STATE_INACTIVE);
 
         // No active ops means INACTIVE should go straight to IDLE.
-        mDeviceIdleController.stepLightIdleStateLocked("testing");
+        mDeviceIdleController.stepLightIdleStateLocked("testing", true);
         verifyLightStateConditions(LIGHT_STATE_IDLE);
-        inOrder.verify(mDeviceIdleController).scheduleLightAlarmLocked(
-                longThat(l -> l == mConstants.LIGHT_IDLE_TIMEOUT),
-                longThat(l -> l == mConstants.LIGHT_IDLE_TIMEOUT_INITIAL_FLEX),
-                eq(false));
+        inOrder.verify(mDeviceIdleController).scheduleLightMaintenanceAlarmLocked(
+                longThat(l -> l == mConstants.LIGHT_IDLE_TIMEOUT));
 
         // Should just alternate between IDLE and IDLE_MAINTENANCE now.
 
-        mDeviceIdleController.stepLightIdleStateLocked("testing");
+        mDeviceIdleController.stepLightIdleStateLocked("testing", true);
         verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
         inOrder.verify(mDeviceIdleController).scheduleLightAlarmLocked(
                 longThat(l -> l >= mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET),
-                longThat(l -> l == mConstants.FLEX_TIME_SHORT),
-                eq(true));
+                longThat(l -> l == mConstants.FLEX_TIME_SHORT));
 
-        mDeviceIdleController.stepLightIdleStateLocked("testing");
+        mDeviceIdleController.stepLightIdleStateLocked("testing", true);
         verifyLightStateConditions(LIGHT_STATE_IDLE);
-        inOrder.verify(mDeviceIdleController).scheduleLightAlarmLocked(
-                longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT),
-                longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT_INITIAL_FLEX),
-                eq(false));
+        inOrder.verify(mDeviceIdleController).scheduleLightMaintenanceAlarmLocked(
+                longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT));
 
-        mDeviceIdleController.stepLightIdleStateLocked("testing");
+        mDeviceIdleController.stepLightIdleStateLocked("testing", true);
         verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
         inOrder.verify(mDeviceIdleController).scheduleLightAlarmLocked(
                 longThat(l -> l >= mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET),
-                longThat(l -> l == mConstants.FLEX_TIME_SHORT),
-                eq(true));
+                longThat(l -> l == mConstants.FLEX_TIME_SHORT));
 
         // Test that motion doesn't reset the idle timeout.
         mDeviceIdleController.handleMotionDetectedLocked(50, "test");
 
-        mDeviceIdleController.stepLightIdleStateLocked("testing");
+        mDeviceIdleController.stepLightIdleStateLocked("testing", true);
         verifyLightStateConditions(LIGHT_STATE_IDLE);
-        inOrder.verify(mDeviceIdleController).scheduleLightAlarmLocked(
-                longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT),
-                longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT_INITIAL_FLEX),
-                eq(false));
+        inOrder.verify(mDeviceIdleController).scheduleLightMaintenanceAlarmLocked(
+                longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT));
     }
 
     ///////////////// EXIT conditions ///////////////////
@@ -1268,10 +1397,6 @@
         mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
         verifyLightStateConditions(LIGHT_STATE_INACTIVE);
 
-        enterLightState(LIGHT_STATE_PRE_IDLE);
-        mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
-        verifyLightStateConditions(LIGHT_STATE_IDLE);
-
         enterLightState(LIGHT_STATE_IDLE);
         mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
         verifyLightStateConditions(LIGHT_STATE_IDLE);
@@ -1307,10 +1432,6 @@
         mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
         verifyLightStateConditions(LIGHT_STATE_INACTIVE);
 
-        enterLightState(LIGHT_STATE_PRE_IDLE);
-        mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
-        verifyLightStateConditions(LIGHT_STATE_PRE_IDLE);
-
         enterLightState(LIGHT_STATE_IDLE);
         mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
         verifyLightStateConditions(LIGHT_STATE_IDLE);
@@ -1344,10 +1465,6 @@
         mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
         verifyLightStateConditions(LIGHT_STATE_INACTIVE);
 
-        enterLightState(LIGHT_STATE_PRE_IDLE);
-        mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
-        verifyLightStateConditions(LIGHT_STATE_PRE_IDLE);
-
         enterLightState(LIGHT_STATE_IDLE);
         mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
         verifyLightStateConditions(LIGHT_STATE_IDLE);
@@ -1381,10 +1498,6 @@
         mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
         verifyLightStateConditions(LIGHT_STATE_INACTIVE);
 
-        enterLightState(LIGHT_STATE_PRE_IDLE);
-        mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
-        verifyLightStateConditions(LIGHT_STATE_PRE_IDLE);
-
         enterLightState(LIGHT_STATE_IDLE);
         mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
         verifyLightStateConditions(LIGHT_STATE_IDLE);
@@ -1510,10 +1623,6 @@
         mDeviceIdleController.handleMotionDetectedLocked(50, "test");
         verifyLightStateConditions(LIGHT_STATE_INACTIVE);
 
-        enterLightState(LIGHT_STATE_PRE_IDLE);
-        mDeviceIdleController.handleMotionDetectedLocked(50, "test");
-        verifyLightStateConditions(LIGHT_STATE_PRE_IDLE);
-
         enterLightState(LIGHT_STATE_IDLE);
         mDeviceIdleController.handleMotionDetectedLocked(50, "test");
         verifyLightStateConditions(LIGHT_STATE_IDLE);
@@ -1580,10 +1689,6 @@
         mDeviceIdleController.becomeActiveLocked("test", 1000);
         verifyLightStateConditions(LIGHT_STATE_ACTIVE);
 
-        enterLightState(LIGHT_STATE_PRE_IDLE);
-        mDeviceIdleController.becomeActiveLocked("test", 1000);
-        verifyLightStateConditions(LIGHT_STATE_ACTIVE);
-
         enterLightState(LIGHT_STATE_IDLE);
         mDeviceIdleController.becomeActiveLocked("test", 1000);
         verifyLightStateConditions(LIGHT_STATE_ACTIVE);
@@ -2059,7 +2164,7 @@
                 while (mDeviceIdleController.getLightState() != lightState) {
                     // Stepping through each state ensures that the proper features are turned
                     // on/off.
-                    mDeviceIdleController.stepLightIdleStateLocked("testing");
+                    mDeviceIdleController.stepLightIdleStateLocked("testing", true);
 
                     count++;
                     if (count > 10) {
@@ -2068,7 +2173,6 @@
                     }
                 }
                 break;
-            case LIGHT_STATE_PRE_IDLE:
             case LIGHT_STATE_WAITING_FOR_NETWORK:
             case LIGHT_STATE_OVERRIDE:
                 setScreenOn(false);
@@ -2213,7 +2317,6 @@
                                 > mAlarmManager.getNextWakeFromIdleTime());
                 break;
             case LIGHT_STATE_INACTIVE:
-            case LIGHT_STATE_PRE_IDLE:
             case LIGHT_STATE_IDLE:
             case LIGHT_STATE_WAITING_FOR_NETWORK:
             case LIGHT_STATE_IDLE_MAINTENANCE:
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
index 67d6929..e7f4d3d 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
@@ -34,6 +34,7 @@
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 
+import android.app.PropertyInvalidatedCache;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
 import android.service.gatekeeper.GateKeeperResponse;
@@ -47,6 +48,7 @@
 import com.android.server.locksettings.FakeGateKeeperService.VerifyHandle;
 import com.android.server.locksettings.LockSettingsStorage.CredentialHash;
 
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -57,6 +59,11 @@
 @Presubmit
 @RunWith(AndroidJUnit4.class)
 public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
+    @Before
+    public void disableProcessCaches() {
+        PropertyInvalidatedCache.disableForTestMode();
+    }
+
     @Test
     public void testCreatePasswordPrimaryUser() throws RemoteException {
         testCreateCredential(PRIMARY_USER_ID, newPassword("password"));
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java b/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java
index 9c0239b..c2f94e2 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java
@@ -24,6 +24,7 @@
 
 import static org.junit.Assert.assertEquals;
 
+import android.app.PropertyInvalidatedCache;
 import android.app.admin.DevicePolicyManager;
 
 import androidx.test.runner.AndroidJUnit4;
@@ -46,6 +47,11 @@
         mSettings.setDeviceProvisioned(false);
     }
 
+    @Before
+    public void disableProcessCaches() {
+        PropertyInvalidatedCache.disableForTestMode();
+    }
+
     @Test
     public void testFrpCredential_setPin() {
         mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index c0a38b8..58e1c43 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -36,6 +36,7 @@
 import static org.mockito.Mockito.when;
 
 import android.app.admin.PasswordMetrics;
+import android.app.PropertyInvalidatedCache;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
@@ -49,6 +50,7 @@
 import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationToken;
 import com.android.server.locksettings.SyntheticPasswordManager.PasswordData;
 
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -68,6 +70,11 @@
     public static final byte[] PAYLOAD = new byte[] {1, 2, -1, -2, 55};
     public static final byte[] PAYLOAD2 = new byte[] {2, 3, -2, -3, 44, 1};
 
+    @Before
+    public void disableProcessCaches() {
+        PropertyInvalidatedCache.disableForTestMode();
+    }
+
     @Test
     public void testPasswordBasedSyntheticPassword() throws RemoteException {
         final int USER_ID = 10;
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 827349a..c94168c 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -87,6 +87,7 @@
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.power.PowerManagerService.BatteryReceiver;
 import com.android.server.power.PowerManagerService.BinderService;
+import com.android.server.power.PowerManagerService.DockReceiver;
 import com.android.server.power.PowerManagerService.Injector;
 import com.android.server.power.PowerManagerService.NativeWrapper;
 import com.android.server.power.PowerManagerService.UserSwitchedReceiver;
@@ -152,6 +153,7 @@
     private Resources mResourcesSpy;
     private OffsettableClock mClock;
     private TestLooper mTestLooper;
+    private DockReceiver mDockReceiver;
 
     private static class IntentFilterMatcher implements ArgumentMatcher<IntentFilter> {
         private final IntentFilter mFilter;
@@ -337,6 +339,14 @@
                 argThat(new IntentFilterMatcher(usFilter)), isNull(), isA(Handler.class));
         mUserSwitchedReceiver = userSwitchedCaptor.getValue();
 
+        // Grab the DockReceiver
+        ArgumentCaptor<DockReceiver> dockReceiverCaptor =
+                ArgumentCaptor.forClass(DockReceiver.class);
+        IntentFilter dockFilter = new IntentFilter(Intent.ACTION_DOCK_EVENT);
+        verify(mContextSpy).registerReceiver(dockReceiverCaptor.capture(),
+                argThat(new IntentFilterMatcher(dockFilter)), isNull(), isA(Handler.class));
+        mDockReceiver = dockReceiverCaptor.getValue();
+
         mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
     }
 
@@ -385,6 +395,16 @@
                 .thenReturn(minimumScreenOffTimeoutConfigMillis);
     }
 
+    private void setScreenOffTimeout(int screenOffTimeoutMillis) {
+        Settings.System.putInt(mContextSpy.getContentResolver(), Settings.System.SCREEN_OFF_TIMEOUT,
+                screenOffTimeoutMillis);
+    }
+
+    private void setScreenOffTimeoutDocked(int screenOffTimeoutMillis) {
+        Settings.System.putInt(mContextSpy.getContentResolver(),
+                Settings.System.SCREEN_OFF_TIMEOUT_DOCKED, screenOffTimeoutMillis);
+    }
+
     private void advanceTime(long timeMs) {
         mClock.fastForward(timeMs);
         mTestLooper.dispatchAll();
@@ -883,6 +903,71 @@
     }
 
     @Test
+    public void testScreenOffTimeout_goesToSleepAfterTimeout() {
+        final DisplayInfo info = new DisplayInfo();
+        info.displayGroupId = Display.DEFAULT_DISPLAY_GROUP;
+        when(mDisplayManagerInternalMock.getDisplayInfo(Display.DEFAULT_DISPLAY)).thenReturn(info);
+
+        setMinimumScreenOffTimeoutConfig(10);
+        setScreenOffTimeout(10);
+
+        createService();
+        startSystem();
+
+        mService.getBinderServiceInstance().userActivity(Display.DEFAULT_DISPLAY, mClock.now(),
+                PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        advanceTime(15);
+        assertThat(mService.getGlobalWakefulnessLocked()).isNotEqualTo(WAKEFULNESS_AWAKE);
+    }
+
+    @Test
+    public void testScreenOffTimeout_usesRegularTimeoutWhenNotDocked() {
+        final DisplayInfo info = new DisplayInfo();
+        info.displayGroupId = Display.DEFAULT_DISPLAY_GROUP;
+        when(mDisplayManagerInternalMock.getDisplayInfo(Display.DEFAULT_DISPLAY)).thenReturn(info);
+
+        setMinimumScreenOffTimeoutConfig(10);
+        setScreenOffTimeout(10);
+        setScreenOffTimeoutDocked(30);
+
+        createService();
+        startSystem();
+
+        mService.getBinderServiceInstance().userActivity(Display.DEFAULT_DISPLAY, mClock.now(),
+                PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        advanceTime(15);
+        assertThat(mService.getGlobalWakefulnessLocked()).isNotEqualTo(WAKEFULNESS_AWAKE);
+    }
+
+    @Test
+    public void testScreenOffTimeout_usesDockedTimeoutWhenDocked() {
+        final DisplayInfo info = new DisplayInfo();
+        info.displayGroupId = Display.DEFAULT_DISPLAY_GROUP;
+        when(mDisplayManagerInternalMock.getDisplayInfo(Display.DEFAULT_DISPLAY)).thenReturn(info);
+
+        setMinimumScreenOffTimeoutConfig(10);
+        setScreenOffTimeout(10);
+        setScreenOffTimeoutDocked(30);
+
+        createService();
+        startSystem();
+
+        mService.getBinderServiceInstance().userActivity(Display.DEFAULT_DISPLAY, mClock.now(),
+                PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
+        mDockReceiver.onReceive(mContextSpy,
+                new Intent(Intent.ACTION_DOCK_EVENT).putExtra(Intent.EXTRA_DOCK_STATE,
+                        Intent.EXTRA_DOCK_STATE_DESK));
+
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        advanceTime(15);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        advanceTime(20);
+        assertThat(mService.getGlobalWakefulnessLocked()).isNotEqualTo(WAKEFULNESS_AWAKE);
+    }
+
+    @Test
     public void testInattentiveSleep_goesToSleepWithWakeLock() {
         final String pkg = mContextSpy.getOpPackageName();
         final Binder token = new Binder();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 511296a..ef9494a 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -4659,6 +4659,59 @@
     }
 
     @Test
+    public void testAdjustmentToImportanceNone_cancelsNotification() throws Exception {
+        NotificationManagerService.WorkerHandler handler = mock(
+                NotificationManagerService.WorkerHandler.class);
+        mService.setHandler(handler);
+        when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
+        when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
+
+        // Set up notifications: r1 is adjusted, r2 is not
+        final NotificationRecord r1 = generateNotificationRecord(
+                mTestNotificationChannel, 1, null, true);
+        r1.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
+        mService.addNotification(r1);
+        final NotificationRecord r2 = generateNotificationRecord(
+                mTestNotificationChannel, 2, null, true);
+        r2.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
+        mService.addNotification(r2);
+
+        // Test an adjustment that sets importance to none (meaning it's cancelling)
+        Bundle signals1 = new Bundle();
+        signals1.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_NONE);
+        Adjustment adjustment1 = new Adjustment(
+                r1.getSbn().getPackageName(), r1.getKey(), signals1, "",
+                r1.getUser().getIdentifier());
+
+        mBinderService.applyAdjustmentFromAssistant(null, adjustment1);
+
+        // Actually apply the adjustments & recalculate importance when run
+        doAnswer(invocationOnMock -> {
+            ((NotificationRecord) invocationOnMock.getArguments()[0])
+                    .applyAdjustments();
+            ((NotificationRecord) invocationOnMock.getArguments()[0])
+                    .calculateImportance();
+            return null;
+        }).when(mRankingHelper).extractSignals(any(NotificationRecord.class));
+
+        // run the CancelNotificationRunnable when it happens
+        ArgumentCaptor<NotificationManagerService.CancelNotificationRunnable> captor =
+                ArgumentCaptor.forClass(
+                        NotificationManagerService.CancelNotificationRunnable.class);
+
+        verify(handler, times(1)).scheduleCancelNotification(
+                captor.capture());
+
+        // Run the runnable given to the cancel notification, and see if it logs properly
+        NotificationManagerService.CancelNotificationRunnable runnable = captor.getValue();
+        runnable.run();
+        assertEquals(1, mNotificationRecordLogger.numCalls());
+        assertEquals(
+                NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_ASSISTANT,
+                mNotificationRecordLogger.event(0));
+    }
+
+    @Test
     public void testEnqueuedAdjustmentAppliesAdjustments() throws Exception {
         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
         mService.addEnqueuedNotification(r);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
index f573b70..e433684 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
@@ -116,7 +116,7 @@
     public void testGetSnapshotMode() {
         final WindowState disabledWindow = createWindow(null,
                 FIRST_APPLICATION_WINDOW, mDisplayContent, "disabledWindow");
-        disabledWindow.mActivityRecord.setDisablePreviewScreenshots(true);
+        disabledWindow.mActivityRecord.setRecentsScreenshotEnabled(false);
         assertEquals(SNAPSHOT_MODE_APP_THEME,
                 mWm.mTaskSnapshotController.getSnapshotMode(disabledWindow.getTask()));
 
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index ba1a6ed..81bcf75 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -7639,7 +7639,7 @@
      * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
      * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
-     * TODO: remove this one. use {@link #rebootRadio()} for reset type 1 and
+     * TODO: remove this one. use {@link #rebootModem()} for reset type 1 and
      * {@link #resetRadioConfig()} for reset type 3
      *
      * @param resetType reset type: 1: reload NV reset, 2: erase NV reset, 3: factory NV reset
@@ -7706,6 +7706,8 @@
      *
      * @return {@code true} on success; {@code false} on any failure.
      *
+     * @deprecated  Using {@link #rebootModem()} instead.
+     *
      * @hide
      */
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
@@ -7726,6 +7728,30 @@
     }
 
     /**
+     * Generate a radio modem reset. Used for device configuration by some carriers.
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     * @throws IllegalStateException if the Telephony process is not currently available.
+     * @throws RuntimeException
+     */
+    @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
+    public void rebootModem() {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony == null) {
+                throw new IllegalStateException("telephony service is null.");
+            }
+            telephony.rebootModem(getSlotIndex());
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "rebootRadio RemoteException", ex);
+            throw ex.rethrowAsRuntimeException();
+        }
+    }
+
+    /**
      * Return an appropriate subscription ID for any situation.
      *
      * If this object has been created with {@link #createForSubscriptionId}, then the provided
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/DisableScreenshotsActivity.java b/tests/ActivityTests/src/com/google/android/test/activity/DisableScreenshotsActivity.java
index fa5724e..ca909a4 100644
--- a/tests/ActivityTests/src/com/google/android/test/activity/DisableScreenshotsActivity.java
+++ b/tests/ActivityTests/src/com/google/android/test/activity/DisableScreenshotsActivity.java
@@ -30,7 +30,7 @@
     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        setDisablePreviewScreenshots(true);
+        setRecentsScreenshotEnabled(false);
         getWindow().getDecorView().setBackgroundColor(Color.RED);
     }
 
diff --git a/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryStatsHelperPerfTest.java b/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryStatsHelperPerfTest.java
deleted file mode 100644
index 6266cda..0000000
--- a/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryStatsHelperPerfTest.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * 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.internal.os;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.Context;
-import android.os.BatteryStats;
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.perftests.utils.BenchmarkState;
-import android.perftests.utils.PerfStatusReporter;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.LargeTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-@LargeTest
-public class BatteryStatsHelperPerfTest {
-
-    @Rule
-    public final PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
-
-    /**
-     * Measures the performance of {@link BatteryStatsHelper#getStats()}, which triggers
-     * a battery stats sync on every iteration.
-     */
-    @Test
-    public void testGetStats_forceUpdate() {
-        final Context context = InstrumentationRegistry.getContext();
-        final BatteryStatsHelper statsHelper = new BatteryStatsHelper(context,
-                true /* collectBatteryBroadcast */);
-        statsHelper.create((Bundle) null);
-        statsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.myUserId());
-
-        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
-        while (state.keepRunning()) {
-            state.pauseTiming();
-            statsHelper.clearStats();
-            state.resumeTiming();
-
-            statsHelper.getStats();
-
-            assertThat(statsHelper.getUsageList()).isNotEmpty();
-        }
-    }
-
-    /**
-     * Measures performance of the {@link BatteryStatsHelper#getStats(boolean)}, which does
-     * not trigger a sync and just returns current values.
-     */
-    @Test
-    public void testGetStats_cached() {
-        final Context context = InstrumentationRegistry.getContext();
-        final BatteryStatsHelper statsHelper = new BatteryStatsHelper(context,
-                true /* collectBatteryBroadcast */);
-        statsHelper.create((Bundle) null);
-        statsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.myUserId());
-
-        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
-        while (state.keepRunning()) {
-            state.pauseTiming();
-            statsHelper.clearStats();
-            state.resumeTiming();
-
-            statsHelper.getStats(false /* forceUpdate */);
-
-            assertThat(statsHelper.getUsageList()).isNotEmpty();
-        }
-    }
-
-    @Test
-    public void testPowerCalculation() {
-        final Context context = InstrumentationRegistry.getContext();
-        final BatteryStatsHelper statsHelper = new BatteryStatsHelper(context,
-                true /* collectBatteryBroadcast */);
-        statsHelper.create((Bundle) null);
-        statsHelper.getStats();
-
-        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
-        while (state.keepRunning()) {
-            // This will use the cached BatteryStatsObject
-            statsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.myUserId());
-
-            assertThat(statsHelper.getUsageList()).isNotEmpty();
-        }
-    }
-
-    @Test
-    public void testEndToEnd() {
-        final Context context = InstrumentationRegistry.getContext();
-        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
-        while (state.keepRunning()) {
-            final BatteryStatsHelper statsHelper = new BatteryStatsHelper(context,
-                    true /* collectBatteryBroadcast */);
-            statsHelper.create((Bundle) null);
-            statsHelper.clearStats();
-            statsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.myUserId());
-
-            state.pauseTiming();
-
-            List<BatterySipper> usageList = statsHelper.getUsageList();
-            double power = 0;
-            for (int i = 0; i < usageList.size(); i++) {
-                BatterySipper sipper = usageList.get(i);
-                power += sipper.sumPower();
-            }
-
-            assertThat(power).isGreaterThan(0.0);
-
-            state.resumeTiming();
-        }
-    }
-}