Merge "Move required back to frameworks target."
diff --git a/Android.bp b/Android.bp
index b597432..9d05ffd 100644
--- a/Android.bp
+++ b/Android.bp
@@ -25,27 +25,32 @@
 //
 // READ ME: ########################################################
 
+filegroup {
+    name: "framework-defaults-java-srcs",
+    srcs: [
+        // java sources under this directory
+        "core/java/**/*.java",
+        "drm/java/**/*.java",
+        "graphics/java/**/*.java",
+        "keystore/java/**/*.java",
+        "location/java/**/*.java",
+        "lowpan/java/**/*.java",
+        "media/java/**/*.java",
+        "media/mca/effect/java/**/*.java",
+        "media/mca/filterfw/java/**/*.java",
+        "media/mca/filterpacks/java/**/*.java",
+        "opengl/java/**/*.java",
+        "rs/java/**/*.java",
+        "sax/java/**/*.java",
+        "telecomm/java/**/*.java",
+        "telephony/java/**/*.java",
+        "wifi/java/**/*.java",
+    ],
+}
+
 // TODO(b/70046217): make these as filegroups where the base directory for aidl files
 // is given as 'path'. Eliminate the need for aidl_local_include_dirs.
 framework_srcs = [
-    // java sources under this directory
-    "core/java/**/*.java",
-    "drm/java/**/*.java",
-    "graphics/java/**/*.java",
-    "keystore/java/**/*.java",
-    "location/java/**/*.java",
-    "lowpan/java/**/*.java",
-    "media/java/**/*.java",
-    "media/mca/effect/java/**/*.java",
-    "media/mca/filterfw/java/**/*.java",
-    "media/mca/filterpacks/java/**/*.java",
-    "opengl/java/**/*.java",
-    "rs/java/**/*.java",
-    "sax/java/**/*.java",
-    "telecomm/java/**/*.java",
-    "telephony/java/**/*.java",
-    "wifi/java/**/*.java",
-
     // aidl under this directory
     // b/70046217#comment15 These MUST come after all java srcs.
     // TODO(b/70046217) remove the above requirement
@@ -132,7 +137,9 @@
     defaults: ["framework-aidl-export-defaults"],
     installable: true,
 
-    srcs: framework_srcs,
+    srcs: [
+        ":framework-defaults-java-srcs",
+    ] + framework_srcs,
 
     aidl: {
         local_include_dirs: framework_aidl_local_include_dirs,
@@ -1165,10 +1172,10 @@
     name: "hiddenapi-mappings",
     defaults: ["metalava-api-stubs-default"],
     srcs: [
-        ":openjdk_java_files",
+        ":framework-defaults-java-srcs",
         ":non_openjdk_java_files",
+        ":openjdk_java_files",
         ":opt-telephony-common-srcs",
-        "core/java/**/*.java",
     ],
     arg_files: [
         "core/res/AndroidManifest.xml",
diff --git a/core/java/android/content/rollback/RollbackManager.java b/core/java/android/content/rollback/RollbackManager.java
index 73b8a48..1609f53 100644
--- a/core/java/android/content/rollback/RollbackManager.java
+++ b/core/java/android/content/rollback/RollbackManager.java
@@ -74,7 +74,10 @@
     }
 
     /**
-     * Returns a list of all currently available rollbacks.
+     * Returns a list of all currently available rollbacks. This includes ones for very recently
+     * installed packages (even if onFinished has not yet been called). As a result, packages that
+     * very recently failed to install may also be included, but those rollbacks will fail with
+     * 'rollback not available'.
      *
      * @throws SecurityException if the caller does not have appropriate permissions.
      */
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index 1142a07..fb6b231 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -100,9 +100,12 @@
     /**
      * @hide
      */
-    public static final int DISMISSED_REASON_POSITIVE = 1;
+    public static final int DISMISSED_REASON_CONFIRMED = 1;
 
     /**
+     * Dialog is done animating away after user clicked on the button set via
+     * {@link BiometricPrompt.Builder#setNegativeButton(CharSequence, Executor,
+     * DialogInterface.OnClickListener)}.
      * @hide
      */
     public static final int DISMISSED_REASON_NEGATIVE = 2;
@@ -112,6 +115,25 @@
      */
     public static final int DISMISSED_REASON_USER_CANCEL = 3;
 
+    /**
+     * Authenticated, confirmation not required. Dialog animated away.
+     * @hide
+     */
+    public static final int DISMISSED_REASON_CONFIRM_NOT_REQUIRED = 4;
+
+    /**
+     * Error message shown on SystemUI. When BiometricService receives this, the UI is already
+     * gone.
+     * @hide
+     */
+    public static final int DISMISSED_REASON_ERROR = 5;
+
+    /**
+     * Dialog dismissal requested by BiometricService.
+     * @hide
+     */
+    public static final int DISMISSED_REASON_SERVER_REQUESTED = 6;
+
     private static class ButtonInfo {
         Executor executor;
         DialogInterface.OnClickListener listener;
@@ -362,7 +384,7 @@
         @Override
         public void onDialogDismissed(int reason) throws RemoteException {
             // Check the reason and invoke OnClickListener(s) if necessary
-            if (reason == DISMISSED_REASON_POSITIVE) {
+            if (reason == DISMISSED_REASON_CONFIRMED) {
                 mPositiveButtonInfo.executor.execute(() -> {
                     mPositiveButtonInfo.listener.onClick(null, DialogInterface.BUTTON_POSITIVE);
                 });
diff --git a/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl b/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl
index 180daaf..ca6114e 100644
--- a/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl
@@ -27,8 +27,8 @@
     // Notify BiometricService that authentication was successful. If user confirmation is required,
     // the auth token must be submitted into KeyStore.
     void onAuthenticationSucceeded(boolean requireConfirmation, in byte[] token);
-    // Notify BiometricService that an error has occurred.
-    void onAuthenticationFailed(int cookie, boolean requireConfirmation);
+    // Notify BiometricService authentication was rejected.
+    void onAuthenticationFailed();
     // Notify BiometricService than an error has occured. Forward to the correct receiver depending
     // on the cookie.
     void onError(int cookie, int error, String message);
diff --git a/core/java/android/hardware/radio/TunerCallbackAdapter.java b/core/java/android/hardware/radio/TunerCallbackAdapter.java
index 0fb93e5..beff0f7 100644
--- a/core/java/android/hardware/radio/TunerCallbackAdapter.java
+++ b/core/java/android/hardware/radio/TunerCallbackAdapter.java
@@ -211,10 +211,12 @@
 
     @Override
     public void onProgramListUpdated(ProgramList.Chunk chunk) {
-        synchronized (mLock) {
-            if (mProgramList == null) return;
-            mProgramList.apply(Objects.requireNonNull(chunk));
-        }
+        mHandler.post(() -> {
+            synchronized (mLock) {
+                if (mProgramList == null) return;
+                mProgramList.apply(Objects.requireNonNull(chunk));
+            }
+        });
     }
 
     @Override
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 9abb64f..213a125 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8350,16 +8350,6 @@
                 BOOLEAN_VALIDATOR;
 
         /**
-         * Whether or not the face unlock education screen has been shown to the user.
-         * @hide
-         */
-        public static final String FACE_UNLOCK_EDUCATION_INFO_DISPLAYED =
-                "face_unlock_education_info_displayed";
-
-        private static final Validator FACE_UNLOCK_EDUCATION_INFO_DISPLAYED_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
-        /**
          * Whether or not debugging is enabled.
          * @hide
          */
@@ -9182,8 +9172,6 @@
             VALIDATORS.put(FACE_UNLOCK_APP_ENABLED, FACE_UNLOCK_APP_ENABLED_VALIDATOR);
             VALIDATORS.put(FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION,
                     FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION_VALIDATOR);
-            VALIDATORS.put(FACE_UNLOCK_EDUCATION_INFO_DISPLAYED,
-                    FACE_UNLOCK_EDUCATION_INFO_DISPLAYED_VALIDATOR);
             VALIDATORS.put(ASSIST_GESTURE_ENABLED, ASSIST_GESTURE_ENABLED_VALIDATOR);
             VALIDATORS.put(ASSIST_GESTURE_SILENCE_ALERTS_ENABLED,
                     ASSIST_GESTURE_SILENCE_ALERTS_ENABLED_VALIDATOR);
@@ -11058,12 +11046,6 @@
        public static final String WIFI_P2P_DEVICE_NAME = "wifi_p2p_device_name";
 
        /**
-        * The min time between wifi disable and wifi enable
-        * @hide
-        */
-       public static final String WIFI_REENABLE_DELAY_MS = "wifi_reenable_delay";
-
-       /**
         * Timeout for ephemeral networks when all known BSSIDs go out of range. We will disconnect
         * from an ephemeral network if there is no BSSID for that network with a non-null score that
         * has been seen in this time period.
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 00206fc..faeecda 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -164,6 +164,8 @@
     public static final String LAUNCH_LOCATON_DIRECT_SHARE = "direct_share";
     private static final int APP_PREDICTION_SHARE_TARGET_QUERY_PACKAGE_LIMIT = 20;
     public static final String APP_PREDICTION_INTENT_FILTER_KEY = "intent_filter";
+
+    private boolean mIsAppPredictorComponentAvailable;
     private AppPredictor mAppPredictor;
     private AppPredictor.Callback mAppPredictorCallback;
     private Map<ChooserTarget, AppTarget> mDirectShareAppTargetCache;
@@ -617,6 +619,9 @@
                 .addTaggedData(MetricsEvent.FIELD_SHARESHEET_MIMETYPE, target.getType())
                 .addTaggedData(MetricsEvent.FIELD_TIME_TO_APP_TARGETS, systemCost));
 
+        // This is the only place this value is being set. Effectively final.
+        mIsAppPredictorComponentAvailable = isAppPredictionServiceAvailable();
+
         AppPredictor appPredictor = getAppPredictorForDirectShareIfEnabled();
         if (appPredictor != null) {
             mDirectShareAppTargetCache = new HashMap<>();
@@ -707,6 +712,32 @@
     }
 
     /**
+     * Returns true if app prediction service is defined and the component exists on device.
+     */
+    private boolean isAppPredictionServiceAvailable() {
+        final String appPredictionServiceName =
+                getString(R.string.config_defaultAppPredictionService);
+        if (appPredictionServiceName == null) {
+            return false;
+        }
+        final ComponentName appPredictionComponentName =
+                ComponentName.unflattenFromString(appPredictionServiceName);
+        if (appPredictionComponentName == null) {
+            return false;
+        }
+
+        // Check if the app prediction component actually exists on the device.
+        Intent intent = new Intent();
+        intent.setComponent(appPredictionComponentName);
+        if (getPackageManager().resolveService(intent, PackageManager.MATCH_ALL) == null) {
+            Log.e(TAG, "App prediction service is defined, but does not exist: "
+                    + appPredictionServiceName);
+            return false;
+        }
+        return true;
+    }
+
+    /**
      * Check if the profile currently used is a work profile.
      * @return true if it is work profile, false if it is parent profile (or no work profile is
      * set up)
@@ -1693,6 +1724,9 @@
 
     @Nullable
     private AppPredictor getAppPredictor() {
+        if (!mIsAppPredictorComponentAvailable) {
+            return null;
+        }
         if (mAppPredictor == null
                     && getPackageManager().getAppPredictionServicePackageName() != null) {
             final IntentFilter filter = getTargetIntentFilter();
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index cf0394d..9441825 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -153,7 +153,7 @@
 
     // Used to show the dialog when BiometricService starts authentication
     void showBiometricDialog(in Bundle bundle, IBiometricServiceReceiverInternal receiver, int type,
-            boolean requireConfirmation, int userId);
+            boolean requireConfirmation, int userId, String opPackageName);
     // Used to hide the dialog when a biometric is authenticated
     void onBiometricAuthenticated(boolean authenticated, String failureReason);
     // Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 85ae18e..4c3a177 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -101,7 +101,7 @@
 
     // Used to show the dialog when BiometricService starts authentication
     void showBiometricDialog(in Bundle bundle, IBiometricServiceReceiverInternal receiver, int type,
-            boolean requireConfirmation, int userId);
+            boolean requireConfirmation, int userId, String opPackageName);
     // Used to hide the dialog when a biometric is authenticated
     void onBiometricAuthenticated(boolean authenticated, String failureReason);
     // Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 5cbf81c..096bf69 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -497,11 +497,8 @@
 
     auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
 
-    std::vector<uint8_t> byteData(parcel->dataSize());
-    memcpy(byteData.data(), parcel->data(), parcel->dataSize());
-
     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
-    transaction->setMetadata(ctrl, id, std::move(byteData));
+    transaction->setMetadata(ctrl, id, *parcel);
 }
 
 static void nativeSetColor(JNIEnv* env, jclass clazz, jlong transactionObj,
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index 0070694..a2d5d2a 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -1013,7 +1013,7 @@
         optional SettingProto watchdog_poor_network_test_enabled = 22 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto suspend_optimizations_enabled = 23 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto verbose_logging_enabled = 24 [ (android.privacy).dest = DEST_AUTOMATIC ];
-        reserved 25; // connected_mac_randomization_enabled
+        reserved 25; reserved "connected_mac_randomization_enabled";
         optional SettingProto max_dhcp_retry_count = 26 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto mobile_data_transition_wakelock_timeout_ms = 27 [ (android.privacy).dest = DEST_AUTOMATIC ];
         // Controls whether WiFi configurations created by a Device Owner app should
@@ -1025,7 +1025,7 @@
         optional SettingProto device_owner_configs_lockdown = 28 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto frequency_band = 29 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto p2p_device_name = 30;
-        optional SettingProto reenable_delay_ms = 31 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        reserved 31; reserved "reenable_delay_ms";
         optional SettingProto ephemeral_out_of_range_timeout_ms = 32 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto on_when_proxy_disconnected = 33 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto bounce_delay_override_ms = 34 [ (android.privacy).dest = DEST_AUTOMATIC ];
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
index 3d9a1d9..7c6271c 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
@@ -19,6 +19,7 @@
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -43,6 +44,7 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.mockito.stubbing.Answer;
+import org.mockito.verification.VerificationWithTimeout;
 
 import java.util.Arrays;
 import java.util.HashSet;
@@ -56,6 +58,8 @@
 public class StartProgramListUpdatesFanoutTest {
     private static final String TAG = "BroadcastRadioTests.hal2.StartProgramListUpdatesFanout";
 
+    private static final VerificationWithTimeout CB_TIMEOUT = timeout(100);
+
     // Mocks
     @Mock IBroadcastRadio mBroadcastRadioMock;
     @Mock ITunerSession mHalTunerSessionMock;
@@ -200,10 +204,10 @@
 
         // Adding mDabEnsembleInfo should not update any client.
         updateHalProgramInfo(false, Arrays.asList(mDabEnsembleInfo), null);
-        verify(mAidlTunerCallbackMocks[0], times(1)).onProgramListUpdated(any());
-        verify(mAidlTunerCallbackMocks[1], times(2)).onProgramListUpdated(any());
-        verify(mAidlTunerCallbackMocks[2], times(1)).onProgramListUpdated(any());
-        verify(mAidlTunerCallbackMocks[3], times(2)).onProgramListUpdated(any());
+        verify(mAidlTunerCallbackMocks[0], CB_TIMEOUT.times(1)).onProgramListUpdated(any());
+        verify(mAidlTunerCallbackMocks[1], CB_TIMEOUT.times(2)).onProgramListUpdated(any());
+        verify(mAidlTunerCallbackMocks[2], CB_TIMEOUT.times(1)).onProgramListUpdated(any());
+        verify(mAidlTunerCallbackMocks[3], CB_TIMEOUT.times(2)).onProgramListUpdated(any());
     }
 
     @Test
@@ -240,7 +244,7 @@
 
         // Update the HAL with mModifiedAmFmInfo, and verify only the remaining client is updated.
         updateHalProgramInfo(true, Arrays.asList(mModifiedAmFmInfo), null);
-        verify(mAidlTunerCallbackMocks[0], times(1)).onProgramListUpdated(any());
+        verify(mAidlTunerCallbackMocks[0], CB_TIMEOUT.times(1)).onProgramListUpdated(any());
         verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[1], true,
                 Arrays.asList(mModifiedAmFmInfo), null);
 
@@ -313,6 +317,6 @@
         }
         ProgramList.Chunk expectedChunk = new ProgramList.Chunk(purge, true, modifiedSet,
                 removedSet);
-        verify(clientMock).onProgramListUpdated(expectedChunk);
+        verify(clientMock, CB_TIMEOUT).onProgramListUpdated(expectedChunk);
     }
 }
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index bdbf368..97b7ae9 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -544,7 +544,6 @@
                     Settings.Global.WIFI_ON,
                     Settings.Global.WIFI_P2P_DEVICE_NAME,
                     Settings.Global.WIFI_P2P_PENDING_FACTORY_RESET,
-                    Settings.Global.WIFI_REENABLE_DELAY_MS,
                     Settings.Global.WIFI_RTT_BACKGROUND_EXEC_GAP_MS,
                     Settings.Global.WIFI_SAVED_STATE,
                     Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE,
@@ -721,7 +720,6 @@
                  Settings.Secure.BIOMETRIC_DEBUG_ENABLED,
                  Settings.Secure.FACE_UNLOCK_ATTENTION_REQUIRED,
                  Settings.Secure.FACE_UNLOCK_DIVERSITY_REQUIRED,
-                 Settings.Secure.FACE_UNLOCK_EDUCATION_INFO_DISPLAYED,
                  Settings.Secure.MANAGED_PROVISIONING_DPC_DOWNLOADED);
 
     @Test
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 89d3cc4..16f2917 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -20,6 +20,7 @@
     ],
 
     shared_libs: [
+        "libbinder",
         "libcutils",
         "liblog",
         "libutils",
diff --git a/libs/input/SpriteController.cpp b/libs/input/SpriteController.cpp
index c1868d3..fd386e9 100644
--- a/libs/input/SpriteController.cpp
+++ b/libs/input/SpriteController.cpp
@@ -245,7 +245,8 @@
         if (update.state.surfaceControl != NULL && (becomingVisible || becomingHidden
                 || (wantSurfaceVisibleAndDrawn && (update.state.dirty & (DIRTY_ALPHA
                         | DIRTY_POSITION | DIRTY_TRANSFORMATION_MATRIX | DIRTY_LAYER
-                        | DIRTY_VISIBILITY | DIRTY_HOTSPOT | DIRTY_DISPLAY_ID))))) {
+                        | DIRTY_VISIBILITY | DIRTY_HOTSPOT | DIRTY_DISPLAY_ID
+                        | DIRTY_ICON_STYLE))))) {
             needApplyTransaction = true;
 
             if (wantSurfaceVisibleAndDrawn
@@ -274,6 +275,21 @@
                         update.state.transformationMatrix.dtdy);
             }
 
+            if (wantSurfaceVisibleAndDrawn
+                    && (becomingVisible
+                            || (update.state.dirty & (DIRTY_HOTSPOT | DIRTY_ICON_STYLE)))) {
+                Parcel p;
+                p.writeInt32(update.state.icon.style);
+                p.writeFloat(update.state.icon.hotSpotX);
+                p.writeFloat(update.state.icon.hotSpotY);
+
+                // Pass cursor metadata in the sprite surface so that when Android is running as a
+                // client OS (e.g. ARC++) the host OS can get the requested cursor metadata and
+                // update mouse cursor in the host OS.
+                t.setMetadata(
+                        update.state.surfaceControl, METADATA_MOUSE_CURSOR, p);
+            }
+
             int32_t surfaceLayer = mOverlayLayer + update.state.layer;
             if (wantSurfaceVisibleAndDrawn
                     && (becomingVisible || (update.state.dirty & DIRTY_LAYER))) {
@@ -397,9 +413,14 @@
         } else {
             dirty = DIRTY_BITMAP;
         }
+
+        if (mLocked.state.icon.style != icon.style) {
+            mLocked.state.icon.style = icon.style;
+            dirty |= DIRTY_ICON_STYLE;
+        }
     } else if (mLocked.state.icon.isValid()) {
         mLocked.state.icon.bitmap.reset();
-        dirty = DIRTY_BITMAP | DIRTY_HOTSPOT;
+        dirty = DIRTY_BITMAP | DIRTY_HOTSPOT | DIRTY_ICON_STYLE;
     } else {
         return; // setting to invalid icon and already invalid so nothing to do
     }
diff --git a/libs/input/SpriteController.h b/libs/input/SpriteController.h
index 5b216f5..79a904f 100644
--- a/libs/input/SpriteController.h
+++ b/libs/input/SpriteController.h
@@ -55,11 +55,12 @@
  * Icon that a sprite displays, including its hotspot.
  */
 struct SpriteIcon {
-    inline SpriteIcon() : hotSpotX(0), hotSpotY(0) { }
-    inline SpriteIcon(const SkBitmap& bitmap, float hotSpotX, float hotSpotY) :
-            bitmap(bitmap), hotSpotX(hotSpotX), hotSpotY(hotSpotY) { }
+    inline SpriteIcon() : style(0), hotSpotX(0), hotSpotY(0) { }
+    inline SpriteIcon(const SkBitmap& bitmap, int32_t style, float hotSpotX, float hotSpotY) :
+            bitmap(bitmap), style(style), hotSpotX(hotSpotX), hotSpotY(hotSpotY) { }
 
     SkBitmap bitmap;
+    int32_t style;
     float hotSpotX;
     float hotSpotY;
 
@@ -69,11 +70,12 @@
             bitmap.readPixels(bitmapCopy.info(), bitmapCopy.getPixels(), bitmapCopy.rowBytes(),
                     0, 0);
         }
-        return SpriteIcon(bitmapCopy, hotSpotX, hotSpotY);
+        return SpriteIcon(bitmapCopy, style, hotSpotX, hotSpotY);
     }
 
     inline void reset() {
         bitmap.reset();
+        style = 0;
         hotSpotX = 0;
         hotSpotY = 0;
     }
@@ -149,15 +151,15 @@
     SpriteController(const sp<Looper>& looper, int32_t overlayLayer);
 
     /* Creates a new sprite, initially invisible. */
-    sp<Sprite> createSprite();
+    virtual sp<Sprite> createSprite();
 
     /* Opens or closes a transaction to perform a batch of sprite updates as part of
      * a single operation such as setPosition and setAlpha.  It is not necessary to
      * open a transaction when updating a single property.
      * Calls to openTransaction() nest and must be matched by an equal number
      * of calls to closeTransaction(). */
-    void openTransaction();
-    void closeTransaction();
+    virtual void openTransaction();
+    virtual void closeTransaction();
 
 private:
     enum {
@@ -174,6 +176,7 @@
         DIRTY_VISIBILITY = 1 << 5,
         DIRTY_HOTSPOT = 1 << 6,
         DIRTY_DISPLAY_ID = 1 << 7,
+        DIRTY_ICON_STYLE = 1 << 8,
     };
 
     /* Describes the state of a sprite.
diff --git a/libs/input/TEST_MAPPING b/libs/input/TEST_MAPPING
new file mode 100644
index 0000000..fe74c62
--- /dev/null
+++ b/libs/input/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+    "presubmit": [
+        {
+            "name": "libinputservice_test"
+        }
+    ]
+}
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
new file mode 100644
index 0000000..e83b2a7
--- /dev/null
+++ b/libs/input/tests/Android.bp
@@ -0,0 +1,45 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "libinputservice_test",
+    srcs: [
+        "PointerController_test.cpp",
+    ],
+    shared_libs: [
+        "libinputservice",
+        "libgui",
+        "libhwui",
+        "libutils",
+    ],
+    static_libs: [
+        "libgmock",
+        "libgtest",
+    ],
+    header_libs: [
+        "libbase_headers",
+        "libinputflinger_headers",
+    ],
+    include_dirs: [
+        "frameworks/base/libs",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+    ],
+    test_suites: [
+        "general-tests",
+    ],
+}
diff --git a/libs/input/tests/PointerController_test.cpp b/libs/input/tests/PointerController_test.cpp
new file mode 100644
index 0000000..92efb4e
--- /dev/null
+++ b/libs/input/tests/PointerController_test.cpp
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mocks/MockSprite.h"
+#include "mocks/MockSpriteController.h"
+
+#include <input/PointerController.h>
+#include <input/SpriteController.h>
+
+#include <atomic>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <thread>
+
+namespace android {
+
+enum TestCursorType {
+    CURSOR_TYPE_DEFAULT = 0,
+    CURSOR_TYPE_HOVER,
+    CURSOR_TYPE_TOUCH,
+    CURSOR_TYPE_ANCHOR,
+    CURSOR_TYPE_ADDITIONAL_1,
+    CURSOR_TYPE_ADDITIONAL_2,
+    CURSOR_TYPE_CUSTOM = -1,
+};
+
+using ::testing::AllOf;
+using ::testing::Field;
+using ::testing::NiceMock;
+using ::testing::Mock;
+using ::testing::Return;
+using ::testing::Test;
+
+std::pair<float, float> getHotSpotCoordinatesForType(int32_t type) {
+    return std::make_pair(type * 10, type * 10 + 5);
+}
+
+class MockPointerControllerPolicyInterface : public PointerControllerPolicyInterface {
+public:
+    virtual void loadPointerIcon(SpriteIcon* icon, int32_t displayId) override;
+    virtual void loadPointerResources(PointerResources* outResources, int32_t displayId) override;
+    virtual void loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources,
+            std::map<int32_t, PointerAnimation>* outAnimationResources, int32_t displayId) override;
+    virtual int32_t getDefaultPointerIconId() override;
+    virtual int32_t getCustomPointerIconId() override;
+
+private:
+    void loadPointerIconForType(SpriteIcon* icon, int32_t cursorType);
+};
+
+void MockPointerControllerPolicyInterface::loadPointerIcon(SpriteIcon* icon, int32_t) {
+    loadPointerIconForType(icon, CURSOR_TYPE_DEFAULT);
+}
+
+void MockPointerControllerPolicyInterface::loadPointerResources(PointerResources* outResources,
+        int32_t) {
+    loadPointerIconForType(&outResources->spotHover, CURSOR_TYPE_HOVER);
+    loadPointerIconForType(&outResources->spotTouch, CURSOR_TYPE_TOUCH);
+    loadPointerIconForType(&outResources->spotAnchor, CURSOR_TYPE_ANCHOR);
+}
+
+void MockPointerControllerPolicyInterface::loadAdditionalMouseResources(
+        std::map<int32_t, SpriteIcon>* outResources,
+        std::map<int32_t, PointerAnimation>* outAnimationResources,
+        int32_t) {
+    SpriteIcon icon;
+    PointerAnimation anim;
+
+    for (int32_t cursorType : {CURSOR_TYPE_ADDITIONAL_1, CURSOR_TYPE_ADDITIONAL_2}) {
+        loadPointerIconForType(&icon, cursorType);
+        anim.animationFrames.push_back(icon);
+        anim.durationPerFrame = 10;
+        (*outResources)[cursorType] = icon;
+        (*outAnimationResources)[cursorType] = anim;
+    }
+}
+
+int32_t MockPointerControllerPolicyInterface::getDefaultPointerIconId() {
+    return CURSOR_TYPE_DEFAULT;
+}
+
+int32_t MockPointerControllerPolicyInterface::getCustomPointerIconId() {
+    return CURSOR_TYPE_CUSTOM;
+}
+
+void MockPointerControllerPolicyInterface::loadPointerIconForType(SpriteIcon* icon, int32_t type) {
+    icon->style = type;
+    std::pair<float, float> hotSpot = getHotSpotCoordinatesForType(type);
+    icon->hotSpotX = hotSpot.first;
+    icon->hotSpotY = hotSpot.second;
+}
+
+class PointerControllerTest : public Test {
+protected:
+    PointerControllerTest();
+    ~PointerControllerTest();
+
+    sp<MockSprite> mPointerSprite;
+    sp<MockPointerControllerPolicyInterface> mPolicy;
+    sp<MockSpriteController> mSpriteController;
+    sp<PointerController> mPointerController;
+
+private:
+    void loopThread();
+
+    std::atomic<bool> mRunning = true;
+    class MyLooper : public Looper {
+    public:
+        MyLooper() : Looper(false) {}
+        ~MyLooper() = default;
+    };
+    sp<MyLooper> mLooper;
+    std::thread mThread;
+};
+
+PointerControllerTest::PointerControllerTest() : mPointerSprite(new NiceMock<MockSprite>),
+        mLooper(new MyLooper), mThread(&PointerControllerTest::loopThread, this) {
+
+    mSpriteController = new NiceMock<MockSpriteController>(mLooper);
+    mPolicy = new MockPointerControllerPolicyInterface();
+
+    EXPECT_CALL(*mSpriteController, createSprite())
+            .WillOnce(Return(mPointerSprite));
+
+    mPointerController = new PointerController(mPolicy, mLooper, mSpriteController);
+
+    DisplayViewport viewport;
+    viewport.displayId = ADISPLAY_ID_DEFAULT;
+    viewport.logicalRight = 1600;
+    viewport.logicalBottom = 1200;
+    viewport.physicalRight = 800;
+    viewport.physicalBottom = 600;
+    viewport.deviceWidth = 400;
+    viewport.deviceHeight = 300;
+    mPointerController->setDisplayViewport(viewport);
+}
+
+PointerControllerTest::~PointerControllerTest() {
+    mRunning.store(false, std::memory_order_relaxed);
+    mThread.join();
+}
+
+void PointerControllerTest::loopThread() {
+    Looper::setForThread(mLooper);
+
+    while (mRunning.load(std::memory_order_relaxed)) {
+        mLooper->pollOnce(100);
+    }
+}
+
+TEST_F(PointerControllerTest, useDefaultCursorTypeByDefault) {
+    mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE);
+
+    std::pair<float, float> hotspot = getHotSpotCoordinatesForType(CURSOR_TYPE_DEFAULT);
+    EXPECT_CALL(*mPointerSprite, setVisible(true));
+    EXPECT_CALL(*mPointerSprite, setAlpha(1.0f));
+    EXPECT_CALL(*mPointerSprite, setIcon(
+            AllOf(
+                    Field(&SpriteIcon::style, CURSOR_TYPE_DEFAULT),
+                    Field(&SpriteIcon::hotSpotX, hotspot.first),
+                    Field(&SpriteIcon::hotSpotY, hotspot.second))));
+    mPointerController->reloadPointerResources();
+}
+
+TEST_F(PointerControllerTest, updatePointerIcon) {
+    mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE);
+
+    int32_t type = CURSOR_TYPE_ADDITIONAL_1;
+    std::pair<float, float> hotspot = getHotSpotCoordinatesForType(type);
+    EXPECT_CALL(*mPointerSprite, setVisible(true));
+    EXPECT_CALL(*mPointerSprite, setAlpha(1.0f));
+    EXPECT_CALL(*mPointerSprite, setIcon(
+            AllOf(
+                    Field(&SpriteIcon::style, type),
+                    Field(&SpriteIcon::hotSpotX, hotspot.first),
+                    Field(&SpriteIcon::hotSpotY, hotspot.second))));
+    mPointerController->updatePointerIcon(type);
+}
+
+TEST_F(PointerControllerTest, setCustomPointerIcon) {
+    mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE);
+
+    int32_t style = CURSOR_TYPE_CUSTOM;
+    float hotSpotX = 15;
+    float hotSpotY = 20;
+
+    SpriteIcon icon;
+    icon.style = style;
+    icon.hotSpotX = hotSpotX;
+    icon.hotSpotY = hotSpotY;
+
+    EXPECT_CALL(*mPointerSprite, setVisible(true));
+    EXPECT_CALL(*mPointerSprite, setAlpha(1.0f));
+    EXPECT_CALL(*mPointerSprite, setIcon(
+            AllOf(
+                    Field(&SpriteIcon::style, style),
+                    Field(&SpriteIcon::hotSpotX, hotSpotX),
+                    Field(&SpriteIcon::hotSpotY, hotSpotY))));
+    mPointerController->setCustomPointerIcon(icon);
+}
+
+}  // namespace android
diff --git a/libs/input/tests/mocks/MockSprite.h b/libs/input/tests/mocks/MockSprite.h
new file mode 100644
index 0000000..013b79c
--- /dev/null
+++ b/libs/input/tests/mocks/MockSprite.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _MOCK_SPRITE_H
+#define _MOCK_SPRITE_H
+
+#include <input/SpriteController.h>
+
+#include <gmock/gmock.h>
+
+namespace android {
+
+class MockSprite : public Sprite {
+public:
+    virtual ~MockSprite() = default;
+
+    MOCK_METHOD(void, setIcon, (const SpriteIcon& icon), (override));
+    MOCK_METHOD(void, setVisible, (bool), (override));
+    MOCK_METHOD(void, setPosition, (float, float), (override));
+    MOCK_METHOD(void, setLayer, (int32_t), (override));
+    MOCK_METHOD(void, setAlpha, (float), (override));
+    MOCK_METHOD(void, setTransformationMatrix, (const SpriteTransformationMatrix&), (override));
+    MOCK_METHOD(void, setDisplayId, (int32_t), (override));
+};
+
+}  // namespace android
+
+#endif  // _MOCK_SPRITE_H
diff --git a/libs/input/tests/mocks/MockSpriteController.h b/libs/input/tests/mocks/MockSpriteController.h
new file mode 100644
index 0000000..a034f66
--- /dev/null
+++ b/libs/input/tests/mocks/MockSpriteController.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _MOCK_SPRITE_CONTROLLER_H
+#define _MOCK_SPRITE_CONTROLLER_H
+
+#include "MockSprite.h"
+
+#include <input/SpriteController.h>
+
+namespace android {
+
+class MockSpriteController : public SpriteController {
+
+public:
+    MockSpriteController(sp<Looper> looper) : SpriteController(looper, 0) {}
+    ~MockSpriteController() {}
+
+    MOCK_METHOD(sp<Sprite>, createSprite, (), (override));
+    MOCK_METHOD(void, openTransaction, (), (override));
+    MOCK_METHOD(void, closeTransaction, (), (override));
+};
+
+}  // namespace android
+
+#endif  // _MOCK_SPRITE_CONTROLLER_H
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index a3b0e6b..b7eddc2 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1607,9 +1607,6 @@
                 Settings.Global.WIFI_P2P_DEVICE_NAME,
                 GlobalSettingsProto.Wifi.P2P_DEVICE_NAME);
         dumpSetting(s, p,
-                Settings.Global.WIFI_REENABLE_DELAY_MS,
-                GlobalSettingsProto.Wifi.REENABLE_DELAY_MS);
-        dumpSetting(s, p,
                 Settings.Global.WIFI_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS,
                 GlobalSettingsProto.Wifi.EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS);
         dumpSetting(s, p,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 7016d30..c1aa0f9 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -314,11 +314,6 @@
     public boolean onCreate() {
         Settings.setInSystemServer();
 
-        // fail to boot if there're any backed up settings that don't have a non-null validator
-        ensureAllBackedUpSystemSettingsHaveValidators();
-        ensureAllBackedUpGlobalSettingsHaveValidators();
-        ensureAllBackedUpSecureSettingsHaveValidators();
-
         synchronized (mLock) {
             mUserManager = UserManager.get(getContext());
             mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
@@ -338,57 +333,6 @@
         return true;
     }
 
-    private void ensureAllBackedUpSystemSettingsHaveValidators() {
-        String offenders = getOffenders(concat(Settings.System.SETTINGS_TO_BACKUP,
-                Settings.System.LEGACY_RESTORE_SETTINGS), Settings.System.VALIDATORS);
-
-        failToBootIfOffendersPresent(offenders, "Settings.System");
-    }
-
-    private void ensureAllBackedUpGlobalSettingsHaveValidators() {
-        String offenders = getOffenders(concat(Settings.Global.SETTINGS_TO_BACKUP,
-                Settings.Global.LEGACY_RESTORE_SETTINGS), Settings.Global.VALIDATORS);
-
-        failToBootIfOffendersPresent(offenders, "Settings.Global");
-    }
-
-    private void ensureAllBackedUpSecureSettingsHaveValidators() {
-        String offenders = getOffenders(concat(Settings.Secure.SETTINGS_TO_BACKUP,
-                Settings.Secure.LEGACY_RESTORE_SETTINGS), Settings.Secure.VALIDATORS);
-
-        failToBootIfOffendersPresent(offenders, "Settings.Secure");
-    }
-
-    private void failToBootIfOffendersPresent(String offenders, String settingsType) {
-        if (offenders.length() > 0) {
-            throw new RuntimeException("All " + settingsType + " settings that are backed up"
-                    + " have to have a non-null validator, but those don't: " + offenders);
-        }
-    }
-
-    private String getOffenders(String[] settingsToBackup, Map<String,
-            SettingsValidators.Validator> validators) {
-        StringBuilder offenders = new StringBuilder();
-        for (String setting : settingsToBackup) {
-            if (validators.get(setting) == null) {
-                offenders.append(setting).append(" ");
-            }
-        }
-        return offenders.toString();
-    }
-
-    private final String[] concat(String[] first, String[] second) {
-        if (second == null || second.length == 0) {
-            return first;
-        }
-        final int firstLen = first.length;
-        final int secondLen = second.length;
-        String[] both = new String[firstLen + secondLen];
-        System.arraycopy(first, 0, both, 0, firstLen);
-        System.arraycopy(second, 0, both, firstLen, secondLen);
-        return both;
-    }
-
     @Override
     public Bundle call(String method, String name, Bundle args) {
         final int requestingUserId = getRequestingUserId(args);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialog.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialog.java
new file mode 100644
index 0000000..d4baefd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialog.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics;
+
+import android.hardware.biometrics.BiometricPrompt;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+import com.android.systemui.biometrics.ui.BiometricDialogView;
+
+/**
+ * Interface for the biometric dialog UI.
+ */
+public interface BiometricDialog {
+
+    // TODO: Clean up save/restore state
+    String[] KEYS_TO_BACKUP = {
+            BiometricPrompt.KEY_TITLE,
+            BiometricPrompt.KEY_USE_DEFAULT_TITLE,
+            BiometricPrompt.KEY_SUBTITLE,
+            BiometricPrompt.KEY_DESCRIPTION,
+            BiometricPrompt.KEY_POSITIVE_TEXT,
+            BiometricPrompt.KEY_NEGATIVE_TEXT,
+            BiometricPrompt.KEY_REQUIRE_CONFIRMATION,
+            BiometricPrompt.KEY_ALLOW_DEVICE_CREDENTIAL,
+            BiometricPrompt.KEY_FROM_CONFIRM_DEVICE_CREDENTIAL,
+
+            BiometricDialogView.KEY_TRY_AGAIN_VISIBILITY,
+            BiometricDialogView.KEY_CONFIRM_VISIBILITY,
+            BiometricDialogView.KEY_CONFIRM_ENABLED,
+            BiometricDialogView.KEY_STATE,
+            BiometricDialogView.KEY_ERROR_TEXT_VISIBILITY,
+            BiometricDialogView.KEY_ERROR_TEXT_STRING,
+            BiometricDialogView.KEY_ERROR_TEXT_IS_TEMPORARY,
+            BiometricDialogView.KEY_ERROR_TEXT_COLOR,
+    };
+
+    /**
+     * Show the dialog.
+     * @param wm
+     * @param skipIntroAnimation
+     */
+    void show(WindowManager wm, boolean skipIntroAnimation);
+
+    /**
+     * Dismiss the dialog without sending a callback.
+     */
+    void dismissWithoutCallback(boolean animate);
+
+    /**
+     * Dismiss the dialog. Animate away.
+     */
+    void dismissFromSystemServer();
+
+    /**
+     * Biometric authenticated. May be pending user confirmation, or completed.
+     */
+    void onAuthenticationSucceeded();
+
+    /**
+     * Authentication failed (reject, timeout). Dialog stays showing.
+     * @param failureReason
+     */
+    void onAuthenticationFailed(String failureReason);
+
+    /**
+     * Authentication rejected, or help message received.
+     * @param help
+     */
+    void onHelp(String help);
+
+    /**
+     * Authentication failed. Dialog going away.
+     * @param error
+     */
+    void onError(String error);
+
+    /**
+     * Save the current state.
+     * @param outState
+     */
+    void onSaveState(Bundle outState);
+
+    /**
+     * Restore a previous state.
+     * @param savedState
+     */
+    void restoreState(Bundle savedState);
+
+    /**
+     * Get the client's package name
+     */
+    String getOpPackageName();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
index e66a8fa..a8e5722 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
@@ -16,137 +16,156 @@
 
 package com.android.systemui.biometrics;
 
+import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
+import android.app.IActivityTaskManager;
+import android.app.TaskStackListener;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
-import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.biometrics.BiometricPrompt;
 import android.hardware.biometrics.IBiometricServiceReceiverInternal;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
-import android.os.Message;
 import android.os.RemoteException;
 import android.util.Log;
 import android.view.WindowManager;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.SomeArgs;
-import com.android.systemui.Dependency;
 import com.android.systemui.SystemUI;
-import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.biometrics.ui.BiometricDialogView;
 import com.android.systemui.statusbar.CommandQueue;
 
+import java.util.List;
+
 /**
- * Receives messages sent from AuthenticationClient and shows the appropriate biometric UI (e.g.
- * BiometricDialogView).
+ * Receives messages sent from {@link com.android.server.biometrics.BiometricService} and shows the
+ * appropriate biometric UI (e.g. BiometricDialogView).
  */
-public class BiometricDialogImpl extends SystemUI implements CommandQueue.Callbacks {
+public class BiometricDialogImpl extends SystemUI implements CommandQueue.Callbacks,
+        DialogViewCallback {
     private static final String TAG = "BiometricDialogImpl";
     private static final boolean DEBUG = true;
 
-    private static final int MSG_SHOW_DIALOG = 1;
-    private static final int MSG_BIOMETRIC_AUTHENTICATED = 2;
-    private static final int MSG_BIOMETRIC_HELP = 3;
-    private static final int MSG_BIOMETRIC_ERROR = 4;
-    private static final int MSG_HIDE_DIALOG = 5;
-    private static final int MSG_BUTTON_NEGATIVE = 6;
-    private static final int MSG_USER_CANCELED = 7;
-    private static final int MSG_BUTTON_POSITIVE = 8;
-    private static final int MSG_TRY_AGAIN_PRESSED = 9;
+    private final Injector mInjector;
 
+    // TODO: These should just be saved from onSaveState
     private SomeArgs mCurrentDialogArgs;
-    private BiometricDialogView mCurrentDialog;
+    @VisibleForTesting
+    BiometricDialog mCurrentDialog;
+
+    private Handler mHandler = new Handler(Looper.getMainLooper());
     private WindowManager mWindowManager;
-    private IBiometricServiceReceiverInternal mReceiver;
-    private boolean mDialogShowing;
-    private Callback mCallback = new Callback();
-    private WakefulnessLifecycle mWakefulnessLifecycle;
+    @VisibleForTesting
+    IActivityTaskManager mActivityTaskManager;
+    @VisibleForTesting
+    BiometricTaskStackListener mTaskStackListener;
+    @VisibleForTesting
+    IBiometricServiceReceiverInternal mReceiver;
 
-    private Handler mHandler = new Handler(Looper.getMainLooper()) {
+    public class BiometricTaskStackListener extends TaskStackListener {
         @Override
-        public void handleMessage(Message msg) {
-            switch(msg.what) {
-                case MSG_SHOW_DIALOG:
-                    handleShowDialog((SomeArgs) msg.obj, false /* skipAnimation */,
-                            null /* savedState */);
-                    break;
-                case MSG_BIOMETRIC_AUTHENTICATED: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    handleBiometricAuthenticated((boolean) args.arg1 /* authenticated */,
-                            (String) args.arg2 /* failureReason */);
-                    args.recycle();
-                    break;
-                }
-                case MSG_BIOMETRIC_HELP: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    handleBiometricHelp((String) args.arg1 /* message */);
-                    args.recycle();
-                    break;
-                }
-                case MSG_BIOMETRIC_ERROR:
-                    handleBiometricError((String) msg.obj);
-                    break;
-                case MSG_HIDE_DIALOG:
-                    handleHideDialog((Boolean) msg.obj);
-                    break;
-                case MSG_BUTTON_NEGATIVE:
-                    handleButtonNegative();
-                    break;
-                case MSG_USER_CANCELED:
-                    handleUserCanceled();
-                    break;
-                case MSG_BUTTON_POSITIVE:
-                    handleButtonPositive();
-                    break;
-                case MSG_TRY_AGAIN_PRESSED:
-                    handleTryAgainPressed();
-                    break;
-                default:
-                    Log.w(TAG, "Unknown message: " + msg.what);
-                    break;
-            }
-        }
-    };
-
-    private class Callback implements DialogViewCallback {
-        @Override
-        public void onUserCanceled() {
-            mHandler.obtainMessage(MSG_USER_CANCELED).sendToTarget();
-        }
-
-        @Override
-        public void onErrorShown() {
-            mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_HIDE_DIALOG,
-                    false /* userCanceled */), BiometricPrompt.HIDE_DIALOG_DELAY);
-        }
-
-        @Override
-        public void onNegativePressed() {
-            mHandler.obtainMessage(MSG_BUTTON_NEGATIVE).sendToTarget();
-        }
-
-        @Override
-        public void onPositivePressed() {
-            mHandler.obtainMessage(MSG_BUTTON_POSITIVE).sendToTarget();
-        }
-
-        @Override
-        public void onTryAgainPressed() {
-            mHandler.obtainMessage(MSG_TRY_AGAIN_PRESSED).sendToTarget();
+        public void onTaskStackChanged() {
+            mHandler.post(mTaskStackChangedRunnable);
         }
     }
 
-    final WakefulnessLifecycle.Observer mWakefulnessObserver = new WakefulnessLifecycle.Observer() {
-        @Override
-        public void onStartedGoingToSleep() {
-            if (mDialogShowing) {
-                if (DEBUG) Log.d(TAG, "User canceled due to screen off");
-                mHandler.obtainMessage(MSG_USER_CANCELED).sendToTarget();
+    private final Runnable mTaskStackChangedRunnable = () -> {
+        if (mCurrentDialog != null) {
+            try {
+                final String clientPackage = mCurrentDialog.getOpPackageName();
+                Log.w(TAG, "Task stack changed, current client: " + clientPackage);
+                final List<ActivityManager.RunningTaskInfo> runningTasks =
+                        mActivityTaskManager.getTasks(1);
+                if (!runningTasks.isEmpty()) {
+                    final String topPackage = runningTasks.get(0).topActivity.getPackageName();
+                    if (!topPackage.contentEquals(clientPackage)) {
+                        Log.w(TAG, "Evicting client due to: " + topPackage);
+                        mCurrentDialog.dismissWithoutCallback(true /* animate */);
+                        mCurrentDialog = null;
+                        mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
+                        mReceiver = null;
+                    }
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG, "Remote exception", e);
             }
         }
     };
 
     @Override
+    public void onTryAgainPressed() {
+        try {
+            mReceiver.onTryAgainPressed();
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException when handling try again", e);
+        }
+    }
+
+    @Override
+    public void onDismissed(@DismissedReason int reason) {
+        switch (reason) {
+            case DialogViewCallback.DISMISSED_USER_CANCELED:
+                sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
+                break;
+
+            case DialogViewCallback.DISMISSED_BUTTON_NEGATIVE:
+                sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_NEGATIVE);
+                break;
+
+            case DialogViewCallback.DISMISSED_BUTTON_POSITIVE:
+                sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_CONFIRMED);
+                break;
+
+            case DialogViewCallback.DISMISSED_AUTHENTICATED:
+                sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_CONFIRM_NOT_REQUIRED);
+                break;
+
+            case DialogViewCallback.DISMISSED_ERROR:
+                sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_ERROR);
+                break;
+
+            case DialogViewCallback.DISMISSED_BY_SYSTEM_SERVER:
+                sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_SERVER_REQUESTED);
+                break;
+
+            default:
+                Log.e(TAG, "Unhandled reason: " + reason);
+                break;
+        }
+    }
+
+    private void sendResultAndCleanUp(@DismissedReason int reason) {
+        if (mReceiver == null) {
+            Log.e(TAG, "Receiver is null");
+            return;
+        }
+        try {
+            mReceiver.onDialogDismissed(reason);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Remote exception", e);
+        }
+        onDialogDismissed(reason);
+    }
+
+    public static class Injector {
+        IActivityTaskManager getActivityTaskManager() {
+            return ActivityTaskManager.getService();
+        }
+    }
+
+    public BiometricDialogImpl() {
+        this(new Injector());
+    }
+
+    @VisibleForTesting
+    BiometricDialogImpl(Injector injector) {
+        mInjector = injector;
+    }
+
+    @Override
     public void start() {
         final PackageManager pm = mContext.getPackageManager();
         if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)
@@ -154,30 +173,38 @@
                 || pm.hasSystemFeature(PackageManager.FEATURE_IRIS)) {
             getComponent(CommandQueue.class).addCallback(this);
             mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
-            mWakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class);
-            mWakefulnessLifecycle.addObserver(mWakefulnessObserver);
+            mActivityTaskManager = mInjector.getActivityTaskManager();
+
+            try {
+                mTaskStackListener = new BiometricTaskStackListener();
+                mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Unable to register task stack listener", e);
+            }
         }
     }
 
     @Override
     public void showBiometricDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver,
-            int type, boolean requireConfirmation, int userId) {
+            int type, boolean requireConfirmation, int userId, String opPackageName) {
         if (DEBUG) {
             Log.d(TAG, "showBiometricDialog, type: " + type
                     + ", requireConfirmation: " + requireConfirmation);
         }
-        // Remove these messages as they are part of the previous client
-        mHandler.removeMessages(MSG_BIOMETRIC_ERROR);
-        mHandler.removeMessages(MSG_BIOMETRIC_HELP);
-        mHandler.removeMessages(MSG_BIOMETRIC_AUTHENTICATED);
-        mHandler.removeMessages(MSG_HIDE_DIALOG);
         SomeArgs args = SomeArgs.obtain();
         args.arg1 = bundle;
         args.arg2 = receiver;
         args.argi1 = type;
         args.arg3 = requireConfirmation;
         args.argi2 = userId;
-        mHandler.obtainMessage(MSG_SHOW_DIALOG, args).sendToTarget();
+        args.arg4 = opPackageName;
+
+        boolean skipAnimation = false;
+        if (mCurrentDialog != null) {
+            Log.w(TAG, "mCurrentDialog: " + mCurrentDialog);
+            skipAnimation = true;
+        }
+        showDialog(args, skipAnimation, null /* savedState */);
     }
 
     @Override
@@ -185,185 +212,111 @@
         if (DEBUG) Log.d(TAG, "onBiometricAuthenticated: " + authenticated
                 + " reason: " + failureReason);
 
-        SomeArgs args = SomeArgs.obtain();
-        args.arg1 = authenticated;
-        args.arg2 = failureReason;
-        mHandler.obtainMessage(MSG_BIOMETRIC_AUTHENTICATED, args).sendToTarget();
-    }
-
-    @Override
-    public void onBiometricHelp(String message) {
-        if (DEBUG) Log.d(TAG, "onBiometricHelp: " + message);
-        SomeArgs args = SomeArgs.obtain();
-        args.arg1 = message;
-        mHandler.obtainMessage(MSG_BIOMETRIC_HELP, args).sendToTarget();
-    }
-
-    @Override
-    public void onBiometricError(String error) {
-        if (DEBUG) Log.d(TAG, "onBiometricError: " + error);
-        mHandler.obtainMessage(MSG_BIOMETRIC_ERROR, error).sendToTarget();
-    }
-
-    @Override
-    public void hideBiometricDialog() {
-        if (DEBUG) Log.d(TAG, "hideBiometricDialog");
-        mHandler.obtainMessage(MSG_HIDE_DIALOG, false /* userCanceled */).sendToTarget();
-    }
-
-    private void handleShowDialog(SomeArgs args, boolean skipAnimation, Bundle savedState) {
-        mCurrentDialogArgs = args;
-        final int type = args.argi1;
-
-        // Create a new dialog but do not replace the current one yet.
-        BiometricDialogView newDialog;
-        if (type == BiometricAuthenticator.TYPE_FINGERPRINT) {
-            newDialog = new FingerprintDialogView(mContext, mCallback);
-        } else if (type == BiometricAuthenticator.TYPE_FACE) {
-            newDialog = new FaceDialogView(mContext, mCallback);
-        } else {
-            Log.e(TAG, "Unsupported type: " + type);
-            return;
-        }
-
-        if (DEBUG) Log.d(TAG, "handleShowDialog, "
-                + " savedState: " + savedState
-                + " mCurrentDialog: " + mCurrentDialog
-                + " newDialog: " + newDialog
-                + " type: " + type);
-
-        if (savedState != null) {
-            // SavedState is only non-null if it's from onConfigurationChanged. Restore the state
-            // even though it may be removed / re-created again
-            newDialog.restoreState(savedState);
-        } else if (mCurrentDialog != null && mDialogShowing) {
-            // If somehow we're asked to show a dialog, the old one doesn't need to be animated
-            // away. This can happen if the app cancels and re-starts auth during configuration
-            // change. This is ugly because we also have to do things on onConfigurationChanged
-            // here.
-            mCurrentDialog.forceRemove();
-        }
-
-        mReceiver = (IBiometricServiceReceiverInternal) args.arg2;
-        newDialog.setBundle((Bundle) args.arg1);
-        newDialog.setRequireConfirmation((boolean) args.arg3);
-        newDialog.setUserId(args.argi2);
-        newDialog.setSkipIntro(skipAnimation);
-        mCurrentDialog = newDialog;
-        mWindowManager.addView(mCurrentDialog, mCurrentDialog.getLayoutParams());
-        mDialogShowing = true;
-    }
-
-    private void handleBiometricAuthenticated(boolean authenticated, String failureReason) {
-        if (DEBUG) Log.d(TAG, "handleBiometricAuthenticated: " + authenticated);
-
         if (authenticated) {
-            mCurrentDialog.announceForAccessibility(
-                    mContext.getResources()
-                            .getText(mCurrentDialog.getAuthenticatedAccessibilityResourceId()));
-            if (mCurrentDialog.requiresConfirmation()) {
-                mCurrentDialog.updateState(BiometricDialogView.STATE_PENDING_CONFIRMATION);
-            } else {
-                mCurrentDialog.updateState(BiometricDialogView.STATE_AUTHENTICATED);
-                mHandler.postDelayed(() -> {
-                    handleHideDialog(false /* userCanceled */);
-                }, mCurrentDialog.getDelayAfterAuthenticatedDurationMs());
-            }
+            mCurrentDialog.onAuthenticationSucceeded();
         } else {
             mCurrentDialog.onAuthenticationFailed(failureReason);
         }
     }
 
-    private void handleBiometricHelp(String message) {
-        if (DEBUG) Log.d(TAG, "handleBiometricHelp: " + message);
-        mCurrentDialog.onHelpReceived(message);
+    @Override
+    public void onBiometricHelp(String message) {
+        if (DEBUG) Log.d(TAG, "onBiometricHelp: " + message);
+
+        mCurrentDialog.onHelp(message);
     }
 
-    private void handleBiometricError(String error) {
-        if (DEBUG) Log.d(TAG, "handleBiometricError: " + error);
-        if (!mDialogShowing) {
-            if (DEBUG) Log.d(TAG, "Dialog already dismissed");
-            return;
-        }
-        mCurrentDialog.onErrorReceived(error);
+    @Override
+    public void onBiometricError(String error) {
+        if (DEBUG) Log.d(TAG, "onBiometricError: " + error);
+        mCurrentDialog.onError(error);
     }
 
-    private void handleHideDialog(boolean userCanceled) {
-        if (DEBUG) Log.d(TAG, "handleHideDialog, userCanceled: " + userCanceled);
-        if (!mDialogShowing) {
-            // This can happen if there's a race and we get called from both
-            // onAuthenticated and onError, etc.
-            Log.w(TAG, "Dialog already dismissed, userCanceled: " + userCanceled);
+    @Override
+    public void hideBiometricDialog() {
+        if (DEBUG) Log.d(TAG, "hideBiometricDialog");
+
+        mCurrentDialog.dismissFromSystemServer();
+    }
+
+    private void showDialog(SomeArgs args, boolean skipAnimation, Bundle savedState) {
+        mCurrentDialogArgs = args;
+        final int type = args.argi1;
+        final Bundle biometricPromptBundle = (Bundle) args.arg1;
+        final boolean requireConfirmation = (boolean) args.arg3;
+        final int userId = args.argi2;
+        final String opPackageName = (String) args.arg4;
+
+        // Create a new dialog but do not replace the current one yet.
+        final BiometricDialog newDialog = buildDialog(
+                biometricPromptBundle,
+                requireConfirmation,
+                userId,
+                type,
+                opPackageName);
+
+        if (newDialog == null) {
+            Log.e(TAG, "Unsupported type: " + type);
             return;
         }
-        if (userCanceled) {
-            try {
-                mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
-            } catch (RemoteException e) {
-                Log.e(TAG, "RemoteException when hiding dialog", e);
-            }
+
+        if (DEBUG) {
+            Log.d(TAG, "showDialog, "
+                    + " savedState: " + savedState
+                    + " mCurrentDialog: " + mCurrentDialog
+                    + " newDialog: " + newDialog
+                    + " type: " + type);
+        }
+
+        if (savedState != null) {
+            // SavedState is only non-null if it's from onConfigurationChanged. Restore the state
+            // even though it may be removed / re-created again
+            newDialog.restoreState(savedState);
+        } else if (mCurrentDialog != null) {
+            // If somehow we're asked to show a dialog, the old one doesn't need to be animated
+            // away. This can happen if the app cancels and re-starts auth during configuration
+            // change. This is ugly because we also have to do things on onConfigurationChanged
+            // here.
+            mCurrentDialog.dismissWithoutCallback(false /* animate */);
+        }
+
+        mReceiver = (IBiometricServiceReceiverInternal) args.arg2;
+        mCurrentDialog = newDialog;
+        mCurrentDialog.show(mWindowManager, skipAnimation);
+    }
+
+    private void onDialogDismissed(@DismissedReason int reason) {
+        if (DEBUG) Log.d(TAG, "onDialogDismissed: " + reason);
+        if (mCurrentDialog == null) {
+            Log.w(TAG, "Dialog already dismissed");
         }
         mReceiver = null;
-        mDialogShowing = false;
-        mCurrentDialog.startDismiss();
-    }
-
-    private void handleButtonNegative() {
-        if (mReceiver == null) {
-            Log.e(TAG, "Receiver is null");
-            return;
-        }
-        try {
-            mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_NEGATIVE);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Remote exception when handling negative button", e);
-        }
-        handleHideDialog(false /* userCanceled */);
-    }
-
-    private void handleButtonPositive() {
-        if (mReceiver == null) {
-            Log.e(TAG, "Receiver is null");
-            return;
-        }
-        try {
-            mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_POSITIVE);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Remote exception when handling positive button", e);
-        }
-        handleHideDialog(false /* userCanceled */);
-    }
-
-    private void handleUserCanceled() {
-        handleHideDialog(true /* userCanceled */);
-    }
-
-    private void handleTryAgainPressed() {
-        try {
-            mReceiver.onTryAgainPressed();
-        } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException when handling try again", e);
-        }
+        mCurrentDialog = null;
     }
 
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
-        final boolean wasShowing = mDialogShowing;
 
         // Save the state of the current dialog (buttons showing, etc)
-        final Bundle savedState = new Bundle();
         if (mCurrentDialog != null) {
+            final Bundle savedState = new Bundle();
             mCurrentDialog.onSaveState(savedState);
-        }
+            mCurrentDialog.dismissWithoutCallback(false /* animate */);
+            mCurrentDialog = null;
 
-        if (mDialogShowing) {
-            mCurrentDialog.forceRemove();
-            mDialogShowing = false;
+            showDialog(mCurrentDialogArgs, true /* skipAnimation */, savedState);
         }
+    }
 
-        if (wasShowing) {
-            handleShowDialog(mCurrentDialogArgs, true /* skipAnimation */, savedState);
-        }
+    protected BiometricDialog buildDialog(Bundle biometricPromptBundle,
+            boolean requireConfirmation, int userId, int type, String opPackageName) {
+        return new BiometricDialogView.Builder(mContext)
+                .setCallback(this)
+                .setBiometricPromptBundle(biometricPromptBundle)
+                .setRequireConfirmation(requireConfirmation)
+                .setUserId(userId)
+                .setOpPackageName(opPackageName)
+                .build(type);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/DialogViewCallback.java b/packages/SystemUI/src/com/android/systemui/biometrics/DialogViewCallback.java
index 24fd22e..b65d1e8 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/DialogViewCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/DialogViewCallback.java
@@ -16,36 +16,38 @@
 
 package com.android.systemui.biometrics;
 
+import android.annotation.IntDef;
+
 /**
  * Callback interface for dialog views. These should be implemented by the controller (e.g.
  * FingerprintDialogImpl) and passed into their views (e.g. FingerprintDialogView).
  */
 public interface DialogViewCallback {
-    /**
-     * Invoked when the user cancels authentication by tapping outside the prompt, etc. The dialog
-     * should be dismissed.
-     */
-    void onUserCanceled();
+
+    int DISMISSED_USER_CANCELED = 1;
+    int DISMISSED_BUTTON_NEGATIVE = 2;
+    int DISMISSED_BUTTON_POSITIVE = 3;
+
+    int DISMISSED_AUTHENTICATED = 4;
+    int DISMISSED_ERROR = 5;
+    int DISMISSED_BY_SYSTEM_SERVER = 6;
+
+    @IntDef({DISMISSED_USER_CANCELED,
+            DISMISSED_BUTTON_NEGATIVE,
+            DISMISSED_BUTTON_POSITIVE,
+            DISMISSED_AUTHENTICATED,
+            DISMISSED_ERROR,
+            DISMISSED_BY_SYSTEM_SERVER})
+    @interface DismissedReason {}
 
     /**
-     * Invoked when an error is shown. The dialog should be dismissed after a set amount of time.
+     * Invoked when the dialog is dismissed
+     * @param reason
      */
-    void onErrorShown();
+    void onDismissed(@DismissedReason int reason);
 
     /**
-     * Invoked when the negative button is pressed. The client should be notified and the dialog
-     * should be dismissed.
-     */
-    void onNegativePressed();
-
-    /**
-     * Invoked when the positive button is pressed. The client should be notified and the dialog
-     * should be dismissed.
-     */
-    void onPositivePressed();
-
-    /**
-     * Invoked when the "try again" button is pressed.
+     * Invoked when the "try again" button is clicked
      */
     void onTryAgainPressed();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/ui/BiometricDialogView.java
similarity index 70%
rename from packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
rename to packages/SystemUI/src/com/android/systemui/biometrics/ui/BiometricDialogView.java
index ce67577..2b4dde5 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/BiometricDialogView.java
@@ -11,10 +11,10 @@
  * 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
+ * limitations under the License.
  */
 
-package com.android.systemui.biometrics;
+package com.android.systemui.biometrics.ui;
 
 import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE;
 
@@ -23,6 +23,7 @@
 import android.graphics.PixelFormat;
 import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
+import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.biometrics.BiometricPrompt;
 import android.os.Binder;
 import android.os.Bundle;
@@ -46,25 +47,30 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
+import com.android.systemui.biometrics.BiometricDialog;
+import com.android.systemui.biometrics.DialogViewCallback;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.util.leak.RotationUtils;
 
 /**
  * Abstract base class. Shows a dialog for BiometricPrompt.
  */
-public abstract class BiometricDialogView extends LinearLayout {
+public abstract class BiometricDialogView extends LinearLayout implements BiometricDialog {
 
     private static final String TAG = "BiometricDialogView";
 
-    private static final String KEY_TRY_AGAIN_VISIBILITY = "key_try_again_visibility";
-    private static final String KEY_CONFIRM_VISIBILITY = "key_confirm_visibility";
-    private static final String KEY_CONFIRM_ENABLED = "key_confirm_enabled";
-    private static final String KEY_STATE = "key_state";
-    private static final String KEY_ERROR_TEXT_VISIBILITY = "key_error_text_visibility";
-    private static final String KEY_ERROR_TEXT_STRING = "key_error_text_string";
-    private static final String KEY_ERROR_TEXT_IS_TEMPORARY = "key_error_text_is_temporary";
-    private static final String KEY_ERROR_TEXT_COLOR = "key_error_text_color";
+    public static final String KEY_TRY_AGAIN_VISIBILITY = "key_try_again_visibility";
+    public static final String KEY_CONFIRM_VISIBILITY = "key_confirm_visibility";
+    public static final String KEY_CONFIRM_ENABLED = "key_confirm_enabled";
+    public static final String KEY_STATE = "key_state";
+    public static final String KEY_ERROR_TEXT_VISIBILITY = "key_error_text_visibility";
+    public static final String KEY_ERROR_TEXT_STRING = "key_error_text_string";
+    public static final String KEY_ERROR_TEXT_IS_TEMPORARY = "key_error_text_is_temporary";
+    public static final String KEY_ERROR_TEXT_COLOR = "key_error_text_color";
 
     private static final int ANIMATION_DURATION_SHOW = 250; // ms
     private static final int ANIMATION_DURATION_AWAY = 350; // ms
@@ -77,6 +83,8 @@
     protected static final int STATE_PENDING_CONFIRMATION = 3;
     protected static final int STATE_AUTHENTICATED = 4;
 
+    @VisibleForTesting
+    final WakefulnessLifecycle mWakefulnessLifecycle;
     private final AccessibilityManager mAccessibilityManager;
     private final IBinder mWindowToken = new Binder();
     private final Interpolator mLinearOutSlowIn;
@@ -90,22 +98,30 @@
 
     protected final ViewGroup mLayout;
     protected final LinearLayout mDialog;
-    protected final TextView mTitleText;
-    protected final TextView mSubtitleText;
-    protected final TextView mDescriptionText;
-    protected final ImageView mBiometricIcon;
-    protected final TextView mErrorText;
-    protected final Button mPositiveButton;
-    protected final Button mNegativeButton;
-    protected final Button mTryAgainButton;
+    @VisibleForTesting
+    final TextView mTitleText;
+    @VisibleForTesting
+    final TextView mSubtitleText;
+    @VisibleForTesting
+    final TextView mDescriptionText;
+    @VisibleForTesting
+    final ImageView mBiometricIcon;
+    @VisibleForTesting
+    final TextView mErrorText;
+    @VisibleForTesting
+    final Button mPositiveButton;
+    @VisibleForTesting
+    final Button mNegativeButton;
+    @VisibleForTesting
+    final Button mTryAgainButton;
 
     protected final int mTextColor;
 
     private Bundle mBundle;
     private Bundle mRestoredState;
+    private String mOpPackageName;
 
     private int mState = STATE_IDLE;
-    private boolean mAnimatingAway;
     private boolean mWasForceRemoved;
     private boolean mSkipIntro;
     protected boolean mRequireConfirmation;
@@ -141,6 +157,15 @@
         }
     };
 
+    @VisibleForTesting
+    final WakefulnessLifecycle.Observer mWakefulnessObserver =
+            new WakefulnessLifecycle.Observer() {
+                @Override
+                public void onStartedGoingToSleep() {
+                    animateAway(DialogViewCallback.DISMISSED_USER_CANCELED);
+                }
+            };
+
     protected Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
@@ -155,8 +180,80 @@
         }
     };
 
-    public BiometricDialogView(Context context, DialogViewCallback callback) {
+    /**
+     * Builds the dialog with specified parameters.
+     */
+    public static class Builder {
+        public static final int TYPE_FINGERPRINT = BiometricAuthenticator.TYPE_FINGERPRINT;
+        public static final int TYPE_FACE = BiometricAuthenticator.TYPE_FACE;
+
+        private Context mContext;
+        private DialogViewCallback mCallback;
+        private Bundle mBundle;
+        private boolean mRequireConfirmation;
+        private int mUserId;
+        private String mOpPackageName;
+
+        public Builder(Context context) {
+            mContext = context;
+        }
+
+        public Builder setCallback(DialogViewCallback callback) {
+            mCallback = callback;
+            return this;
+        }
+
+        public Builder setBiometricPromptBundle(Bundle bundle) {
+            mBundle = bundle;
+            return this;
+        }
+
+        public Builder setRequireConfirmation(boolean requireConfirmation) {
+            mRequireConfirmation = requireConfirmation;
+            return this;
+        }
+
+        public Builder setUserId(int userId) {
+            mUserId = userId;
+            return this;
+        }
+
+        public Builder setOpPackageName(String opPackageName) {
+            mOpPackageName = opPackageName;
+            return this;
+        }
+
+        public BiometricDialogView build(int type) {
+            return build(type, new Injector());
+        }
+
+        public BiometricDialogView build(int type, Injector injector) {
+            BiometricDialogView dialog;
+            if (type == TYPE_FINGERPRINT) {
+                dialog = new FingerprintDialogView(mContext, mCallback, injector);
+            } else if (type == TYPE_FACE) {
+                dialog = new FaceDialogView(mContext, mCallback, injector);
+            } else {
+                return null;
+            }
+            dialog.setBundle(mBundle);
+            dialog.setRequireConfirmation(mRequireConfirmation);
+            dialog.setUserId(mUserId);
+            dialog.setOpPackageName(mOpPackageName);
+            return dialog;
+        }
+    }
+
+    public static class Injector {
+        public WakefulnessLifecycle getWakefulnessLifecycle() {
+            return Dependency.get(WakefulnessLifecycle.class);
+        }
+    }
+
+    protected BiometricDialogView(Context context, DialogViewCallback callback, Injector injector) {
         super(context);
+        mWakefulnessLifecycle = injector.getWakefulnessLifecycle();
+
         mCallback = callback;
         mLinearOutSlowIn = Interpolators.LINEAR_OUT_SLOW_IN;
         mAccessibilityManager = mContext.getSystemService(AccessibilityManager.class);
@@ -178,19 +275,13 @@
         addView(mLayout);
 
         mLayout.setOnKeyListener(new View.OnKeyListener() {
-            boolean downPressed = false;
             @Override
             public boolean onKey(View v, int keyCode, KeyEvent event) {
                 if (keyCode != KeyEvent.KEYCODE_BACK) {
                     return false;
                 }
-                if (event.getAction() == KeyEvent.ACTION_DOWN && downPressed == false) {
-                    downPressed = true;
-                } else if (event.getAction() == KeyEvent.ACTION_DOWN) {
-                    downPressed = false;
-                } else if (event.getAction() == KeyEvent.ACTION_UP && downPressed == true) {
-                    downPressed = false;
-                    mCallback.onUserCanceled();
+                if (event.getAction() == KeyEvent.ACTION_UP) {
+                    animateAway(DialogViewCallback.DISMISSED_USER_CANCELED);
                 }
                 return true;
             }
@@ -219,16 +310,16 @@
 
         mNegativeButton.setOnClickListener((View v) -> {
             if (mState == STATE_PENDING_CONFIRMATION || mState == STATE_AUTHENTICATED) {
-                mCallback.onUserCanceled();
+                animateAway(DialogViewCallback.DISMISSED_USER_CANCELED);
             } else {
-                mCallback.onNegativePressed();
+                animateAway(DialogViewCallback.DISMISSED_BUTTON_NEGATIVE);
             }
         });
 
         mPositiveButton.setOnClickListener((View v) -> {
             updateState(STATE_AUTHENTICATED);
             mHandler.postDelayed(() -> {
-                mCallback.onPositivePressed();
+                animateAway(DialogViewCallback.DISMISSED_BUTTON_POSITIVE);
             }, getDelayAfterAuthenticatedDurationMs());
         });
 
@@ -248,21 +339,12 @@
         mLayout.requestFocus();
     }
 
-    public void onSaveState(Bundle bundle) {
-        bundle.putInt(KEY_TRY_AGAIN_VISIBILITY, mTryAgainButton.getVisibility());
-        bundle.putInt(KEY_CONFIRM_VISIBILITY, mPositiveButton.getVisibility());
-        bundle.putBoolean(KEY_CONFIRM_ENABLED, mPositiveButton.isEnabled());
-        bundle.putInt(KEY_STATE, mState);
-        bundle.putInt(KEY_ERROR_TEXT_VISIBILITY, mErrorText.getVisibility());
-        bundle.putCharSequence(KEY_ERROR_TEXT_STRING, mErrorText.getText());
-        bundle.putBoolean(KEY_ERROR_TEXT_IS_TEMPORARY, mHandler.hasMessages(MSG_RESET_MESSAGE));
-        bundle.putInt(KEY_ERROR_TEXT_COLOR, mErrorText.getCurrentTextColor());
-    }
-
     @Override
     public void onAttachedToWindow() {
         super.onAttachedToWindow();
 
+        mWakefulnessLifecycle.addObserver(mWakefulnessObserver);
+
         final ImageView backgroundView = mLayout.findViewById(R.id.background);
 
         if (mUserManager.isManagedProfile(mUserId)) {
@@ -278,6 +360,7 @@
         }
 
         mNegativeButton.setVisibility(View.VISIBLE);
+        mNegativeButton.setText(mBundle.getCharSequence(BiometricPrompt.KEY_NEGATIVE_TEXT));
 
         if (RotationUtils.getRotation(mContext) != RotationUtils.ROTATION_NONE) {
             mDialog.getLayoutParams().width = (int) mDialogWidth;
@@ -285,7 +368,6 @@
 
         if (mRestoredState == null) {
             updateState(STATE_AUTHENTICATING);
-            mNegativeButton.setText(mBundle.getCharSequence(BiometricPrompt.KEY_NEGATIVE_TEXT));
             final int hint = getHintStringResourceId();
             if (hint != 0) {
                 mErrorText.setText(hint);
@@ -346,34 +428,49 @@
         mSkipIntro = false;
     }
 
+    @Override
+    public void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+
+        mWakefulnessLifecycle.removeObserver(mWakefulnessObserver);
+    }
+
     private void setDismissesDialog(View v) {
         v.setClickable(true);
         v.setOnClickListener(v1 -> {
             if (mState != STATE_AUTHENTICATED && shouldGrayAreaDismissDialog()) {
-                mCallback.onUserCanceled();
+                animateAway(DialogViewCallback.DISMISSED_USER_CANCELED);
             }
         });
     }
 
-    public void startDismiss() {
+    private void animateAway(@DialogViewCallback.DismissedReason int reason) {
+        animateAway(true /* sendReason */, reason);
+    }
+
+    /**
+     * Animate the dialog away
+     * @param reason one of the {@link DialogViewCallback} codes
+     */
+    private void animateAway(boolean sendReason, @DialogViewCallback.DismissedReason int reason) {
         if (!mCompletedAnimatingIn) {
             Log.w(TAG, "startDismiss(): waiting for onDialogAnimatedIn");
             mPendingDismissDialog = true;
             return;
         }
 
-        mAnimatingAway = true;
-
         // This is where final cleanup should occur.
         final Runnable endActionRunnable = new Runnable() {
             @Override
             public void run() {
                 mWindowManager.removeView(BiometricDialogView.this);
-                mAnimatingAway = false;
                 // Set the icons / text back to normal state
                 handleResetMessage();
                 showTryAgainButton(false /* show */);
                 updateState(STATE_IDLE);
+                if (sendReason) {
+                    mCallback.onDismissed(reason);
+                }
             }
         };
 
@@ -398,47 +495,30 @@
     }
 
     /**
-     * Force remove the window, cancelling any animation that's happening. This should only be
-     * called if we want to quickly show the dialog again (e.g. on rotation). Calling this method
-     * will cause the dialog to show without an animation the next time it's attached.
-     */
-    public void forceRemove() {
-        mLayout.animate().cancel();
-        mDialog.animate().cancel();
-        mWindowManager.removeView(BiometricDialogView.this);
-        mAnimatingAway = false;
-        mWasForceRemoved = true;
-    }
-
-    /**
      * Skip the intro animation
      */
-    public void setSkipIntro(boolean skip) {
+    private void setSkipIntro(boolean skip) {
         mSkipIntro = skip;
     }
 
-    public boolean isAnimatingAway() {
-        return mAnimatingAway;
-    }
-
-    public void setBundle(Bundle bundle) {
+    private void setBundle(Bundle bundle) {
         mBundle = bundle;
     }
 
-    public void setRequireConfirmation(boolean requireConfirmation) {
+    private void setRequireConfirmation(boolean requireConfirmation) {
         mRequireConfirmation = requireConfirmation;
     }
 
-    public boolean requiresConfirmation() {
+    protected boolean requiresConfirmation() {
         return mRequireConfirmation;
     }
 
-    public void setUserId(int userId) {
+    private void setUserId(int userId) {
         mUserId = userId;
     }
 
-    public ViewGroup getLayout() {
-        return mLayout;
+    private void setOpPackageName(String opPackageName) {
+        mOpPackageName = opPackageName;
     }
 
     // Shows an error/help message
@@ -452,17 +532,63 @@
                 BiometricPrompt.HIDE_DIALOG_DELAY);
     }
 
+    @Override
+    public void show(WindowManager wm, boolean skipIntroAnimation) {
+        setSkipIntro(skipIntroAnimation);
+        wm.addView(this, getLayoutParams(mWindowToken));
+    }
+
+    /**
+     * Force remove the window, cancelling any animation that's happening. This should only be
+     * called if we want to quickly show the dialog again (e.g. on rotation). Calling this method
+     * will cause the dialog to show without an animation the next time it's attached.
+     */
+    @Override
+    public void dismissWithoutCallback(boolean animate) {
+        if (animate) {
+            animateAway(false /* sendReason */, 0 /* reason */);
+        } else {
+            mLayout.animate().cancel();
+            mDialog.animate().cancel();
+            mWindowManager.removeView(BiometricDialogView.this);
+            mWasForceRemoved = true;
+        }
+    }
+
+    @Override
+    public void dismissFromSystemServer() {
+        animateAway(DialogViewCallback.DISMISSED_BY_SYSTEM_SERVER);
+    }
+
+    @Override
+    public void onAuthenticationSucceeded() {
+        announceForAccessibility(getResources().getText(getAuthenticatedAccessibilityResourceId()));
+
+        if (requiresConfirmation()) {
+            updateState(STATE_PENDING_CONFIRMATION);
+        } else {
+            mHandler.postDelayed(() -> {
+                animateAway(DialogViewCallback.DISMISSED_AUTHENTICATED);
+            }, getDelayAfterAuthenticatedDurationMs());
+
+            updateState(STATE_AUTHENTICATED);
+        }
+    }
+
+
+    @Override
+    public void onAuthenticationFailed(String message) {
+        updateState(STATE_ERROR);
+        showTemporaryMessage(message);
+    }
+
     /**
      * Transient help message (acquire) is received, dialog stays showing. Sensor stays in
      * "authenticating" state.
      * @param message
      */
-    public void onHelpReceived(String message) {
-        updateState(STATE_ERROR);
-        showTemporaryMessage(message);
-    }
-
-    public void onAuthenticationFailed(String message) {
+    @Override
+    public void onHelp(String message) {
         updateState(STATE_ERROR);
         showTemporaryMessage(message);
     }
@@ -471,14 +597,61 @@
      * Hard error is received, dialog will be dismissed soon.
      * @param error
      */
-    public void onErrorReceived(String error) {
+    @Override
+    public void onError(String error) {
         updateState(STATE_ERROR);
         showTemporaryMessage(error);
         showTryAgainButton(false /* show */);
-        mCallback.onErrorShown(); // TODO: Split between fp and face
+
+        mHandler.postDelayed(() -> {
+            animateAway(DialogViewCallback.DISMISSED_ERROR);
+        }, BiometricPrompt.HIDE_DIALOG_DELAY);
     }
 
-    public void updateState(int newState) {
+
+    @Override
+    public void onSaveState(Bundle bundle) {
+        bundle.putInt(KEY_TRY_AGAIN_VISIBILITY, mTryAgainButton.getVisibility());
+        bundle.putInt(KEY_CONFIRM_VISIBILITY, mPositiveButton.getVisibility());
+        bundle.putBoolean(KEY_CONFIRM_ENABLED, mPositiveButton.isEnabled());
+        bundle.putInt(KEY_STATE, mState);
+        bundle.putInt(KEY_ERROR_TEXT_VISIBILITY, mErrorText.getVisibility());
+        bundle.putCharSequence(KEY_ERROR_TEXT_STRING, mErrorText.getText());
+        bundle.putBoolean(KEY_ERROR_TEXT_IS_TEMPORARY, mHandler.hasMessages(MSG_RESET_MESSAGE));
+        bundle.putInt(KEY_ERROR_TEXT_COLOR, mErrorText.getCurrentTextColor());
+    }
+
+    @Override
+    public void restoreState(Bundle bundle) {
+        mRestoredState = bundle;
+        final int tryAgainVisibility = bundle.getInt(KEY_TRY_AGAIN_VISIBILITY);
+        mTryAgainButton.setVisibility(tryAgainVisibility);
+        final int confirmVisibility = bundle.getInt(KEY_CONFIRM_VISIBILITY);
+        mPositiveButton.setVisibility(confirmVisibility);
+        final boolean confirmEnabled = bundle.getBoolean(KEY_CONFIRM_ENABLED);
+        mPositiveButton.setEnabled(confirmEnabled);
+        mState = bundle.getInt(KEY_STATE);
+        mErrorText.setText(bundle.getCharSequence(KEY_ERROR_TEXT_STRING));
+        mErrorText.setContentDescription(bundle.getCharSequence(KEY_ERROR_TEXT_STRING));
+        final int errorTextVisibility = bundle.getInt(KEY_ERROR_TEXT_VISIBILITY);
+        mErrorText.setVisibility(errorTextVisibility);
+        if (errorTextVisibility == View.INVISIBLE || tryAgainVisibility == View.INVISIBLE
+                || confirmVisibility == View.INVISIBLE) {
+            announceAccessibilityEvent();
+        }
+        mErrorText.setTextColor(bundle.getInt(KEY_ERROR_TEXT_COLOR));
+        if (bundle.getBoolean(KEY_ERROR_TEXT_IS_TEMPORARY)) {
+            mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_RESET_MESSAGE),
+                    BiometricPrompt.HIDE_DIALOG_DELAY);
+        }
+    }
+
+    @Override
+    public String getOpPackageName() {
+        return mOpPackageName;
+    }
+
+    protected void updateState(int newState) {
         if (newState == STATE_PENDING_CONFIRMATION) {
             mHandler.removeMessages(MSG_RESET_MESSAGE);
             mErrorText.setTextColor(mTextColor);
@@ -505,48 +678,24 @@
         mState = newState;
     }
 
-    public void showTryAgainButton(boolean show) {
+    protected void showTryAgainButton(boolean show) {
     }
 
-    public void onDialogAnimatedIn() {
+    protected void onDialogAnimatedIn() {
         mCompletedAnimatingIn = true;
 
         if (mPendingDismissDialog) {
             Log.d(TAG, "onDialogAnimatedIn(): mPendingDismissDialog=true, dismissing now");
-            startDismiss();
+            animateAway(false /* sendReason */, 0);
             mPendingDismissDialog = false;
         }
     }
 
-    public void restoreState(Bundle bundle) {
-        mRestoredState = bundle;
-        final int tryAgainVisibility = bundle.getInt(KEY_TRY_AGAIN_VISIBILITY);
-        mTryAgainButton.setVisibility(tryAgainVisibility);
-        final int confirmVisibility = bundle.getInt(KEY_CONFIRM_VISIBILITY);
-        mPositiveButton.setVisibility(confirmVisibility);
-        final boolean confirmEnabled = bundle.getBoolean(KEY_CONFIRM_ENABLED);
-        mPositiveButton.setEnabled(confirmEnabled);
-        mState = bundle.getInt(KEY_STATE);
-        mErrorText.setText(bundle.getCharSequence(KEY_ERROR_TEXT_STRING));
-        mErrorText.setContentDescription(bundle.getCharSequence(KEY_ERROR_TEXT_STRING));
-        final int errorTextVisibility = bundle.getInt(KEY_ERROR_TEXT_VISIBILITY);
-        mErrorText.setVisibility(errorTextVisibility);
-        if (errorTextVisibility == View.INVISIBLE || tryAgainVisibility == View.INVISIBLE
-                || confirmVisibility == View.INVISIBLE) {
-            announceAccessibilityEvent();
-        }
-        mErrorText.setTextColor(bundle.getInt(KEY_ERROR_TEXT_COLOR));
-        if (bundle.getBoolean(KEY_ERROR_TEXT_IS_TEMPORARY)) {
-            mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_RESET_MESSAGE),
-                    BiometricPrompt.HIDE_DIALOG_DELAY);
-        }
-    }
-
-    protected int getState() {
-        return mState;
-    }
-
-    public WindowManager.LayoutParams getLayoutParams() {
+    /**
+     * @param windowToken token for the window
+     * @return
+     */
+    public static WindowManager.LayoutParams getLayoutParams(IBinder windowToken) {
         final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT,
                 ViewGroup.LayoutParams.MATCH_PARENT,
@@ -555,7 +704,7 @@
                 PixelFormat.TRANSLUCENT);
         lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
         lp.setTitle("BiometricDialogView");
-        lp.token = mWindowToken;
+        lp.token = windowToken;
         return lp;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/ui/FaceDialogView.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
rename to packages/SystemUI/src/com/android/systemui/biometrics/ui/FaceDialogView.java
index ae6cb5c..bd87148 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/FaceDialogView.java
@@ -11,10 +11,10 @@
  * 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
+ * limitations under the License.
  */
 
-package com.android.systemui.biometrics;
+package com.android.systemui.biometrics.ui;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -33,7 +33,9 @@
 import android.view.View;
 import android.view.ViewOutlineProvider;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.R;
+import com.android.systemui.biometrics.DialogViewCallback;
 
 /**
  * This class loads the view for the system-provided dialog. The view consists of:
@@ -52,7 +54,8 @@
     private static final int TEXT_ANIMATE_DISTANCE = 32; // dp
 
     private static final int SIZE_UNKNOWN = 0;
-    private static final int SIZE_SMALL = 1;
+    @VisibleForTesting
+    static final int SIZE_SMALL = 1;
     private static final int SIZE_GROWING = 2;
     private static final int SIZE_BIG = 3;
 
@@ -152,13 +155,13 @@
         announceAccessibilityEvent();
     };
 
-    public FaceDialogView(Context context,
-            DialogViewCallback callback) {
-        super(context, callback);
+    protected FaceDialogView(Context context, DialogViewCallback callback, Injector injector) {
+        super(context, callback, injector);
         mIconController = new IconController();
     }
 
-    private void updateSize(int newSize) {
+    @VisibleForTesting
+    void updateSize(int newSize) {
         final float padding = dpToPixels(IMPLICIT_Y_PADDING);
         final float iconSmallPositionY = mDialog.getHeight() - mBiometricIcon.getHeight() - padding;
 
@@ -339,8 +342,8 @@
     }
 
     @Override
-    public void onErrorReceived(String error) {
-        super.onErrorReceived(error);
+    public void onError(String error) {
+        super.onError(error);
         // All error messages will cause the dialog to go from small -> big. Error messages
         // are messages such as lockout, auth failed, etc.
         if (mSize == SIZE_SMALL) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/ui/FingerprintDialogView.java
similarity index 93%
rename from packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java
rename to packages/SystemUI/src/com/android/systemui/biometrics/ui/FingerprintDialogView.java
index 183933e..e597080 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/FingerprintDialogView.java
@@ -11,10 +11,10 @@
  * 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
+ * limitations under the License.
  */
 
-package com.android.systemui.biometrics;
+package com.android.systemui.biometrics.ui;
 
 import android.content.Context;
 import android.graphics.drawable.AnimatedVectorDrawable;
@@ -22,6 +22,7 @@
 import android.util.Log;
 
 import com.android.systemui.R;
+import com.android.systemui.biometrics.DialogViewCallback;
 
 /**
  * This class loads the view for the system-provided dialog. The view consists of:
@@ -32,9 +33,9 @@
 
     private static final String TAG = "FingerprintDialogView";
 
-    public FingerprintDialogView(Context context,
-            DialogViewCallback callback) {
-        super(context, callback);
+    protected FingerprintDialogView(Context context, DialogViewCallback callback,
+            Injector injector) {
+        super(context, callback, injector);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index fa0fe13..134d4b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -271,7 +271,7 @@
         default void onRotationProposal(int rotation, boolean isValid) { }
 
         default void showBiometricDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver,
-                int type, boolean requireConfirmation, int userId) { }
+                int type, boolean requireConfirmation, int userId, String opPackageName) { }
         default void onBiometricAuthenticated(boolean authenticated, String failureReason) { }
         default void onBiometricHelp(String message) { }
         default void onBiometricError(String error) { }
@@ -741,7 +741,7 @@
 
     @Override
     public void showBiometricDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver,
-            int type, boolean requireConfirmation, int userId) {
+            int type, boolean requireConfirmation, int userId, String opPackageName) {
         synchronized (mLock) {
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = bundle;
@@ -749,6 +749,7 @@
             args.argi1 = type;
             args.arg3 = requireConfirmation;
             args.argi2 = userId;
+            args.arg4 = opPackageName;
             mHandler.obtainMessage(MSG_BIOMETRIC_SHOW, args)
                     .sendToTarget();
         }
@@ -1036,7 +1037,8 @@
                                 (IBiometricServiceReceiverInternal) someArgs.arg2,
                                 someArgs.argi1 /* type */,
                                 (boolean) someArgs.arg3 /* requireConfirmation */,
-                                someArgs.argi2 /* userId */);
+                                someArgs.argi2 /* userId */,
+                                (String) someArgs.arg4 /* opPackageName */);
                     }
                     someArgs.recycle();
                     break;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDialogImplTest.java
new file mode 100644
index 0000000..8f2f8b1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDialogImplTest.java
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.TestCase.assertNotNull;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.app.IActivityTaskManager;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.hardware.biometrics.BiometricPrompt;
+import android.hardware.biometrics.IBiometricServiceReceiverInternal;
+import android.os.Bundle;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableContext;
+import android.testing.TestableLooper.RunWithLooper;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.phone.StatusBar;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+@SmallTest
+public class BiometricDialogImplTest extends SysuiTestCase {
+
+    @Mock
+    private PackageManager mPackageManager;
+    @Mock
+    private IBiometricServiceReceiverInternal mReceiver;
+    @Mock
+    private BiometricDialog mDialog1;
+    @Mock
+    private BiometricDialog mDialog2;
+
+    private TestableBiometricDialogImpl mBiometricDialogImpl;
+
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+
+        TestableContext context = spy(mContext);
+
+        mContext.putComponent(StatusBar.class, mock(StatusBar.class));
+        mContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
+
+        when(context.getPackageManager()).thenReturn(mPackageManager);
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE))
+            .thenReturn(true);
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
+            .thenReturn(true);
+
+        when(mDialog1.getOpPackageName()).thenReturn("Dialog1");
+        when(mDialog2.getOpPackageName()).thenReturn("Dialog2");
+
+        mBiometricDialogImpl = new TestableBiometricDialogImpl(new MockInjector());
+        mBiometricDialogImpl.mContext = context;
+        mBiometricDialogImpl.mComponents = mContext.getComponents();
+
+        mBiometricDialogImpl.start();
+    }
+
+    // Callback tests
+
+    @Test
+    public void testSendsReasonUserCanceled_whenDismissedByUserCancel() throws Exception {
+        showDialog(BiometricPrompt.TYPE_FACE);
+        mBiometricDialogImpl.onDismissed(DialogViewCallback.DISMISSED_USER_CANCELED);
+        verify(mReceiver).onDialogDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
+    }
+
+    @Test
+    public void testSendsReasonNegative_whenDismissedByButtonNegative() throws Exception {
+        showDialog(BiometricPrompt.TYPE_FACE);
+        mBiometricDialogImpl.onDismissed(DialogViewCallback.DISMISSED_BUTTON_NEGATIVE);
+        verify(mReceiver).onDialogDismissed(BiometricPrompt.DISMISSED_REASON_NEGATIVE);
+    }
+
+    @Test
+    public void testSendsReasonConfirmed_whenDismissedByButtonPositive() throws Exception {
+        showDialog(BiometricPrompt.TYPE_FACE);
+        mBiometricDialogImpl.onDismissed(DialogViewCallback.DISMISSED_BUTTON_POSITIVE);
+        verify(mReceiver).onDialogDismissed(BiometricPrompt.DISMISSED_REASON_CONFIRMED);
+    }
+
+    @Test
+    public void testSendsReasonConfirmNotRequired_whenDismissedByAuthenticated() throws Exception {
+        showDialog(BiometricPrompt.TYPE_FACE);
+        mBiometricDialogImpl.onDismissed(DialogViewCallback.DISMISSED_AUTHENTICATED);
+        verify(mReceiver).onDialogDismissed(BiometricPrompt.DISMISSED_REASON_CONFIRM_NOT_REQUIRED);
+    }
+
+    @Test
+    public void testSendsReasonError_whenDismissedByError() throws Exception {
+        showDialog(BiometricPrompt.TYPE_FACE);
+        mBiometricDialogImpl.onDismissed(DialogViewCallback.DISMISSED_ERROR);
+        verify(mReceiver).onDialogDismissed(BiometricPrompt.DISMISSED_REASON_ERROR);
+    }
+
+    @Test
+    public void testSendsReasonDismissedBySystemServer_whenDismissedByServer() throws Exception {
+        showDialog(BiometricPrompt.TYPE_FACE);
+        mBiometricDialogImpl.onDismissed(DialogViewCallback.DISMISSED_BY_SYSTEM_SERVER);
+        verify(mReceiver).onDialogDismissed(BiometricPrompt.DISMISSED_REASON_SERVER_REQUESTED);
+    }
+
+    // Statusbar tests
+
+    @Test
+    public void testShowInvoked_whenSystemRequested()
+            throws Exception {
+        showDialog(BiometricPrompt.TYPE_FACE);
+        verify(mDialog1).show(any(), eq(false) /* skipIntro */);
+    }
+
+    @Test
+    public void testOnAuthenticationSucceededInvoked_whenSystemRequested() throws Exception {
+        showDialog(BiometricPrompt.TYPE_FACE);
+        mBiometricDialogImpl.onBiometricAuthenticated(true, null /* failureReason */);
+        verify(mDialog1).onAuthenticationSucceeded();
+    }
+
+    @Test
+    public void testOnAuthenticationFailedInvoked_whenSystemRequested() throws Exception {
+        showDialog(BiometricPrompt.TYPE_FACE);
+        final String failureReason = "failure reason";
+        mBiometricDialogImpl.onBiometricAuthenticated(false, failureReason);
+
+        ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
+        verify(mDialog1).onAuthenticationFailed(captor.capture());
+
+        assertEquals(captor.getValue(), failureReason);
+    }
+
+    @Test
+    public void testOnHelpInvoked_whenSystemRequested() throws Exception {
+        showDialog(BiometricPrompt.TYPE_FACE);
+        final String helpMessage = "help";
+        mBiometricDialogImpl.onBiometricHelp(helpMessage);
+
+        ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
+        verify(mDialog1).onHelp(captor.capture());
+
+        assertEquals(captor.getValue(), helpMessage);
+    }
+
+    @Test
+    public void testOnErrorInvoked_whenSystemRequested() throws Exception {
+        showDialog(BiometricPrompt.TYPE_FACE);
+        final String errMessage = "error message";
+        mBiometricDialogImpl.onBiometricError(errMessage);
+
+        ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
+        verify(mDialog1).onError(captor.capture());
+
+        assertEquals(captor.getValue(), errMessage);
+    }
+
+    @Test
+    public void testDismissWithoutCallbackInvoked_whenSystemRequested() throws Exception {
+        showDialog(BiometricPrompt.TYPE_FACE);
+        mBiometricDialogImpl.hideBiometricDialog();
+        verify(mDialog1).dismissFromSystemServer();
+    }
+
+    @Test
+    public void testClientNotified_whenDismissedBySystemServer() throws Exception {
+        showDialog(BiometricPrompt.TYPE_FACE);
+        mBiometricDialogImpl.hideBiometricDialog();
+        verify(mDialog1).dismissFromSystemServer();
+
+        assertNotNull(mBiometricDialogImpl.mCurrentDialog);
+        assertNotNull(mBiometricDialogImpl.mReceiver);
+    }
+
+    // Corner case tests
+
+    @Test
+    public void testShowNewDialog_beforeOldDialogDismissed_SkipsAnimations() throws Exception {
+        showDialog(BiometricPrompt.TYPE_FACE);
+        verify(mDialog1).show(any(), eq(false) /* skipIntro */);
+
+        showDialog(BiometricPrompt.TYPE_FACE);
+
+        // First dialog should be dismissed without animation
+        verify(mDialog1).dismissWithoutCallback(eq(false) /* animate */);
+
+        // Second dialog should be shown without animation
+        verify(mDialog2).show(any(), eq(true)) /* skipIntro */;
+    }
+
+    @Test
+    public void testConfigurationPersists_whenOnConfigurationChanged() throws Exception {
+        showDialog(BiometricPrompt.TYPE_FACE);
+        verify(mDialog1).show(any(), eq(false) /* skipIntro */);
+
+        mBiometricDialogImpl.onConfigurationChanged(new Configuration());
+
+        ArgumentCaptor<Bundle> captor = ArgumentCaptor.forClass(Bundle.class);
+        verify(mDialog1).onSaveState(captor.capture());
+
+        // Old dialog doesn't animate
+        verify(mDialog1).dismissWithoutCallback(eq(false /* animate */));
+
+        // Saved state is restored into new dialog
+        ArgumentCaptor<Bundle> captor2 = ArgumentCaptor.forClass(Bundle.class);
+        verify(mDialog2).restoreState(captor2.capture());
+
+        // Dialog for new configuration skips intro
+        verify(mDialog2).show(any(), eq(true) /* skipIntro */);
+
+        // TODO: This should check all values we want to save/restore
+        assertEquals(captor.getValue(), captor2.getValue());
+    }
+
+    @Test
+    public void testClientNotified_whenTaskStackChangesDuringAuthentication() throws Exception {
+        showDialog(BiometricPrompt.TYPE_FACE);
+
+        List<ActivityManager.RunningTaskInfo> tasks = new ArrayList<>();
+        ActivityManager.RunningTaskInfo taskInfo = mock(ActivityManager.RunningTaskInfo.class);
+        taskInfo.topActivity = mock(ComponentName.class);
+        when(taskInfo.topActivity.getPackageName()).thenReturn("other_package");
+        tasks.add(taskInfo);
+        when(mBiometricDialogImpl.mActivityTaskManager.getTasks(anyInt())).thenReturn(tasks);
+
+        mBiometricDialogImpl.mTaskStackListener.onTaskStackChanged();
+        waitForIdleSync();
+
+        assertNull(mBiometricDialogImpl.mCurrentDialog);
+        assertNull(mBiometricDialogImpl.mReceiver);
+        verify(mDialog1).dismissWithoutCallback(true /* animate */);
+        verify(mReceiver).onDialogDismissed(eq(BiometricPrompt.DISMISSED_REASON_USER_CANCEL));
+    }
+
+    // Helpers
+
+    private void showDialog(int type) {
+        mBiometricDialogImpl.showBiometricDialog(createTestDialogBundle(),
+                mReceiver /* receiver */,
+                type,
+                true /* requireConfirmation */,
+                0 /* userId */,
+                "testPackage");
+    }
+
+    private Bundle createTestDialogBundle() {
+        Bundle bundle = new Bundle();
+
+        bundle.putCharSequence(BiometricPrompt.KEY_TITLE, "Title");
+        bundle.putCharSequence(BiometricPrompt.KEY_SUBTITLE, "Subtitle");
+        bundle.putCharSequence(BiometricPrompt.KEY_DESCRIPTION, "Description");
+        bundle.putCharSequence(BiometricPrompt.KEY_NEGATIVE_TEXT, "Negative Button");
+
+        // RequireConfirmation is a hint to BiometricService. This can be forced to be required
+        // by user settings, and should be tested in BiometricService.
+        bundle.putBoolean(BiometricPrompt.KEY_REQUIRE_CONFIRMATION, true);
+
+        return bundle;
+    }
+
+    private final class TestableBiometricDialogImpl extends BiometricDialogImpl {
+        private int mBuildCount = 0;
+
+        public TestableBiometricDialogImpl(Injector injector) {
+            super(injector);
+        }
+
+        @Override
+        protected BiometricDialog buildDialog(Bundle biometricPromptBundle,
+                boolean requireConfirmation, int userId, int type, String opPackageName) {
+            BiometricDialog dialog;
+            if (mBuildCount == 0) {
+                dialog = mDialog1;
+            } else if (mBuildCount == 1) {
+                dialog = mDialog2;
+            } else {
+                dialog = null;
+            }
+            mBuildCount++;
+            return dialog;
+        }
+    }
+
+    private final class MockInjector extends BiometricDialogImpl.Injector {
+        @Override
+        IActivityTaskManager getActivityTaskManager() {
+            return mock(IActivityTaskManager.class);
+        }
+    }
+}
+
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/BiometricDialogViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/BiometricDialogViewTest.java
new file mode 100644
index 0000000..bbdd837
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/BiometricDialogViewTest.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics.ui;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotSame;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.spy;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.hardware.biometrics.BiometricPrompt;
+import android.os.Bundle;
+import android.os.UserManager;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableContext;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.accessibility.AccessibilityManager;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.biometrics.DialogViewCallback;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+@SmallTest
+public class BiometricDialogViewTest extends SysuiTestCase {
+
+    FaceDialogView mFaceDialogView;
+
+    private static final String TITLE = "Title";
+    private static final String SUBTITLE = "Subtitle";
+    private static final String DESCRIPTION = "Description";
+    private static final String NEGATIVE_BUTTON = "Negative Button";
+
+    private static final String TEST_HELP = "Help";
+
+    TestableContext mTestableContext;
+    @Mock
+    private DialogViewCallback mCallback;
+    @Mock
+    private UserManager mUserManager;
+    @Mock
+    private DevicePolicyManager mDpm;
+
+    private static class Injector extends BiometricDialogView.Injector {
+        @Override
+        public WakefulnessLifecycle getWakefulnessLifecycle() {
+            final WakefulnessLifecycle lifecycle = new WakefulnessLifecycle();
+            lifecycle.dispatchFinishedWakingUp();
+            return lifecycle;
+        }
+    }
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mTestableContext = spy(mContext);
+        mTestableContext.addMockSystemService(UserManager.class, mUserManager);
+        mTestableContext.addMockSystemService(DevicePolicyManager.class, mDpm);
+    }
+
+    @Test
+    public void testContentStates_confirmationRequired_authenticated() {
+        mFaceDialogView = buildFaceDialogView(mTestableContext, mCallback,
+                true /* requireConfirmation */);
+        mFaceDialogView.onAttachedToWindow();
+
+        // When starting authentication
+        assertEquals(View.VISIBLE, mFaceDialogView.mTitleText.getVisibility());
+        assertEquals(View.VISIBLE, mFaceDialogView.mSubtitleText.getVisibility());
+        assertEquals(View.VISIBLE, mFaceDialogView.mDescriptionText.getVisibility());
+        assertEquals(View.INVISIBLE, mFaceDialogView.mErrorText.getVisibility());
+        assertEquals(View.VISIBLE, mFaceDialogView.mPositiveButton.getVisibility());
+        assertEquals(View.VISIBLE, mFaceDialogView.mNegativeButton.getVisibility());
+        assertEquals(View.GONE, mFaceDialogView.mTryAgainButton.getVisibility());
+
+        // Contents are as expected
+        assertTrue(TITLE.contentEquals(mFaceDialogView.mTitleText.getText()));
+        assertTrue(SUBTITLE.contentEquals(mFaceDialogView.mSubtitleText.getText()));
+        assertTrue(DESCRIPTION.contentEquals(mFaceDialogView.mDescriptionText.getText()));
+        assertTrue(mFaceDialogView.mPositiveButton.getText().toString()
+                .contentEquals(mContext.getString(R.string.biometric_dialog_confirm)));
+        assertTrue(NEGATIVE_BUTTON.contentEquals(mFaceDialogView.mNegativeButton.getText()));
+        assertTrue(mFaceDialogView.mTryAgainButton.getText().toString()
+                .contentEquals(mContext.getString(R.string.biometric_dialog_try_again)));
+
+        // When help message is received
+        mFaceDialogView.onHelp(TEST_HELP);
+        assertEquals(mFaceDialogView.mErrorText.getVisibility(), View.VISIBLE);
+        assertTrue(TEST_HELP.contentEquals(mFaceDialogView.mErrorText.getText()));
+
+        // When authenticated, confirm button comes out
+        mFaceDialogView.onAuthenticationSucceeded();
+        assertEquals(View.VISIBLE, mFaceDialogView.mPositiveButton.getVisibility());
+        assertEquals(true, mFaceDialogView.mPositiveButton.isEnabled());
+    }
+
+    @Test
+    public void testContentStates_confirmationNotRequired_authenticated() {
+        mFaceDialogView = buildFaceDialogView(mTestableContext, mCallback,
+                false /* requireConfirmation */);
+        mFaceDialogView.onAttachedToWindow();
+        mFaceDialogView.updateSize(FaceDialogView.SIZE_SMALL);
+
+        assertEquals(View.INVISIBLE, mFaceDialogView.mTitleText.getVisibility());
+        assertNotSame(View.VISIBLE, mFaceDialogView.mSubtitleText.getVisibility());
+        assertNotSame(View.VISIBLE, mFaceDialogView.mDescriptionText.getVisibility());
+        assertEquals(View.INVISIBLE, mFaceDialogView.mErrorText.getVisibility());
+        assertEquals(View.GONE, mFaceDialogView.mPositiveButton.getVisibility());
+        assertEquals(View.GONE, mFaceDialogView.mTryAgainButton.getVisibility());
+        assertEquals(View.GONE, mFaceDialogView.mTryAgainButton.getVisibility());
+    }
+
+    @Test
+    public void testContentStates_confirmationNotRequired_help() {
+        mFaceDialogView = buildFaceDialogView(mTestableContext, mCallback,
+                false /* requireConfirmation */);
+        mFaceDialogView.onAttachedToWindow();
+
+        mFaceDialogView.onHelp(TEST_HELP);
+        assertEquals(mFaceDialogView.mErrorText.getVisibility(), View.VISIBLE);
+        assertTrue(TEST_HELP.contentEquals(mFaceDialogView.mErrorText.getText()));
+    }
+
+    @Test
+    public void testBack_sendsUserCanceled() {
+        // TODO: Need robolectric framework to wait for handler to complete
+    }
+
+    @Test
+    public void testScreenOff_sendsUserCanceled() {
+        // TODO: Need robolectric framework to wait for handler to complete
+    }
+
+    @Test
+    public void testRestoreState_contentStatesCorrect() {
+        mFaceDialogView = buildFaceDialogView(mTestableContext, mCallback,
+                false /* requireConfirmation */);
+        mFaceDialogView.onAttachedToWindow();
+        mFaceDialogView.onAuthenticationFailed(TEST_HELP);
+
+        final Bundle bundle = new Bundle();
+        mFaceDialogView.onSaveState(bundle);
+
+        mFaceDialogView = buildFaceDialogView(mTestableContext, mCallback,
+                false /* requireConfirmation */);
+        mFaceDialogView.restoreState(bundle);
+        mFaceDialogView.onAttachedToWindow();
+
+        assertEquals(View.VISIBLE, mFaceDialogView.mTryAgainButton.getVisibility());
+    }
+
+    private FaceDialogView buildFaceDialogView(Context context, DialogViewCallback callback,
+            boolean requireConfirmation) {
+        return (FaceDialogView) new BiometricDialogView.Builder(context)
+                .setCallback(callback)
+                .setBiometricPromptBundle(createTestDialogBundle())
+                .setRequireConfirmation(requireConfirmation)
+                .setUserId(0)
+                .setOpPackageName("test_package")
+                .build(BiometricDialogView.Builder.TYPE_FACE, new Injector());
+    }
+
+    private Bundle createTestDialogBundle() {
+        Bundle bundle = new Bundle();
+
+        bundle.putCharSequence(BiometricPrompt.KEY_TITLE, TITLE);
+        bundle.putCharSequence(BiometricPrompt.KEY_SUBTITLE, SUBTITLE);
+        bundle.putCharSequence(BiometricPrompt.KEY_DESCRIPTION, DESCRIPTION);
+        bundle.putCharSequence(BiometricPrompt.KEY_NEGATIVE_TEXT, NEGATIVE_BUTTON);
+
+        // RequireConfirmation is a hint to BiometricService. This can be forced to be required
+        // by user settings, and should be tested in BiometricService.
+        bundle.putBoolean(BiometricPrompt.KEY_REQUIRE_CONFIRMATION, true);
+
+        return bundle;
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index 1e1f2156..b252a0d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -365,4 +365,45 @@
         waitForIdleSync();
         verify(mCallbacks).onRecentsAnimationStateChanged(eq(true));
     }
+
+    @Test
+    public void testShowBiometricDialog() {
+        Bundle bundle = new Bundle();
+        String packageName = "test";
+        mCommandQueue.showBiometricDialog(bundle, null /* receiver */, 1, true, 3, packageName);
+        waitForIdleSync();
+        verify(mCallbacks).showBiometricDialog(eq(bundle), eq(null), eq(1), eq(true), eq(3),
+                eq(packageName));
+    }
+
+    @Test
+    public void testOnBiometricAuthenticated() {
+        String failureReason = "test_failure_reason";
+        mCommandQueue.onBiometricAuthenticated(true /* authenticated */, failureReason);
+        waitForIdleSync();
+        verify(mCallbacks).onBiometricAuthenticated(eq(true), eq(failureReason));
+    }
+
+    @Test
+    public void testOnBiometricHelp() {
+        String helpMessage = "test_help_message";
+        mCommandQueue.onBiometricHelp(helpMessage);
+        waitForIdleSync();
+        verify(mCallbacks).onBiometricHelp(eq(helpMessage));
+    }
+
+    @Test
+    public void testOnBiometricError() {
+        String errorMessage = "test_error_message";
+        mCommandQueue.onBiometricError(errorMessage);
+        waitForIdleSync();
+        verify(mCallbacks).onBiometricError(eq(errorMessage));
+    }
+
+    @Test
+    public void testHideBiometricDialog() {
+        mCommandQueue.hideBiometricDialog();
+        waitForIdleSync();
+        verify(mCallbacks).hideBiometricDialog();
+    }
 }
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 23afce6..222a6f2 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,12 +18,56 @@
 
 import static com.android.internal.util.Preconditions.checkNotNull;
 
+import static java.util.Collections.emptySet;
+
+import android.Manifest;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.app.admin.DevicePolicyManager;
+import android.app.backup.BackupManager;
+import android.app.backup.IBackupManager;
+import android.app.backup.IBackupManagerMonitor;
+import android.app.backup.IBackupObserver;
+import android.app.backup.IFullBackupRestoreObserver;
+import android.app.backup.IRestoreSession;
+import android.app.backup.ISelectBackupTransportCallback;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.FileUtils;
+import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.os.Trace;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Slog;
 import android.util.SparseArray;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.DumpUtils;
+import com.android.server.SystemConfig;
 import com.android.server.SystemService;
+import com.android.server.backup.utils.RandomAccessFileUtils;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Set;
 
 /**
  * Definition of the system service that performs backup/restore operations.
@@ -31,53 +75,1502 @@
  * <p>This class is responsible for handling user-aware operations and acts as a delegator, routing
  * incoming calls to the appropriate per-user {@link UserBackupManagerService} to handle the
  * corresponding backup/restore operation.
+ *
+ * <p>It also determines whether the backup service is available. It can be disabled in the
+ * following two ways:
+ *
+ * <ul>
+ *  <li>Temporary - call {@link #setBackupServiceActive(int, boolean)}, or
+ *  <li>Permanent - set the system property {@link #BACKUP_DISABLE_PROPERTY} to true.
+ * </ul>
+ *
+ * Temporary disabling is controlled by {@link #setBackupServiceActive(int, boolean)} through
+ * privileged callers (currently {@link DevicePolicyManager}). If called on {@link
+ * UserHandle#USER_SYSTEM}, backup is disabled for all users.
  */
-public class BackupManagerService {
+public class BackupManagerService extends IBackupManager.Stub {
     public static final String TAG = "BackupManagerService";
     public static final boolean DEBUG = true;
     public static final boolean MORE_DEBUG = false;
     public static final boolean DEBUG_SCHEDULING = true;
 
-    private final Context mContext;
-    private final Trampoline mTrampoline;
-    private final SparseArray<UserBackupManagerService> mServiceUsers;
+    @VisibleForTesting
+    static final String DUMP_RUNNING_USERS_MESSAGE = "Backup Manager is running for users:";
 
-    /** Instantiate a new instance of {@link BackupManagerService}. */
-    public BackupManagerService(
-            Context context,
-            Trampoline trampoline,
-            SparseArray<UserBackupManagerService> userServices) {
-        mContext = checkNotNull(context);
-        mTrampoline = checkNotNull(trampoline);
-        // TODO(b/135661048): Remove
-        mServiceUsers = userServices;
+    /**
+     * Name of file that disables the backup service. If this file exists, then backup is disabled
+     * for all users.
+     */
+    private static final String BACKUP_SUPPRESS_FILENAME = "backup-suppress";
+
+    /**
+     * Name of file for non-system users that enables the backup service for the user. Backup is
+     * disabled by default in non-system users.
+     */
+    private static final String BACKUP_ACTIVATED_FILENAME = "backup-activated";
+
+    /**
+     * Name of file for non-system users that remembers whether backup was explicitly activated or
+     * deactivated with a call to setBackupServiceActive.
+     */
+    private static final String REMEMBER_ACTIVATED_FILENAME = "backup-remember-activated";
+
+    // Product-level suppression of backup/restore.
+    private static final String BACKUP_DISABLE_PROPERTY = "ro.backup.disable";
+
+    private static final String BACKUP_THREAD = "backup";
+
+    static BackupManagerService sInstance;
+
+    static BackupManagerService getInstance() {
+        return checkNotNull(sInstance);
+    }
+
+    private final Context mContext;
+    private final UserManager mUserManager;
+
+    private final boolean mGlobalDisable;
+    // Lock to write backup suppress files.
+    // TODD(b/121198006): remove this object and synchronized all methods on "this".
+    private final Object mStateLock = new Object();
+
+    private final Handler mHandler;
+    private final Set<ComponentName> mTransportWhitelist;
+
+    /** Keeps track of all unlocked users registered with this service. Indexed by user id. */
+    private final SparseArray<UserBackupManagerService> mUserServices;
+
+    private final BroadcastReceiver mUserRemovedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
+                int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+                if (userId > 0) { // for only non system users
+                    mHandler.post(() -> onRemovedNonSystemUser(userId));
+                }
+            }
+        }
+    };
+
+    public BackupManagerService(Context context) {
+        this(context, new SparseArray<>());
+    }
+
+    @VisibleForTesting
+    BackupManagerService(Context context, SparseArray<UserBackupManagerService> userServices) {
+        mContext = context;
+        mGlobalDisable = isBackupDisabled();
+        HandlerThread handlerThread =
+                new HandlerThread(BACKUP_THREAD, Process.THREAD_PRIORITY_BACKGROUND);
+        handlerThread.start();
+        mHandler = new Handler(handlerThread.getLooper());
+        mUserManager = UserManager.get(context);
+        mUserServices = userServices;
+        Set<ComponentName> transportWhitelist =
+                SystemConfig.getInstance().getBackupTransportWhitelist();
+        mTransportWhitelist = (transportWhitelist == null) ? emptySet() : transportWhitelist;
+        mContext.registerReceiver(
+                mUserRemovedReceiver, new IntentFilter(Intent.ACTION_USER_REMOVED));
+    }
+
+    // TODO: Remove this when we implement DI by injecting in the construtor.
+    @VisibleForTesting
+    Handler getBackupHandler() {
+        return mHandler;
+    }
+
+    protected boolean isBackupDisabled() {
+        return SystemProperties.getBoolean(BACKUP_DISABLE_PROPERTY, false);
+    }
+
+    protected int binderGetCallingUserId() {
+        return Binder.getCallingUserHandle().getIdentifier();
+    }
+
+    protected int binderGetCallingUid() {
+        return Binder.getCallingUid();
+    }
+
+    /** Stored in the system user's directory. */
+    protected File getSuppressFileForSystemUser() {
+        return new File(UserBackupManagerFiles.getBaseStateDir(UserHandle.USER_SYSTEM),
+                BACKUP_SUPPRESS_FILENAME);
+    }
+
+    /** Stored in the system user's directory and the file is indexed by the user it refers to. */
+    protected File getRememberActivatedFileForNonSystemUser(int userId) {
+        return UserBackupManagerFiles.getStateFileInSystemDir(REMEMBER_ACTIVATED_FILENAME, userId);
+    }
+
+    /** Stored in the system user's directory and the file is indexed by the user it refers to. */
+    protected File getActivatedFileForNonSystemUser(int userId) {
+        return UserBackupManagerFiles.getStateFileInSystemDir(BACKUP_ACTIVATED_FILENAME, userId);
+    }
+
+    /**
+     * Remove backup state for non system {@code userId} when the user is removed from the device.
+     * For non system users, backup state is stored in both the user's own dir and the system dir.
+     * When the user is removed, the user's own dir gets removed by the OS. This method ensures that
+     * the part of the user backup state which is in the system dir also gets removed.
+     */
+    private void onRemovedNonSystemUser(int userId) {
+        Slog.i(TAG, "Removing state for non system user " + userId);
+        File dir = UserBackupManagerFiles.getStateDirInSystemDir(userId);
+        if (!FileUtils.deleteContentsAndDir(dir)) {
+            Slog.w(TAG, "Failed to delete state dir for removed user: " + userId);
+        }
+    }
+
+    // TODO (b/124359804) move to util method in FileUtils
+    private void createFile(File file) throws IOException {
+        if (file.exists()) {
+            return;
+        }
+
+        file.getParentFile().mkdirs();
+        if (!file.createNewFile()) {
+            Slog.w(TAG, "Failed to create file " + file.getPath());
+        }
+    }
+
+    // TODO (b/124359804) move to util method in FileUtils
+    private void deleteFile(File file) {
+        if (!file.exists()) {
+            return;
+        }
+
+        if (!file.delete()) {
+            Slog.w(TAG, "Failed to delete file " + file.getPath());
+        }
+    }
+
+    /**
+     * Deactivates the backup service for user {@code userId}. If this is the system user, it
+     * creates a suppress file which disables backup for all users. If this is a non-system user, it
+     * only deactivates backup for that user by deleting its activate file.
+     */
+    @GuardedBy("mStateLock")
+    private void deactivateBackupForUserLocked(int userId) throws IOException {
+        if (userId == UserHandle.USER_SYSTEM) {
+            createFile(getSuppressFileForSystemUser());
+        } else {
+            deleteFile(getActivatedFileForNonSystemUser(userId));
+        }
+    }
+
+    /**
+     * Enables the backup service for user {@code userId}. If this is the system user, it deletes
+     * the suppress file. If this is a non-system user, it creates the user's activate file. Note,
+     * deleting the suppress file does not automatically enable backup for non-system users, they
+     * need their own activate file in order to participate in the service.
+     */
+    @GuardedBy("mStateLock")
+    private void activateBackupForUserLocked(int userId) throws IOException {
+        if (userId == UserHandle.USER_SYSTEM) {
+            deleteFile(getSuppressFileForSystemUser());
+        } else {
+            createFile(getActivatedFileForNonSystemUser(userId));
+        }
+    }
+
+    // This method should not perform any I/O (e.g. do not call isBackupActivatedForUser),
+    // it's used in multiple places where I/O waits would cause system lock-ups.
+    private boolean isUserReadyForBackup(int userId) {
+        return mUserServices.get(UserHandle.USER_SYSTEM) != null
+                && mUserServices.get(userId) != null;
+    }
+
+    /**
+     * Backup is activated for the system user if the suppress file does not exist. Backup is
+     * activated for non-system users if the suppress file does not exist AND the user's activated
+     * file exists.
+     */
+    private boolean isBackupActivatedForUser(int userId) {
+        if (getSuppressFileForSystemUser().exists()) {
+            return false;
+        }
+
+        return userId == UserHandle.USER_SYSTEM
+                || getActivatedFileForNonSystemUser(userId).exists();
+    }
+
+    protected Context getContext() {
+        return mContext;
+    }
+
+    protected UserManager getUserManager() {
+        return mUserManager;
+    }
+
+    protected void postToHandler(Runnable runnable) {
+        mHandler.post(runnable);
+    }
+
+    /**
+     * Called from {@link BackupManagerService.Lifecycle} when a user {@code userId} is unlocked.
+     * Starts the backup service for this user if backup is active for this user. Offloads work onto
+     * the handler thread {@link #mHandlerThread} to keep unlock time low since backup is not
+     * essential for device functioning.
+     */
+    void onUnlockUser(int userId) {
+        postToHandler(() -> startServiceForUser(userId));
+    }
+
+    /**
+     * Starts the backup service for user {@code userId} by creating a new instance of {@link
+     * UserBackupManagerService} and registering it with this service.
+     */
+    @VisibleForTesting
+    void startServiceForUser(int userId) {
+        // We know that the user is unlocked here because it is called from setBackupServiceActive
+        // and unlockUser which have these guarantees. So we can check if the file exists.
+        if (mGlobalDisable) {
+            Slog.i(TAG, "Backup service not supported");
+            return;
+        }
+        if (!isBackupActivatedForUser(userId)) {
+            Slog.i(TAG, "Backup not activated for user " + userId);
+            return;
+        }
+        if (mUserServices.get(userId) != null) {
+            Slog.i(TAG, "userId " + userId + " already started, so not starting again");
+            return;
+        }
+        Slog.i(TAG, "Starting service for user: " + userId);
+        UserBackupManagerService userBackupManagerService =
+                UserBackupManagerService.createAndInitializeService(
+                        userId, mContext, this, mTransportWhitelist);
+        startServiceForUser(userId, userBackupManagerService);
+    }
+
+    /**
+     * Starts the backup service for user {@code userId} by registering its instance of {@link
+     * UserBackupManagerService} with this service and setting enabled state.
+     */
+    void startServiceForUser(int userId, UserBackupManagerService userBackupManagerService) {
+        mUserServices.put(userId, userBackupManagerService);
+
+        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup enable");
+        userBackupManagerService.initializeBackupEnableState();
+        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+    }
+
+    /** Stops the backup service for user {@code userId} when the user is stopped. */
+    @VisibleForTesting
+    protected void stopServiceForUser(int userId) {
+        UserBackupManagerService userBackupManagerService = mUserServices.removeReturnOld(userId);
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.tearDownService();
+
+            KeyValueBackupJob.cancel(userId, mContext);
+            FullBackupJob.cancel(userId, mContext);
+        }
+    }
+
+    /**
+     *  Returns a list of users currently unlocked that have a {@link UserBackupManagerService}
+     *  registered.
+     *
+     *  Warning: Do NOT modify returned object as it's used inside.
+     *
+     *  TODO: Return a copy or only expose read-only information through other means.
+     */
+    @VisibleForTesting
+    SparseArray<UserBackupManagerService> getUserServices() {
+        return mUserServices;
+    }
+
+    /**
+     * Called from {@link BackupManagerService.Lifecycle} when a user {@code userId} is stopped.
+     * Offloads work onto the handler thread {@link #mHandlerThread} to keep stopping time low.
+     */
+    void onStopUser(int userId) {
+        postToHandler(
+                () -> {
+                    if (!mGlobalDisable) {
+                        Slog.i(TAG, "Stopping service for user: " + userId);
+                        stopServiceForUser(userId);
+                    }
+                });
+    }
+
+    /** Returns {@link UserBackupManagerService} for user {@code userId}. */
+    @Nullable
+    public UserBackupManagerService getUserService(int userId) {
+        return mUserServices.get(userId);
+    }
+
+    /**
+     * The system user and managed profiles can only be acted on by callers in the system or root
+     * processes. Other users can be acted on by callers who have both android.permission.BACKUP and
+     * android.permission.INTERACT_ACROSS_USERS_FULL permissions.
+     */
+    private void enforcePermissionsOnUser(int userId) throws SecurityException {
+        boolean isRestrictedUser =
+                userId == UserHandle.USER_SYSTEM
+                        || getUserManager().getUserInfo(userId).isManagedProfile();
+
+        if (isRestrictedUser) {
+            int caller = binderGetCallingUid();
+            if (caller != Process.SYSTEM_UID && caller != Process.ROOT_UID) {
+                throw new SecurityException("No permission to configure backup activity");
+            }
+        } else {
+            mContext.enforceCallingOrSelfPermission(
+                    Manifest.permission.BACKUP, "No permission to configure backup activity");
+            mContext.enforceCallingOrSelfPermission(
+                    Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                    "No permission to configure backup activity");
+        }
+    }
+
+    /**
+     * Only privileged callers should be changing the backup state. Deactivating backup in the
+     * system user also deactivates backup in all users. We are not guaranteed that {@code userId}
+     * is unlocked at this point yet, so handle both cases.
+     */
+    public void setBackupServiceActive(int userId, boolean makeActive) {
+        enforcePermissionsOnUser(userId);
+
+        // In Q, backup is OFF by default for non-system users. In the future, we will change that
+        // to ON unless backup was explicitly deactivated with a (permissioned) call to
+        // setBackupServiceActive.
+        // Therefore, remember this for use in the future. Basically the default in the future will
+        // be: rememberFile.exists() ? rememberFile.value() : ON
+        // Note that this has to be done right after the permission checks and before any other
+        // action since we need to remember that a permissioned call was made irrespective of
+        // whether the call changes the state or not.
+        if (userId != UserHandle.USER_SYSTEM) {
+            try {
+                File rememberFile = getRememberActivatedFileForNonSystemUser(userId);
+                createFile(rememberFile);
+                RandomAccessFileUtils.writeBoolean(rememberFile, makeActive);
+            } catch (IOException e) {
+                Slog.e(TAG, "Unable to persist backup service activity", e);
+            }
+        }
+
+        if (mGlobalDisable) {
+            Slog.i(TAG, "Backup service not supported");
+            return;
+        }
+
+        synchronized (mStateLock) {
+            Slog.i(TAG, "Making backup " + (makeActive ? "" : "in") + "active");
+            if (makeActive) {
+                try {
+                    activateBackupForUserLocked(userId);
+                } catch (IOException e) {
+                    Slog.e(TAG, "Unable to persist backup service activity");
+                }
+
+                // If the user is unlocked, we can start the backup service for it. Otherwise we
+                // will start the service when the user is unlocked as part of its unlock callback.
+                if (getUserManager().isUserUnlocked(userId)) {
+                    // Clear calling identity as initialization enforces the system identity but we
+                    // can be coming from shell.
+                    long oldId = Binder.clearCallingIdentity();
+                    try {
+                        startServiceForUser(userId);
+                    } finally {
+                        Binder.restoreCallingIdentity(oldId);
+                    }
+                }
+            } else {
+                try {
+                    //TODO(b/121198006): what if this throws an exception?
+                    deactivateBackupForUserLocked(userId);
+                } catch (IOException e) {
+                    Slog.e(TAG, "Unable to persist backup service inactivity");
+                }
+                //TODO(b/121198006): loop through active users that have work profile and
+                // stop them as well.
+                onStopUser(userId);
+            }
+        }
+    }
+
+    // IBackupManager binder API
+
+    /**
+     * Querying activity state of backup service.
+     *
+     * @param userId The user in which the activity state of backup service is queried.
+     * @return true if the service is active.
+     */
+    @Override
+    public boolean isBackupServiceActive(int userId) {
+        synchronized (mStateLock) {
+            return !mGlobalDisable && isBackupActivatedForUser(userId);
+        }
+    }
+
+    @Override
+    public void dataChangedForUser(int userId, String packageName) throws RemoteException {
+        if (isUserReadyForBackup(userId)) {
+            dataChanged(userId, packageName);
+        }
+    }
+
+    @Override
+    public void dataChanged(String packageName) throws RemoteException {
+        dataChangedForUser(binderGetCallingUserId(), packageName);
+    }
+
+    /**
+     * An app's backup agent calls this method to let the service know that there's new data to
+     * backup for their app {@code packageName}. Only used for apps participating in key-value
+     * backup.
+     */
+    public void dataChanged(@UserIdInt int userId, String packageName) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "dataChanged()");
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.dataChanged(packageName);
+        }
+    }
+
+    // ---------------------------------------------
+    // TRANSPORT OPERATIONS
+    // ---------------------------------------------
+
+    @Override
+    public void initializeTransportsForUser(
+            int userId, String[] transportNames, IBackupObserver observer) throws RemoteException {
+        if (isUserReadyForBackup(userId)) {
+            initializeTransports(userId, transportNames, observer);
+        }
+    }
+
+    /** Run an initialize operation for the given transports {@code transportNames}. */
+    public void initializeTransports(
+            @UserIdInt int userId, String[] transportNames, IBackupObserver observer) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "initializeTransports()");
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.initializeTransports(transportNames, observer);
+        }
+    }
+
+    @Override
+    public void clearBackupDataForUser(int userId, String transportName, String packageName)
+            throws RemoteException {
+        if (isUserReadyForBackup(userId)) {
+            clearBackupData(userId, transportName, packageName);
+        }
+    }
+
+    /**
+     * Clear the given package {@code packageName}'s backup data from the transport {@code
+     * transportName}.
+     */
+    public void clearBackupData(@UserIdInt int userId, String transportName, String packageName) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "clearBackupData()");
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.clearBackupData(transportName, packageName);
+        }
+    }
+
+    @Override
+    public void clearBackupData(String transportName, String packageName)
+            throws RemoteException {
+        clearBackupDataForUser(binderGetCallingUserId(), transportName, packageName);
+    }
+
+    @Override
+    public void agentConnectedForUser(int userId, String packageName, IBinder agent)
+            throws RemoteException {
+        if (isUserReadyForBackup(userId)) {
+            agentConnected(userId, packageName, agent);
+        }
+    }
+
+    @Override
+    public void agentConnected(String packageName, IBinder agent) throws RemoteException {
+        agentConnectedForUser(binderGetCallingUserId(), packageName, agent);
+    }
+
+    /**
+     * Callback: a requested backup agent has been instantiated. This should only be called from the
+     * {@link ActivityManager}.
+     */
+    public void agentConnected(@UserIdInt int userId, String packageName, IBinder agentBinder) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "agentConnected()");
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.agentConnected(packageName, agentBinder);
+        }
+    }
+
+    @Override
+    public void agentDisconnectedForUser(int userId, String packageName) throws RemoteException {
+        if (isUserReadyForBackup(userId)) {
+            agentDisconnected(userId, packageName);
+        }
+    }
+
+    @Override
+    public void agentDisconnected(String packageName) throws RemoteException {
+        agentDisconnectedForUser(binderGetCallingUserId(), packageName);
+    }
+
+    /**
+     * Callback: a backup agent has failed to come up, or has unexpectedly quit. This should only be
+     * called from the {@link ActivityManager}.
+     */
+    public void agentDisconnected(@UserIdInt int userId, String packageName) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "agentDisconnected()");
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.agentDisconnected(packageName);
+        }
+    }
+
+    @Override
+    public void restoreAtInstallForUser(int userId, String packageName, int token)
+            throws RemoteException {
+        if (isUserReadyForBackup(userId)) {
+            restoreAtInstall(userId, packageName, token);
+        }
+    }
+
+    @Override
+    public void restoreAtInstall(String packageName, int token) throws RemoteException {
+        restoreAtInstallForUser(binderGetCallingUserId(), packageName, token);
+    }
+
+    /**
+     * Used to run a restore pass for an application that is being installed. This should only be
+     * called from the {@link PackageManager}.
+     */
+    public void restoreAtInstall(@UserIdInt int userId, String packageName, int token) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "restoreAtInstall()");
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.restoreAtInstall(packageName, token);
+        }
+    }
+
+    @Override
+    public void setBackupEnabledForUser(@UserIdInt int userId, boolean isEnabled)
+            throws RemoteException {
+        if (isUserReadyForBackup(userId)) {
+            setBackupEnabled(userId, isEnabled);
+        }
+    }
+
+    @Override
+    public void setBackupEnabled(boolean isEnabled) throws RemoteException {
+        setBackupEnabledForUser(binderGetCallingUserId(), isEnabled);
+    }
+
+    /** Enable/disable the backup service. This is user-configurable via backup settings. */
+    public void setBackupEnabled(@UserIdInt int userId, boolean enable) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "setBackupEnabled()");
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.setBackupEnabled(enable);
+        }
+    }
+
+    @Override
+    public void setAutoRestoreForUser(int userId, boolean doAutoRestore) throws RemoteException {
+        if (isUserReadyForBackup(userId)) {
+            setAutoRestore(userId, doAutoRestore);
+        }
+    }
+
+    @Override
+    public void setAutoRestore(boolean doAutoRestore) throws RemoteException {
+        setAutoRestoreForUser(binderGetCallingUserId(), doAutoRestore);
+    }
+
+    /** Enable/disable automatic restore of app data at install time. */
+    public void setAutoRestore(@UserIdInt int userId, boolean autoRestore) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "setAutoRestore()");
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.setAutoRestore(autoRestore);
+        }
+    }
+
+    @Override
+    public boolean isBackupEnabledForUser(@UserIdInt int userId) throws RemoteException {
+        return isUserReadyForBackup(userId) && isBackupEnabled(userId);
+    }
+
+    @Override
+    public boolean isBackupEnabled() throws RemoteException {
+        return isBackupEnabledForUser(binderGetCallingUserId());
+    }
+
+    /**
+     * Return {@code true} if the backup mechanism is currently enabled, else returns {@code false}.
+     */
+    public boolean isBackupEnabled(@UserIdInt int userId) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "isBackupEnabled()");
+
+        return userBackupManagerService != null && userBackupManagerService.isBackupEnabled();
+    }
+
+    /** Sets the backup password used when running adb backup. */
+    @Override
+    public boolean setBackupPassword(String currentPassword, String newPassword) {
+        int userId = binderGetCallingUserId();
+        if (!isUserReadyForBackup(userId)) {
+            return false;
+        }
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(
+                        UserHandle.USER_SYSTEM, "setBackupPassword()");
+
+        return userBackupManagerService != null
+                && userBackupManagerService.setBackupPassword(currentPassword, newPassword);
+    }
+
+    /** Returns {@code true} if adb backup was run with a password, else returns {@code false}. */
+    @Override
+    public boolean hasBackupPassword() throws RemoteException {
+        int userId = binderGetCallingUserId();
+        if (!isUserReadyForBackup(userId)) {
+            return false;
+        }
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(
+                        UserHandle.USER_SYSTEM, "hasBackupPassword()");
+
+        return userBackupManagerService != null && userBackupManagerService.hasBackupPassword();
+    }
+
+    @Override
+    public void backupNowForUser(@UserIdInt int userId) throws RemoteException {
+        if (isUserReadyForBackup(userId)) {
+            backupNow(userId);
+        }
+    }
+
+    @Override
+    public void backupNow() throws RemoteException {
+        backupNowForUser(binderGetCallingUserId());
+    }
+
+    /**
+     * Run a backup pass immediately for any key-value backup applications that have declared that
+     * they have pending updates.
+     */
+    public void backupNow(@UserIdInt int userId) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "backupNow()");
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.backupNow();
+        }
+    }
+
+    /**
+     * Used by 'adb backup' to run a backup pass for packages {@code packageNames} supplied via the
+     * command line, writing the resulting data stream to the supplied {@code fd}. This method is
+     * synchronous and does not return to the caller until the backup has been completed. It
+     * requires on-screen confirmation by the user.
+     */
+    @Override
+    public void adbBackup(
+            @UserIdInt int userId,
+            ParcelFileDescriptor fd,
+            boolean includeApks,
+            boolean includeObbs,
+            boolean includeShared,
+            boolean doWidgets,
+            boolean doAllApps,
+            boolean includeSystem,
+            boolean doCompress,
+            boolean doKeyValue,
+            String[] packageNames) {
+        if (!isUserReadyForBackup(userId)) {
+            return;
+        }
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "adbBackup()");
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.adbBackup(
+                    fd,
+                    includeApks,
+                    includeObbs,
+                    includeShared,
+                    doWidgets,
+                    doAllApps,
+                    includeSystem,
+                    doCompress,
+                    doKeyValue,
+                    packageNames);
+        }
+    }
+
+    @Override
+    public void fullTransportBackupForUser(int userId, String[] packageNames)
+            throws RemoteException {
+        if (isUserReadyForBackup(userId)) {
+            fullTransportBackup(userId, packageNames);
+        }
+    }
+
+    /**
+     * Run a full backup pass for the given packages {@code packageNames}. Used by 'adb shell bmgr'.
+     */
+    public void fullTransportBackup(@UserIdInt int userId, String[] packageNames) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "fullTransportBackup()");
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.fullTransportBackup(packageNames);
+        }
+    }
+
+    /**
+     * Used by 'adb restore' to run a restore pass reading from the supplied {@code fd}. This method
+     * is synchronous and does not return to the caller until the restore has been completed. It
+     * requires on-screen confirmation by the user.
+     */
+    @Override
+    public void adbRestore(@UserIdInt int userId, ParcelFileDescriptor fd) {
+        if (!isUserReadyForBackup(userId)) {
+            return;
+        }
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "adbRestore()");
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.adbRestore(fd);
+        }
+    }
+
+    @Override
+    public void acknowledgeFullBackupOrRestoreForUser(
+            int userId,
+            int token,
+            boolean allow,
+            String curPassword,
+            String encryptionPassword,
+            IFullBackupRestoreObserver observer)
+            throws RemoteException {
+        if (isUserReadyForBackup(userId)) {
+            acknowledgeAdbBackupOrRestore(userId, token, allow,
+                    curPassword, encryptionPassword, observer);
+        }
+    }
+
+    /**
+     * Confirm that the previously requested adb backup/restore operation can proceed. This is used
+     * to require a user-facing disclosure about the operation.
+     */
+    public void acknowledgeAdbBackupOrRestore(
+            @UserIdInt int userId,
+            int token,
+            boolean allow,
+            String currentPassword,
+            String encryptionPassword,
+            IFullBackupRestoreObserver observer) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "acknowledgeAdbBackupOrRestore()");
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.acknowledgeAdbBackupOrRestore(
+                    token, allow, currentPassword, encryptionPassword, observer);
+        }
+    }
+
+    @Override
+    public void acknowledgeFullBackupOrRestore(int token, boolean allow, String curPassword,
+            String encryptionPassword, IFullBackupRestoreObserver observer)
+            throws RemoteException {
+        acknowledgeFullBackupOrRestoreForUser(
+                binderGetCallingUserId(), token, allow, curPassword, encryptionPassword, observer);
+    }
+
+
+    @Override
+    public String getCurrentTransportForUser(int userId) throws RemoteException {
+        return (isUserReadyForBackup(userId)) ? getCurrentTransport(userId) : null;
+    }
+
+    @Override
+    public String getCurrentTransport() throws RemoteException {
+        return getCurrentTransportForUser(binderGetCallingUserId());
+    }
+
+    /** Return the name of the currently active transport. */
+    @Nullable
+    public String getCurrentTransport(@UserIdInt int userId) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "getCurrentTransport()");
+
+        return userBackupManagerService == null
+                ? null
+                : userBackupManagerService.getCurrentTransport();
+    }
+
+    /**
+     * Returns the {@link ComponentName} of the host service of the selected transport or
+     * {@code null} if no transport selected or if the transport selected is not registered.
+     */
+    @Override
+    @Nullable
+    public ComponentName getCurrentTransportComponentForUser(int userId) {
+        return (isUserReadyForBackup(userId)) ? getCurrentTransportComponent(userId) : null;
+    }
+
+    /**
+     * Returns the {@link ComponentName} of the host service of the selected transport or {@code
+     * null} if no transport selected or if the transport selected is not registered.
+     */
+    @Nullable
+    public ComponentName getCurrentTransportComponent(@UserIdInt int userId) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "getCurrentTransportComponent()");
+
+        return userBackupManagerService == null
+                ? null
+                : userBackupManagerService.getCurrentTransportComponent();
+    }
+
+    @Override
+    public String[] listAllTransportsForUser(int userId) throws RemoteException {
+        return (isUserReadyForBackup(userId)) ? listAllTransports(userId) : null;
+    }
+
+    /** Report all known, available backup transports by name. */
+    @Nullable
+    public String[] listAllTransports(@UserIdInt int userId) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "listAllTransports()");
+
+        return userBackupManagerService == null
+                ? null
+                : userBackupManagerService.listAllTransports();
+    }
+
+    @Override
+    public String[] listAllTransports() throws RemoteException {
+        return listAllTransportsForUser(binderGetCallingUserId());
+    }
+
+    @Override
+    public ComponentName[] listAllTransportComponentsForUser(int userId) throws RemoteException {
+        return (isUserReadyForBackup(userId))
+                ? listAllTransportComponents(userId) : null;
+    }
+
+    /** Report all known, available backup transports by {@link ComponentName}. */
+    @Nullable
+    public ComponentName[] listAllTransportComponents(@UserIdInt int userId) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "listAllTransportComponents()");
+
+        return userBackupManagerService == null
+                ? null
+                : userBackupManagerService.listAllTransportComponents();
+    }
+
+    @Override
+    public String[] getTransportWhitelist() {
+        int userId = binderGetCallingUserId();
+        if (!isUserReadyForBackup(userId)) {
+            return null;
+        }
+        // No permission check, intentionally.
+        String[] whitelistedTransports = new String[mTransportWhitelist.size()];
+        int i = 0;
+        for (ComponentName component : mTransportWhitelist) {
+            whitelistedTransports[i] = component.flattenToShortString();
+            i++;
+        }
+        return whitelistedTransports;
+    }
+
+    @Override
+    public void updateTransportAttributesForUser(
+            int userId,
+            ComponentName transportComponent,
+            String name,
+            @Nullable Intent configurationIntent,
+            String currentDestinationString,
+            @Nullable Intent dataManagementIntent,
+            CharSequence dataManagementLabel) {
+        if (isUserReadyForBackup(userId)) {
+            updateTransportAttributes(
+                    userId,
+                    transportComponent,
+                    name,
+                    configurationIntent,
+                    currentDestinationString,
+                    dataManagementIntent,
+                    dataManagementLabel);
+        }
+    }
+
+    /**
+     * Update the attributes of the transport identified by {@code transportComponent}. If the
+     * specified transport has not been bound at least once (for registration), this call will be
+     * ignored. Only the host process of the transport can change its description, otherwise a
+     * {@link SecurityException} will be thrown.
+     *
+     * @param transportComponent The identity of the transport being described.
+     * @param name A {@link String} with the new name for the transport. This is NOT for
+     *     identification. MUST NOT be {@code null}.
+     * @param configurationIntent An {@link Intent} that can be passed to {@link
+     *     Context#startActivity} in order to launch the transport's configuration UI. It may be
+     *     {@code null} if the transport does not offer any user-facing configuration UI.
+     * @param currentDestinationString A {@link String} describing the destination to which the
+     *     transport is currently sending data. MUST NOT be {@code null}.
+     * @param dataManagementIntent An {@link Intent} that can be passed to {@link
+     *     Context#startActivity} in order to launch the transport's data-management UI. It may be
+     *     {@code null} if the transport does not offer any user-facing data management UI.
+     * @param dataManagementLabel A {@link CharSequence} to be used as the label for the transport's
+     *     data management affordance. This MUST be {@code null} when dataManagementIntent is {@code
+     *     null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}.
+     * @throws SecurityException If the UID of the calling process differs from the package UID of
+     *     {@code transportComponent} or if the caller does NOT have BACKUP permission.
+     */
+    public void updateTransportAttributes(
+            @UserIdInt int userId,
+            ComponentName transportComponent,
+            String name,
+            @Nullable Intent configurationIntent,
+            String currentDestinationString,
+            @Nullable Intent dataManagementIntent,
+            CharSequence dataManagementLabel) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "updateTransportAttributes()");
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.updateTransportAttributes(
+                    transportComponent,
+                    name,
+                    configurationIntent,
+                    currentDestinationString,
+                    dataManagementIntent,
+                    dataManagementLabel);
+        }
+    }
+
+    @Override
+    public String selectBackupTransportForUser(int userId, String transport)
+            throws RemoteException {
+        return (isUserReadyForBackup(userId))
+                ? selectBackupTransport(userId, transport) : null;
+    }
+
+    @Override
+    public String selectBackupTransport(String transport) throws RemoteException {
+        return selectBackupTransportForUser(binderGetCallingUserId(), transport);
+    }
+
+    /**
+     * Selects transport {@code transportName} and returns the previously selected transport.
+     *
+     * @deprecated Use {@link #selectBackupTransportAsync(ComponentName,
+     *     ISelectBackupTransportCallback)} instead.
+     */
+    @Deprecated
+    @Nullable
+    public String selectBackupTransport(@UserIdInt int userId, String transportName) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "selectBackupTransport()");
+
+        return userBackupManagerService == null
+                ? null
+                : userBackupManagerService.selectBackupTransport(transportName);
+    }
+
+    @Override
+    public void selectBackupTransportAsyncForUser(int userId, ComponentName transport,
+            ISelectBackupTransportCallback listener) throws RemoteException {
+        if (isUserReadyForBackup(userId)) {
+            selectBackupTransportAsync(userId, transport, listener);
+        } else {
+            if (listener != null) {
+                try {
+                    listener.onFailure(BackupManager.ERROR_BACKUP_NOT_ALLOWED);
+                } catch (RemoteException ex) {
+                    // ignore
+                }
+            }
+        }
+    }
+
+    /**
+     * Selects transport {@code transportComponent} asynchronously and notifies {@code listener}
+     * with the result upon completion.
+     */
+    public void selectBackupTransportAsync(
+            @UserIdInt int userId,
+            ComponentName transportComponent,
+            ISelectBackupTransportCallback listener) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "selectBackupTransportAsync()");
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.selectBackupTransportAsync(transportComponent, listener);
+        }
+    }
+
+    @Override
+    public Intent getConfigurationIntentForUser(int userId, String transport)
+            throws RemoteException {
+        return isUserReadyForBackup(userId) ? getConfigurationIntent(userId, transport)
+                : null;
+    }
+
+    @Override
+    public Intent getConfigurationIntent(String transport)
+            throws RemoteException {
+        return getConfigurationIntentForUser(binderGetCallingUserId(), transport);
+    }
+
+    /**
+     * Supply the configuration intent for the given transport. If the name is not one of the
+     * available transports, or if the transport does not supply any configuration UI, the method
+     * returns {@code null}.
+     */
+    @Nullable
+    public Intent getConfigurationIntent(@UserIdInt int userId, String transportName) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "getConfigurationIntent()");
+
+        return userBackupManagerService == null
+                ? null
+                : userBackupManagerService.getConfigurationIntent(transportName);
+    }
+
+    @Override
+    public String getDestinationStringForUser(int userId, String transport) throws RemoteException {
+        return isUserReadyForBackup(userId) ? getDestinationString(userId, transport)
+                : null;
+    }
+
+    @Override
+    public String getDestinationString(String transport) throws RemoteException {
+        return getDestinationStringForUser(binderGetCallingUserId(), transport);
+    }
+
+    /**
+     * Supply the current destination string for the given transport. If the name is not one of the
+     * registered transports the method will return null.
+     *
+     * <p>This string is used VERBATIM as the summary text of the relevant Settings item.
+     *
+     * @param transportName The name of the registered transport.
+     * @return The current destination string or null if the transport is not registered.
+     */
+    @Nullable
+    public String getDestinationString(@UserIdInt int userId, String transportName) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "getDestinationString()");
+
+        return userBackupManagerService == null
+                ? null
+                : userBackupManagerService.getDestinationString(transportName);
+    }
+
+    @Override
+    public Intent getDataManagementIntentForUser(int userId, String transport)
+            throws RemoteException {
+        return isUserReadyForBackup(userId)
+                ? getDataManagementIntent(userId, transport) : null;
+    }
+
+    @Override
+    public Intent getDataManagementIntent(String transport)
+            throws RemoteException {
+        return getDataManagementIntentForUser(binderGetCallingUserId(), transport);
+    }
+
+    /** Supply the manage-data intent for the given transport. */
+    @Nullable
+    public Intent getDataManagementIntent(@UserIdInt int userId, String transportName) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "getDataManagementIntent()");
+
+        return userBackupManagerService == null
+                ? null
+                : userBackupManagerService.getDataManagementIntent(transportName);
+    }
+
+    @Override
+    public CharSequence getDataManagementLabelForUser(int userId, String transport)
+            throws RemoteException {
+        return isUserReadyForBackup(userId) ? getDataManagementLabel(userId, transport)
+                : null;
+    }
+
+    /**
+     * Supply the menu label for affordances that fire the manage-data intent for the given
+     * transport.
+     */
+    @Nullable
+    public CharSequence getDataManagementLabel(@UserIdInt int userId, String transportName) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "getDataManagementLabel()");
+
+        return userBackupManagerService == null
+                ? null
+                : userBackupManagerService.getDataManagementLabel(transportName);
+    }
+
+    @Override
+    public IRestoreSession beginRestoreSessionForUser(
+            int userId, String packageName, String transportID) throws RemoteException {
+        return isUserReadyForBackup(userId)
+                ? beginRestoreSession(userId, packageName, transportID) : null;
+    }
+
+    /**
+     * Begin a restore for the specified package {@code packageName} using the specified transport
+     * {@code transportName}.
+     */
+    @Nullable
+    public IRestoreSession beginRestoreSession(
+            @UserIdInt int userId, String packageName, String transportName) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "beginRestoreSession()");
+
+        return userBackupManagerService == null
+                ? null
+                : userBackupManagerService.beginRestoreSession(packageName, transportName);
+    }
+
+    @Override
+    public void opCompleteForUser(int userId, int token, long result) throws RemoteException {
+        if (isUserReadyForBackup(userId)) {
+            opComplete(userId, token, result);
+        }
+    }
+
+    @Override
+    public void opComplete(int token, long result) throws RemoteException {
+        opCompleteForUser(binderGetCallingUserId(), token, result);
+    }
+
+    /**
+     * Used by a currently-active backup agent to notify the service that it has completed its given
+     * outstanding asynchronous backup/restore operation.
+     */
+    public void opComplete(@UserIdInt int userId, int token, long result) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "opComplete()");
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.opComplete(token, result);
+        }
+    }
+
+    @Override
+    public long getAvailableRestoreTokenForUser(int userId, String packageName) {
+        return isUserReadyForBackup(userId) ? getAvailableRestoreToken(userId, packageName) : 0;
+    }
+
+    /**
+     * Get the restore-set token for the best-available restore set for this {@code packageName}:
+     * the active set if possible, else the ancestral one. Returns zero if none available.
+     */
+    public long getAvailableRestoreToken(@UserIdInt int userId, String packageName) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "getAvailableRestoreToken()");
+
+        return userBackupManagerService == null
+                ? 0
+                : userBackupManagerService.getAvailableRestoreToken(packageName);
+    }
+
+    @Override
+    public boolean isAppEligibleForBackupForUser(int userId, String packageName) {
+        return isUserReadyForBackup(userId) && isAppEligibleForBackup(userId,
+                packageName);
+    }
+
+    /** Checks if the given package {@code packageName} is eligible for backup. */
+    public boolean isAppEligibleForBackup(@UserIdInt int userId, String packageName) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "isAppEligibleForBackup()");
+
+        return userBackupManagerService != null
+                && userBackupManagerService.isAppEligibleForBackup(packageName);
+    }
+
+    @Override
+    public String[] filterAppsEligibleForBackupForUser(int userId, String[] packages) {
+        return isUserReadyForBackup(userId) ? filterAppsEligibleForBackup(userId, packages) : null;
+    }
+
+    /**
+     * Returns from the inputted packages {@code packages}, the ones that are eligible for backup.
+     */
+    @Nullable
+    public String[] filterAppsEligibleForBackup(@UserIdInt int userId, String[] packages) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "filterAppsEligibleForBackup()");
+
+        return userBackupManagerService == null
+                ? null
+                : userBackupManagerService.filterAppsEligibleForBackup(packages);
+    }
+
+    @Override
+    public int requestBackupForUser(@UserIdInt int userId, String[] packages, IBackupObserver
+            observer, IBackupManagerMonitor monitor, int flags) throws RemoteException {
+        if (!isUserReadyForBackup(userId)) {
+            return BackupManager.ERROR_BACKUP_NOT_ALLOWED;
+        }
+        return requestBackup(userId, packages, observer, monitor, flags);
+    }
+
+    @Override
+    public int requestBackup(String[] packages, IBackupObserver observer,
+            IBackupManagerMonitor monitor, int flags) throws RemoteException {
+        return requestBackupForUser(binderGetCallingUserId(), packages,
+                observer, monitor, flags);
+    }
+
+    /**
+     * Requests a backup for the inputted {@code packages} with a specified callback {@link
+     * IBackupManagerMonitor} for receiving events during the operation.
+     */
+    public int requestBackup(
+            @UserIdInt int userId,
+            String[] packages,
+            IBackupObserver observer,
+            IBackupManagerMonitor monitor,
+            int flags) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "requestBackup()");
+
+        return userBackupManagerService == null
+                ? BackupManager.ERROR_BACKUP_NOT_ALLOWED
+                : userBackupManagerService.requestBackup(packages, observer, monitor, flags);
+    }
+
+    @Override
+    public void cancelBackupsForUser(@UserIdInt int userId) throws RemoteException {
+        if (isUserReadyForBackup(userId)) {
+            cancelBackups(userId);
+        }
+    }
+
+    @Override
+    public void cancelBackups() throws RemoteException {
+        cancelBackupsForUser(binderGetCallingUserId());
+    }
+
+    /** Cancel all running backup operations. */
+    public void cancelBackups(@UserIdInt int userId) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "cancelBackups()");
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.cancelBackups();
+        }
+    }
+
+    /**
+     * Returns a {@link UserHandle} for the user that has {@code ancestralSerialNumber} as the
+     * serial number of its ancestral work profile or null if there is no {@link
+     * UserBackupManagerService} associated with that user.
+     *
+     * <p> The ancestral work profile is set by {@link #setAncestralSerialNumber(long)}
+     * and it corresponds to the profile that was used to restore to the callers profile.
+     */
+    @Override
+    @Nullable
+    public UserHandle getUserForAncestralSerialNumber(long ancestralSerialNumber) {
+        if (mGlobalDisable) {
+            return null;
+        }
+        int callingUserId = Binder.getCallingUserHandle().getIdentifier();
+        long oldId = Binder.clearCallingIdentity();
+        final int[] userIds;
+        try {
+            userIds =
+                    mContext
+                            .getSystemService(UserManager.class)
+                            .getProfileIds(callingUserId, false);
+        } finally {
+            Binder.restoreCallingIdentity(oldId);
+        }
+
+        for (int userId : userIds) {
+            UserBackupManagerService userBackupManagerService = mUserServices.get(userId);
+            if (userBackupManagerService != null) {
+                if (userBackupManagerService.getAncestralSerialNumber() == ancestralSerialNumber) {
+                    return UserHandle.of(userId);
+                }
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Sets the ancestral work profile for the calling user.
+     *
+     * <p> The ancestral work profile corresponds to the profile that was used to restore to the
+     * callers profile.
+     */
+    @Override
+    public void setAncestralSerialNumber(long ancestralSerialNumber) {
+        if (mGlobalDisable) {
+            return;
+        }
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(
+                        Binder.getCallingUserHandle().getIdentifier(),
+                        "setAncestralSerialNumber()");
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.setAncestralSerialNumber(ancestralSerialNumber);
+        }
+    }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) {
+            return;
+        }
+        int userId = binderGetCallingUserId();
+        if (!isUserReadyForBackup(userId)) {
+            pw.println("Inactive");
+            return;
+        }
+
+        if (args != null) {
+            for (String arg : args) {
+                if ("users".equals(arg.toLowerCase())) {
+                    pw.print(DUMP_RUNNING_USERS_MESSAGE);
+                    for (int i = 0; i < mUserServices.size(); i++) {
+                        pw.print(" " + mUserServices.keyAt(i));
+                    }
+                    pw.println();
+                    return;
+                }
+            }
+        }
+
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(UserHandle.USER_SYSTEM, "dump()");
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.dump(fd, pw, args);
+        }
+    }
+
+    /**
+     * Used by the {@link JobScheduler} to run a full backup when conditions are right. The model we
+     * use is to perform one app backup per scheduled job execution, and to reschedule the job with
+     * zero latency as long as conditions remain right and we still have work to do.
+     *
+     * @return Whether ongoing work will continue. The return value here will be passed along as the
+     *     return value to the callback {@link JobService#onStartJob(JobParameters)}.
+     */
+    public boolean beginFullBackup(@UserIdInt int userId, FullBackupJob scheduledJob) {
+        if (!isUserReadyForBackup(userId)) {
+            return false;
+        }
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "beginFullBackup()");
+
+        return userBackupManagerService != null
+                && userBackupManagerService.beginFullBackup(scheduledJob);
+    }
+
+    /**
+     * Used by the {@link JobScheduler} to end the current full backup task when conditions are no
+     * longer met for running the full backup job.
+     */
+    public void endFullBackup(@UserIdInt int userId) {
+        if (!isUserReadyForBackup(userId)) {
+            return;
+        }
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "endFullBackup()");
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.endFullBackup();
+        }
+    }
+
+    /**
+     * Returns the {@link UserBackupManagerService} instance for the specified user {@code userId}.
+     * If the user is not registered with the service (either the user is locked or not eligible for
+     * the backup service) then return {@code null}.
+     *
+     * @param userId The id of the user to retrieve its instance of {@link
+     *     UserBackupManagerService}.
+     * @param caller A {@link String} identifying the caller for logging purposes.
+     * @throws SecurityException if {@code userId} is different from the calling user id and the
+     *     caller does NOT have the android.permission.INTERACT_ACROSS_USERS_FULL permission.
+     */
+    @Nullable
+    @VisibleForTesting
+    UserBackupManagerService getServiceForUserIfCallerHasPermission(
+            @UserIdInt int userId, String caller) {
+        enforceCallingPermissionOnUserId(userId, caller);
+        UserBackupManagerService userBackupManagerService = mUserServices.get(userId);
+        if (userBackupManagerService == null) {
+            Slog.w(TAG, "Called " + caller + " for unknown user: " + userId);
+        }
+        return userBackupManagerService;
+    }
+
+    /**
+     * If {@code userId} is different from the calling user id, then the caller must hold the
+     * android.permission.INTERACT_ACROSS_USERS_FULL permission.
+     *
+     * @param userId User id on which the backup operation is being requested.
+     * @param message A message to include in the exception if it is thrown.
+     */
+    void enforceCallingPermissionOnUserId(@UserIdInt int userId, String message) {
+        if (Binder.getCallingUserHandle().getIdentifier() != userId) {
+            mContext.enforceCallingOrSelfPermission(
+                    Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
+        }
     }
 
     /** Implementation to receive lifecycle event callbacks for system services. */
     public static class Lifecycle extends SystemService {
         public Lifecycle(Context context) {
-            this(context, new Trampoline(context));
+            this(context, new BackupManagerService(context));
         }
 
         @VisibleForTesting
-        Lifecycle(Context context, Trampoline trampoline) {
+        Lifecycle(Context context, BackupManagerService backupManagerService) {
             super(context);
-            Trampoline.sInstance = trampoline;
+            sInstance = backupManagerService;
         }
 
         @Override
         public void onStart() {
-            publishService(Context.BACKUP_SERVICE, Trampoline.sInstance);
+            publishService(Context.BACKUP_SERVICE, BackupManagerService.sInstance);
         }
 
         @Override
         public void onUnlockUser(int userId) {
-            Trampoline.sInstance.onUnlockUser(userId);
+            sInstance.onUnlockUser(userId);
         }
 
         @Override
         public void onStopUser(int userId) {
-            Trampoline.sInstance.onStopUser(userId);
+            sInstance.onStopUser(userId);
         }
 
         @VisibleForTesting
diff --git a/services/backup/java/com/android/server/backup/FullBackupJob.java b/services/backup/java/com/android/server/backup/FullBackupJob.java
index 19a8543..0bb25e3 100644
--- a/services/backup/java/com/android/server/backup/FullBackupJob.java
+++ b/services/backup/java/com/android/server/backup/FullBackupJob.java
@@ -91,7 +91,7 @@
             mParamsForUser.put(userId, params);
         }
 
-        Trampoline service = Trampoline.getInstance();
+        BackupManagerService service = BackupManagerService.getInstance();
         return service.beginFullBackup(userId, this);
     }
 
@@ -105,7 +105,7 @@
             }
         }
 
-        Trampoline service = Trampoline.getInstance();
+        BackupManagerService service = BackupManagerService.getInstance();
         service.endFullBackup(userId);
 
         return false;
diff --git a/services/backup/java/com/android/server/backup/KeyValueBackupJob.java b/services/backup/java/com/android/server/backup/KeyValueBackupJob.java
index 7b5dbd7..058dcae 100644
--- a/services/backup/java/com/android/server/backup/KeyValueBackupJob.java
+++ b/services/backup/java/com/android/server/backup/KeyValueBackupJob.java
@@ -144,7 +144,7 @@
         }
 
         // Time to run a key/value backup!
-        Trampoline service = Trampoline.getInstance();
+        BackupManagerService service = BackupManagerService.getInstance();
         try {
             service.backupNowForUser(userId);
         } catch (RemoteException e) {}
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
deleted file mode 100644
index 4cd1e17..0000000
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ /dev/null
@@ -1,1549 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.backup;
-
-import static com.android.internal.util.Preconditions.checkNotNull;
-import static com.android.server.backup.BackupManagerService.TAG;
-
-import static java.util.Collections.emptySet;
-
-import android.Manifest;
-import android.annotation.Nullable;
-import android.annotation.UserIdInt;
-import android.app.ActivityManager;
-import android.app.admin.DevicePolicyManager;
-import android.app.backup.BackupManager;
-import android.app.backup.IBackupManager;
-import android.app.backup.IBackupManagerMonitor;
-import android.app.backup.IBackupObserver;
-import android.app.backup.IFullBackupRestoreObserver;
-import android.app.backup.IRestoreSession;
-import android.app.backup.ISelectBackupTransportCallback;
-import android.app.job.JobParameters;
-import android.app.job.JobScheduler;
-import android.app.job.JobService;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.os.Binder;
-import android.os.FileUtils;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.SystemProperties;
-import android.os.Trace;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.Slog;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.DumpUtils;
-import com.android.server.SystemConfig;
-import com.android.server.backup.utils.RandomAccessFileUtils;
-
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.Set;
-
-/**
- * A proxy to the {@link BackupManagerService} implementation.
- *
- * <p>This is an external interface to the {@link BackupManagerService} which is being accessed via
- * published binder {@link BackupManagerService.Lifecycle}. This lets us turn down the heavy
- * implementation object on the fly without disturbing binders that have been cached somewhere in
- * the system.
- *
- * <p>Trampoline determines whether the backup service is available. It can be disabled in the
- * following two ways:
- *
- * <ul>
- * <li>Temporary - create the file {@link #BACKUP_SUPPRESS_FILENAME}, or
- * <li>Permanent - set the system property {@link #BACKUP_DISABLE_PROPERTY} to true.
- * </ul>
- *
- * Temporary disabling is controlled by {@link #setBackupServiceActive(int, boolean)} through
- * privileged callers (currently {@link DevicePolicyManager}). This is called on {@link
- * UserHandle#USER_SYSTEM} and disables backup for all users.
- */
-public class Trampoline extends IBackupManager.Stub {
-    @VisibleForTesting
-    static final String DUMP_RUNNING_USERS_MESSAGE = "Backup Manager is running for users:";
-
-    /**
-     * Name of file that disables the backup service. If this file exists, then backup is disabled
-     * for all users.
-     */
-    private static final String BACKUP_SUPPRESS_FILENAME = "backup-suppress";
-
-    /**
-     * Name of file for non-system users that enables the backup service for the user. Backup is
-     * disabled by default in non-system users.
-     */
-    private static final String BACKUP_ACTIVATED_FILENAME = "backup-activated";
-
-    /**
-     * Name of file for non-system users that remembers whether backup was explicitly activated or
-     * deactivated with a call to setBackupServiceActive.
-     */
-    private static final String REMEMBER_ACTIVATED_FILENAME = "backup-remember-activated";
-
-    // Product-level suppression of backup/restore.
-    private static final String BACKUP_DISABLE_PROPERTY = "ro.backup.disable";
-
-    private static final String BACKUP_THREAD = "backup";
-
-    static Trampoline sInstance;
-
-    static Trampoline getInstance() {
-        return checkNotNull(sInstance);
-    }
-
-    private final Context mContext;
-    private final UserManager mUserManager;
-
-    private final boolean mGlobalDisable;
-    // Lock to write backup suppress files.
-    // TODD(b/121198006): remove this object and synchronized all methods on "this".
-    private final Object mStateLock = new Object();
-
-    // TODO: This is not marked as final because of test code. Since we'll merge BMS and Trampoline,
-    // it doesn't make sense to refactor for final. It's never null.
-    @VisibleForTesting
-    protected volatile BackupManagerService mService;
-    private final Handler mHandler;
-    private final Set<ComponentName> mTransportWhitelist;
-
-    /** Keeps track of all unlocked users registered with this service. Indexed by user id. */
-    private final SparseArray<UserBackupManagerService> mUserServices;
-
-    private final BroadcastReceiver mUserRemovedReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
-                int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
-                if (userId > 0) { // for only non system users
-                    mHandler.post(() -> onRemovedNonSystemUser(userId));
-                }
-            }
-        }
-    };
-
-    public Trampoline(Context context) {
-        this(context, new SparseArray<>());
-    }
-
-    @VisibleForTesting
-    Trampoline(Context context, SparseArray<UserBackupManagerService> userServices) {
-        mContext = context;
-        mGlobalDisable = isBackupDisabled();
-        HandlerThread handlerThread =
-                new HandlerThread(BACKUP_THREAD, Process.THREAD_PRIORITY_BACKGROUND);
-        handlerThread.start();
-        mHandler = new Handler(handlerThread.getLooper());
-        mUserManager = UserManager.get(context);
-        mUserServices = userServices;
-        mService = new BackupManagerService(mContext, this, mUserServices);
-        Set<ComponentName> transportWhitelist =
-                SystemConfig.getInstance().getBackupTransportWhitelist();
-        mTransportWhitelist = (transportWhitelist == null) ? emptySet() : transportWhitelist;
-        mContext.registerReceiver(
-                mUserRemovedReceiver, new IntentFilter(Intent.ACTION_USER_REMOVED));
-    }
-
-    // TODO: Remove this when we implement DI by injecting in the construtor.
-    @VisibleForTesting
-    Handler getBackupHandler() {
-        return mHandler;
-    }
-
-    protected boolean isBackupDisabled() {
-        return SystemProperties.getBoolean(BACKUP_DISABLE_PROPERTY, false);
-    }
-
-    protected int binderGetCallingUserId() {
-        return Binder.getCallingUserHandle().getIdentifier();
-    }
-
-    protected int binderGetCallingUid() {
-        return Binder.getCallingUid();
-    }
-
-    /** Stored in the system user's directory. */
-    protected File getSuppressFileForSystemUser() {
-        return new File(UserBackupManagerFiles.getBaseStateDir(UserHandle.USER_SYSTEM),
-                BACKUP_SUPPRESS_FILENAME);
-    }
-
-    /** Stored in the system user's directory and the file is indexed by the user it refers to. */
-    protected File getRememberActivatedFileForNonSystemUser(int userId) {
-        return UserBackupManagerFiles.getStateFileInSystemDir(REMEMBER_ACTIVATED_FILENAME, userId);
-    }
-
-    /** Stored in the system user's directory and the file is indexed by the user it refers to. */
-    protected File getActivatedFileForNonSystemUser(int userId) {
-        return UserBackupManagerFiles.getStateFileInSystemDir(BACKUP_ACTIVATED_FILENAME, userId);
-    }
-
-    /**
-     * Remove backup state for non system {@code userId} when the user is removed from the device.
-     * For non system users, backup state is stored in both the user's own dir and the system dir.
-     * When the user is removed, the user's own dir gets removed by the OS. This method ensures that
-     * the part of the user backup state which is in the system dir also gets removed.
-     */
-    private void onRemovedNonSystemUser(int userId) {
-        Slog.i(TAG, "Removing state for non system user " + userId);
-        File dir = UserBackupManagerFiles.getStateDirInSystemDir(userId);
-        if (!FileUtils.deleteContentsAndDir(dir)) {
-            Slog.w(TAG, "Failed to delete state dir for removed user: " + userId);
-        }
-    }
-
-    // TODO (b/124359804) move to util method in FileUtils
-    private void createFile(File file) throws IOException {
-        if (file.exists()) {
-            return;
-        }
-
-        file.getParentFile().mkdirs();
-        if (!file.createNewFile()) {
-            Slog.w(TAG, "Failed to create file " + file.getPath());
-        }
-    }
-
-    // TODO (b/124359804) move to util method in FileUtils
-    private void deleteFile(File file) {
-        if (!file.exists()) {
-            return;
-        }
-
-        if (!file.delete()) {
-            Slog.w(TAG, "Failed to delete file " + file.getPath());
-        }
-    }
-
-    /**
-     * Deactivates the backup service for user {@code userId}. If this is the system user, it
-     * creates a suppress file which disables backup for all users. If this is a non-system user, it
-     * only deactivates backup for that user by deleting its activate file.
-     */
-    @GuardedBy("mStateLock")
-    private void deactivateBackupForUserLocked(int userId) throws IOException {
-        if (userId == UserHandle.USER_SYSTEM) {
-            createFile(getSuppressFileForSystemUser());
-        } else {
-            deleteFile(getActivatedFileForNonSystemUser(userId));
-        }
-    }
-
-    /**
-     * Enables the backup service for user {@code userId}. If this is the system user, it deletes
-     * the suppress file. If this is a non-system user, it creates the user's activate file. Note,
-     * deleting the suppress file does not automatically enable backup for non-system users, they
-     * need their own activate file in order to participate in the service.
-     */
-    @GuardedBy("mStateLock")
-    private void activateBackupForUserLocked(int userId) throws IOException {
-        if (userId == UserHandle.USER_SYSTEM) {
-            deleteFile(getSuppressFileForSystemUser());
-        } else {
-            createFile(getActivatedFileForNonSystemUser(userId));
-        }
-    }
-
-    // This method should not perform any I/O (e.g. do not call isBackupActivatedForUser),
-    // it's used in multiple places where I/O waits would cause system lock-ups.
-    private boolean isUserReadyForBackup(int userId) {
-        return mUserServices.get(UserHandle.USER_SYSTEM) != null
-                && mUserServices.get(userId) != null;
-    }
-
-    /**
-     * Backup is activated for the system user if the suppress file does not exist. Backup is
-     * activated for non-system users if the suppress file does not exist AND the user's activated
-     * file exists.
-     */
-    private boolean isBackupActivatedForUser(int userId) {
-        if (getSuppressFileForSystemUser().exists()) {
-            return false;
-        }
-
-        return userId == UserHandle.USER_SYSTEM
-                || getActivatedFileForNonSystemUser(userId).exists();
-    }
-
-    protected Context getContext() {
-        return mContext;
-    }
-
-    protected UserManager getUserManager() {
-        return mUserManager;
-    }
-
-    protected void postToHandler(Runnable runnable) {
-        mHandler.post(runnable);
-    }
-
-    /**
-     * Called from {@link BackupManagerService.Lifecycle} when a user {@code userId} is unlocked.
-     * Starts the backup service for this user if backup is active for this user. Offloads work onto
-     * the handler thread {@link #mHandlerThread} to keep unlock time low since backup is not
-     * essential for device functioning.
-     */
-    void onUnlockUser(int userId) {
-        postToHandler(() -> startServiceForUser(userId));
-    }
-
-    /**
-     * Starts the backup service for user {@code userId} by creating a new instance of {@link
-     * UserBackupManagerService} and registering it with this service.
-     */
-    @VisibleForTesting
-    void startServiceForUser(int userId) {
-        // We know that the user is unlocked here because it is called from setBackupServiceActive
-        // and unlockUser which have these guarantees. So we can check if the file exists.
-        if (mGlobalDisable) {
-            Slog.i(TAG, "Backup service not supported");
-            return;
-        }
-        if (!isBackupActivatedForUser(userId)) {
-            Slog.i(TAG, "Backup not activated for user " + userId);
-            return;
-        }
-        if (mUserServices.get(userId) != null) {
-            Slog.i(TAG, "userId " + userId + " already started, so not starting again");
-            return;
-        }
-        Slog.i(TAG, "Starting service for user: " + userId);
-        UserBackupManagerService userBackupManagerService =
-                UserBackupManagerService.createAndInitializeService(
-                        userId, mContext, this, mTransportWhitelist);
-        startServiceForUser(userId, userBackupManagerService);
-    }
-
-    /**
-     * Starts the backup service for user {@code userId} by registering its instance of {@link
-     * UserBackupManagerService} with this service and setting enabled state.
-     */
-    void startServiceForUser(int userId, UserBackupManagerService userBackupManagerService) {
-        mUserServices.put(userId, userBackupManagerService);
-
-        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup enable");
-        userBackupManagerService.initializeBackupEnableState();
-        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
-    }
-
-    /** Stops the backup service for user {@code userId} when the user is stopped. */
-    @VisibleForTesting
-    protected void stopServiceForUser(int userId) {
-        UserBackupManagerService userBackupManagerService = mUserServices.removeReturnOld(userId);
-
-        if (userBackupManagerService != null) {
-            userBackupManagerService.tearDownService();
-
-            KeyValueBackupJob.cancel(userId, mContext);
-            FullBackupJob.cancel(userId, mContext);
-        }
-    }
-
-    /**
-     *  Returns a list of users currently unlocked that have a {@link UserBackupManagerService}
-     *  registered.
-     *
-     *  Warning: Do NOT modify returned object as it's used inside.
-     *
-     *  TODO: Return a copy or only expose read-only information through other means.
-     */
-    @VisibleForTesting
-    SparseArray<UserBackupManagerService> getUserServices() {
-        return mUserServices;
-    }
-
-    /**
-     * Called from {@link BackupManagerService.Lifecycle} when a user {@code userId} is stopped.
-     * Offloads work onto the handler thread {@link #mHandlerThread} to keep stopping time low.
-     */
-    void onStopUser(int userId) {
-        postToHandler(
-                () -> {
-                    if (!mGlobalDisable) {
-                        Slog.i(TAG, "Stopping service for user: " + userId);
-                        stopServiceForUser(userId);
-                    }
-                });
-    }
-
-    /** Returns {@link UserBackupManagerService} for user {@code userId}. */
-    @Nullable
-    public UserBackupManagerService getUserService(int userId) {
-        return mUserServices.get(userId);
-    }
-
-    /**
-     * The system user and managed profiles can only be acted on by callers in the system or root
-     * processes. Other users can be acted on by callers who have both android.permission.BACKUP and
-     * android.permission.INTERACT_ACROSS_USERS_FULL permissions.
-     */
-    private void enforcePermissionsOnUser(int userId) throws SecurityException {
-        boolean isRestrictedUser =
-                userId == UserHandle.USER_SYSTEM
-                        || getUserManager().getUserInfo(userId).isManagedProfile();
-
-        if (isRestrictedUser) {
-            int caller = binderGetCallingUid();
-            if (caller != Process.SYSTEM_UID && caller != Process.ROOT_UID) {
-                throw new SecurityException("No permission to configure backup activity");
-            }
-        } else {
-            mContext.enforceCallingOrSelfPermission(
-                    Manifest.permission.BACKUP, "No permission to configure backup activity");
-            mContext.enforceCallingOrSelfPermission(
-                    Manifest.permission.INTERACT_ACROSS_USERS_FULL,
-                    "No permission to configure backup activity");
-        }
-    }
-
-    /**
-     * Only privileged callers should be changing the backup state. Deactivating backup in the
-     * system user also deactivates backup in all users. We are not guaranteed that {@code userId}
-     * is unlocked at this point yet, so handle both cases.
-     */
-    public void setBackupServiceActive(int userId, boolean makeActive) {
-        enforcePermissionsOnUser(userId);
-
-        // In Q, backup is OFF by default for non-system users. In the future, we will change that
-        // to ON unless backup was explicitly deactivated with a (permissioned) call to
-        // setBackupServiceActive.
-        // Therefore, remember this for use in the future. Basically the default in the future will
-        // be: rememberFile.exists() ? rememberFile.value() : ON
-        // Note that this has to be done right after the permission checks and before any other
-        // action since we need to remember that a permissioned call was made irrespective of
-        // whether the call changes the state or not.
-        if (userId != UserHandle.USER_SYSTEM) {
-            try {
-                File rememberFile = getRememberActivatedFileForNonSystemUser(userId);
-                createFile(rememberFile);
-                RandomAccessFileUtils.writeBoolean(rememberFile, makeActive);
-            } catch (IOException e) {
-                Slog.e(TAG, "Unable to persist backup service activity", e);
-            }
-        }
-
-        if (mGlobalDisable) {
-            Slog.i(TAG, "Backup service not supported");
-            return;
-        }
-
-        synchronized (mStateLock) {
-            Slog.i(TAG, "Making backup " + (makeActive ? "" : "in") + "active");
-            if (makeActive) {
-                try {
-                    activateBackupForUserLocked(userId);
-                } catch (IOException e) {
-                    Slog.e(TAG, "Unable to persist backup service activity");
-                }
-
-                // If the user is unlocked, we can start the backup service for it. Otherwise we
-                // will start the service when the user is unlocked as part of its unlock callback.
-                if (getUserManager().isUserUnlocked(userId)) {
-                    // Clear calling identity as initialization enforces the system identity but we
-                    // can be coming from shell.
-                    long oldId = Binder.clearCallingIdentity();
-                    try {
-                        startServiceForUser(userId);
-                    } finally {
-                        Binder.restoreCallingIdentity(oldId);
-                    }
-                }
-            } else {
-                try {
-                    //TODO(b/121198006): what if this throws an exception?
-                    deactivateBackupForUserLocked(userId);
-                } catch (IOException e) {
-                    Slog.e(TAG, "Unable to persist backup service inactivity");
-                }
-                //TODO(b/121198006): loop through active users that have work profile and
-                // stop them as well.
-                onStopUser(userId);
-            }
-        }
-    }
-
-    // IBackupManager binder API
-
-    /**
-     * Querying activity state of backup service.
-     *
-     * @param userId The user in which the activity state of backup service is queried.
-     * @return true if the service is active.
-     */
-    @Override
-    public boolean isBackupServiceActive(int userId) {
-        synchronized (mStateLock) {
-            return !mGlobalDisable && isBackupActivatedForUser(userId);
-        }
-    }
-
-    @Override
-    public void dataChangedForUser(int userId, String packageName) throws RemoteException {
-        if (isUserReadyForBackup(userId)) {
-            dataChanged(userId, packageName);
-        }
-    }
-
-    @Override
-    public void dataChanged(String packageName) throws RemoteException {
-        dataChangedForUser(binderGetCallingUserId(), packageName);
-    }
-
-    /**
-     * An app's backup agent calls this method to let the service know that there's new data to
-     * backup for their app {@code packageName}. Only used for apps participating in key-value
-     * backup.
-     */
-    public void dataChanged(@UserIdInt int userId, String packageName) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "dataChanged()");
-
-        if (userBackupManagerService != null) {
-            userBackupManagerService.dataChanged(packageName);
-        }
-    }
-
-    // ---------------------------------------------
-    // TRANSPORT OPERATIONS
-    // ---------------------------------------------
-
-    @Override
-    public void initializeTransportsForUser(
-            int userId, String[] transportNames, IBackupObserver observer) throws RemoteException {
-        if (isUserReadyForBackup(userId)) {
-            initializeTransports(userId, transportNames, observer);
-        }
-    }
-
-    /** Run an initialize operation for the given transports {@code transportNames}. */
-    public void initializeTransports(
-            @UserIdInt int userId, String[] transportNames, IBackupObserver observer) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "initializeTransports()");
-
-        if (userBackupManagerService != null) {
-            userBackupManagerService.initializeTransports(transportNames, observer);
-        }
-    }
-
-    @Override
-    public void clearBackupDataForUser(int userId, String transportName, String packageName)
-            throws RemoteException {
-        if (isUserReadyForBackup(userId)) {
-            clearBackupData(userId, transportName, packageName);
-        }
-    }
-
-    /**
-     * Clear the given package {@code packageName}'s backup data from the transport {@code
-     * transportName}.
-     */
-    public void clearBackupData(@UserIdInt int userId, String transportName, String packageName) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "clearBackupData()");
-
-        if (userBackupManagerService != null) {
-            userBackupManagerService.clearBackupData(transportName, packageName);
-        }
-    }
-
-    @Override
-    public void clearBackupData(String transportName, String packageName)
-            throws RemoteException {
-        clearBackupDataForUser(binderGetCallingUserId(), transportName, packageName);
-    }
-
-    @Override
-    public void agentConnectedForUser(int userId, String packageName, IBinder agent)
-            throws RemoteException {
-        if (isUserReadyForBackup(userId)) {
-            agentConnected(userId, packageName, agent);
-        }
-    }
-
-    @Override
-    public void agentConnected(String packageName, IBinder agent) throws RemoteException {
-        agentConnectedForUser(binderGetCallingUserId(), packageName, agent);
-    }
-
-    /**
-     * Callback: a requested backup agent has been instantiated. This should only be called from the
-     * {@link ActivityManager}.
-     */
-    public void agentConnected(@UserIdInt int userId, String packageName, IBinder agentBinder) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "agentConnected()");
-
-        if (userBackupManagerService != null) {
-            userBackupManagerService.agentConnected(packageName, agentBinder);
-        }
-    }
-
-    @Override
-    public void agentDisconnectedForUser(int userId, String packageName) throws RemoteException {
-        if (isUserReadyForBackup(userId)) {
-            agentDisconnected(userId, packageName);
-        }
-    }
-
-    @Override
-    public void agentDisconnected(String packageName) throws RemoteException {
-        agentDisconnectedForUser(binderGetCallingUserId(), packageName);
-    }
-
-    /**
-     * Callback: a backup agent has failed to come up, or has unexpectedly quit. This should only be
-     * called from the {@link ActivityManager}.
-     */
-    public void agentDisconnected(@UserIdInt int userId, String packageName) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "agentDisconnected()");
-
-        if (userBackupManagerService != null) {
-            userBackupManagerService.agentDisconnected(packageName);
-        }
-    }
-
-    @Override
-    public void restoreAtInstallForUser(int userId, String packageName, int token)
-            throws RemoteException {
-        if (isUserReadyForBackup(userId)) {
-            restoreAtInstall(userId, packageName, token);
-        }
-    }
-
-    @Override
-    public void restoreAtInstall(String packageName, int token) throws RemoteException {
-        restoreAtInstallForUser(binderGetCallingUserId(), packageName, token);
-    }
-
-    /**
-     * Used to run a restore pass for an application that is being installed. This should only be
-     * called from the {@link PackageManager}.
-     */
-    public void restoreAtInstall(@UserIdInt int userId, String packageName, int token) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "restoreAtInstall()");
-
-        if (userBackupManagerService != null) {
-            userBackupManagerService.restoreAtInstall(packageName, token);
-        }
-    }
-
-    @Override
-    public void setBackupEnabledForUser(@UserIdInt int userId, boolean isEnabled)
-            throws RemoteException {
-        if (isUserReadyForBackup(userId)) {
-            setBackupEnabled(userId, isEnabled);
-        }
-    }
-
-    @Override
-    public void setBackupEnabled(boolean isEnabled) throws RemoteException {
-        setBackupEnabledForUser(binderGetCallingUserId(), isEnabled);
-    }
-
-    /** Enable/disable the backup service. This is user-configurable via backup settings. */
-    public void setBackupEnabled(@UserIdInt int userId, boolean enable) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "setBackupEnabled()");
-
-        if (userBackupManagerService != null) {
-            userBackupManagerService.setBackupEnabled(enable);
-        }
-    }
-
-    @Override
-    public void setAutoRestoreForUser(int userId, boolean doAutoRestore) throws RemoteException {
-        if (isUserReadyForBackup(userId)) {
-            setAutoRestore(userId, doAutoRestore);
-        }
-    }
-
-    @Override
-    public void setAutoRestore(boolean doAutoRestore) throws RemoteException {
-        setAutoRestoreForUser(binderGetCallingUserId(), doAutoRestore);
-    }
-
-    /** Enable/disable automatic restore of app data at install time. */
-    public void setAutoRestore(@UserIdInt int userId, boolean autoRestore) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "setAutoRestore()");
-
-        if (userBackupManagerService != null) {
-            userBackupManagerService.setAutoRestore(autoRestore);
-        }
-    }
-
-    @Override
-    public boolean isBackupEnabledForUser(@UserIdInt int userId) throws RemoteException {
-        return isUserReadyForBackup(userId) && isBackupEnabled(userId);
-    }
-
-    @Override
-    public boolean isBackupEnabled() throws RemoteException {
-        return isBackupEnabledForUser(binderGetCallingUserId());
-    }
-
-    /**
-     * Return {@code true} if the backup mechanism is currently enabled, else returns {@code false}.
-     */
-    public boolean isBackupEnabled(@UserIdInt int userId) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "isBackupEnabled()");
-
-        return userBackupManagerService != null && userBackupManagerService.isBackupEnabled();
-    }
-
-    /** Sets the backup password used when running adb backup. */
-    @Override
-    public boolean setBackupPassword(String currentPassword, String newPassword) {
-        int userId = binderGetCallingUserId();
-        if (!isUserReadyForBackup(userId)) {
-            return false;
-        }
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(
-                        UserHandle.USER_SYSTEM, "setBackupPassword()");
-
-        return userBackupManagerService != null
-                && userBackupManagerService.setBackupPassword(currentPassword, newPassword);
-    }
-
-    /** Returns {@code true} if adb backup was run with a password, else returns {@code false}. */
-    @Override
-    public boolean hasBackupPassword() throws RemoteException {
-        int userId = binderGetCallingUserId();
-        if (!isUserReadyForBackup(userId)) {
-            return false;
-        }
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(
-                        UserHandle.USER_SYSTEM, "hasBackupPassword()");
-
-        return userBackupManagerService != null && userBackupManagerService.hasBackupPassword();
-    }
-
-    @Override
-    public void backupNowForUser(@UserIdInt int userId) throws RemoteException {
-        if (isUserReadyForBackup(userId)) {
-            backupNow(userId);
-        }
-    }
-
-    @Override
-    public void backupNow() throws RemoteException {
-        backupNowForUser(binderGetCallingUserId());
-    }
-
-    /**
-     * Run a backup pass immediately for any key-value backup applications that have declared that
-     * they have pending updates.
-     */
-    public void backupNow(@UserIdInt int userId) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "backupNow()");
-
-        if (userBackupManagerService != null) {
-            userBackupManagerService.backupNow();
-        }
-    }
-
-    /**
-     * Used by 'adb backup' to run a backup pass for packages {@code packageNames} supplied via the
-     * command line, writing the resulting data stream to the supplied {@code fd}. This method is
-     * synchronous and does not return to the caller until the backup has been completed. It
-     * requires on-screen confirmation by the user.
-     */
-    @Override
-    public void adbBackup(
-            @UserIdInt int userId,
-            ParcelFileDescriptor fd,
-            boolean includeApks,
-            boolean includeObbs,
-            boolean includeShared,
-            boolean doWidgets,
-            boolean doAllApps,
-            boolean includeSystem,
-            boolean doCompress,
-            boolean doKeyValue,
-            String[] packageNames) {
-        if (!isUserReadyForBackup(userId)) {
-            return;
-        }
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "adbBackup()");
-
-        if (userBackupManagerService != null) {
-            userBackupManagerService.adbBackup(
-                    fd,
-                    includeApks,
-                    includeObbs,
-                    includeShared,
-                    doWidgets,
-                    doAllApps,
-                    includeSystem,
-                    doCompress,
-                    doKeyValue,
-                    packageNames);
-        }
-    }
-
-    @Override
-    public void fullTransportBackupForUser(int userId, String[] packageNames)
-            throws RemoteException {
-        if (isUserReadyForBackup(userId)) {
-            fullTransportBackup(userId, packageNames);
-        }
-    }
-
-    /**
-     * Run a full backup pass for the given packages {@code packageNames}. Used by 'adb shell bmgr'.
-     */
-    public void fullTransportBackup(@UserIdInt int userId, String[] packageNames) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "fullTransportBackup()");
-
-        if (userBackupManagerService != null) {
-            userBackupManagerService.fullTransportBackup(packageNames);
-        }
-    }
-
-    /**
-     * Used by 'adb restore' to run a restore pass reading from the supplied {@code fd}. This method
-     * is synchronous and does not return to the caller until the restore has been completed. It
-     * requires on-screen confirmation by the user.
-     */
-    @Override
-    public void adbRestore(@UserIdInt int userId, ParcelFileDescriptor fd) {
-        if (!isUserReadyForBackup(userId)) {
-            return;
-        }
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "adbRestore()");
-
-        if (userBackupManagerService != null) {
-            userBackupManagerService.adbRestore(fd);
-        }
-    }
-
-    @Override
-    public void acknowledgeFullBackupOrRestoreForUser(
-            int userId,
-            int token,
-            boolean allow,
-            String curPassword,
-            String encryptionPassword,
-            IFullBackupRestoreObserver observer)
-            throws RemoteException {
-        if (isUserReadyForBackup(userId)) {
-            acknowledgeAdbBackupOrRestore(userId, token, allow,
-                    curPassword, encryptionPassword, observer);
-        }
-    }
-
-    /**
-     * Confirm that the previously requested adb backup/restore operation can proceed. This is used
-     * to require a user-facing disclosure about the operation.
-     */
-    public void acknowledgeAdbBackupOrRestore(
-            @UserIdInt int userId,
-            int token,
-            boolean allow,
-            String currentPassword,
-            String encryptionPassword,
-            IFullBackupRestoreObserver observer) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "acknowledgeAdbBackupOrRestore()");
-
-        if (userBackupManagerService != null) {
-            userBackupManagerService.acknowledgeAdbBackupOrRestore(
-                    token, allow, currentPassword, encryptionPassword, observer);
-        }
-    }
-
-    @Override
-    public void acknowledgeFullBackupOrRestore(int token, boolean allow, String curPassword,
-            String encryptionPassword, IFullBackupRestoreObserver observer)
-            throws RemoteException {
-        acknowledgeFullBackupOrRestoreForUser(
-                binderGetCallingUserId(), token, allow, curPassword, encryptionPassword, observer);
-    }
-
-
-    @Override
-    public String getCurrentTransportForUser(int userId) throws RemoteException {
-        return (isUserReadyForBackup(userId)) ? getCurrentTransport(userId) : null;
-    }
-
-    @Override
-    public String getCurrentTransport() throws RemoteException {
-        return getCurrentTransportForUser(binderGetCallingUserId());
-    }
-
-    /** Return the name of the currently active transport. */
-    @Nullable
-    public String getCurrentTransport(@UserIdInt int userId) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "getCurrentTransport()");
-
-        return userBackupManagerService == null
-                ? null
-                : userBackupManagerService.getCurrentTransport();
-    }
-
-    /**
-     * Returns the {@link ComponentName} of the host service of the selected transport or
-     * {@code null} if no transport selected or if the transport selected is not registered.
-     */
-    @Override
-    @Nullable
-    public ComponentName getCurrentTransportComponentForUser(int userId) {
-        return (isUserReadyForBackup(userId)) ? getCurrentTransportComponent(userId) : null;
-    }
-
-    /**
-     * Returns the {@link ComponentName} of the host service of the selected transport or {@code
-     * null} if no transport selected or if the transport selected is not registered.
-     */
-    @Nullable
-    public ComponentName getCurrentTransportComponent(@UserIdInt int userId) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "getCurrentTransportComponent()");
-
-        return userBackupManagerService == null
-                ? null
-                : userBackupManagerService.getCurrentTransportComponent();
-    }
-
-    @Override
-    public String[] listAllTransportsForUser(int userId) throws RemoteException {
-        return (isUserReadyForBackup(userId)) ? listAllTransports(userId) : null;
-    }
-
-    /** Report all known, available backup transports by name. */
-    @Nullable
-    public String[] listAllTransports(@UserIdInt int userId) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "listAllTransports()");
-
-        return userBackupManagerService == null
-                ? null
-                : userBackupManagerService.listAllTransports();
-    }
-
-    @Override
-    public String[] listAllTransports() throws RemoteException {
-        return listAllTransportsForUser(binderGetCallingUserId());
-    }
-
-    @Override
-    public ComponentName[] listAllTransportComponentsForUser(int userId) throws RemoteException {
-        return (isUserReadyForBackup(userId))
-                ? listAllTransportComponents(userId) : null;
-    }
-
-    /** Report all known, available backup transports by {@link ComponentName}. */
-    @Nullable
-    public ComponentName[] listAllTransportComponents(@UserIdInt int userId) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "listAllTransportComponents()");
-
-        return userBackupManagerService == null
-                ? null
-                : userBackupManagerService.listAllTransportComponents();
-    }
-
-    @Override
-    public String[] getTransportWhitelist() {
-        int userId = binderGetCallingUserId();
-        if (!isUserReadyForBackup(userId)) {
-            return null;
-        }
-        // No permission check, intentionally.
-        String[] whitelistedTransports = new String[mTransportWhitelist.size()];
-        int i = 0;
-        for (ComponentName component : mTransportWhitelist) {
-            whitelistedTransports[i] = component.flattenToShortString();
-            i++;
-        }
-        return whitelistedTransports;
-    }
-
-    @Override
-    public void updateTransportAttributesForUser(
-            int userId,
-            ComponentName transportComponent,
-            String name,
-            @Nullable Intent configurationIntent,
-            String currentDestinationString,
-            @Nullable Intent dataManagementIntent,
-            CharSequence dataManagementLabel) {
-        if (isUserReadyForBackup(userId)) {
-            updateTransportAttributes(
-                    userId,
-                    transportComponent,
-                    name,
-                    configurationIntent,
-                    currentDestinationString,
-                    dataManagementIntent,
-                    dataManagementLabel);
-        }
-    }
-
-    /**
-     * Update the attributes of the transport identified by {@code transportComponent}. If the
-     * specified transport has not been bound at least once (for registration), this call will be
-     * ignored. Only the host process of the transport can change its description, otherwise a
-     * {@link SecurityException} will be thrown.
-     *
-     * @param transportComponent The identity of the transport being described.
-     * @param name A {@link String} with the new name for the transport. This is NOT for
-     *     identification. MUST NOT be {@code null}.
-     * @param configurationIntent An {@link Intent} that can be passed to {@link
-     *     Context#startActivity} in order to launch the transport's configuration UI. It may be
-     *     {@code null} if the transport does not offer any user-facing configuration UI.
-     * @param currentDestinationString A {@link String} describing the destination to which the
-     *     transport is currently sending data. MUST NOT be {@code null}.
-     * @param dataManagementIntent An {@link Intent} that can be passed to {@link
-     *     Context#startActivity} in order to launch the transport's data-management UI. It may be
-     *     {@code null} if the transport does not offer any user-facing data management UI.
-     * @param dataManagementLabel A {@link CharSequence} to be used as the label for the transport's
-     *     data management affordance. This MUST be {@code null} when dataManagementIntent is {@code
-     *     null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}.
-     * @throws SecurityException If the UID of the calling process differs from the package UID of
-     *     {@code transportComponent} or if the caller does NOT have BACKUP permission.
-     */
-    public void updateTransportAttributes(
-            @UserIdInt int userId,
-            ComponentName transportComponent,
-            String name,
-            @Nullable Intent configurationIntent,
-            String currentDestinationString,
-            @Nullable Intent dataManagementIntent,
-            CharSequence dataManagementLabel) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "updateTransportAttributes()");
-
-        if (userBackupManagerService != null) {
-            userBackupManagerService.updateTransportAttributes(
-                    transportComponent,
-                    name,
-                    configurationIntent,
-                    currentDestinationString,
-                    dataManagementIntent,
-                    dataManagementLabel);
-        }
-    }
-
-    @Override
-    public String selectBackupTransportForUser(int userId, String transport)
-            throws RemoteException {
-        return (isUserReadyForBackup(userId))
-                ? selectBackupTransport(userId, transport) : null;
-    }
-
-    @Override
-    public String selectBackupTransport(String transport) throws RemoteException {
-        return selectBackupTransportForUser(binderGetCallingUserId(), transport);
-    }
-
-    /**
-     * Selects transport {@code transportName} and returns the previously selected transport.
-     *
-     * @deprecated Use {@link #selectBackupTransportAsync(ComponentName,
-     *     ISelectBackupTransportCallback)} instead.
-     */
-    @Deprecated
-    @Nullable
-    public String selectBackupTransport(@UserIdInt int userId, String transportName) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "selectBackupTransport()");
-
-        return userBackupManagerService == null
-                ? null
-                : userBackupManagerService.selectBackupTransport(transportName);
-    }
-
-    @Override
-    public void selectBackupTransportAsyncForUser(int userId, ComponentName transport,
-            ISelectBackupTransportCallback listener) throws RemoteException {
-        if (isUserReadyForBackup(userId)) {
-            selectBackupTransportAsync(userId, transport, listener);
-        } else {
-            if (listener != null) {
-                try {
-                    listener.onFailure(BackupManager.ERROR_BACKUP_NOT_ALLOWED);
-                } catch (RemoteException ex) {
-                    // ignore
-                }
-            }
-        }
-    }
-
-    /**
-     * Selects transport {@code transportComponent} asynchronously and notifies {@code listener}
-     * with the result upon completion.
-     */
-    public void selectBackupTransportAsync(
-            @UserIdInt int userId,
-            ComponentName transportComponent,
-            ISelectBackupTransportCallback listener) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "selectBackupTransportAsync()");
-
-        if (userBackupManagerService != null) {
-            userBackupManagerService.selectBackupTransportAsync(transportComponent, listener);
-        }
-    }
-
-    @Override
-    public Intent getConfigurationIntentForUser(int userId, String transport)
-            throws RemoteException {
-        return isUserReadyForBackup(userId) ? getConfigurationIntent(userId, transport)
-                : null;
-    }
-
-    @Override
-    public Intent getConfigurationIntent(String transport)
-            throws RemoteException {
-        return getConfigurationIntentForUser(binderGetCallingUserId(), transport);
-    }
-
-    /**
-     * Supply the configuration intent for the given transport. If the name is not one of the
-     * available transports, or if the transport does not supply any configuration UI, the method
-     * returns {@code null}.
-     */
-    @Nullable
-    public Intent getConfigurationIntent(@UserIdInt int userId, String transportName) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "getConfigurationIntent()");
-
-        return userBackupManagerService == null
-                ? null
-                : userBackupManagerService.getConfigurationIntent(transportName);
-    }
-
-    @Override
-    public String getDestinationStringForUser(int userId, String transport) throws RemoteException {
-        return isUserReadyForBackup(userId) ? getDestinationString(userId, transport)
-                : null;
-    }
-
-    @Override
-    public String getDestinationString(String transport) throws RemoteException {
-        return getDestinationStringForUser(binderGetCallingUserId(), transport);
-    }
-
-    /**
-     * Supply the current destination string for the given transport. If the name is not one of the
-     * registered transports the method will return null.
-     *
-     * <p>This string is used VERBATIM as the summary text of the relevant Settings item.
-     *
-     * @param transportName The name of the registered transport.
-     * @return The current destination string or null if the transport is not registered.
-     */
-    @Nullable
-    public String getDestinationString(@UserIdInt int userId, String transportName) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "getDestinationString()");
-
-        return userBackupManagerService == null
-                ? null
-                : userBackupManagerService.getDestinationString(transportName);
-    }
-
-    @Override
-    public Intent getDataManagementIntentForUser(int userId, String transport)
-            throws RemoteException {
-        return isUserReadyForBackup(userId)
-                ? getDataManagementIntent(userId, transport) : null;
-    }
-
-    @Override
-    public Intent getDataManagementIntent(String transport)
-            throws RemoteException {
-        return getDataManagementIntentForUser(binderGetCallingUserId(), transport);
-    }
-
-    /** Supply the manage-data intent for the given transport. */
-    @Nullable
-    public Intent getDataManagementIntent(@UserIdInt int userId, String transportName) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "getDataManagementIntent()");
-
-        return userBackupManagerService == null
-                ? null
-                : userBackupManagerService.getDataManagementIntent(transportName);
-    }
-
-    @Override
-    public CharSequence getDataManagementLabelForUser(int userId, String transport)
-            throws RemoteException {
-        return isUserReadyForBackup(userId) ? getDataManagementLabel(userId, transport)
-                : null;
-    }
-
-    /**
-     * Supply the menu label for affordances that fire the manage-data intent for the given
-     * transport.
-     */
-    @Nullable
-    public CharSequence getDataManagementLabel(@UserIdInt int userId, String transportName) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "getDataManagementLabel()");
-
-        return userBackupManagerService == null
-                ? null
-                : userBackupManagerService.getDataManagementLabel(transportName);
-    }
-
-    @Override
-    public IRestoreSession beginRestoreSessionForUser(
-            int userId, String packageName, String transportID) throws RemoteException {
-        return isUserReadyForBackup(userId)
-                ? beginRestoreSession(userId, packageName, transportID) : null;
-    }
-
-    /**
-     * Begin a restore for the specified package {@code packageName} using the specified transport
-     * {@code transportName}.
-     */
-    @Nullable
-    public IRestoreSession beginRestoreSession(
-            @UserIdInt int userId, String packageName, String transportName) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "beginRestoreSession()");
-
-        return userBackupManagerService == null
-                ? null
-                : userBackupManagerService.beginRestoreSession(packageName, transportName);
-    }
-
-    @Override
-    public void opCompleteForUser(int userId, int token, long result) throws RemoteException {
-        if (isUserReadyForBackup(userId)) {
-            opComplete(userId, token, result);
-        }
-    }
-
-    @Override
-    public void opComplete(int token, long result) throws RemoteException {
-        opCompleteForUser(binderGetCallingUserId(), token, result);
-    }
-
-    /**
-     * Used by a currently-active backup agent to notify the service that it has completed its given
-     * outstanding asynchronous backup/restore operation.
-     */
-    public void opComplete(@UserIdInt int userId, int token, long result) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "opComplete()");
-
-        if (userBackupManagerService != null) {
-            userBackupManagerService.opComplete(token, result);
-        }
-    }
-
-    @Override
-    public long getAvailableRestoreTokenForUser(int userId, String packageName) {
-        return isUserReadyForBackup(userId) ? getAvailableRestoreToken(userId, packageName) : 0;
-    }
-
-    /**
-     * Get the restore-set token for the best-available restore set for this {@code packageName}:
-     * the active set if possible, else the ancestral one. Returns zero if none available.
-     */
-    public long getAvailableRestoreToken(@UserIdInt int userId, String packageName) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "getAvailableRestoreToken()");
-
-        return userBackupManagerService == null
-                ? 0
-                : userBackupManagerService.getAvailableRestoreToken(packageName);
-    }
-
-    @Override
-    public boolean isAppEligibleForBackupForUser(int userId, String packageName) {
-        return isUserReadyForBackup(userId) && isAppEligibleForBackup(userId,
-                packageName);
-    }
-
-    /** Checks if the given package {@code packageName} is eligible for backup. */
-    public boolean isAppEligibleForBackup(@UserIdInt int userId, String packageName) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "isAppEligibleForBackup()");
-
-        return userBackupManagerService != null
-                && userBackupManagerService.isAppEligibleForBackup(packageName);
-    }
-
-    @Override
-    public String[] filterAppsEligibleForBackupForUser(int userId, String[] packages) {
-        return isUserReadyForBackup(userId) ? filterAppsEligibleForBackup(userId, packages) : null;
-    }
-
-    /**
-     * Returns from the inputted packages {@code packages}, the ones that are eligible for backup.
-     */
-    @Nullable
-    public String[] filterAppsEligibleForBackup(@UserIdInt int userId, String[] packages) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "filterAppsEligibleForBackup()");
-
-        return userBackupManagerService == null
-                ? null
-                : userBackupManagerService.filterAppsEligibleForBackup(packages);
-    }
-
-    @Override
-    public int requestBackupForUser(@UserIdInt int userId, String[] packages, IBackupObserver
-            observer, IBackupManagerMonitor monitor, int flags) throws RemoteException {
-        if (!isUserReadyForBackup(userId)) {
-            return BackupManager.ERROR_BACKUP_NOT_ALLOWED;
-        }
-        return requestBackup(userId, packages, observer, monitor, flags);
-    }
-
-    @Override
-    public int requestBackup(String[] packages, IBackupObserver observer,
-            IBackupManagerMonitor monitor, int flags) throws RemoteException {
-        return requestBackupForUser(binderGetCallingUserId(), packages,
-                observer, monitor, flags);
-    }
-
-    /**
-     * Requests a backup for the inputted {@code packages} with a specified callback {@link
-     * IBackupManagerMonitor} for receiving events during the operation.
-     */
-    public int requestBackup(
-            @UserIdInt int userId,
-            String[] packages,
-            IBackupObserver observer,
-            IBackupManagerMonitor monitor,
-            int flags) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "requestBackup()");
-
-        return userBackupManagerService == null
-                ? BackupManager.ERROR_BACKUP_NOT_ALLOWED
-                : userBackupManagerService.requestBackup(packages, observer, monitor, flags);
-    }
-
-    @Override
-    public void cancelBackupsForUser(@UserIdInt int userId) throws RemoteException {
-        if (isUserReadyForBackup(userId)) {
-            cancelBackups(userId);
-        }
-    }
-
-    @Override
-    public void cancelBackups() throws RemoteException {
-        cancelBackupsForUser(binderGetCallingUserId());
-    }
-
-    /** Cancel all running backup operations. */
-    public void cancelBackups(@UserIdInt int userId) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "cancelBackups()");
-
-        if (userBackupManagerService != null) {
-            userBackupManagerService.cancelBackups();
-        }
-    }
-
-    /**
-     * Returns a {@link UserHandle} for the user that has {@code ancestralSerialNumber} as the
-     * serial number of its ancestral work profile or null if there is no {@link
-     * UserBackupManagerService} associated with that user.
-     *
-     * <p> The ancestral work profile is set by {@link #setAncestralSerialNumber(long)}
-     * and it corresponds to the profile that was used to restore to the callers profile.
-     */
-    @Override
-    @Nullable
-    public UserHandle getUserForAncestralSerialNumber(long ancestralSerialNumber) {
-        if (mGlobalDisable) {
-            return null;
-        }
-        int callingUserId = Binder.getCallingUserHandle().getIdentifier();
-        long oldId = Binder.clearCallingIdentity();
-        final int[] userIds;
-        try {
-            userIds =
-                    mContext
-                            .getSystemService(UserManager.class)
-                            .getProfileIds(callingUserId, false);
-        } finally {
-            Binder.restoreCallingIdentity(oldId);
-        }
-
-        for (int userId : userIds) {
-            UserBackupManagerService userBackupManagerService = mUserServices.get(userId);
-            if (userBackupManagerService != null) {
-                if (userBackupManagerService.getAncestralSerialNumber() == ancestralSerialNumber) {
-                    return UserHandle.of(userId);
-                }
-            }
-        }
-
-        return null;
-    }
-
-    /**
-     * Sets the ancestral work profile for the calling user.
-     *
-     * <p> The ancestral work profile corresponds to the profile that was used to restore to the
-     * callers profile.
-     */
-    @Override
-    public void setAncestralSerialNumber(long ancestralSerialNumber) {
-        if (mGlobalDisable) {
-            return;
-        }
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(
-                        Binder.getCallingUserHandle().getIdentifier(),
-                        "setAncestralSerialNumber()");
-
-        if (userBackupManagerService != null) {
-            userBackupManagerService.setAncestralSerialNumber(ancestralSerialNumber);
-        }
-    }
-
-    @Override
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) {
-            return;
-        }
-        int userId = binderGetCallingUserId();
-        if (!isUserReadyForBackup(userId)) {
-            pw.println("Inactive");
-            return;
-        }
-
-        if (args != null) {
-            for (String arg : args) {
-                if ("users".equals(arg.toLowerCase())) {
-                    pw.print(DUMP_RUNNING_USERS_MESSAGE);
-                    for (int i = 0; i < mUserServices.size(); i++) {
-                        pw.print(" " + mUserServices.keyAt(i));
-                    }
-                    pw.println();
-                    return;
-                }
-            }
-        }
-
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(UserHandle.USER_SYSTEM, "dump()");
-
-        if (userBackupManagerService != null) {
-            userBackupManagerService.dump(fd, pw, args);
-        }
-    }
-
-    /**
-     * Used by the {@link JobScheduler} to run a full backup when conditions are right. The model we
-     * use is to perform one app backup per scheduled job execution, and to reschedule the job with
-     * zero latency as long as conditions remain right and we still have work to do.
-     *
-     * @return Whether ongoing work will continue. The return value here will be passed along as the
-     *     return value to the callback {@link JobService#onStartJob(JobParameters)}.
-     */
-    public boolean beginFullBackup(@UserIdInt int userId, FullBackupJob scheduledJob) {
-        if (!isUserReadyForBackup(userId)) {
-            return false;
-        }
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "beginFullBackup()");
-
-        return userBackupManagerService != null
-                && userBackupManagerService.beginFullBackup(scheduledJob);
-    }
-
-    /**
-     * Used by the {@link JobScheduler} to end the current full backup task when conditions are no
-     * longer met for running the full backup job.
-     */
-    public void endFullBackup(@UserIdInt int userId) {
-        if (!isUserReadyForBackup(userId)) {
-            return;
-        }
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "endFullBackup()");
-
-        if (userBackupManagerService != null) {
-            userBackupManagerService.endFullBackup();
-        }
-    }
-
-    /**
-     * Returns the {@link UserBackupManagerService} instance for the specified user {@code userId}.
-     * If the user is not registered with the service (either the user is locked or not eligible for
-     * the backup service) then return {@code null}.
-     *
-     * @param userId The id of the user to retrieve its instance of {@link
-     *     UserBackupManagerService}.
-     * @param caller A {@link String} identifying the caller for logging purposes.
-     * @throws SecurityException if {@code userId} is different from the calling user id and the
-     *     caller does NOT have the android.permission.INTERACT_ACROSS_USERS_FULL permission.
-     */
-    @Nullable
-    @VisibleForTesting
-    UserBackupManagerService getServiceForUserIfCallerHasPermission(
-            @UserIdInt int userId, String caller) {
-        enforceCallingPermissionOnUserId(userId, caller);
-        UserBackupManagerService userBackupManagerService = mUserServices.get(userId);
-        if (userBackupManagerService == null) {
-            Slog.w(TAG, "Called " + caller + " for unknown user: " + userId);
-        }
-        return userBackupManagerService;
-    }
-
-    /**
-     * If {@code userId} is different from the calling user id, then the caller must hold the
-     * android.permission.INTERACT_ACROSS_USERS_FULL permission.
-     *
-     * @param userId User id on which the backup operation is being requested.
-     * @param message A message to include in the exception if it is thrown.
-     */
-    void enforceCallingPermissionOnUserId(@UserIdInt int userId, String message) {
-        if (Binder.getCallingUserHandle().getIdentifier() != userId) {
-            mContext.enforceCallingOrSelfPermission(
-                    Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
-        }
-    }
-}
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 0e81e07..77888db 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -421,13 +421,13 @@
      * Creates an instance of {@link UserBackupManagerService} and initializes state for it. This
      * includes setting up the directories where we keep our bookkeeping and transport management.
      *
-     * @see #createAndInitializeService(int, Context, Trampoline, HandlerThread, File, File,
-     *     TransportManager)
+     * @see #createAndInitializeService(int, Context, BackupManagerService, HandlerThread, File,
+     * File, TransportManager)
      */
     static UserBackupManagerService createAndInitializeService(
             @UserIdInt int userId,
             Context context,
-            Trampoline trampoline,
+            BackupManagerService backupManagerService,
             Set<ComponentName> transportWhitelist) {
         String currentTransport =
                 Settings.Secure.getStringForUser(
@@ -455,7 +455,7 @@
         return createAndInitializeService(
                 userId,
                 context,
-                trampoline,
+                backupManagerService,
                 userBackupThread,
                 baseStateDir,
                 dataDir,
@@ -467,7 +467,7 @@
      *
      * @param userId The user which this service is for.
      * @param context The system server context.
-     * @param trampoline A reference to the proxy to {@link BackupManagerService}.
+     * @param backupManagerService A reference to the proxy to {@link BackupManagerService}.
      * @param userBackupThread The thread running backup/restore operations for the user.
      * @param baseStateDir The directory we store the user's persistent bookkeeping data.
      * @param dataDir The directory we store the user's temporary staging data.
@@ -478,7 +478,7 @@
     public static UserBackupManagerService createAndInitializeService(
             @UserIdInt int userId,
             Context context,
-            Trampoline trampoline,
+            BackupManagerService backupManagerService,
             HandlerThread userBackupThread,
             File baseStateDir,
             File dataDir,
@@ -486,7 +486,7 @@
         return new UserBackupManagerService(
                 userId,
                 context,
-                trampoline,
+                backupManagerService,
                 userBackupThread,
                 baseStateDir,
                 dataDir,
@@ -509,7 +509,7 @@
     private UserBackupManagerService(
             @UserIdInt int userId,
             Context context,
-            Trampoline parent,
+            BackupManagerService parent,
             HandlerThread userBackupThread,
             File baseStateDir,
             File dataDir,
@@ -525,8 +525,8 @@
         mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         mStorageManager = IStorageManager.Stub.asInterface(ServiceManager.getService("mount"));
 
-        checkNotNull(parent, "trampoline cannot be null");
-        mBackupManagerBinder = Trampoline.asInterface(parent.asBinder());
+        checkNotNull(parent, "parent cannot be null");
+        mBackupManagerBinder = BackupManagerService.asInterface(parent.asBinder());
 
         mAgentTimeoutParameters = new
                 BackupAgentTimeoutParameters(Handler.getMain(), mContext.getContentResolver());
diff --git a/services/core/java/com/android/server/AnimationThread.java b/services/core/java/com/android/server/AnimationThread.java
index c86042b..c607b1e 100644
--- a/services/core/java/com/android/server/AnimationThread.java
+++ b/services/core/java/com/android/server/AnimationThread.java
@@ -21,6 +21,8 @@
 import android.os.Handler;
 import android.os.Trace;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 /**
  * Thread for handling all legacy window animations, or anything that's directly impacting
  * animations like starting windows or traversals.
@@ -55,4 +57,20 @@
             return sHandler;
         }
     }
+
+    /**
+     * Disposes current animation thread if it's initialized. Should only be used in tests to set up
+     * a new environment.
+     */
+    @VisibleForTesting
+    public static void dispose() {
+        synchronized (DisplayThread.class) {
+            if (sInstance == null) {
+                return;
+            }
+
+            getHandler().runWithScissors(() -> sInstance.quit(), 0 /* timeout */);
+            sInstance = null;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/DisplayThread.java b/services/core/java/com/android/server/DisplayThread.java
index 85c799c..a07ade0 100644
--- a/services/core/java/com/android/server/DisplayThread.java
+++ b/services/core/java/com/android/server/DisplayThread.java
@@ -20,6 +20,8 @@
 import android.os.Process;
 import android.os.Trace;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 /**
  * Shared singleton foreground thread for the system.  This is a thread for
  * operations that affect what's on the display, which needs to have a minimum
@@ -58,4 +60,20 @@
             return sHandler;
         }
     }
+
+    /**
+     * Disposes current display thread if it's initialized. Should only be used in tests to set up a
+     * new environment.
+     */
+    @VisibleForTesting
+    public static void dispose() {
+        synchronized (DisplayThread.class) {
+            if (sInstance == null) {
+                return;
+            }
+
+            getHandler().runWithScissors(() -> sInstance.quit(), 0 /* timeout */);
+            sInstance = null;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 19c818f..d759be2 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1480,8 +1480,9 @@
     public ActivityTaskManagerService mActivityTaskManager;
     @VisibleForTesting
     public ActivityTaskManagerInternal mAtmInternal;
+    UriGrantsManagerInternal mUgmInternal;
     @VisibleForTesting
-    public UriGrantsManagerInternal mUgmInternal;
+    public final ActivityManagerInternal mInternal;
     final ActivityThread mSystemThread;
 
     private final class AppDeathRecipient implements IBinder.DeathRecipient {
@@ -2413,6 +2414,8 @@
         mProcStartHandler = null;
         mHiddenApiBlacklist = null;
         mFactoryTest = FACTORY_TEST_OFF;
+        mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
+        mInternal = new LocalService();
     }
 
     // Note: This method is invoked on the main thread but may need to attach various
@@ -2566,6 +2569,7 @@
             Slog.w(TAG, "Setting background thread cpuset failed");
         }
 
+        mInternal = new LocalService();
     }
 
     public void setSystemServiceManager(SystemServiceManager mgr) {
@@ -2583,7 +2587,7 @@
         mBatteryStatsService.publish();
         mAppOpsService.publish(mContext);
         Slog.d("AppOps", "AppOpsService published");
-        LocalServices.addService(ActivityManagerInternal.class, new LocalService());
+        LocalServices.addService(ActivityManagerInternal.class, mInternal);
         mActivityTaskManager.onActivityManagerInternalAdded();
         mUgmInternal.onActivityManagerInternalAdded();
         mPendingIntentController.onActivityManagerInternalAdded();
diff --git a/services/core/java/com/android/server/biometrics/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
index 4a9ccde..766e5c4 100644
--- a/services/core/java/com/android/server/biometrics/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
@@ -209,8 +209,7 @@
                     // will show briefly and be replaced by "device locked out" message.
                     if (listener != null) {
                         if (isBiometricPrompt()) {
-                            listener.onAuthenticationFailedInternal(getCookie(),
-                                    getRequireConfirmation());
+                            listener.onAuthenticationFailedInternal();
                         } else {
                             listener.onAuthenticationFailed(getHalDeviceId());
                         }
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index af2f24f..24e6a75 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -25,11 +25,9 @@
 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE;
 
 import android.app.ActivityManager;
-import android.app.ActivityTaskManager;
 import android.app.AppOpsManager;
-import android.app.IActivityTaskManager;
+import android.app.IActivityManager;
 import android.app.KeyguardManager;
-import android.app.TaskStackListener;
 import android.app.UserSwitchObserver;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -69,6 +67,7 @@
 import android.util.StatsLog;
 
 import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.server.SystemService;
@@ -88,9 +87,8 @@
     private static final String TAG = "BiometricService";
     private static final boolean DEBUG = true;
 
-    private static final int MSG_ON_TASK_STACK_CHANGED = 1;
     private static final int MSG_ON_AUTHENTICATION_SUCCEEDED = 2;
-    private static final int MSG_ON_AUTHENTICATION_FAILED = 3;
+    private static final int MSG_ON_AUTHENTICATION_REJECTED = 3;
     private static final int MSG_ON_ERROR = 4;
     private static final int MSG_ON_ACQUIRED = 5;
     private static final int MSG_ON_DISMISSED = 6;
@@ -101,6 +99,7 @@
     private static final int MSG_ON_CONFIRM_DEVICE_CREDENTIAL_SUCCESS = 11;
     private static final int MSG_ON_CONFIRM_DEVICE_CREDENTIAL_ERROR = 12;
     private static final int MSG_REGISTER_CANCELLATION_CALLBACK = 13;
+    private static final int MSG_ON_AUTHENTICATION_TIMED_OUT = 14;
 
     private static final int[] FEATURE_ID = {
         TYPE_FINGERPRINT,
@@ -112,33 +111,41 @@
      * Authentication either just called and we have not transitioned to the CALLED state, or
      * authentication terminated (success or error).
      */
-    private static final int STATE_AUTH_IDLE = 0;
+    static final int STATE_AUTH_IDLE = 0;
     /**
      * Authentication was called and we are waiting for the <Biometric>Services to return their
      * cookies before starting the hardware and showing the BiometricPrompt.
      */
-    private static final int STATE_AUTH_CALLED = 1;
+    static final int STATE_AUTH_CALLED = 1;
     /**
      * Authentication started, BiometricPrompt is showing and the hardware is authenticating.
      */
-    private static final int STATE_AUTH_STARTED = 2;
+    static final int STATE_AUTH_STARTED = 2;
     /**
      * Authentication is paused, waiting for the user to press "try again" button. Only
      * passive modalities such as Face or Iris should have this state. Note that for passive
      * modalities, the HAL enters the idle state after onAuthenticated(false) which differs from
      * fingerprint.
      */
-    private static final int STATE_AUTH_PAUSED = 3;
+    static final int STATE_AUTH_PAUSED = 3;
     /**
      * Authentication is successful, but we're waiting for the user to press "confirm" button.
      */
-    private static final int STATE_AUTH_PENDING_CONFIRM = 5;
+    static final int STATE_AUTH_PENDING_CONFIRM = 5;
     /**
      * Biometric authentication was canceled, but the device is now showing ConfirmDeviceCredential
      */
-    private static final int STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC = 6;
+    static final int STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC = 6;
+    /**
+     * Biometric authenticated, waiting for SysUI to finish animation
+     */
+    static final int STATE_AUTHENTICATED_PENDING_SYSUI = 7;
+    /**
+     * Biometric error, waiting for SysUI to finish animation
+     */
+    static final int STATE_ERROR_PENDING_SYSUI = 8;
 
-    private final class AuthSession implements IBinder.DeathRecipient {
+    final class AuthSession implements IBinder.DeathRecipient {
         // Map of Authenticator/Cookie pairs. We expect to receive the cookies back from
         // <Biometric>Services before we can start authenticating. Pairs that have been returned
         // are moved to mModalitiesMatched.
@@ -165,10 +172,13 @@
         final boolean mRequireConfirmation;
 
         // The current state, which can be either idle, called, or started
-        private int mState = STATE_AUTH_IDLE;
+        int mState = STATE_AUTH_IDLE;
         // For explicit confirmation, do not send to keystore until the user has confirmed
         // the authentication.
         byte[] mTokenEscrow;
+        // Waiting for SystemUI to complete animation
+        int mErrorEscrow;
+        String mErrorStringEscrow;
 
         // Timestamp when authentication started
         private long mStartTimeMs;
@@ -244,42 +254,37 @@
         }
     }
 
-    private final class BiometricTaskStackListener extends TaskStackListener {
-        @Override
-        public void onTaskStackChanged() {
-            mHandler.sendEmptyMessage(MSG_ON_TASK_STACK_CHANGED);
-        }
-    }
-
+    private final Injector mInjector;
+    @VisibleForTesting
+    final IBiometricService.Stub mImpl;
     private final AppOpsManager mAppOps;
     private final boolean mHasFeatureFingerprint;
     private final boolean mHasFeatureIris;
     private final boolean mHasFeatureFace;
-    private final SettingObserver mSettingObserver;
+    @VisibleForTesting
+    SettingObserver mSettingObserver;
     private final List<EnabledOnKeyguardCallback> mEnabledOnKeyguardCallbacks;
-    private final BiometricTaskStackListener mTaskStackListener = new BiometricTaskStackListener();
     private final Random mRandom = new Random();
 
-    private IFingerprintService mFingerprintService;
-    private IFaceService mFaceService;
-    private IActivityTaskManager mActivityTaskManager;
-    private IStatusBarService mStatusBarService;
+    @VisibleForTesting
+    IFingerprintService mFingerprintService;
+    @VisibleForTesting
+    IFaceService mFaceService;
+    @VisibleForTesting
+    IStatusBarService mStatusBarService;
+    @VisibleForTesting
+    KeyStore mKeyStore;
 
     // Get and cache the available authenticator (manager) classes. Used since aidl doesn't support
     // polymorphism :/
     final ArrayList<Authenticator> mAuthenticators = new ArrayList<>();
 
-    // Cache the current service that's being used. This is the service which
-    // cancelAuthentication() must be forwarded to. This is just a cache, and the actual
-    // check (is caller the current client) is done in the <Biometric>Service.
-    // Since Settings/System (not application) is responsible for changing preference, this
-    // should be safe.
-    private int mCurrentModality;
-
     // The current authentication session, null if idle/done. We need to track both the current
     // and pending sessions since errors may be sent to either.
-    private AuthSession mCurrentAuthSession;
-    private AuthSession mPendingAuthSession;
+    @VisibleForTesting
+    AuthSession mCurrentAuthSession;
+    @VisibleForTesting
+    AuthSession mPendingAuthSession;
 
     // TODO(b/123378871): Remove when moved.
     // When BiometricPrompt#setAllowDeviceCredentials is set to true, we need to store the
@@ -289,15 +294,11 @@
     // to this receiver.
     private IBiometricServiceReceiver mConfirmDeviceCredentialReceiver;
 
-    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+    @VisibleForTesting
+    final Handler mHandler = new Handler(Looper.getMainLooper()) {
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
-                case MSG_ON_TASK_STACK_CHANGED: {
-                    handleTaskStackChanged();
-                    break;
-                }
-
                 case MSG_ON_AUTHENTICATION_SUCCEEDED: {
                     SomeArgs args = (SomeArgs) msg.obj;
                     handleAuthenticationSucceeded(
@@ -307,8 +308,8 @@
                     break;
                 }
 
-                case MSG_ON_AUTHENTICATION_FAILED: {
-                    handleAuthenticationFailed((String) msg.obj /* failureReason */);
+                case MSG_ON_AUTHENTICATION_REJECTED: {
+                    handleAuthenticationRejected((String) msg.obj /* failureReason */);
                     break;
                 }
 
@@ -397,6 +398,11 @@
                     break;
                 }
 
+                case MSG_ON_AUTHENTICATION_TIMED_OUT: {
+                    handleAuthenticationTimedOut((String) msg.obj /* errorMessage */);
+                    break;
+                }
+
                 default:
                     Slog.e(TAG, "Unknown message: " + msg);
                     break;
@@ -422,7 +428,8 @@
         }
     }
 
-    private final class SettingObserver extends ContentObserver {
+    @VisibleForTesting
+    public static class SettingObserver extends ContentObserver {
 
         private static final boolean DEFAULT_KEYGUARD_ENABLED = true;
         private static final boolean DEFAULT_APP_ENABLED = true;
@@ -436,6 +443,7 @@
                 Settings.Secure.getUriFor(Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION);
 
         private final ContentResolver mContentResolver;
+        private final List<BiometricService.EnabledOnKeyguardCallback> mCallbacks;
 
         private Map<Integer, Boolean> mFaceEnabledOnKeyguard = new HashMap<>();
         private Map<Integer, Boolean> mFaceEnabledForApps = new HashMap<>();
@@ -446,13 +454,15 @@
          *
          * @param handler The handler to run {@link #onChange} on, or null if none.
          */
-        SettingObserver(Handler handler) {
+        public SettingObserver(Context context, Handler handler,
+                List<BiometricService.EnabledOnKeyguardCallback> callbacks) {
             super(handler);
-            mContentResolver = getContext().getContentResolver();
+            mContentResolver = context.getContentResolver();
+            mCallbacks = callbacks;
             updateContentObserver();
         }
 
-        void updateContentObserver() {
+        public void updateContentObserver() {
             mContentResolver.unregisterContentObserver(this);
             mContentResolver.registerContentObserver(FACE_UNLOCK_KEYGUARD_ENABLED,
                     false /* notifyForDescendents */,
@@ -495,7 +505,7 @@
             }
         }
 
-        boolean getFaceEnabledOnKeyguard() {
+        public boolean getFaceEnabledOnKeyguard() {
             final int user = ActivityManager.getCurrentUser();
             if (!mFaceEnabledOnKeyguard.containsKey(user)) {
                 onChange(true /* selfChange */, FACE_UNLOCK_KEYGUARD_ENABLED, user);
@@ -503,22 +513,23 @@
             return mFaceEnabledOnKeyguard.get(user);
         }
 
-        boolean getFaceEnabledForApps(int userId) {
+        public boolean getFaceEnabledForApps(int userId) {
+            Slog.e(TAG, "getFaceEnabledForApps: " + userId, new Exception());
             if (!mFaceEnabledForApps.containsKey(userId)) {
                 onChange(true /* selfChange */, FACE_UNLOCK_APP_ENABLED, userId);
             }
             return mFaceEnabledForApps.getOrDefault(userId, DEFAULT_APP_ENABLED);
         }
 
-        boolean getFaceAlwaysRequireConfirmation(int userId) {
+        public boolean getFaceAlwaysRequireConfirmation(int userId) {
             if (!mFaceAlwaysRequireConfirmation.containsKey(userId)) {
                 onChange(true /* selfChange */, FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION, userId);
             }
             return mFaceAlwaysRequireConfirmation.get(userId);
         }
 
-        void notifyEnabledOnKeyguardCallbacks(int userId) {
-            List<EnabledOnKeyguardCallback> callbacks = mEnabledOnKeyguardCallbacks;
+        public void notifyEnabledOnKeyguardCallbacks(int userId) {
+            List<EnabledOnKeyguardCallback> callbacks = mCallbacks;
             for (int i = 0; i < callbacks.size(); i++) {
                 callbacks.get(i).notify(BiometricSourceType.FACE,
                         mFaceEnabledOnKeyguard.getOrDefault(userId, DEFAULT_KEYGUARD_ENABLED),
@@ -527,7 +538,7 @@
         }
     }
 
-    private final class EnabledOnKeyguardCallback implements IBinder.DeathRecipient {
+    final class EnabledOnKeyguardCallback implements IBinder.DeathRecipient {
 
         private final IBiometricEnabledOnKeyguardCallback mCallback;
 
@@ -559,7 +570,8 @@
     }
 
     // Wrap the client's receiver so we can do things with the BiometricDialog first
-    private final IBiometricServiceReceiverInternal mInternalReceiver =
+    @VisibleForTesting
+    final IBiometricServiceReceiverInternal mInternalReceiver =
             new IBiometricServiceReceiverInternal.Stub() {
         @Override
         public void onAuthenticationSucceeded(boolean requireConfirmation, byte[] token)
@@ -571,10 +583,11 @@
         }
 
         @Override
-        public void onAuthenticationFailed(int cookie, boolean requireConfirmation)
+        public void onAuthenticationFailed()
                 throws RemoteException {
             String failureReason = getContext().getString(R.string.biometric_not_recognized);
-            mHandler.obtainMessage(MSG_ON_AUTHENTICATION_FAILED, failureReason).sendToTarget();
+            Slog.v(TAG, "onAuthenticationFailed: " + failureReason);
+            mHandler.obtainMessage(MSG_ON_AUTHENTICATION_REJECTED, failureReason).sendToTarget();
         }
 
         @Override
@@ -583,7 +596,7 @@
             // soft errors and we should allow the user to try authenticating again instead of
             // dismissing BiometricPrompt.
             if (error == BiometricConstants.BIOMETRIC_ERROR_TIMEOUT) {
-                mHandler.obtainMessage(MSG_ON_AUTHENTICATION_FAILED, message).sendToTarget();
+                mHandler.obtainMessage(MSG_ON_AUTHENTICATION_TIMED_OUT, message).sendToTarget();
             } else {
                 SomeArgs args = SomeArgs.obtain();
                 args.argi1 = cookie;
@@ -873,6 +886,44 @@
         }
     }
 
+    @VisibleForTesting
+    static class Injector {
+        IActivityManager getActivityManagerService() {
+            return ActivityManager.getService();
+        }
+
+        IStatusBarService getStatusBarService() {
+            return IStatusBarService.Stub.asInterface(
+                    ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+        }
+
+        IFingerprintService getFingerprintService() {
+            return IFingerprintService.Stub.asInterface(
+                    ServiceManager.getService(Context.FINGERPRINT_SERVICE));
+        }
+
+        IFaceService getFaceService() {
+            return IFaceService.Stub.asInterface(ServiceManager.getService(Context.FACE_SERVICE));
+        }
+
+        SettingObserver getSettingObserver(Context context, Handler handler,
+                List<EnabledOnKeyguardCallback> callbacks) {
+            return new SettingObserver(context, handler, callbacks);
+        }
+
+        KeyStore getKeyStore() {
+            return KeyStore.getInstance();
+        }
+
+        boolean isDebugEnabled(Context context, int userId) {
+            return Utils.isDebugEnabled(context, userId);
+        }
+
+        void publishBinderService(BiometricService service, IBiometricService.Stub impl) {
+            service.publishBinderService(Context.BIOMETRIC_SERVICE, impl);
+        }
+    }
+
     /**
      * Initializes the system service.
      * <p>
@@ -883,11 +934,19 @@
      * @param context The system server context.
      */
     public BiometricService(Context context) {
+        this(context, new Injector());
+    }
+
+    @VisibleForTesting
+    BiometricService(Context context, Injector injector) {
         super(context);
 
+        mInjector = injector;
+        mImpl = new BiometricServiceWrapper();
         mAppOps = context.getSystemService(AppOpsManager.class);
         mEnabledOnKeyguardCallbacks = new ArrayList<>();
-        mSettingObserver = new SettingObserver(mHandler);
+        mSettingObserver = mInjector.getSettingObserver(context, mHandler,
+                mEnabledOnKeyguardCallbacks);
 
         final PackageManager pm = context.getPackageManager();
         mHasFeatureFingerprint = pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT);
@@ -895,7 +954,7 @@
         mHasFeatureFace = pm.hasSystemFeature(PackageManager.FEATURE_FACE);
 
         try {
-            ActivityManager.getService().registerUserSwitchObserver(
+            injector.getActivityManagerService().registerUserSwitchObserver(
                     new UserSwitchObserver() {
                         @Override
                         public void onUserSwitchComplete(int newUserId) {
@@ -913,17 +972,14 @@
     public void onStart() {
         // TODO: maybe get these on-demand
         if (mHasFeatureFingerprint) {
-            mFingerprintService = IFingerprintService.Stub.asInterface(
-                    ServiceManager.getService(Context.FINGERPRINT_SERVICE));
+            mFingerprintService = mInjector.getFingerprintService();
         }
         if (mHasFeatureFace) {
-            mFaceService = IFaceService.Stub.asInterface(
-                    ServiceManager.getService(Context.FACE_SERVICE));
+            mFaceService = mInjector.getFaceService();
         }
 
-        mActivityTaskManager = ActivityTaskManager.getService();
-        mStatusBarService = IStatusBarService.Stub.asInterface(
-                ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+        mKeyStore = mInjector.getKeyStore();
+        mStatusBarService = mInjector.getStatusBarService();
 
         // Cache the authenticators
         for (int i = 0; i < FEATURE_ID.length; i++) {
@@ -934,7 +990,7 @@
             }
         }
 
-        publishBinderService(Context.BIOMETRIC_SERVICE, new BiometricServiceWrapper());
+        mInjector.publishBinderService(this, mImpl);
     }
 
     /**
@@ -1068,7 +1124,7 @@
     }
 
     private void logDialogDismissed(int reason) {
-        if (reason == BiometricPrompt.DISMISSED_REASON_POSITIVE) {
+        if (reason == BiometricPrompt.DISMISSED_REASON_CONFIRMED) {
             // Explicit auth, authentication confirmed.
             // Latency in this case is authenticated -> confirmed. <Biometric>Service
             // should have the first half (first acquired -> authenticated).
@@ -1094,7 +1150,7 @@
                     mCurrentAuthSession.mRequireConfirmation,
                     StatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED,
                     latency,
-                    Utils.isDebugEnabled(getContext(), mCurrentAuthSession.mUserId));
+                    mInjector.isDebugEnabled(getContext(), mCurrentAuthSession.mUserId));
         } else {
 
             final long latency = System.currentTimeMillis() - mCurrentAuthSession.mStartTimeMs;
@@ -1122,7 +1178,7 @@
                     BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT,
                     error,
                     0 /* vendorCode */,
-                    Utils.isDebugEnabled(getContext(), mCurrentAuthSession.mUserId),
+                    mInjector.isDebugEnabled(getContext(), mCurrentAuthSession.mUserId),
                     latency);
         }
     }
@@ -1145,51 +1201,22 @@
         return modality;
     }
 
-    private void handleTaskStackChanged() {
-        try {
-            final List<ActivityManager.RunningTaskInfo> runningTasks =
-                    mActivityTaskManager.getTasks(1);
-            if (!runningTasks.isEmpty()) {
-                final String topPackage = runningTasks.get(0).topActivity.getPackageName();
-                if (mCurrentAuthSession != null
-                        && !topPackage.contentEquals(mCurrentAuthSession.mOpPackageName)) {
-                    mStatusBarService.hideBiometricDialog();
-                    mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
-                    mCurrentAuthSession.mClientReceiver.onError(
-                            BiometricConstants.BIOMETRIC_ERROR_CANCELED,
-                            getContext().getString(
-                                    com.android.internal.R.string.biometric_error_canceled)
-                    );
-                    mCurrentAuthSession.mState = STATE_AUTH_IDLE;
-                    mCurrentAuthSession = null;
-                }
-            }
-        } catch (RemoteException e) {
-            Slog.e(TAG, "Unable to get running tasks", e);
-        }
-    }
-
     private void handleAuthenticationSucceeded(boolean requireConfirmation, byte[] token) {
-
         try {
             // Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded
             // after user dismissed/canceled dialog).
             if (mCurrentAuthSession == null) {
-                Slog.e(TAG, "onAuthenticationSucceeded(): Auth session is null");
+                Slog.e(TAG, "handleAuthenticationSucceeded: Auth session is null");
                 return;
             }
 
+            // Store the auth token and submit it to keystore after the dialog is confirmed /
+            // animating away.
+            mCurrentAuthSession.mTokenEscrow = token;
             if (!requireConfirmation) {
-                mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
-                KeyStore.getInstance().addAuthToken(token);
-                mCurrentAuthSession.mClientReceiver.onAuthenticationSucceeded();
-                mCurrentAuthSession.mState = STATE_AUTH_IDLE;
-                mCurrentAuthSession = null;
+                mCurrentAuthSession.mState = STATE_AUTHENTICATED_PENDING_SYSUI;
             } else {
                 mCurrentAuthSession.mAuthenticatedTimeMs = System.currentTimeMillis();
-                // Store the auth token and submit it to keystore after the confirmation
-                // button has been pressed.
-                mCurrentAuthSession.mTokenEscrow = token;
                 mCurrentAuthSession.mState = STATE_AUTH_PENDING_CONFIRM;
             }
 
@@ -1201,12 +1228,13 @@
         }
     }
 
-    private void handleAuthenticationFailed(String failureReason) {
+    private void handleAuthenticationRejected(String failureReason) {
+        Slog.v(TAG, "handleAuthenticationRejected: " + failureReason);
         try {
             // Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded
             // after user dismissed/canceled dialog).
             if (mCurrentAuthSession == null) {
-                Slog.e(TAG, "onAuthenticationFailed(): Auth session is null");
+                Slog.e(TAG, "handleAuthenticationRejected: Auth session is null");
                 return;
             }
 
@@ -1225,16 +1253,31 @@
         }
     }
 
+    private void handleAuthenticationTimedOut(String message) {
+        Slog.v(TAG, "handleAuthenticationTimedOut: " + message);
+        try {
+            // Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded
+            // after user dismissed/canceled dialog).
+            if (mCurrentAuthSession == null) {
+                Slog.e(TAG, "handleAuthenticationTimedOut: Auth session is null");
+                return;
+            }
+
+            mStatusBarService.onBiometricAuthenticated(false, message);
+            mCurrentAuthSession.mState = STATE_AUTH_PAUSED;
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Remote exception", e);
+        }
+    }
+
     private void handleOnConfirmDeviceCredentialSuccess() {
         if (mConfirmDeviceCredentialReceiver == null) {
-            Slog.w(TAG, "onCDCASuccess null!");
+            Slog.w(TAG, "handleOnConfirmDeviceCredentialSuccess null!");
             return;
         }
         try {
-            mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
             mConfirmDeviceCredentialReceiver.onAuthenticationSucceeded();
             if (mCurrentAuthSession != null) {
-                mCurrentAuthSession.mState = STATE_AUTH_IDLE;
                 mCurrentAuthSession = null;
             }
         } catch (RemoteException e) {
@@ -1245,14 +1288,13 @@
 
     private void handleOnConfirmDeviceCredentialError(int error, String message) {
         if (mConfirmDeviceCredentialReceiver == null) {
-            Slog.w(TAG, "onCDCAError null! Error: " + error + " " + message);
+            Slog.w(TAG, "handleOnConfirmDeviceCredentialError null! Error: "
+                    + error + " " + message);
             return;
         }
         try {
-            mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
             mConfirmDeviceCredentialReceiver.onError(error, message);
             if (mCurrentAuthSession != null) {
-                mCurrentAuthSession.mState = STATE_AUTH_IDLE;
                 mCurrentAuthSession = null;
             }
         } catch (RemoteException e) {
@@ -1272,7 +1314,7 @@
     }
 
     private void handleOnError(int cookie, int error, String message) {
-        Slog.d(TAG, "Error: " + error + " cookie: " + cookie);
+        Slog.d(TAG, "handleOnError: " + error + " cookie: " + cookie);
         // Errors can either be from the current auth session or the pending auth session.
         // The pending auth session may receive errors such as ERROR_LOCKOUT before
         // it becomes the current auth session. Similarly, the current auth session may
@@ -1282,6 +1324,9 @@
         try {
             if (mCurrentAuthSession != null && mCurrentAuthSession.containsCookie(cookie)) {
 
+                mCurrentAuthSession.mErrorEscrow = error;
+                mCurrentAuthSession.mErrorStringEscrow = message;
+
                 if (mCurrentAuthSession.isFromConfirmDeviceCredential()) {
                     // If we were invoked by ConfirmDeviceCredential, do not delete the current
                     // auth session since we still need to respond to cancel signal while
@@ -1293,39 +1338,18 @@
                     mCurrentAuthSession.mState = STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC;
                     mStatusBarService.hideBiometricDialog();
                 } else if (mCurrentAuthSession.mState == STATE_AUTH_STARTED) {
-                    mStatusBarService.onBiometricError(message);
+                    mCurrentAuthSession.mState = STATE_ERROR_PENDING_SYSUI;
                     if (error == BiometricConstants.BIOMETRIC_ERROR_CANCELED) {
-                        mActivityTaskManager.unregisterTaskStackListener(
-                                mTaskStackListener);
-                        mCurrentAuthSession.mClientReceiver.onError(error, message);
-                        mCurrentAuthSession.mState = STATE_AUTH_IDLE;
-                        mCurrentAuthSession = null;
                         mStatusBarService.hideBiometricDialog();
                     } else {
-                        // Send errors after the dialog is dismissed.
-                        mHandler.postDelayed(() -> {
-                            try {
-                                if (mCurrentAuthSession != null) {
-                                    mActivityTaskManager.unregisterTaskStackListener(
-                                            mTaskStackListener);
-                                    mCurrentAuthSession.mClientReceiver.onError(error,
-                                            message);
-                                    mCurrentAuthSession.mState = STATE_AUTH_IDLE;
-                                    mCurrentAuthSession = null;
-                                }
-                            } catch (RemoteException e) {
-                                Slog.e(TAG, "Remote exception", e);
-                            }
-                        }, BiometricPrompt.HIDE_DIALOG_DELAY);
+                        mStatusBarService.onBiometricError(message);
                     }
                 } else if (mCurrentAuthSession.mState == STATE_AUTH_PAUSED) {
                     // In the "try again" state, we should forward canceled errors to
-                    // the client and and clean up.
+                    // the client and and clean up. The only error we should get here is
+                    // ERROR_CANCELED due to another client kicking us out.
                     mCurrentAuthSession.mClientReceiver.onError(error, message);
-                    mStatusBarService.onBiometricError(message);
-                    mActivityTaskManager.unregisterTaskStackListener(
-                            mTaskStackListener);
-                    mCurrentAuthSession.mState = STATE_AUTH_IDLE;
+                    mStatusBarService.hideBiometricDialog();
                     mCurrentAuthSession = null;
                 } else {
                     Slog.e(TAG, "Impossible session error state: "
@@ -1335,7 +1359,6 @@
                     && mPendingAuthSession.containsCookie(cookie)) {
                 if (mPendingAuthSession.mState == STATE_AUTH_CALLED) {
                     mPendingAuthSession.mClientReceiver.onError(error, message);
-                    mPendingAuthSession.mState = STATE_AUTH_IDLE;
                     mPendingAuthSession = null;
                 } else {
                     Slog.e(TAG, "Impossible pending session error state: "
@@ -1370,42 +1393,50 @@
 
     private void handleOnDismissed(int reason) {
         if (mCurrentAuthSession == null) {
-            Slog.e(TAG, "onDialogDismissed: " + reason + ", auth session null");
+            Slog.e(TAG, "onDismissed: " + reason + ", auth session null");
             return;
         }
 
         logDialogDismissed(reason);
 
         try {
-            if (reason != BiometricPrompt.DISMISSED_REASON_POSITIVE) {
-                // Positive button is used by passive modalities as a "confirm" button,
-                // do not send to client
-                mCurrentAuthSession.mClientReceiver.onDialogDismissed(reason);
-                // Cancel authentication. Skip the token/package check since we are cancelling
-                // from system server. The interface is permission protected so this is fine.
-                cancelInternal(null /* token */, null /* package */, false /* fromClient */);
-            }
-            if (reason == BiometricPrompt.DISMISSED_REASON_USER_CANCEL) {
-                mCurrentAuthSession.mClientReceiver.onError(
-                        BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED,
-                        getContext().getString(
-                                com.android.internal.R.string.biometric_error_user_canceled));
-            } else if (reason == BiometricPrompt.DISMISSED_REASON_POSITIVE) {
-                // Have the service send the token to KeyStore, and send onAuthenticated
-                // to the application
-                KeyStore.getInstance().addAuthToken(mCurrentAuthSession.mTokenEscrow);
-                mCurrentAuthSession.mClientReceiver.onAuthenticationSucceeded();
+            switch (reason) {
+                case BiometricPrompt.DISMISSED_REASON_CONFIRMED:
+                case BiometricPrompt.DISMISSED_REASON_CONFIRM_NOT_REQUIRED:
+                    mKeyStore.addAuthToken(mCurrentAuthSession.mTokenEscrow);
+                    mCurrentAuthSession.mClientReceiver.onAuthenticationSucceeded();
+                    break;
+
+                case BiometricPrompt.DISMISSED_REASON_NEGATIVE:
+                    mCurrentAuthSession.mClientReceiver.onDialogDismissed(reason);
+                    // Cancel authentication. Skip the token/package check since we are cancelling
+                    // from system server. The interface is permission protected so this is fine.
+                    cancelInternal(null /* token */, null /* package */, false /* fromClient */);
+                    break;
+
+                case BiometricPrompt.DISMISSED_REASON_USER_CANCEL:
+                    mCurrentAuthSession.mClientReceiver.onError(
+                            BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED,
+                            getContext().getString(R.string.biometric_error_user_canceled));
+                    // Cancel authentication. Skip the token/package check since we are cancelling
+                    // from system server. The interface is permission protected so this is fine.
+                    cancelInternal(null /* token */, null /* package */, false /* fromClient */);
+                    break;
+
+                case BiometricPrompt.DISMISSED_REASON_SERVER_REQUESTED:
+                case BiometricPrompt.DISMISSED_REASON_ERROR:
+                    mCurrentAuthSession.mClientReceiver.onError(mCurrentAuthSession.mErrorEscrow,
+                            mCurrentAuthSession.mErrorStringEscrow);
+                    break;
+
+                default:
+                    Slog.w(TAG, "Unhandled reason: " + reason);
+                    break;
             }
 
-            // Do not clean up yet if we are from ConfirmDeviceCredential. We should be in the
-            // STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC. The session should only be removed when
-            // ConfirmDeviceCredential is confirmed or canceled.
-            // TODO(b/123378871): Remove when moved
-            if (!mCurrentAuthSession.isFromConfirmDeviceCredential()) {
-                mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
-                mCurrentAuthSession.mState = STATE_AUTH_IDLE;
-                mCurrentAuthSession = null;
-            }
+            // Dialog is gone, auth session is done.
+            mCurrentAuthSession = null;
+
         } catch (RemoteException e) {
             Slog.e(TAG, "Remote exception", e);
         }
@@ -1472,8 +1503,8 @@
 
                 if (!continuing) {
                     mStatusBarService.showBiometricDialog(mCurrentAuthSession.mBundle,
-                            mInternalReceiver, modality, requireConfirmation, userId);
-                    mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
+                            mInternalReceiver, modality, requireConfirmation, userId,
+                            mCurrentAuthSession.mOpPackageName);
                 }
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote exception", e);
@@ -1517,8 +1548,6 @@
                 return;
             }
 
-            mCurrentModality = modality;
-
             // Start preparing for authentication. Authentication starts when
             // all modalities requested have invoked onReadyForAuthentication.
             authenticateInternal(token, sessionId, userId, receiver, opPackageName, bundle,
@@ -1610,7 +1639,6 @@
                                 com.android.internal.R.string.biometric_error_user_canceled)
                 );
 
-                mCurrentAuthSession.mState = STATE_AUTH_IDLE;
                 mCurrentAuthSession = null;
                 mStatusBarService.hideBiometricDialog();
             } catch (RemoteException e) {
@@ -1637,25 +1665,31 @@
         final int callingUid = Binder.getCallingUid();
         final int callingPid = Binder.getCallingPid();
         final int callingUserId = UserHandle.getCallingUserId();
-        mHandler.post(() -> {
-            try {
-                // TODO: For multiple modalities, send a single ERROR_CANCELED only when all
-                // drivers have canceled authentication.
-                if ((mCurrentModality & TYPE_FINGERPRINT) != 0) {
-                    mFingerprintService.cancelAuthenticationFromService(token, opPackageName,
-                            callingUid, callingPid, callingUserId, fromClient);
-                }
-                if ((mCurrentModality & TYPE_IRIS) != 0) {
-                    Slog.w(TAG, "Iris unsupported");
-                }
-                if ((mCurrentModality & TYPE_FACE) != 0) {
-                    mFaceService.cancelAuthenticationFromService(token, opPackageName,
-                            callingUid, callingPid, callingUserId, fromClient);
-                }
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Unable to cancel authentication");
-            }
-        });
-    }
 
+        try {
+            if (mCurrentAuthSession == null) {
+                Slog.w(TAG, "Skipping cancelInternal");
+                return;
+            } else if (mCurrentAuthSession.mState != STATE_AUTH_STARTED) {
+                Slog.w(TAG, "Skipping cancelInternal, state: " + mCurrentAuthSession.mState);
+                return;
+            }
+
+            // TODO: For multiple modalities, send a single ERROR_CANCELED only when all
+            // drivers have canceled authentication.
+            if ((mCurrentAuthSession.mModality & TYPE_FINGERPRINT) != 0) {
+                mFingerprintService.cancelAuthenticationFromService(token, opPackageName,
+                        callingUid, callingPid, callingUserId, fromClient);
+            }
+            if ((mCurrentAuthSession.mModality & TYPE_IRIS) != 0) {
+                Slog.w(TAG, "Iris unsupported");
+            }
+            if ((mCurrentAuthSession.mModality & TYPE_FACE) != 0) {
+                mFaceService.cancelAuthenticationFromService(token, opPackageName,
+                        callingUid, callingPid, callingUserId, fromClient);
+            }
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Unable to cancel authentication");
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index f3f9754..2de18c3 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -420,7 +420,7 @@
             throw new UnsupportedOperationException("Stub!");
         }
 
-        default void onAuthenticationFailedInternal(int cookie, boolean requireConfirmation)
+        default void onAuthenticationFailedInternal()
                 throws RemoteException {
             throw new UnsupportedOperationException("Stub!");
         }
@@ -457,10 +457,10 @@
         }
 
         @Override
-        public void onAuthenticationFailedInternal(int cookie, boolean requireConfirmation)
+        public void onAuthenticationFailedInternal()
                 throws RemoteException {
             if (getWrapperReceiver() != null) {
-                getWrapperReceiver().onAuthenticationFailed(cookie, requireConfirmation);
+                getWrapperReceiver().onAuthenticationFailed();
             }
         }
     }
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
index 53890a4..a0eafb4 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
@@ -35,6 +35,8 @@
 import android.hardware.broadcastradio.V2_0.VendorKeyValue;
 import android.hardware.radio.RadioManager;
 import android.os.DeadObjectException;
+import android.os.Handler;
+import android.os.Looper;
 import android.os.RemoteException;
 import android.util.MutableInt;
 import android.util.Slog;
@@ -45,6 +47,7 @@
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 import java.util.stream.Collectors;
@@ -56,6 +59,7 @@
     @NonNull public final RadioManager.ModuleProperties mProperties;
 
     private final Object mLock = new Object();
+    @NonNull private final Handler mHandler;
 
     @GuardedBy("mLock")
     private ITunerSession mHalTunerSession;
@@ -77,22 +81,24 @@
     private final ITunerCallback mHalTunerCallback = new ITunerCallback.Stub() {
         @Override
         public void onTuneFailed(int result, ProgramSelector programSelector) {
-            fanoutAidlCallback(cb -> cb.onTuneFailed(result, Convert.programSelectorFromHal(
-                    programSelector)));
+            lockAndFireLater(() -> {
+                android.hardware.radio.ProgramSelector csel =
+                        Convert.programSelectorFromHal(programSelector);
+                fanoutAidlCallbackLocked(cb -> cb.onTuneFailed(result, csel));
+            });
         }
 
         @Override
         public void onCurrentProgramInfoChanged(ProgramInfo halProgramInfo) {
-            RadioManager.ProgramInfo programInfo = Convert.programInfoFromHal(halProgramInfo);
-            synchronized (mLock) {
-                mCurrentProgramInfo = programInfo;
-                fanoutAidlCallbackLocked(cb -> cb.onCurrentProgramInfoChanged(programInfo));
-            }
+            lockAndFireLater(() -> {
+                mCurrentProgramInfo = Convert.programInfoFromHal(halProgramInfo);
+                fanoutAidlCallbackLocked(cb -> cb.onCurrentProgramInfoChanged(mCurrentProgramInfo));
+            });
         }
 
         @Override
         public void onProgramListUpdated(ProgramListChunk programListChunk) {
-            synchronized (mLock) {
+            lockAndFireLater(() -> {
                 android.hardware.radio.ProgramList.Chunk chunk =
                         Convert.programListChunkFromHal(programListChunk);
                 mProgramInfoCache.filterAndApplyChunk(chunk);
@@ -100,20 +106,23 @@
                 for (TunerSession tunerSession : mAidlTunerSessions) {
                     tunerSession.onMergedProgramListUpdateFromHal(chunk);
                 }
-            }
+            });
         }
 
         @Override
         public void onAntennaStateChange(boolean connected) {
-            synchronized (mLock) {
+            lockAndFireLater(() -> {
                 mAntennaConnected = connected;
                 fanoutAidlCallbackLocked(cb -> cb.onAntennaState(connected));
-            }
+            });
         }
 
         @Override
         public void onParametersUpdated(ArrayList<VendorKeyValue> parameters) {
-            fanoutAidlCallback(cb -> cb.onParametersUpdated(Convert.vendorInfoFromHal(parameters)));
+            lockAndFireLater(() -> {
+                Map<String, String> cparam = Convert.vendorInfoFromHal(parameters);
+                fanoutAidlCallbackLocked(cb -> cb.onParametersUpdated(cparam));
+            });
         }
     };
 
@@ -126,6 +135,7 @@
             @NonNull RadioManager.ModuleProperties properties) {
         mProperties = Objects.requireNonNull(properties);
         mService = Objects.requireNonNull(service);
+        mHandler = new Handler(Looper.getMainLooper());
     }
 
     public static @Nullable RadioModule tryLoadingModule(int idx, @NonNull String fqName) {
@@ -310,15 +320,22 @@
         }
     }
 
+    // add to mHandler queue, but ensure the runnable holds mLock when it gets executed
+    private void lockAndFireLater(Runnable r) {
+        mHandler.post(() -> {
+            synchronized (mLock) {
+                r.run();
+            }
+        });
+    }
+
     interface AidlCallbackRunnable {
         void run(android.hardware.radio.ITunerCallback callback) throws RemoteException;
     }
 
     // Invokes runnable with each TunerSession currently open.
     void fanoutAidlCallback(AidlCallbackRunnable runnable) {
-        synchronized (mLock) {
-            fanoutAidlCallbackLocked(runnable);
-        }
+        lockAndFireLater(() -> fanoutAidlCallbackLocked(runnable));
     }
 
     private void fanoutAidlCallbackLocked(AidlCallbackRunnable runnable) {
diff --git a/services/core/java/com/android/server/om/IdmapDaemon.java b/services/core/java/com/android/server/om/IdmapDaemon.java
index 91824c3..20a4c75 100644
--- a/services/core/java/com/android/server/om/IdmapDaemon.java
+++ b/services/core/java/com/android/server/om/IdmapDaemon.java
@@ -129,11 +129,11 @@
         }
     }
 
-    static void startIdmapService() {
+    private static void startIdmapService() {
         SystemProperties.set("ctl.start", IDMAP_DAEMON);
     }
 
-    static void stopIdmapService() {
+    private static void stopIdmapService() {
         SystemProperties.set("ctl.stop", IDMAP_DAEMON);
     }
 
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 8171a8d..965ddc9 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -262,7 +262,6 @@
 
             initIfNeeded();
             onSwitchUser(UserHandle.USER_SYSTEM);
-            IdmapDaemon.stopIdmapService();
 
             publishBinderService(Context.OVERLAY_SERVICE, mService);
             publishLocalService(OverlayManagerService.class, this);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 0032e9a..3aeb2b1 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -1184,9 +1184,26 @@
         synchronized (mSessions) {
             pw.println("Active install sessions:");
             pw.increaseIndent();
+
+            List<PackageInstallerSession> finalizedSessions = new ArrayList<>();
             int N = mSessions.size();
             for (int i = 0; i < N; i++) {
                 final PackageInstallerSession session = mSessions.valueAt(i);
+                if (session.isStagedAndInTerminalState()) {
+                    finalizedSessions.add(session);
+                    continue;
+                }
+                session.dump(pw);
+                pw.println();
+            }
+            pw.println();
+            pw.decreaseIndent();
+
+            pw.println("Finalized install sessions:");
+            pw.increaseIndent();
+            N = finalizedSessions.size();
+            for (int i = 0; i < N; i++) {
+                final PackageInstallerSession session = finalizedSessions.get(i);
                 session.dump(pw);
                 pw.println();
             }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 4eddb930..b720290 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -2337,6 +2337,7 @@
         pw.printPair("mInstallerPackageName", mInstallerPackageName);
         pw.printPair("mInstallerUid", mInstallerUid);
         pw.printPair("createdMillis", createdMillis);
+        pw.printPair("updatedMillis", updatedMillis);
         pw.printPair("stageDir", stageDir);
         pw.printPair("stageCid", stageCid);
         pw.println();
@@ -2356,6 +2357,13 @@
         pw.printPair("mFinalMessage", mFinalMessage);
         pw.printPair("params.isMultiPackage", params.isMultiPackage);
         pw.printPair("params.isStaged", params.isStaged);
+        pw.printPair("mParentSessionId", mParentSessionId);
+        pw.printPair("mChildSessionIds", mChildSessionIds);
+        pw.printPair("mStagedSessionApplied", mStagedSessionApplied);
+        pw.printPair("mStagedSessionFailed", mStagedSessionFailed);
+        pw.printPair("mStagedSessionReady", mStagedSessionReady);
+        pw.printPair("mStagedSessionErrorCode", mStagedSessionErrorCode);
+        pw.printPair("mStagedSessionErrorMessage", mStagedSessionErrorMessage);
         pw.println();
 
         pw.decreaseIndent();
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 02f98b4..bfd280c 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -271,33 +271,9 @@
         }, filter, null, getHandler());
     }
 
-    /**
-     * This method posts a blocking call to the handler thread, so it should not be called from
-     * that same thread.
-     * @throws {@link IllegalStateException} if called from {@link #mHandlerThread}
-     */
     @Override
     public ParceledListSlice getAvailableRollbacks() {
         enforceManageRollbacks("getAvailableRollbacks");
-        if (Thread.currentThread().equals(mHandlerThread)) {
-            Slog.wtf(TAG, "Calling getAvailableRollbacks from mHandlerThread "
-                    + "causes a deadlock");
-            throw new IllegalStateException("Cannot call RollbackManager#getAvailableRollbacks "
-                    + "from the handler thread!");
-        }
-
-        // Wait for the handler thread to get the list of available rollbacks
-        // to get the most up-to-date results. This is intended to reduce test
-        // flakiness when checking available rollbacks immediately after
-        // installing a package with rollback enabled.
-        CountDownLatch latch = new CountDownLatch(1);
-        getHandler().post(() -> latch.countDown());
-        try {
-            latch.await();
-        } catch (InterruptedException ie) {
-            throw new IllegalStateException("RollbackManagerHandlerThread interrupted");
-        }
-
         synchronized (mLock) {
             List<RollbackInfo> rollbacks = new ArrayList<>();
             for (int i = 0; i < mRollbacks.size(); ++i) {
@@ -306,6 +282,15 @@
                     rollbacks.add(rollback.info);
                 }
             }
+
+            // Also return new rollbacks for which the PackageRollbackInfo is complete.
+            for (NewRollback newRollback : mNewRollbacks) {
+                if (newRollback.rollback.info.getPackages().size()
+                        == newRollback.packageSessionIds.length
+                        && !newRollback.isCancelled) {
+                    rollbacks.add(newRollback.rollback.info);
+                }
+            }
             return new ParceledListSlice<>(rollbacks);
         }
     }
@@ -562,6 +547,14 @@
                     }
                 }
             }
+            for (NewRollback newRollback : mNewRollbacks) {
+                for (PackageRollbackInfo info : newRollback.rollback.info.getPackages()) {
+                    if (info.getPackageName().equals(packageName)) {
+                        newRollback.isCancelled = true;
+                        break;
+                    }
+                }
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index d67048f..8897eca 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -610,11 +610,12 @@
 
     @Override
     public void showBiometricDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver,
-            int type, boolean requireConfirmation, int userId) {
+            int type, boolean requireConfirmation, int userId, String opPackageName) {
         enforceBiometricDialog();
         if (mBar != null) {
             try {
-                mBar.showBiometricDialog(bundle, receiver, type, requireConfirmation, userId);
+                mBar.showBiometricDialog(bundle, receiver, type, requireConfirmation, userId,
+                        opPackageName);
             } catch (RemoteException ex) {
             }
         }
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index f1cd721..5a0dfd0 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -41,6 +41,7 @@
 import static com.android.server.am.ActivityDisplayProto.SINGLE_TASK_INSTANCE;
 import static com.android.server.am.ActivityDisplayProto.STACKS;
 import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
+import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
 import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK;
@@ -173,18 +174,10 @@
         mService = root.mService;
         mDisplayId = display.getDisplayId();
         mDisplay = display;
-        mDisplayContent = createDisplayContent();
+        mDisplayContent = mService.mWindowManager.mRoot.createDisplayContent(mDisplay, this);
         mDisplayContent.reconfigureDisplayLocked();
-        updateBounds();
-    }
-
-    protected DisplayContent createDisplayContent() {
-        return mService.mWindowManager.mRoot.createDisplayContent(mDisplay, this);
-    }
-
-    private void updateBounds() {
-        mDisplay.getRealSize(mTmpDisplaySize);
-        setBounds(0, 0, mTmpDisplaySize.x, mTmpDisplaySize.y);
+        onRequestedOverrideConfigurationChanged(
+                mDisplayContent.getRequestedOverrideConfiguration());
     }
 
     void onDisplayChanged() {
@@ -200,7 +193,8 @@
             }
         }
 
-        updateBounds();
+        mDisplay.getRealSize(mTmpDisplaySize);
+        setBounds(0, 0, mTmpDisplaySize.x, mTmpDisplaySize.y);
         if (mDisplayContent != null) {
             mDisplayContent.updateDisplayInfo();
             mService.mWindowManager.requestTraversal();
@@ -1541,6 +1535,17 @@
         return mSingleTaskInstance;
     }
 
+    @VisibleForTesting
+    void removeAllTasks() {
+        for (int i = getChildCount() - 1; i >= 0; --i) {
+            final ActivityStack stack = getChildAt(i);
+            final ArrayList<TaskRecord> tasks = stack.getAllTasks();
+            for (int j = tasks.size() - 1; j >= 0; --j) {
+                stack.removeTask(tasks.get(j), "removeAllTasks", REMOVE_TASK_MODE_DESTROYING);
+            }
+        }
+    }
+
     public void dump(PrintWriter pw, String prefix) {
         pw.println(prefix + "displayId=" + mDisplayId + " stacks=" + mStacks.size()
                 + (mSingleTaskInstance ? " mSingleTaskInstance" : ""));
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 31e8bbdab..2269537 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -121,6 +121,7 @@
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
 import static com.android.server.wm.ActivityStack.STOP_TIMEOUT_MSG;
 import static com.android.server.wm.ActivityStackSupervisor.PAUSE_IMMEDIATELY;
+import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONTAINERS;
@@ -1372,16 +1373,17 @@
         return stack != null ? stack.getDisplay() : null;
     }
 
-    boolean changeWindowTranslucency(boolean toOpaque) {
-        if (fullscreen == toOpaque) {
-            return false;
+    boolean setOccludesParent(boolean occludesParent) {
+        final boolean changed = mAppWindowToken.setOccludesParent(occludesParent);
+        if (changed) {
+            if (!occludesParent) {
+                getActivityStack().convertActivityToTranslucent(this);
+            }
+            // Keep track of the number of fullscreen activities in this task.
+            task.numFullscreen += occludesParent ? +1 : -1;
+            mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
         }
-
-        // Keep track of the number of fullscreen activities in this task.
-        task.numFullscreen += toOpaque ? +1 : -1;
-
-        fullscreen = toOpaque;
-        return true;
+        return changed;
     }
 
     void takeFromHistory() {
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 12eab50..daf3286 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -2492,7 +2492,7 @@
             mHandler.removeMessages(TRANSLUCENT_TIMEOUT_MSG);
 
             if (waitingActivity != null) {
-                mWindowManager.setWindowOpaque(waitingActivity.appToken, false);
+                mWindowManager.setWindowOpaqueLocked(waitingActivity.appToken, false);
                 if (waitingActivity.attachedToProcess()) {
                     try {
                         waitingActivity.app.getThread().scheduleTranslucentConversionComplete(
@@ -2813,7 +2813,7 @@
         // Launching this app's activity, make sure the app is no longer
         // considered stopped.
         try {
-            AppGlobals.getPackageManager().setPackageStoppedState(
+            mService.getPackageManager().setPackageStoppedState(
                     next.packageName, false, next.mUserId); /* TODO: Verify if correct userid */
         } catch (RemoteException e1) {
         } catch (IllegalArgumentException e) {
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 1c56a10..22f72a4 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -250,7 +250,7 @@
     RecentTasks mRecentTasks;
 
     /** Helper class to abstract out logic for fetching the set of currently running tasks */
-    RunningTasks mRunningTasks;
+    private RunningTasks mRunningTasks;
 
     final ActivityStackSupervisorHandler mHandler;
     final Looper mLooper;
@@ -444,7 +444,7 @@
         }
 
         mInitialized = true;
-        mRunningTasks = createRunningTasks();
+        setRunningTasks(new RunningTasks());
 
         mActivityMetricsLogger = new ActivityMetricsLogger(this, mService.mContext,
                 mHandler.getLooper());
@@ -485,13 +485,20 @@
     }
 
     void setRecentTasks(RecentTasks recentTasks) {
+        if (mRecentTasks != null) {
+            mRecentTasks.unregisterCallback(this);
+        }
         mRecentTasks = recentTasks;
         mRecentTasks.registerCallback(this);
     }
 
     @VisibleForTesting
-    RunningTasks createRunningTasks() {
-        return new RunningTasks();
+    void setRunningTasks(RunningTasks runningTasks) {
+        mRunningTasks = runningTasks;
+    }
+
+    RunningTasks getRunningTasks() {
+        return mRunningTasks;
     }
 
     /**
@@ -2735,7 +2742,7 @@
         mWindowManager.deferSurfaceLayout();
         try {
             if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
-                mWindowManager.setDockedStackCreateState(
+                mWindowManager.setDockedStackCreateStateLocked(
                         activityOptions.getSplitScreenCreateMode(), null /* initialBounds */);
 
                 // Defer updating the stack in which recents is until the app transition is done, to
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index a3ab27e..7283ca5 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -43,7 +43,6 @@
 import static android.content.pm.ConfigurationInfo.GL_ES_VERSION_UNDEFINED;
 import static android.content.pm.PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS;
 import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
-import static android.content.pm.PackageManager.FEATURE_PC;
 import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.content.res.Configuration.UI_MODE_TYPE_TELEVISION;
@@ -361,7 +360,7 @@
     /* Global service lock used by the package the owns this service. */
     final WindowManagerGlobalLock mGlobalLock = new WindowManagerGlobalLock();
     /**
-     * It is the same instance as {@link mGlobalLock}, just declared as a type that the
+     * It is the same instance as {@link #mGlobalLock}, just declared as a type that the
      * locked-region-code-injection does't recognize it. It is used to skip wrapping priority
      * booster for places that are already in the scope of another booster (e.g. computing oom-adj).
      *
@@ -730,7 +729,6 @@
         final boolean forceRtl = Settings.Global.getInt(resolver, DEVELOPMENT_FORCE_RTL, 0) != 0;
         final boolean forceResizable = Settings.Global.getInt(
                 resolver, DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, 0) != 0;
-        final boolean isPc = mContext.getPackageManager().hasSystemFeature(FEATURE_PC);
 
         // Transfer any global setting for forcing RTL layout, into a System Property
         DisplayProperties.debug_force_rtl(forceRtl);
@@ -761,10 +759,6 @@
                 mSupportsPictureInPicture = false;
                 mSupportsMultiDisplay = false;
             }
-            mWindowManager.setForceResizableTasks(mForceResizableActivities);
-            mWindowManager.setSupportsPictureInPicture(mSupportsPictureInPicture);
-            mWindowManager.setSupportsFreeformWindowManagement(mSupportsFreeformWindowManagement);
-            mWindowManager.setIsPc(isPc);
             mWindowManager.mRoot.onSettingsRetrieved();
             // This happens before any activities are started, so we can change global configuration
             // in-place.
@@ -821,8 +815,7 @@
                 new TaskChangeNotificationController(mGlobalLock, mStackSupervisor, mH);
         mLockTaskController = new LockTaskController(mContext, mStackSupervisor, mH);
         mActivityStartController = new ActivityStartController(this);
-        mRecentTasks = createRecentTasks();
-        mStackSupervisor.setRecentTasks(mRecentTasks);
+        setRecentTasks(new RecentTasks(this, mStackSupervisor));
         mVrController = new VrController(mGlobalLock);
         mKeyguardController = mStackSupervisor.getKeyguardController();
     }
@@ -890,8 +883,10 @@
         return mode == AppOpsManager.MODE_ALLOWED;
     }
 
-    protected RecentTasks createRecentTasks() {
-        return new RecentTasks(this, mStackSupervisor);
+    @VisibleForTesting
+    protected void setRecentTasks(RecentTasks recentTasks) {
+        mRecentTasks = recentTasks;
+        mStackSupervisor.setRecentTasks(recentTasks);
     }
 
     RecentTasks getRecentTasks() {
@@ -1954,12 +1949,7 @@
                 if (r == null) {
                     return false;
                 }
-                final boolean translucentChanged = r.changeWindowTranslucency(true);
-                if (translucentChanged) {
-                    mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
-                }
-                mWindowManager.setAppFullscreen(token, true);
-                return translucentChanged;
+                return r.setOccludesParent(true);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -1982,13 +1972,7 @@
                     ActivityRecord under = task.mActivities.get(index - 1);
                     under.returningOptions = safeOptions != null ? safeOptions.getOptions(r) : null;
                 }
-                final boolean translucentChanged = r.changeWindowTranslucency(false);
-                if (translucentChanged) {
-                    r.getActivityStack().convertActivityToTranslucent(r);
-                }
-                mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
-                mWindowManager.setAppFullscreen(token, false);
-                return translucentChanged;
+                return r.setOccludesParent(false);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -2581,7 +2565,7 @@
                             + taskId + " to stack " + stackId);
                 }
                 if (stack.inSplitScreenPrimaryWindowingMode()) {
-                    mWindowManager.setDockedStackCreateState(
+                    mWindowManager.setDockedStackCreateStateLocked(
                             SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, null /* initialBounds */);
                 }
                 task.reparent(stack, toTop, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME,
@@ -2700,7 +2684,7 @@
                             + " non-standard task " + taskId + " to split-screen windowing mode");
                 }
 
-                mWindowManager.setDockedStackCreateState(createMode, initialBounds);
+                mWindowManager.setDockedStackCreateStateLocked(createMode, initialBounds);
                 final int windowingMode = task.getWindowingMode();
                 final ActivityStack stack = task.getStack();
                 if (toTop) {
@@ -2802,7 +2786,7 @@
         try {
             synchronized (mGlobalLock) {
                 // Cancel the recents animation synchronously (do not hold the WM lock)
-                mWindowManager.cancelRecentsAnimationSynchronously(restoreHomeStackPosition
+                mWindowManager.cancelRecentsAnimation(restoreHomeStackPosition
                         ? REORDER_MOVE_TO_ORIGINAL_POSITION
                         : REORDER_KEEP_IN_PLACE, "cancelRecentsAnimation/uid=" + callingUid);
             }
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 7fde6de..7e0d9a0 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -92,6 +92,7 @@
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.graphics.GraphicBuffer;
+import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Binder;
@@ -153,8 +154,11 @@
     final ComponentName mActivityComponent;
     final boolean mVoiceInteraction;
 
-    /** @see WindowContainer#fillsParent() */
-    private boolean mFillsParent;
+    /**
+     * The activity is opaque and fills the entire space of this task.
+     * @see WindowContainer#fillsParent()
+     */
+    private boolean mOccludesParent;
     boolean mShowForAllUsers;
     int mTargetSdk;
 
@@ -373,7 +377,7 @@
         appToken = token;
         mActivityComponent = activityComponent;
         mVoiceInteraction = voiceInteraction;
-        mFillsParent = fillsParent;
+        mOccludesParent = fillsParent;
         mInputApplicationHandle = new InputApplicationHandle(appToken.asBinder());
     }
 
@@ -2354,11 +2358,29 @@
 
     @Override
     boolean fillsParent() {
-        return mFillsParent;
+        return occludesParent();
     }
 
-    void setFillsParent(boolean fillsParent) {
-        mFillsParent = fillsParent;
+    /** Returns true if this activity is opaque and fills the entire space of this task. */
+    boolean occludesParent() {
+        return mOccludesParent;
+    }
+
+    boolean setOccludesParent(boolean occludesParent) {
+        final boolean changed = occludesParent != mOccludesParent;
+        mOccludesParent = occludesParent;
+        setMainWindowOpaque(occludesParent);
+        mWmService.mWindowPlacerLocked.requestTraversal();
+        return changed;
+    }
+
+    void setMainWindowOpaque(boolean isOpaque) {
+        final WindowState win = findMainWindow();
+        if (win == null) {
+            return;
+        }
+        isOpaque = isOpaque & !PixelFormat.formatHasAlpha(win.getAttrs().format);
+        win.mWinAnimator.setOpaqueLocked(isOpaque);
     }
 
     boolean containsDismissKeyguardWindow() {
@@ -3035,7 +3057,7 @@
         }
         pw.println(prefix + "component=" + mActivityComponent.flattenToShortString());
         pw.print(prefix); pw.print("task="); pw.println(getTask());
-        pw.print(prefix); pw.print(" mFillsParent="); pw.print(mFillsParent);
+        pw.print(prefix); pw.print(" mOccludesParent="); pw.print(mOccludesParent);
                 pw.print(" mOrientation="); pw.println(mOrientation);
         pw.println(prefix + "hiddenRequested=" + hiddenRequested + " mClientHidden=" + mClientHidden
             + ((mDeferHidingClient) ? " mDeferHidingClient=" + mDeferHidingClient : "")
@@ -3152,7 +3174,7 @@
         if (mThumbnail != null){
             mThumbnail.writeToProto(proto, THUMBNAIL);
         }
-        proto.write(FILLS_PARENT, mFillsParent);
+        proto.write(FILLS_PARENT, mOccludesParent);
         proto.write(APP_STOPPED, mAppStopped);
         proto.write(HIDDEN_REQUESTED, hiddenRequested);
         proto.write(CLIENT_HIDDEN, mClientHidden);
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 282ed42..410cc94 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -295,7 +295,8 @@
                 false /* forceRelayout */);
     }
 
-    private void setUserRotation(int userRotationMode, int userRotation) {
+    @VisibleForTesting
+    void setUserRotation(int userRotationMode, int userRotation) {
         if (isDefaultDisplay) {
             // We'll be notified via settings listener, so we don't need to update internal values.
             final ContentResolver res = mContext.getContentResolver();
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index 207e8ef..8507918 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -275,14 +275,14 @@
         // This display used to be in freeform, but we don't support freeform anymore, so fall
         // back to fullscreen.
         if (windowingMode == WindowConfiguration.WINDOWING_MODE_FREEFORM
-                && !mService.mSupportsFreeformWindowManagement) {
+                && !mService.mAtmService.mSupportsFreeformWindowManagement) {
             return WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
         }
         // No record is present so use default windowing mode policy.
         if (windowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
             final boolean forceDesktopMode = mService.mForceDesktopModeOnExternalDisplays
                     && displayId != Display.DEFAULT_DISPLAY;
-            windowingMode = mService.mSupportsFreeformWindowManagement
+            windowingMode = mService.mAtmService.mSupportsFreeformWindowManagement
                     && (mService.mIsPc || forceDesktopMode)
                     ? WindowConfiguration.WINDOWING_MODE_FREEFORM
                     : WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index b1bc2197..120ce3e 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -355,7 +355,9 @@
 
     void getTouchRegion(Rect outRegion) {
         outRegion.set(mTouchRegion);
-        outRegion.offset(mWindow.getFrameLw().left, mWindow.getFrameLw().top);
+        if (mWindow != null) {
+            outRegion.offset(mWindow.getFrameLw().left, mWindow.getFrameLw().top);
+        }
     }
 
     private void resetDragResizingChangeReported() {
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 4f0332c..caa8363 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -241,7 +241,7 @@
             // Fetch all the surface controls and pass them to the client to get the animation
             // started. Cancel any existing recents animation running synchronously (do not hold the
             // WM lock)
-            mWindowManager.cancelRecentsAnimationSynchronously(REORDER_MOVE_TO_ORIGINAL_POSITION,
+            mWindowManager.cancelRecentsAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION,
                     "startRecentsActivity");
             mWindowManager.initializeRecentsAnimation(mTargetActivityType, recentsAnimationRunner,
                     this, mDefaultDisplay.mDisplayId,
@@ -396,12 +396,8 @@
 
     @Override
     public void onAnimationFinished(@RecentsAnimationController.ReorderMode int reorderMode,
-            boolean runSychronously, boolean sendUserLeaveHint) {
-        if (runSychronously) {
-            finishAnimation(reorderMode, sendUserLeaveHint);
-        } else {
-            mService.mH.post(() -> finishAnimation(reorderMode, sendUserLeaveHint));
-        }
+            boolean sendUserLeaveHint) {
+        finishAnimation(reorderMode, sendUserLeaveHint);
     }
 
     @Override
@@ -435,8 +431,7 @@
         } else {
             // Just cancel directly to unleash from launcher when the next launching task is the
             // current top task.
-            mWindowManager.cancelRecentsAnimationSynchronously(REORDER_KEEP_IN_PLACE,
-                    "stackOrderChanged");
+            mWindowManager.cancelRecentsAnimation(REORDER_KEEP_IN_PLACE, "stackOrderChanged");
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 724a72e..8752f37 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -168,8 +168,7 @@
 
     public interface RecentsAnimationCallbacks {
         /** Callback when recents animation is finished. */
-        void onAnimationFinished(@ReorderMode int reorderMode, boolean runSychronously,
-                boolean sendUserLeaveHint);
+        void onAnimationFinished(@ReorderMode int reorderMode, boolean sendUserLeaveHint);
     }
 
     private final IRecentsAnimationController mController =
@@ -221,8 +220,7 @@
                 // prior to calling the callback
                 mCallbacks.onAnimationFinished(moveHomeToTop
                         ? REORDER_MOVE_TO_TOP
-                        : REORDER_MOVE_TO_ORIGINAL_POSITION,
-                        true /* runSynchronously */, sendUserLeaveHint);
+                        : REORDER_MOVE_TO_ORIGINAL_POSITION, sendUserLeaveHint);
                 mDisplayContent.mBoundsAnimationController.setAnimationType(FADE_IN);
             } finally {
                 Binder.restoreCallingIdentity(token);
@@ -498,21 +496,15 @@
     }
 
     void cancelAnimation(@ReorderMode int reorderMode, String reason) {
-        cancelAnimation(reorderMode, false /* runSynchronously */, false /*screenshot */, reason);
-    }
-
-    void cancelAnimationSynchronously(@ReorderMode int reorderMode, String reason) {
-        cancelAnimation(reorderMode, true /* runSynchronously */, false /* screenshot */, reason);
+        cancelAnimation(reorderMode, false /*screenshot */, reason);
     }
 
     void cancelAnimationWithScreenshot(boolean screenshot) {
-        cancelAnimation(REORDER_KEEP_IN_PLACE, true /* sync */, screenshot, "stackOrderChanged");
+        cancelAnimation(REORDER_KEEP_IN_PLACE, screenshot, "stackOrderChanged");
     }
 
-    private void cancelAnimation(@ReorderMode int reorderMode, boolean runSynchronously,
-            boolean screenshot, String reason) {
-        if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "cancelAnimation(): reason=" + reason
-                + " runSynchronously=" + runSynchronously);
+    private void cancelAnimation(@ReorderMode int reorderMode, boolean screenshot, String reason) {
+        if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "cancelAnimation(): reason=" + reason);
         synchronized (mService.getWindowManagerLock()) {
             if (mCanceled) {
                 // We've already canceled the animation
@@ -525,16 +517,14 @@
                 // Screen shot previous task when next task starts transition and notify the runner.
                 // We will actually finish the animation once the runner calls cleanUpScreenshot().
                 final Task task = mPendingAnimations.get(0).mTask;
-                final TaskSnapshot taskSnapshot = screenshotRecentTask(task, reorderMode,
-                        runSynchronously);
+                final TaskSnapshot taskSnapshot = screenshotRecentTask(task, reorderMode);
                 try {
                     mRunner.onAnimationCanceled(taskSnapshot);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Failed to cancel recents animation", e);
                 }
                 if (taskSnapshot == null) {
-                    mCallbacks.onAnimationFinished(reorderMode, runSynchronously,
-                            false /* sendUserLeaveHint */);
+                    mCallbacks.onAnimationFinished(reorderMode, false /* sendUserLeaveHint */);
                 }
             } else {
                 // Otherwise, notify the runner and clean up the animation immediately
@@ -545,8 +535,7 @@
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Failed to cancel recents animation", e);
                 }
-                mCallbacks.onAnimationFinished(reorderMode, runSynchronously,
-                        false /* sendUserLeaveHint */);
+                mCallbacks.onAnimationFinished(reorderMode, false /* sendUserLeaveHint */);
             }
         }
     }
@@ -592,8 +581,7 @@
         return mRequestDeferCancelUntilNextTransition && mCancelDeferredWithScreenshot;
     }
 
-    TaskSnapshot screenshotRecentTask(Task task, @ReorderMode int reorderMode,
-            boolean runSynchronously) {
+    TaskSnapshot screenshotRecentTask(Task task, @ReorderMode int reorderMode) {
         final TaskSnapshotController snapshotController = mService.mTaskSnapshotController;
         final ArraySet<Task> tasks = Sets.newArraySet(task);
         snapshotController.snapshotTasks(tasks);
@@ -613,8 +601,7 @@
                     if (DEBUG_RECENTS_ANIMATIONS) {
                         Slog.d(TAG, "mRecentScreenshotAnimator finish");
                     }
-                    mCallbacks.onAnimationFinished(reorderMode, runSynchronously,
-                            false /* sendUserLeaveHint */);
+                    mCallbacks.onAnimationFinished(reorderMode, false /* sendUserLeaveHint */);
                 }, mService);
         mRecentScreenshotAnimator.transferAnimation(task.mSurfaceAnimator);
         return taskSnapshot;
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index 66d42db..3401de6 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -227,15 +227,10 @@
         mStackSupervisor.mRootActivityContainer = this;
     }
 
-    @VisibleForTesting
-    void setWindowContainer(RootWindowContainer container) {
-        mRootWindowContainer = container;
-        mRootWindowContainer.setRootActivityContainer(this);
-    }
-
     void setWindowManager(WindowManagerService wm) {
         mWindowManager = wm;
-        setWindowContainer(mWindowManager.mRoot);
+        mRootWindowContainer = mWindowManager.mRoot;
+        mRootWindowContainer.setRootActivityContainer(this);
         mDisplayManager = mService.mContext.getSystemService(DisplayManager.class);
         mDisplayManager.registerDisplayListener(this, mService.mUiHandler);
         mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
@@ -2266,7 +2261,7 @@
             @WindowConfiguration.ActivityType int ignoreActivityType,
             @WindowConfiguration.WindowingMode int ignoreWindowingMode, int callingUid,
             boolean allowed) {
-        mStackSupervisor.mRunningTasks.getTasks(maxNum, list, ignoreActivityType,
+        mStackSupervisor.getRunningTasks().getTasks(maxNum, list, ignoreActivityType,
                 ignoreWindowingMode, mActivityDisplays, callingUid, allowed);
     }
 
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index fd86faa..3a2eb57 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -380,7 +380,7 @@
 
     boolean isResizeable() {
         return ActivityInfo.isResizeableMode(mResizeMode) || mSupportsPictureInPicture
-                || mWmService.mForceResizableTasks;
+                || mWmService.mAtmService.mForceResizableActivities;
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 79367a0..cc2112e 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -1666,7 +1666,7 @@
      *         default bounds.
      */
     Rect getPictureInPictureBounds(float aspectRatio, Rect stackBounds) {
-        if (!mWmService.mSupportsPictureInPicture) {
+        if (!mWmService.mAtmService.mSupportsPictureInPicture) {
             return null;
         }
 
@@ -1762,7 +1762,7 @@
      * Sets the current picture-in-picture aspect ratio.
      */
     void setPictureInPictureAspectRatio(float aspectRatio) {
-        if (!mWmService.mSupportsPictureInPicture) {
+        if (!mWmService.mAtmService.mSupportsPictureInPicture) {
             return;
         }
 
@@ -1792,7 +1792,7 @@
      * Sets the current picture-in-picture actions.
      */
     void setPictureInPictureActions(List<RemoteAction> actions) {
-        if (!mWmService.mSupportsPictureInPicture) {
+        if (!mWmService.mAtmService.mSupportsPictureInPicture) {
             return;
         }
 
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index bbef261..29d232f 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -767,11 +767,11 @@
      */
     void setOrientation(int orientation, @Nullable IBinder freezeDisplayToken,
             @Nullable ConfigurationContainer requestingContainer) {
-        final boolean changed = mOrientation != orientation;
-        mOrientation = orientation;
-        if (!changed) {
+        if (mOrientation == orientation) {
             return;
         }
+
+        mOrientation = orientation;
         final WindowContainer parent = getParent();
         if (parent != null) {
             onDescendantOrientationChanged(freezeDisplayToken, requestingContainer);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 86faad0..d8d6841 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -28,6 +28,7 @@
 import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
 import static android.app.StatusBarManager.DISABLE_MASK;
 import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED;
+import static android.content.pm.PackageManager.FEATURE_PC;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.os.Process.SYSTEM_UID;
 import static android.os.Process.myPid;
@@ -591,9 +592,6 @@
     int mDockedStackCreateMode = SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
     Rect mDockedStackCreateBounds;
 
-    boolean mForceResizableTasks;
-    boolean mSupportsPictureInPicture;
-    boolean mSupportsFreeformWindowManagement;
     boolean mIsPc;
     /**
      * Flag that indicates that desktop mode is forced for public secondary screens.
@@ -819,7 +817,7 @@
     int mTransactionSequence;
 
     final WindowAnimator mAnimator;
-    final SurfaceAnimationRunner mSurfaceAnimationRunner;
+    SurfaceAnimationRunner mSurfaceAnimationRunner;
 
     /**
      * Keeps track of which animations got transferred to which animators. Entries will get cleaned
@@ -957,6 +955,9 @@
 
     final ArrayList<AppFreezeListener> mAppFreezeListeners = new ArrayList<>();
 
+    @VisibleForTesting
+    final DeviceConfig.OnPropertiesChangedListener mPropertiesChangedListener;
+
     interface AppFreezeListener {
         void onAppFreezeTimeout();
     }
@@ -1010,6 +1011,7 @@
         mGlobalLock = atm.getGlobalLock();
         mAtmService = atm;
         mContext = context;
+        mIsPc = mContext.getPackageManager().hasSystemFeature(FEATURE_PC);
         mAllowBootMessages = showBootMsgs;
         mOnlyCore = onlyCore;
         mLimitedAlphaCompositing = context.getResources().getBoolean(
@@ -1159,26 +1161,28 @@
         mSystemGestureExcludedByPreQStickyImmersive =
                 DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
                         KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE, false);
-        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
-                new HandlerExecutor(mH), properties -> {
-                    synchronized (mGlobalLock) {
-                        final int exclusionLimitDp = Math.max(MIN_GESTURE_EXCLUSION_LIMIT_DP,
-                                properties.getInt(KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP, 0));
-                        final boolean excludedByPreQSticky = DeviceConfig.getBoolean(
-                                DeviceConfig.NAMESPACE_WINDOW_MANAGER,
-                                KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE, false);
-                        if (mSystemGestureExcludedByPreQStickyImmersive != excludedByPreQSticky
-                                || mSystemGestureExclusionLimitDp != exclusionLimitDp) {
-                            mSystemGestureExclusionLimitDp = exclusionLimitDp;
-                            mSystemGestureExcludedByPreQStickyImmersive = excludedByPreQSticky;
-                            mRoot.forAllDisplays(DisplayContent::updateSystemGestureExclusionLimit);
-                        }
 
-                        mSystemGestureExclusionLogDebounceTimeoutMillis =
-                                DeviceConfig.getInt(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
-                                        KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS, 0);
-                    }
-                });
+        mPropertiesChangedListener = properties -> {
+            synchronized (mGlobalLock) {
+                final int exclusionLimitDp = Math.max(MIN_GESTURE_EXCLUSION_LIMIT_DP,
+                        properties.getInt(KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP, 0));
+                final boolean excludedByPreQSticky = DeviceConfig.getBoolean(
+                        DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+                        KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE, false);
+                if (mSystemGestureExcludedByPreQStickyImmersive != excludedByPreQSticky
+                        || mSystemGestureExclusionLimitDp != exclusionLimitDp) {
+                    mSystemGestureExclusionLimitDp = exclusionLimitDp;
+                    mSystemGestureExcludedByPreQStickyImmersive = excludedByPreQSticky;
+                    mRoot.forAllDisplays(DisplayContent::updateSystemGestureExclusionLimit);
+                }
+
+                mSystemGestureExclusionLogDebounceTimeoutMillis =
+                        DeviceConfig.getInt(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+                                KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS, 0);
+            }
+        };
+        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+                new HandlerExecutor(mH), mPropertiesChangedListener);
 
         LocalServices.addService(WindowManagerInternal.class, new LocalService());
     }
@@ -2595,7 +2599,7 @@
         mRecentsAnimationController = controller;
     }
 
-    public RecentsAnimationController getRecentsAnimationController() {
+    RecentsAnimationController getRecentsAnimationController() {
         return mRecentsAnimationController;
     }
 
@@ -2603,74 +2607,37 @@
      * @return Whether the next recents animation can continue to start. Called from
      *         {@link RecentsAnimation#startRecentsActivity}.
      */
-    public boolean canStartRecentsAnimation() {
-        synchronized (mGlobalLock) {
-            // TODO(multi-display): currently only default display support recent activity
-            if (getDefaultDisplayContentLocked().mAppTransition.isTransitionSet()) {
-                return false;
-            }
-            return true;
+    boolean canStartRecentsAnimation() {
+        // TODO(multi-display): currently only default display support recent activity
+        if (getDefaultDisplayContentLocked().mAppTransition.isTransitionSet()) {
+            return false;
         }
+        return true;
     }
 
-    /**
-     * Cancels any running recents animation. The caller should NOT hold the WM lock while calling
-     * this method, as it will call back into AM and may cause a deadlock. Any locking will be done
-     * in the animation controller itself.
-     */
-    public void cancelRecentsAnimationSynchronously(
+    void cancelRecentsAnimation(
             @RecentsAnimationController.ReorderMode int reorderMode, String reason) {
         if (mRecentsAnimationController != null) {
             // This call will call through to cleanupAnimation() below after the animation is
             // canceled
-            mRecentsAnimationController.cancelAnimationSynchronously(reorderMode, reason);
+            mRecentsAnimationController.cancelAnimation(reorderMode, reason);
         }
     }
 
-    public void cleanupRecentsAnimation(@RecentsAnimationController.ReorderMode int reorderMode) {
-        synchronized (mGlobalLock) {
-            if (mRecentsAnimationController != null) {
-                final RecentsAnimationController controller = mRecentsAnimationController;
-                mRecentsAnimationController = null;
-                controller.cleanupAnimation(reorderMode);
-                // TODO(mult-display): currently only default display support recents animation.
-                getDefaultDisplayContentLocked().mAppTransition.updateBooster();
-            }
+    void cleanupRecentsAnimation(@RecentsAnimationController.ReorderMode int reorderMode) {
+        if (mRecentsAnimationController != null) {
+            final RecentsAnimationController controller = mRecentsAnimationController;
+            mRecentsAnimationController = null;
+            controller.cleanupAnimation(reorderMode);
+            // TODO(mult-display): currently only default display support recents animation.
+            getDefaultDisplayContentLocked().mAppTransition.updateBooster();
         }
     }
 
-    public void setAppFullscreen(IBinder token, boolean toOpaque) {
-        synchronized (mGlobalLock) {
-            final AppWindowToken atoken = mRoot.getAppWindowToken(token);
-            if (atoken != null) {
-                atoken.setFillsParent(toOpaque);
-                setWindowOpaqueLocked(token, toOpaque);
-                mWindowPlacerLocked.requestTraversal();
-            }
-        }
-    }
-
-    public void setWindowOpaque(IBinder token, boolean isOpaque) {
-        synchronized (mGlobalLock) {
-            setWindowOpaqueLocked(token, isOpaque);
-        }
-    }
-
-    private void setWindowOpaqueLocked(IBinder token, boolean isOpaque) {
+    void setWindowOpaqueLocked(IBinder token, boolean isOpaque) {
         final AppWindowToken wtoken = mRoot.getAppWindowToken(token);
         if (wtoken != null) {
-            final WindowState win = wtoken.findMainWindow();
-            if (win == null) {
-                return;
-            }
-            isOpaque = isOpaque & !PixelFormat.formatHasAlpha(win.getAttrs().format);
-            win.mWinAnimator.setOpaqueLocked(isOpaque);
-        }
-    }
-
-    public void setDockedStackCreateState(int mode, Rect bounds) {
-        synchronized (mGlobalLock) {
-            setDockedStackCreateStateLocked(mode, bounds);
+            wtoken.setMainWindowOpaque(isOpaque);
         }
     }
 
@@ -2679,14 +2646,12 @@
         mDockedStackCreateBounds = bounds;
     }
 
-    public void checkSplitScreenMinimizedChanged(boolean animate) {
-        synchronized (mGlobalLock) {
-            final DisplayContent displayContent = getDefaultDisplayContentLocked();
-            displayContent.getDockedDividerController().checkMinimizeChanged(animate);
-        }
+    void checkSplitScreenMinimizedChanged(boolean animate) {
+        final DisplayContent displayContent = getDefaultDisplayContentLocked();
+        displayContent.getDockedDividerController().checkMinimizeChanged(animate);
     }
 
-    public boolean isValidPictureInPictureAspectRatio(int displayId, float aspectRatio) {
+    boolean isValidPictureInPictureAspectRatio(int displayId, float aspectRatio) {
         final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
         return displayContent.getPinnedStackController().isValidPictureInPictureAspectRatio(
                 aspectRatio);
@@ -4847,8 +4812,10 @@
                 case UPDATE_DOCKED_STACK_DIVIDER: {
                     synchronized (mGlobalLock) {
                         final DisplayContent displayContent = getDefaultDisplayContentLocked();
-                        displayContent.getDockedDividerController().reevaluateVisibility(false);
-                        displayContent.adjustForImeIfNeeded();
+                        if (displayContent != null) {
+                            displayContent.getDockedDividerController().reevaluateVisibility(false);
+                            displayContent.adjustForImeIfNeeded();
+                        }
                     }
                     break;
                 }
@@ -6495,31 +6462,14 @@
         }
     }
 
-    public void setForceResizableTasks(boolean forceResizableTasks) {
-        synchronized (mGlobalLock) {
-            mForceResizableTasks = forceResizableTasks;
-        }
-    }
-
-    public void setSupportsPictureInPicture(boolean supportsPictureInPicture) {
-        synchronized (mGlobalLock) {
-            mSupportsPictureInPicture = supportsPictureInPicture;
-        }
-    }
-
-    public void setSupportsFreeformWindowManagement(boolean supportsFreeformWindowManagement) {
-        synchronized (mGlobalLock) {
-            mSupportsFreeformWindowManagement = supportsFreeformWindowManagement;
-        }
-    }
-
     void setForceDesktopModeOnExternalDisplays(boolean forceDesktopModeOnExternalDisplays) {
         synchronized (mGlobalLock) {
             mForceDesktopModeOnExternalDisplays = forceDesktopModeOnExternalDisplays;
         }
     }
 
-    public void setIsPc(boolean isPc) {
+    @VisibleForTesting
+    void setIsPc(boolean isPc) {
         synchronized (mGlobalLock) {
             mIsPc = isPc;
         }
@@ -6546,7 +6496,7 @@
                 "registerPinnedStackListener()")) {
             return;
         }
-        if (!mSupportsPictureInPicture) {
+        if (!mAtmService.mSupportsPictureInPicture) {
             return;
         }
         synchronized (mGlobalLock) {
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 466ca93..03f4755 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -165,6 +165,7 @@
             outPointerIcon->bitmap.readPixels(bitmapCopy->info(), bitmapCopy->getPixels(),
                     bitmapCopy->rowBytes(), 0, 0);
         }
+        outSpriteIcon->style = outPointerIcon->style;
         outSpriteIcon->hotSpotX = outPointerIcon->hotSpotX;
         outSpriteIcon->hotSpotY = outPointerIcon->hotSpotY;
     }
@@ -1252,7 +1253,8 @@
     status_t status = android_view_PointerIcon_load(env, pointerIconObj.get(),
             displayContext.get(), &pointerIcon);
     if (!status && !pointerIcon.isNullIcon()) {
-        *icon = SpriteIcon(pointerIcon.bitmap, pointerIcon.hotSpotX, pointerIcon.hotSpotY);
+        *icon = SpriteIcon(
+                pointerIcon.bitmap, pointerIcon.style, pointerIcon.hotSpotX, pointerIcon.hotSpotY);
     } else {
         *icon = SpriteIcon();
     }
@@ -1293,10 +1295,12 @@
                     milliseconds_to_nanoseconds(pointerIcon.durationPerFrame);
             animationData.animationFrames.reserve(numFrames);
             animationData.animationFrames.push_back(SpriteIcon(
-                    pointerIcon.bitmap, pointerIcon.hotSpotX, pointerIcon.hotSpotY));
+                    pointerIcon.bitmap, pointerIcon.style,
+                    pointerIcon.hotSpotX, pointerIcon.hotSpotY));
             for (size_t i = 0; i < numFrames - 1; ++i) {
               animationData.animationFrames.push_back(SpriteIcon(
-                      pointerIcon.bitmapFrames[i], pointerIcon.hotSpotX, pointerIcon.hotSpotY));
+                      pointerIcon.bitmapFrames[i], pointerIcon.style,
+                      pointerIcon.hotSpotX, pointerIcon.hotSpotY));
             }
         }
     }
@@ -1711,6 +1715,7 @@
         pointerIcon.bitmap.readPixels(spriteInfo, spriteIcon.bitmap.getPixels(),
                 spriteIcon.bitmap.rowBytes(), 0, 0);
     }
+    spriteIcon.style = pointerIcon.style;
     spriteIcon.hotSpotX = pointerIcon.hotSpotX;
     spriteIcon.hotSpotY = pointerIcon.hotSpotY;
     im->setCustomPointerIcon(spriteIcon);
diff --git a/services/robotests/backup/src/com/android/server/backup/TrampolineRoboTest.java b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
similarity index 86%
rename from services/robotests/backup/src/com/android/server/backup/TrampolineRoboTest.java
rename to services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
index f0a5d37..a1bfcdf 100644
--- a/services/robotests/backup/src/com/android/server/backup/TrampolineRoboTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
@@ -26,8 +26,12 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.robolectric.Shadows.shadowOf;
 import static org.testng.Assert.expectThrows;
@@ -72,7 +76,7 @@
 import java.io.PrintWriter;
 import java.io.StringWriter;
 
-/** Tests for {@link com.android.server.backup.Trampoline}. */
+/** Tests for {@link BackupManagerService}. */
 @RunWith(RobolectricTestRunner.class)
 @Config(
         shadows = {
@@ -83,7 +87,7 @@
                 ShadowSystemServiceRegistry.class
         })
 @Presubmit
-public class TrampolineRoboTest {
+public class BackupManagerServiceRoboTest {
     private static final String TEST_PACKAGE = "package";
     private static final String TEST_TRANSPORT = "transport";
     private static final String[] ADB_TEST_PACKAGES = {TEST_PACKAGE};
@@ -121,7 +125,7 @@
     /** Test that the service registers users. */
     @Test
     public void testStartServiceForUser_registersUser() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         backupManagerService.setBackupServiceActive(mUserOneId, true);
 
         backupManagerService.startServiceForUser(mUserOneId);
@@ -134,7 +138,7 @@
     /** Test that the service registers users. */
     @Test
     public void testStartServiceForUser_withServiceInstance_registersUser() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         backupManagerService.setBackupServiceActive(mUserOneId, true);
 
         backupManagerService.startServiceForUser(mUserOneId, mUserOneService);
@@ -147,7 +151,7 @@
     /** Test that the service unregisters users when stopped. */
     @Test
     public void testStopServiceForUser_forRegisteredUser_unregistersCorrectUser() throws Exception {
-        Trampoline backupManagerService =
+        BackupManagerService backupManagerService =
                 createServiceAndRegisterUser(mUserOneId, mUserOneService);
         backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService);
         ShadowBinder.setCallingUid(Process.SYSTEM_UID);
@@ -163,7 +167,7 @@
     /** Test that the service unregisters users when stopped. */
     @Test
     public void testStopServiceForUser_forRegisteredUser_tearsDownCorrectUser() throws Exception {
-        Trampoline backupManagerService =
+        BackupManagerService backupManagerService =
                 createServiceAndRegisterUser(mUserOneId, mUserOneService);
         backupManagerService.setBackupServiceActive(mUserTwoId, true);
         backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService);
@@ -177,7 +181,7 @@
     /** Test that the service unregisters users when stopped. */
     @Test
     public void testStopServiceForUser_forUnknownUser_doesNothing() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         backupManagerService.setBackupServiceActive(mUserOneId, true);
         ShadowBinder.setCallingUid(Process.SYSTEM_UID);
 
@@ -194,7 +198,7 @@
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
     public void testDataChanged_onRegisteredUser_callsMethodForUser() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
@@ -206,7 +210,7 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testDataChanged_onUnknownUser_doesNotPropagateCall() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
@@ -218,7 +222,7 @@
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
     public void testAgentConnected_onRegisteredUser_callsMethodForUser() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
         IBinder agentBinder = mock(IBinder.class);
@@ -231,7 +235,7 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testAgentConnected_onUnknownUser_doesNotPropagateCall() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
         IBinder agentBinder = mock(IBinder.class);
@@ -244,7 +248,7 @@
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
     public void testOpComplete_onRegisteredUser_callsMethodForUser() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
@@ -256,7 +260,7 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testOpComplete_onUnknownUser_doesNotPropagateCall() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
@@ -272,7 +276,7 @@
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
     public void testInitializeTransports_onRegisteredUser_callsMethodForUser() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
         String[] transports = {TEST_TRANSPORT};
@@ -285,7 +289,7 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testInitializeTransports_onUnknownUser_doesNotPropagateCall() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
         String[] transports = {TEST_TRANSPORT};
@@ -298,7 +302,7 @@
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
     public void testClearBackupData_onRegisteredUser_callsMethodForUser() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
@@ -310,7 +314,7 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testClearBackupData_onUnknownUser_doesNotPropagateCall() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
@@ -322,7 +326,7 @@
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
     public void testGetCurrentTransport_onRegisteredUser_callsMethodForUser() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
@@ -334,7 +338,7 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testGetCurrentTransport_onUnknownUser_doesNotPropagateCall() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
@@ -347,7 +351,7 @@
     @Test
     public void testGetCurrentTransportComponent_onRegisteredUser_callsMethodForUser()
             throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
@@ -360,7 +364,7 @@
     @Test
     public void testGetCurrentTransportComponent_onUnknownUser_doesNotPropagateCall()
             throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
@@ -372,7 +376,7 @@
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
     public void testListAllTransports_onRegisteredUser_callsMethodForUser() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
@@ -384,7 +388,7 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testListAllTransports_onUnknownUser_doesNotPropagateCall() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
@@ -397,7 +401,7 @@
     @Test
     public void testListAllTransportComponents_onRegisteredUser_callsMethodForUser()
             throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
@@ -410,7 +414,7 @@
     @Test
     public void testListAllTransportComponents_onUnknownUser_doesNotPropagateCall()
             throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
@@ -422,7 +426,7 @@
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
     public void testSelectBackupTransport_onRegisteredUser_callsMethodForUser() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
@@ -434,7 +438,7 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testSelectBackupTransport_onUnknownUser_doesNotPropagateCall() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
@@ -446,7 +450,7 @@
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
     public void testSelectTransportAsync_onRegisteredUser_callsMethodForUser() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
         TransportData transport = backupTransport();
@@ -463,7 +467,7 @@
     @Test
     public void testSelectBackupTransportAsync_onUnknownUser_doesNotPropagateCall()
             throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
         TransportData transport = backupTransport();
@@ -479,7 +483,7 @@
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
     public void testGetConfigurationIntent_onRegisteredUser_callsMethodForUser() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
@@ -491,7 +495,7 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testGetConfigurationIntent_onUnknownUser_doesNotPropagateCall() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
@@ -503,7 +507,7 @@
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
     public void testGetDestinationString_onRegisteredUser_callsMethodForUser() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
@@ -515,7 +519,7 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testGetDestinationString_onUnknownUser_doesNotPropagateCall() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
@@ -527,7 +531,7 @@
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
     public void testGetDataManagementIntent_onRegisteredUser_callsMethodForUser() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
@@ -539,7 +543,7 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testGetDataManagementIntent_onUnknownUser_doesNotPropagateCall() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
@@ -551,7 +555,7 @@
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
     public void testGetDataManagementLabel_onRegisteredUser_callsMethodForUser() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
@@ -563,7 +567,7 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testGetDataManagementLabel_onUnknownUser_doesNotPropagateCall() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
@@ -576,7 +580,7 @@
     @Test
     public void testUpdateTransportAttributes_onRegisteredUser_callsMethodForUser()
             throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
         TransportData transport = backupTransport();
@@ -606,7 +610,7 @@
     @Test
     public void testUpdateTransportAttributes_onUnknownUser_doesNotPropagateCall()
             throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
         TransportData transport = backupTransport();
@@ -642,7 +646,7 @@
      */
     @Test
     public void testSetBackupEnabled_withoutPermission_throwsSecurityExceptionForNonCallingUser() {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
@@ -657,7 +661,7 @@
      */
     @Test
     public void testSetBackupEnabled_withPermission_propagatesForNonCallingUser() {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         registerUser(backupManagerService, mUserTwoId, mUserTwoService);
 
@@ -671,7 +675,7 @@
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
     public void testSetBackupEnabled_onRegisteredUser_callsMethodForUser() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
@@ -683,7 +687,7 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testSetBackupEnabled_onUnknownUser_doesNotPropagateCall() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
@@ -695,7 +699,7 @@
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
     public void testSetAutoRestore_onRegisteredUser_callsMethodForUser() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
@@ -707,7 +711,7 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testSetAutoRestore_onUnknownUser_doesNotPropagateCall() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
@@ -719,7 +723,7 @@
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
     public void testIsBackupEnabled_onRegisteredUser_callsMethodForUser() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
@@ -731,7 +735,7 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testIsBackupEnabled_onUnknownUser_doesNotPropagateCall() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
@@ -747,7 +751,7 @@
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
     public void testIsAppEligibleForBackup_onRegisteredUser_callsMethodForUser() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
@@ -759,7 +763,7 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testIsAppEligibleForBackup_onUnknownUser_doesNotPropagateCall() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
@@ -772,7 +776,7 @@
     @Test
     public void testFilterAppsEligibleForBackup_onRegisteredUser_callsMethodForUser()
             throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
         String[] packages = {TEST_PACKAGE};
@@ -786,7 +790,7 @@
     @Test
     public void testFilterAppsEligibleForBackup_onUnknownUser_doesNotPropagateCall()
             throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
         String[] packages = {TEST_PACKAGE};
@@ -802,7 +806,7 @@
      */
     @Test
     public void testBackupNow_withoutPermission_throwsSecurityExceptionForNonCallingUser() {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
@@ -815,7 +819,7 @@
      */
     @Test
     public void testBackupNow_withPermission_propagatesForNonCallingUser() {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         registerUser(backupManagerService, mUserTwoId, mUserTwoService);
 
@@ -829,7 +833,7 @@
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
     public void testBackupNow_onRegisteredUser_callsMethodForUser() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
@@ -841,7 +845,7 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testBackupNow_onUnknownUser_doesNotPropagateCall() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
@@ -856,7 +860,7 @@
      */
     @Test
     public void testRequestBackup_withoutPermission_throwsSecurityExceptionForNonCallingUser() {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
         String[] packages = {TEST_PACKAGE};
@@ -876,7 +880,7 @@
      */
     @Test
     public void testRequestBackup_withPermission_propagatesForNonCallingUser() {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         registerUser(backupManagerService, mUserTwoId, mUserTwoService);
 
@@ -893,7 +897,7 @@
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
     public void testRequestBackup_onRegisteredUser_callsMethodForUser() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         String[] packages = {TEST_PACKAGE};
         IBackupObserver observer = mock(IBackupObserver.class);
@@ -908,7 +912,7 @@
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
     public void testRequestBackup_onUnknownUser_doesNotPropagateCall() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         String[] packages = {TEST_PACKAGE};
         IBackupObserver observer = mock(IBackupObserver.class);
@@ -926,7 +930,7 @@
      */
     @Test
     public void testCancelBackups_withoutPermission_throwsSecurityExceptionForNonCallingUser() {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
@@ -939,7 +943,7 @@
      */
     @Test
     public void testCancelBackups_withPermission_propagatesForNonCallingUser() {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         registerUser(backupManagerService, mUserTwoId, mUserTwoService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ true);
@@ -952,7 +956,7 @@
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
     public void testCancelBackups_onRegisteredUser_callsMethodForUser() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
@@ -964,7 +968,7 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testCancelBackups_onUnknownUser_doesNotPropagateCall() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
@@ -976,7 +980,7 @@
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
     public void testBeginFullBackup_onRegisteredUser_callsMethodForUser() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, UserHandle.USER_SYSTEM, mUserOneService);
         FullBackupJob job = new FullBackupJob();
 
@@ -988,7 +992,7 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testBeginFullBackup_onUnknownUser_doesNotPropagateCall() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         FullBackupJob job = new FullBackupJob();
 
         backupManagerService.beginFullBackup(UserHandle.USER_SYSTEM, job);
@@ -999,7 +1003,7 @@
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
     public void testEndFullBackup_onRegisteredUser_callsMethodForUser() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, UserHandle.USER_SYSTEM, mUserOneService);
 
         backupManagerService.endFullBackup(UserHandle.USER_SYSTEM);
@@ -1010,7 +1014,7 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testEndFullBackup_onUnknownUser_doesNotPropagateCall() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
 
         backupManagerService.endFullBackup(UserHandle.USER_SYSTEM);
 
@@ -1020,7 +1024,7 @@
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
     public void testFullTransportBackup_onRegisteredUser_callsMethodForUser() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
         String[] packages = {TEST_PACKAGE};
@@ -1033,7 +1037,7 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testFullTransportBackup_onUnknownUser_doesNotPropagateCall() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
         String[] packages = {TEST_PACKAGE};
@@ -1050,7 +1054,7 @@
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
     public void testRestoreAtInstall_onRegisteredUser_callsMethodForUser() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
@@ -1062,7 +1066,7 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testRestoreAtInstall_onUnknownUser_doesNotPropagateCall() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
@@ -1074,7 +1078,7 @@
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
     public void testBeginRestoreSession_onRegisteredUser_callsMethodForUser() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
@@ -1086,7 +1090,7 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testBeginRestoreSession_onUnknownUser_doesNotPropagateCall() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
@@ -1099,7 +1103,7 @@
     @Test
     public void testGetAvailableRestoreToken_onRegisteredUser_callsMethodForUser()
             throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
@@ -1111,7 +1115,7 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testGetAvailableRestoreToken_onUnknownUser_doesNotPropagateCall() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
@@ -1127,7 +1131,7 @@
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
     public void testSetBackupPassword_onRegisteredUser_callsMethodForUser() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, UserHandle.USER_SYSTEM, mUserOneService);
         ShadowBinder.setCallingUserHandle(UserHandle.of(UserHandle.USER_SYSTEM));
 
@@ -1139,7 +1143,7 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testSetBackupPassword_onUnknownUser_doesNotPropagateCall() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
 
         backupManagerService.setBackupPassword("currentPassword", "newPassword");
 
@@ -1149,7 +1153,7 @@
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
     public void testHasBackupPassword_onRegisteredUser_callsMethodForUser() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, UserHandle.USER_SYSTEM, mUserOneService);
         ShadowBinder.setCallingUserHandle(UserHandle.of(UserHandle.USER_SYSTEM));
 
@@ -1161,7 +1165,7 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testHasBackupPassword_onUnknownUser_doesNotPropagateCall() throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
 
         backupManagerService.hasBackupPassword();
 
@@ -1174,7 +1178,7 @@
      */
     @Test
     public void testAdbBackup_withoutPermission_throwsSecurityExceptionForNonCallingUser() {
-        Trampoline backupManagerService = createSystemRegisteredService();
+        BackupManagerService backupManagerService = createSystemRegisteredService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         registerUser(backupManagerService, mUserTwoId, mUserTwoService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
@@ -1202,7 +1206,7 @@
      */
     @Test
     public void testAdbBackup_withPermission_propagatesForNonCallingUser() throws Exception {
-        Trampoline backupManagerService = createSystemRegisteredService();
+        BackupManagerService backupManagerService = createSystemRegisteredService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         registerUser(backupManagerService, mUserTwoId, mUserTwoService);
 
@@ -1239,7 +1243,7 @@
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
     public void testAdbBackup_onRegisteredUser_callsMethodForUser() throws Exception {
-        Trampoline backupManagerService = createSystemRegisteredService();
+        BackupManagerService backupManagerService = createSystemRegisteredService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         ParcelFileDescriptor parcelFileDescriptor = getFileDescriptorForAdbTest();
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
@@ -1274,7 +1278,7 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testAdbBackup_onUnknownUser_doesNotPropagateCall() throws Exception {
-        Trampoline backupManagerService = createSystemRegisteredService();
+        BackupManagerService backupManagerService = createSystemRegisteredService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         ParcelFileDescriptor parcelFileDescriptor = getFileDescriptorForAdbTest();
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
@@ -1312,7 +1316,7 @@
      */
     @Test
     public void testAdbRestore_withoutPermission_throwsSecurityExceptionForNonCallingUser() {
-        Trampoline backupManagerService = createSystemRegisteredService();
+        BackupManagerService backupManagerService = createSystemRegisteredService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         registerUser(backupManagerService, mUserTwoId, mUserTwoService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
@@ -1327,7 +1331,7 @@
      */
     @Test
     public void testAdbRestore_withPermission_propagatesForNonCallingUser() throws Exception {
-        Trampoline backupManagerService = createSystemRegisteredService();
+        BackupManagerService backupManagerService = createSystemRegisteredService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         registerUser(backupManagerService, mUserTwoId, mUserTwoService);
         ParcelFileDescriptor parcelFileDescriptor = getFileDescriptorForAdbTest();
@@ -1341,7 +1345,7 @@
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
     public void testAdbRestore_onRegisteredUser_callsMethodForUser() throws Exception {
-        Trampoline backupManagerService = createSystemRegisteredService();
+        BackupManagerService backupManagerService = createSystemRegisteredService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         ParcelFileDescriptor parcelFileDescriptor = getFileDescriptorForAdbTest();
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
@@ -1354,7 +1358,7 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testAdbRestore_onUnknownUser_doesNotPropagateCall() throws Exception {
-        Trampoline backupManagerService = createSystemRegisteredService();
+        BackupManagerService backupManagerService = createSystemRegisteredService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         ParcelFileDescriptor parcelFileDescriptor = getFileDescriptorForAdbTest();
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
@@ -1374,7 +1378,7 @@
     @Test
     public void testAcknowledgeAdbBackupOrRestore_onRegisteredUser_callsMethodForUser()
             throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
         IFullBackupRestoreObserver observer = mock(IFullBackupRestoreObserver.class);
@@ -1400,7 +1404,7 @@
     @Test
     public void testAcknowledgeAdbBackupOrRestore_onUnknownUser_doesNotPropagateCall()
             throws Exception {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
         IFullBackupRestoreObserver observer = mock(IFullBackupRestoreObserver.class);
@@ -1430,7 +1434,7 @@
     @Test
     public void testDump_onRegisteredUser_callsMethodForUser() throws Exception {
         grantDumpPermissions();
-        Trampoline backupManagerService = createSystemRegisteredService();
+        BackupManagerService backupManagerService = createSystemRegisteredService();
         File testFile = createTestFile();
         FileDescriptor fileDescriptor = new FileDescriptor();
         PrintWriter printWriter = new PrintWriter(testFile);
@@ -1446,7 +1450,7 @@
     @Test
     public void testDump_onUnknownUser_doesNotPropagateCall() throws Exception {
         grantDumpPermissions();
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         File testFile = createTestFile();
         FileDescriptor fileDescriptor = new FileDescriptor();
         PrintWriter printWriter = new PrintWriter(testFile);
@@ -1461,7 +1465,7 @@
     @Test
     public void testDump_users_dumpsListOfRegisteredUsers() {
         grantDumpPermissions();
-        Trampoline backupManagerService = createSystemRegisteredService();
+        BackupManagerService backupManagerService = createSystemRegisteredService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         StringWriter out = new StringWriter();
         PrintWriter writer = new PrintWriter(out);
@@ -1471,7 +1475,7 @@
 
         writer.flush();
         assertEquals(
-                String.format("%s %d %d\n", Trampoline.DUMP_RUNNING_USERS_MESSAGE,
+                String.format("%s %d %d\n", BackupManagerService.DUMP_RUNNING_USERS_MESSAGE,
                         UserHandle.USER_SYSTEM, mUserOneId),
                 out.toString());
     }
@@ -1493,7 +1497,7 @@
      */
     @Test
     public void testGetServiceForUser_withoutPermission_throwsSecurityExceptionForNonCallingUser() {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
@@ -1510,7 +1514,7 @@
      */
     @Test
     public void testGetServiceForUserIfCallerHasPermission_withPermission_worksForNonCallingUser() {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ true);
 
@@ -1525,7 +1529,7 @@
      */
     @Test
     public void testGetServiceForUserIfCallerHasPermission_withoutPermission_worksForCallingUser() {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
@@ -1534,25 +1538,98 @@
                 backupManagerService.getServiceForUserIfCallerHasPermission(mUserOneId, "test"));
     }
 
-    private Trampoline createService() {
-        return new Trampoline(mContext);
+    /**
+     * Test verifying that {@link BackupManagerService#MORE_DEBUG} is set to {@code false}. This is
+     * specifically to prevent overloading the logs in production.
+     */
+    @Test
+    public void testMoreDebug_isFalse() throws Exception {
+        boolean moreDebug = BackupManagerService.MORE_DEBUG;
+
+        assertThat(moreDebug).isFalse();
     }
 
-    private Trampoline createSystemRegisteredService() {
-        Trampoline trampoline = createService();
-        registerUser(trampoline, UserHandle.USER_SYSTEM, mUserSystemService);
-        return trampoline;
+    /** Test that the constructor handles {@code null} parameters. */
+    @Test
+    public void testConstructor_withNullContext_throws() throws Exception {
+        expectThrows(
+                NullPointerException.class,
+                () ->
+                        new BackupManagerService(
+                                /* context */ null,
+                                new SparseArray<>()));
+    }
+
+    /** Test that the constructor does not create {@link UserBackupManagerService} instances. */
+    @Test
+    public void testConstructor_doesNotRegisterUsers() throws Exception {
+        BackupManagerService backupManagerService = createService();
+
+        assertThat(backupManagerService.getUserServices().size()).isEqualTo(0);
+    }
+
+    // ---------------------------------------------
+    //  Lifecycle tests
+    // ---------------------------------------------
+
+    /** testOnStart_publishesService */
+    @Test
+    public void testOnStart_publishesService() {
+        BackupManagerService backupManagerService = mock(BackupManagerService.class);
+        BackupManagerService.Lifecycle lifecycle =
+                spy(new BackupManagerService.Lifecycle(mContext, backupManagerService));
+        doNothing().when(lifecycle).publishService(anyString(), any());
+
+        lifecycle.onStart();
+
+        verify(lifecycle).publishService(Context.BACKUP_SERVICE, backupManagerService);
+    }
+
+    /** testOnUnlockUser_forwards */
+    @Test
+    public void testOnUnlockUser_forwards() {
+        BackupManagerService backupManagerService = mock(BackupManagerService.class);
+        BackupManagerService.Lifecycle lifecycle =
+                new BackupManagerService.Lifecycle(mContext, backupManagerService);
+
+        lifecycle.onUnlockUser(UserHandle.USER_SYSTEM);
+
+        verify(backupManagerService).onUnlockUser(UserHandle.USER_SYSTEM);
+    }
+
+    /** testOnStopUser_forwards */
+    @Test
+    public void testOnStopUser_forwards() {
+        BackupManagerService backupManagerService = mock(BackupManagerService.class);
+        BackupManagerService.Lifecycle lifecycle =
+                new BackupManagerService.Lifecycle(mContext, backupManagerService);
+
+        lifecycle.onStopUser(UserHandle.USER_SYSTEM);
+
+        verify(backupManagerService).onStopUser(UserHandle.USER_SYSTEM);
+    }
+
+    private BackupManagerService createService() {
+        return new BackupManagerService(mContext);
+    }
+
+    private BackupManagerService createSystemRegisteredService() {
+        BackupManagerService backupManagerService = createService();
+        registerUser(backupManagerService, UserHandle.USER_SYSTEM, mUserSystemService);
+        return backupManagerService;
     }
 
     private void registerUser(
-            Trampoline trampoline, int userId, UserBackupManagerService userBackupManagerService) {
-        trampoline.setBackupServiceActive(userId, true);
-        trampoline.startServiceForUser(userId, userBackupManagerService);
+            BackupManagerService backupManagerService,
+            int userId,
+            UserBackupManagerService userBackupManagerService) {
+        backupManagerService.setBackupServiceActive(userId, true);
+        backupManagerService.startServiceForUser(userId, userBackupManagerService);
     }
 
-    private Trampoline createServiceAndRegisterUser(
+    private BackupManagerService createServiceAndRegisterUser(
             int userId, UserBackupManagerService userBackupManagerService) {
-        Trampoline backupManagerService = createService();
+        BackupManagerService backupManagerService = createService();
         backupManagerService.setBackupServiceActive(userBackupManagerService.getUserId(), true);
         backupManagerService.startServiceForUser(userId, userBackupManagerService);
         return backupManagerService;
diff --git a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
deleted file mode 100644
index a034474..0000000
--- a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
+++ /dev/null
@@ -1,231 +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.server.backup;
-
-import static android.Manifest.permission.BACKUP;
-import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.robolectric.Shadows.shadowOf;
-import static org.testng.Assert.expectThrows;
-
-import android.annotation.UserIdInt;
-import android.app.Application;
-import android.content.Context;
-import android.os.ParcelFileDescriptor;
-import android.os.Process;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.platform.test.annotations.Presubmit;
-import android.util.SparseArray;
-
-import com.android.server.testing.shadows.ShadowApplicationPackageManager;
-import com.android.server.testing.shadows.ShadowBinder;
-import com.android.server.testing.shadows.ShadowEnvironment;
-import com.android.server.testing.shadows.ShadowSystemServiceRegistry;
-import com.android.server.testing.shadows.ShadowUserManager;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-import org.robolectric.shadow.api.Shadow;
-import org.robolectric.shadows.ShadowContextWrapper;
-
-import java.io.File;
-
-/** Tests for the user-aware backup/restore system service {@link BackupManagerService}. */
-@RunWith(RobolectricTestRunner.class)
-@Config(
-        shadows = {
-            ShadowApplicationPackageManager.class,
-            ShadowBinder.class,
-            ShadowEnvironment.class,
-            ShadowSystemServiceRegistry.class,
-            ShadowUserManager.class,
-        })
-@Presubmit
-public class BackupManagerServiceTest {
-    private static final String TEST_PACKAGE = "package";
-    private static final String TEST_TRANSPORT = "transport";
-    private static final String[] ADB_TEST_PACKAGES = {TEST_PACKAGE};
-
-    private ShadowContextWrapper mShadowContext;
-    private ShadowUserManager mShadowUserManager;
-    private Context mContext;
-    private Trampoline mTrampoline;
-    @UserIdInt private int mUserOneId;
-    @UserIdInt private int mUserTwoId;
-    @Mock private UserBackupManagerService mUserOneService;
-    @Mock private UserBackupManagerService mUserTwoService;
-
-    /** Initialize {@link BackupManagerService}. */
-    @Before
-    public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-
-        Application application = RuntimeEnvironment.application;
-        mContext = application;
-        mShadowContext = shadowOf(application);
-        mShadowUserManager = Shadow.extract(UserManager.get(application));
-
-        mUserOneId = UserHandle.USER_SYSTEM + 1;
-        mUserTwoId = mUserOneId + 1;
-        mShadowUserManager.addUser(mUserOneId, "mUserOneId", 0);
-        mShadowUserManager.addUser(mUserTwoId, "mUserTwoId", 0);
-
-        mShadowContext.grantPermissions(BACKUP);
-        mShadowContext.grantPermissions(INTERACT_ACROSS_USERS_FULL);
-
-        mTrampoline = new Trampoline(mContext);
-        ShadowBinder.setCallingUid(Process.SYSTEM_UID);
-    }
-
-    /**
-     * Clean up and reset state that was created for testing {@link BackupManagerService}
-     * operations.
-     */
-    @After
-    public void tearDown() throws Exception {
-        ShadowBinder.reset();
-    }
-
-    /**
-     * Test verifying that {@link BackupManagerService#MORE_DEBUG} is set to {@code false}. This is
-     * specifically to prevent overloading the logs in production.
-     */
-    @Test
-    public void testMoreDebug_isFalse() throws Exception {
-        boolean moreDebug = BackupManagerService.MORE_DEBUG;
-
-        assertThat(moreDebug).isFalse();
-    }
-
-    /** Test that the constructor does not create {@link UserBackupManagerService} instances. */
-    @Test
-    public void testConstructor_doesNotRegisterUsers() throws Exception {
-        BackupManagerService backupManagerService = createService();
-
-        assertThat(mTrampoline.getUserServices().size()).isEqualTo(0);
-    }
-
-    /** Test that the constructor handles {@code null} parameters. */
-    @Test
-    public void testConstructor_withNullContext_throws() throws Exception {
-        expectThrows(
-                NullPointerException.class,
-                () ->
-                        new BackupManagerService(
-                                /* context */ null,
-                                new Trampoline(mContext),
-                                new SparseArray<>()));
-    }
-
-    /** Test that the constructor handles {@code null} parameters. */
-    @Test
-    public void testConstructor_withNullTrampoline_throws() throws Exception {
-        expectThrows(
-                NullPointerException.class,
-                () ->
-                        new BackupManagerService(
-                                mContext, /* trampoline */ null, new SparseArray<>()));
-    }
-
-    // ---------------------------------------------
-    //  Lifecycle tests
-    // ---------------------------------------------
-
-    /** testOnStart_publishesService */
-    @Test
-    public void testOnStart_publishesService() {
-        Trampoline trampoline = mock(Trampoline.class);
-        BackupManagerService.Lifecycle lifecycle =
-                spy(new BackupManagerService.Lifecycle(mContext, trampoline));
-        doNothing().when(lifecycle).publishService(anyString(), any());
-
-        lifecycle.onStart();
-
-        verify(lifecycle).publishService(Context.BACKUP_SERVICE, trampoline);
-    }
-
-    /** testOnUnlockUser_forwards */
-    @Test
-    public void testOnUnlockUser_forwards() {
-        Trampoline trampoline = mock(Trampoline.class);
-        BackupManagerService.Lifecycle lifecycle =
-                new BackupManagerService.Lifecycle(mContext, trampoline);
-
-        lifecycle.onUnlockUser(UserHandle.USER_SYSTEM);
-
-        verify(trampoline).onUnlockUser(UserHandle.USER_SYSTEM);
-    }
-
-    /** testOnStopUser_forwards */
-    @Test
-    public void testOnStopUser_forwards() {
-        Trampoline trampoline = mock(Trampoline.class);
-        BackupManagerService.Lifecycle lifecycle =
-                new BackupManagerService.Lifecycle(mContext, trampoline);
-
-        lifecycle.onStopUser(UserHandle.USER_SYSTEM);
-
-        verify(trampoline).onStopUser(UserHandle.USER_SYSTEM);
-    }
-
-    private BackupManagerService createService() {
-        mShadowContext.grantPermissions(BACKUP);
-        return new BackupManagerService(mContext, mTrampoline, mTrampoline.getUserServices());
-    }
-
-    private void registerUser(int userId, UserBackupManagerService userBackupManagerService) {
-        mTrampoline.setBackupServiceActive(userId, true);
-        mTrampoline.startServiceForUser(userId, userBackupManagerService);
-    }
-
-    /**
-     * Sets the calling user to {@code userId} and grants the permission INTERACT_ACROSS_USERS_FULL
-     * to the caller if {@code shouldGrantPermission} is {@code true}, else it denies the
-     * permission.
-     */
-    private void setCallerAndGrantInteractUserPermission(
-            @UserIdInt int userId, boolean shouldGrantPermission) {
-        ShadowBinder.setCallingUserHandle(UserHandle.of(userId));
-        if (shouldGrantPermission) {
-            mShadowContext.grantPermissions(INTERACT_ACROSS_USERS_FULL);
-        } else {
-            mShadowContext.denyPermissions(INTERACT_ACROSS_USERS_FULL);
-        }
-    }
-
-    private ParcelFileDescriptor getFileDescriptorForAdbTest() throws Exception {
-        File testFile = new File(mContext.getFilesDir(), "test");
-        testFile.createNewFile();
-        return ParcelFileDescriptor.open(testFile, ParcelFileDescriptor.MODE_READ_WRITE);
-    }
-}
diff --git a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
index 84e810d..8632ca4 100644
--- a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
@@ -1005,7 +1005,7 @@
         UserBackupManagerService.createAndInitializeService(
                 USER_ID,
                 mContext,
-                new Trampoline(mContext),
+                new BackupManagerService(mContext),
                 mBackupThread,
                 mBaseStateDir,
                 mDataDir,
@@ -1026,7 +1026,7 @@
         UserBackupManagerService.createAndInitializeService(
                 USER_ID,
                 mContext,
-                new Trampoline(mContext),
+                new BackupManagerService(mContext),
                 mBackupThread,
                 mBaseStateDir,
                 mDataDir,
@@ -1045,7 +1045,7 @@
                         UserBackupManagerService.createAndInitializeService(
                                 USER_ID,
                                 /* context */ null,
-                                new Trampoline(mContext),
+                                new BackupManagerService(mContext),
                                 mBackupThread,
                                 mBaseStateDir,
                                 mDataDir,
@@ -1077,7 +1077,7 @@
                         UserBackupManagerService.createAndInitializeService(
                                 USER_ID,
                                 mContext,
-                                new Trampoline(mContext),
+                                new BackupManagerService(mContext),
                                 /* backupThread */ null,
                                 mBaseStateDir,
                                 mDataDir,
@@ -1093,7 +1093,7 @@
                         UserBackupManagerService.createAndInitializeService(
                                 USER_ID,
                                 mContext,
-                                new Trampoline(mContext),
+                                new BackupManagerService(mContext),
                                 mBackupThread,
                                 /* baseStateDir */ null,
                                 mDataDir,
@@ -1102,8 +1102,8 @@
 
     /**
      * Test checking non-null argument on {@link
-     * UserBackupManagerService#createAndInitializeService(int, Context, Trampoline, HandlerThread,
-     * File, File, TransportManager)}.
+     * UserBackupManagerService#createAndInitializeService(int, Context, BackupManagerService,
+     * HandlerThread, File, File, TransportManager)}.
      */
     @Test
     public void testCreateAndInitializeService_withNullDataDir_throws() {
@@ -1113,7 +1113,7 @@
                         UserBackupManagerService.createAndInitializeService(
                                 USER_ID,
                                 mContext,
-                                new Trampoline(mContext),
+                                new BackupManagerService(mContext),
                                 mBackupThread,
                                 mBaseStateDir,
                                 /* dataDir */ null,
@@ -1122,8 +1122,8 @@
 
     /**
      * Test checking non-null argument on {@link
-     * UserBackupManagerService#createAndInitializeService(int, Context, Trampoline, HandlerThread,
-     * File, File, TransportManager)}.
+     * UserBackupManagerService#createAndInitializeService(int, Context, BackupManagerService,
+     * HandlerThread, File, File, TransportManager)}.
      */
     @Test
     public void testCreateAndInitializeService_withNullTransportManager_throws() {
@@ -1133,7 +1133,7 @@
                         UserBackupManagerService.createAndInitializeService(
                                 USER_ID,
                                 mContext,
-                                new Trampoline(mContext),
+                                new BackupManagerService(mContext),
                                 mBackupThread,
                                 mBaseStateDir,
                                 mDataDir,
@@ -1151,7 +1151,7 @@
         UserBackupManagerService service = UserBackupManagerService.createAndInitializeService(
                 USER_ID,
                 contextSpy,
-                new Trampoline(mContext),
+                new BackupManagerService(mContext),
                 mBackupThread,
                 mBaseStateDir,
                 mDataDir,
diff --git a/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java b/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java
index 392d182..84421ef 100644
--- a/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java
+++ b/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java
@@ -37,7 +37,7 @@
 import android.util.Log;
 
 import com.android.server.backup.BackupAgentTimeoutParameters;
-import com.android.server.backup.Trampoline;
+import com.android.server.backup.BackupManagerService;
 import com.android.server.backup.TransportManager;
 import com.android.server.backup.UserBackupManagerService;
 
@@ -89,7 +89,7 @@
                 UserBackupManagerService.createAndInitializeService(
                         userId,
                         context,
-                        new Trampoline(context),
+                        new BackupManagerService(context),
                         backupThread,
                         baseStateDir,
                         dataDir,
diff --git a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java b/services/tests/servicestests/src/com/android/server/backup/BackupManagerServiceTest.java
similarity index 63%
rename from services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
rename to services/tests/servicestests/src/com/android/server/backup/BackupManagerServiceTest.java
index 848ef45..68b413f 100644
--- a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/BackupManagerServiceTest.java
@@ -11,7 +11,7 @@
  * 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
+ * limitations under the License.
  */
 
 package com.android.server.backup;
@@ -76,7 +76,7 @@
 @SmallTest
 @Presubmit
 @RunWith(AndroidJUnit4.class)
-public class TrampolineTest {
+public class BackupManagerServiceTest {
     private static final String PACKAGE_NAME = "some.package.name";
     private static final String TRANSPORT_NAME = "some.transport.name";
     private static final String CURRENT_PASSWORD = "current_password";
@@ -100,8 +100,6 @@
     @UserIdInt
     private int mUserId;
     @Mock
-    private BackupManagerService mBackupManagerServiceMock;
-    @Mock
     private UserBackupManagerService mUserBackupManagerService;
     @Mock
     private Context mContextMock;
@@ -124,7 +122,7 @@
 
     private FileDescriptor mFileDescriptorStub = new FileDescriptor();
 
-    private TrampolineTestable mTrampoline;
+    private BackupManagerServiceTestable mService;
     private File mTestDir;
     private File mSuppressFile;
     private SparseArray<UserBackupManagerService> mUserServices;
@@ -142,38 +140,37 @@
         when(mUserManagerMock.getUserInfo(NON_USER_SYSTEM)).thenReturn(mUserInfoMock);
         when(mUserManagerMock.getUserInfo(UNSTARTED_NON_USER_SYSTEM)).thenReturn(mUserInfoMock);
 
-        TrampolineTestable.sBackupManagerServiceMock = mBackupManagerServiceMock;
-        TrampolineTestable.sCallingUserId = UserHandle.USER_SYSTEM;
-        TrampolineTestable.sCallingUid = Process.SYSTEM_UID;
-        TrampolineTestable.sBackupDisabled = false;
-        TrampolineTestable.sUserManagerMock = mUserManagerMock;
+        BackupManagerServiceTestable.sCallingUserId = UserHandle.USER_SYSTEM;
+        BackupManagerServiceTestable.sCallingUid = Process.SYSTEM_UID;
+        BackupManagerServiceTestable.sBackupDisabled = false;
+        BackupManagerServiceTestable.sUserManagerMock = mUserManagerMock;
 
         mTestDir = InstrumentationRegistry.getContext().getFilesDir();
         mTestDir.mkdirs();
 
         mSuppressFile = new File(mTestDir, "suppress");
-        TrampolineTestable.sSuppressFile = mSuppressFile;
+        BackupManagerServiceTestable.sSuppressFile = mSuppressFile;
 
         setUpStateFilesForNonSystemUser(NON_USER_SYSTEM);
         setUpStateFilesForNonSystemUser(UNSTARTED_NON_USER_SYSTEM);
 
         when(mContextMock.getSystemService(Context.JOB_SCHEDULER_SERVICE))
                 .thenReturn(mock(JobScheduler.class));
-        mTrampoline = new TrampolineTestable(mContextMock, mUserServices);
+        mService = new BackupManagerServiceTestable(mContextMock, mUserServices);
     }
 
     private void setUpStateFilesForNonSystemUser(int userId) {
         File activatedFile = new File(mTestDir, "activate-" + userId);
-        TrampolineTestable.sActivatedFiles.append(userId, activatedFile);
+        BackupManagerServiceTestable.sActivatedFiles.append(userId, activatedFile);
         File rememberActivatedFile = new File(mTestDir, "rem-activate-" + userId);
-        TrampolineTestable.sRememberActivatedFiles.append(userId, rememberActivatedFile);
+        BackupManagerServiceTestable.sRememberActivatedFiles.append(userId, rememberActivatedFile);
     }
 
     @After
     public void tearDown() throws Exception {
         mSuppressFile.delete();
-        deleteFiles(TrampolineTestable.sActivatedFiles);
-        deleteFiles(TrampolineTestable.sRememberActivatedFiles);
+        deleteFiles(BackupManagerServiceTestable.sActivatedFiles);
+        deleteFiles(BackupManagerServiceTestable.sRememberActivatedFiles);
     }
 
     private void deleteFiles(SparseArray<File> files) {
@@ -185,144 +182,149 @@
 
     @Test
     public void testIsBackupServiceActive_whenBackupsNotDisabledAndSuppressFileDoesNotExist() {
-        assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
+        assertTrue(mService.isBackupServiceActive(UserHandle.USER_SYSTEM));
     }
 
     @Test
     public void testOnUnlockUser_forNonSystemUserWhenBackupsDisabled_doesNotStartUser() {
-        TrampolineTestable.sBackupDisabled = true;
-        TrampolineTestable trampoline = new TrampolineTestable(mContextMock, new SparseArray<>());
+        BackupManagerServiceTestable.sBackupDisabled = true;
+        BackupManagerServiceTestable service =
+                new BackupManagerServiceTestable(mContextMock, new SparseArray<>());
         ConditionVariable unlocked = new ConditionVariable(false);
 
-        trampoline.onUnlockUser(NON_USER_SYSTEM);
+        service.onUnlockUser(NON_USER_SYSTEM);
 
-        trampoline.getBackupHandler().post(unlocked::open);
+        service.getBackupHandler().post(unlocked::open);
         unlocked.block();
-        assertNull(trampoline.getUserService(NON_USER_SYSTEM));
+        assertNull(service.getUserService(NON_USER_SYSTEM));
     }
 
     @Test
     public void testOnUnlockUser_forSystemUserWhenBackupsDisabled_doesNotStartUser() {
-        TrampolineTestable.sBackupDisabled = true;
-        TrampolineTestable trampoline = new TrampolineTestable(mContextMock, new SparseArray<>());
+        BackupManagerServiceTestable.sBackupDisabled = true;
+        BackupManagerServiceTestable service =
+                new BackupManagerServiceTestable(mContextMock, new SparseArray<>());
         ConditionVariable unlocked = new ConditionVariable(false);
 
-        trampoline.onUnlockUser(UserHandle.USER_SYSTEM);
+        service.onUnlockUser(UserHandle.USER_SYSTEM);
 
-        trampoline.getBackupHandler().post(unlocked::open);
+        service.getBackupHandler().post(unlocked::open);
         unlocked.block();
-        assertNull(trampoline.getUserService(UserHandle.USER_SYSTEM));
+        assertNull(service.getUserService(UserHandle.USER_SYSTEM));
     }
 
     @Test
     public void testOnUnlockUser_whenBackupNotActivated_doesNotStartUser() {
-        TrampolineTestable.sBackupDisabled = false;
-        TrampolineTestable trampoline = new TrampolineTestable(mContextMock, new SparseArray<>());
-        trampoline.setBackupServiceActive(NON_USER_SYSTEM, false);
+        BackupManagerServiceTestable.sBackupDisabled = false;
+        BackupManagerServiceTestable service =
+                new BackupManagerServiceTestable(mContextMock, new SparseArray<>());
+        service.setBackupServiceActive(NON_USER_SYSTEM, false);
         ConditionVariable unlocked = new ConditionVariable(false);
 
-        trampoline.onUnlockUser(NON_USER_SYSTEM);
+        service.onUnlockUser(NON_USER_SYSTEM);
 
-        trampoline.getBackupHandler().post(unlocked::open);
+        service.getBackupHandler().post(unlocked::open);
         unlocked.block();
-        assertNull(trampoline.getUserService(NON_USER_SYSTEM));
+        assertNull(service.getUserService(NON_USER_SYSTEM));
     }
 
     @Test
     public void testIsBackupServiceActive_forSystemUserWhenBackupDisabled_returnsTrue()
             throws Exception {
-        TrampolineTestable.sBackupDisabled = true;
-        Trampoline trampoline = new TrampolineTestable(mContextMock, mUserServices);
-        trampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+        BackupManagerServiceTestable.sBackupDisabled = true;
+        BackupManagerService backupManagerService =
+                new BackupManagerServiceTestable(mContextMock, mUserServices);
+        backupManagerService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
 
-        assertFalse(trampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
+        assertFalse(backupManagerService.isBackupServiceActive(UserHandle.USER_SYSTEM));
     }
 
     @Test
     public void testIsBackupServiceActive_forNonSystemUserWhenBackupDisabled_returnsTrue()
             throws Exception {
-        TrampolineTestable.sBackupDisabled = true;
-        Trampoline trampoline = new TrampolineTestable(mContextMock, mUserServices);
-        trampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+        BackupManagerServiceTestable.sBackupDisabled = true;
+        BackupManagerService backupManagerService =
+                new BackupManagerServiceTestable(mContextMock, mUserServices);
+        backupManagerService.setBackupServiceActive(NON_USER_SYSTEM, true);
 
-        assertFalse(trampoline.isBackupServiceActive(NON_USER_SYSTEM));
+        assertFalse(backupManagerService.isBackupServiceActive(NON_USER_SYSTEM));
     }
 
     @Test
     public void isBackupServiceActive_forSystemUser_returnsTrueWhenActivated() throws Exception {
-        mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+        mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
 
-        assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
+        assertTrue(mService.isBackupServiceActive(UserHandle.USER_SYSTEM));
     }
 
     @Test
     public void isBackupServiceActive_forSystemUser_returnsFalseWhenDeactivated() throws Exception {
-        mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
+        mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
 
-        assertFalse(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
+        assertFalse(mService.isBackupServiceActive(UserHandle.USER_SYSTEM));
     }
 
     @Test
     public void isBackupServiceActive_forNonSystemUser_returnsFalseWhenSystemUserDeactivated()
             throws Exception {
-        mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
-        mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+        mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
+        mService.setBackupServiceActive(NON_USER_SYSTEM, true);
 
-        assertFalse(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM));
+        assertFalse(mService.isBackupServiceActive(NON_USER_SYSTEM));
     }
 
     @Test
     public void isBackupServiceActive_forNonSystemUser_returnsFalseWhenNonSystemUserDeactivated()
             throws Exception {
-        mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+        mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
         // Don't activate non-system user.
 
-        assertFalse(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM));
+        assertFalse(mService.isBackupServiceActive(NON_USER_SYSTEM));
     }
 
     @Test
     public void
             isBackupServiceActive_forNonSystemUser_returnsTrueWhenSystemAndNonSystemUserActivated()
-                throws Exception {
-        mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
-        mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+            throws Exception {
+        mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+        mService.setBackupServiceActive(NON_USER_SYSTEM, true);
 
-        assertTrue(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM));
+        assertTrue(mService.isBackupServiceActive(NON_USER_SYSTEM));
     }
 
     @Test
     public void
             isBackupServiceActive_forUnstartedNonSystemUser_returnsTrueWhenSystemAndUserActivated()
             throws Exception {
-        mTrampoline.setBackupServiceActive(UNSTARTED_NON_USER_SYSTEM, true);
+        mService.setBackupServiceActive(UNSTARTED_NON_USER_SYSTEM, true);
 
-        assertTrue(mTrampoline.isBackupServiceActive(UNSTARTED_NON_USER_SYSTEM));
+        assertTrue(mService.isBackupServiceActive(UNSTARTED_NON_USER_SYSTEM));
     }
 
     @Test
     public void setBackupServiceActive_forSystemUserAndCallerSystemUid_serviceCreated() {
-        TrampolineTestable.sCallingUid = Process.SYSTEM_UID;
+        BackupManagerServiceTestable.sCallingUid = Process.SYSTEM_UID;
 
-        mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+        mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
 
-        assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
+        assertTrue(mService.isBackupServiceActive(UserHandle.USER_SYSTEM));
     }
 
     @Test
     public void setBackupServiceActive_forSystemUserAndCallerRootUid_serviceCreated() {
-        TrampolineTestable.sCallingUid = Process.ROOT_UID;
+        BackupManagerServiceTestable.sCallingUid = Process.ROOT_UID;
 
-        mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+        mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
 
-        assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
+        assertTrue(mService.isBackupServiceActive(UserHandle.USER_SYSTEM));
     }
 
     @Test
     public void setBackupServiceActive_forSystemUserAndCallerNonRootNonSystem_throws() {
-        TrampolineTestable.sCallingUid = Process.FIRST_APPLICATION_UID;
+        BackupManagerServiceTestable.sCallingUid = Process.FIRST_APPLICATION_UID;
 
         try {
-            mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+            mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
             fail();
         } catch (SecurityException expected) {
         }
@@ -331,30 +333,30 @@
     @Test
     public void setBackupServiceActive_forManagedProfileAndCallerSystemUid_serviceCreated() {
         when(mUserInfoMock.isManagedProfile()).thenReturn(true);
-        TrampolineTestable.sCallingUid = Process.SYSTEM_UID;
+        BackupManagerServiceTestable.sCallingUid = Process.SYSTEM_UID;
 
-        mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+        mService.setBackupServiceActive(NON_USER_SYSTEM, true);
 
-        assertTrue(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM));
+        assertTrue(mService.isBackupServiceActive(NON_USER_SYSTEM));
     }
 
     @Test
     public void setBackupServiceActive_forManagedProfileAndCallerRootUid_serviceCreated() {
         when(mUserInfoMock.isManagedProfile()).thenReturn(true);
-        TrampolineTestable.sCallingUid = Process.ROOT_UID;
+        BackupManagerServiceTestable.sCallingUid = Process.ROOT_UID;
 
-        mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+        mService.setBackupServiceActive(NON_USER_SYSTEM, true);
 
-        assertTrue(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM));
+        assertTrue(mService.isBackupServiceActive(NON_USER_SYSTEM));
     }
 
     @Test
     public void setBackupServiceActive_forManagedProfileAndCallerNonRootNonSystem_throws() {
         when(mUserInfoMock.isManagedProfile()).thenReturn(true);
-        TrampolineTestable.sCallingUid = Process.FIRST_APPLICATION_UID;
+        BackupManagerServiceTestable.sCallingUid = Process.FIRST_APPLICATION_UID;
 
         try {
-            mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+            mService.setBackupServiceActive(NON_USER_SYSTEM, true);
             fail();
         } catch (SecurityException expected) {
         }
@@ -367,7 +369,7 @@
                 .enforceCallingOrSelfPermission(eq(Manifest.permission.BACKUP), anyString());
 
         try {
-            mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+            mService.setBackupServiceActive(NON_USER_SYSTEM, true);
             fail();
         } catch (SecurityException expected) {
         }
@@ -381,7 +383,7 @@
                         eq(Manifest.permission.INTERACT_ACROSS_USERS_FULL), anyString());
 
         try {
-            mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+            mService.setBackupServiceActive(NON_USER_SYSTEM, true);
             fail();
         } catch (SecurityException expected) {
         }
@@ -389,95 +391,96 @@
 
     @Test
     public void setBackupServiceActive_backupDisabled_ignored() {
-        TrampolineTestable.sBackupDisabled = true;
-        TrampolineTestable trampoline = new TrampolineTestable(mContextMock, mUserServices);
+        BackupManagerServiceTestable.sBackupDisabled = true;
+        BackupManagerServiceTestable service =
+                new BackupManagerServiceTestable(mContextMock, mUserServices);
 
-        trampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+        service.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
 
-        assertFalse(trampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
+        assertFalse(service.isBackupServiceActive(UserHandle.USER_SYSTEM));
     }
 
     @Test
     public void setBackupServiceActive_alreadyActive_ignored() {
-        mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
-        assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
+        mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+        assertTrue(mService.isBackupServiceActive(UserHandle.USER_SYSTEM));
 
-        mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
-        assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
+        mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+        assertTrue(mService.isBackupServiceActive(UserHandle.USER_SYSTEM));
     }
 
     @Test
     public void setBackupServiceActive_makeNonActive_alreadyNonActive_ignored() {
-        mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
-        mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
+        mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
+        mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
 
-        assertFalse(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
+        assertFalse(mService.isBackupServiceActive(UserHandle.USER_SYSTEM));
     }
 
     @Test
     public void setBackupServiceActive_makeActive_serviceCreatedAndSuppressFileDeleted() {
-        mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+        mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
 
-        assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
+        assertTrue(mService.isBackupServiceActive(UserHandle.USER_SYSTEM));
     }
 
     @Test
     public void setBackupServiceActive_makeNonActive_serviceDeletedAndSuppressFileCreated()
             throws IOException {
-        assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
+        assertTrue(mService.isBackupServiceActive(UserHandle.USER_SYSTEM));
 
-        mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
+        mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
 
-        assertFalse(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
+        assertFalse(mService.isBackupServiceActive(UserHandle.USER_SYSTEM));
     }
 
     @Test
     public void setBackupActive_nonSystemUser_disabledForSystemUser_ignored() {
-        mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
-        mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+        mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
+        mService.setBackupServiceActive(NON_USER_SYSTEM, true);
 
-        assertFalse(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM));
+        assertFalse(mService.isBackupServiceActive(NON_USER_SYSTEM));
     }
 
     @Test
     public void setBackupServiceActive_forOneNonSystemUser_doesNotActivateForAllNonSystemUsers() {
         int otherUser = NON_USER_SYSTEM + 1;
         File activateFile = new File(mTestDir, "activate-" + otherUser);
-        TrampolineTestable.sActivatedFiles.append(otherUser, activateFile);
-        mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+        BackupManagerServiceTestable.sActivatedFiles.append(otherUser, activateFile);
+        mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
 
-        mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+        mService.setBackupServiceActive(NON_USER_SYSTEM, true);
 
-        assertTrue(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM));
-        assertFalse(mTrampoline.isBackupServiceActive(otherUser));
+        assertTrue(mService.isBackupServiceActive(NON_USER_SYSTEM));
+        assertFalse(mService.isBackupServiceActive(otherUser));
         activateFile.delete();
     }
 
     @Test
     public void setBackupServiceActive_forNonSystemUser_remembersActivated() {
 
-        mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+        mService.setBackupServiceActive(NON_USER_SYSTEM, true);
 
         assertTrue(RandomAccessFileUtils.readBoolean(
-                TrampolineTestable.sRememberActivatedFiles.get(NON_USER_SYSTEM), false));
+                BackupManagerServiceTestable.sRememberActivatedFiles.get(NON_USER_SYSTEM), false));
     }
 
     @Test
     public void setBackupServiceActiveFalse_forNonSystemUser_remembersActivated() {
 
-        mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, false);
+        mService.setBackupServiceActive(NON_USER_SYSTEM, false);
 
         assertFalse(RandomAccessFileUtils.readBoolean(
-                TrampolineTestable.sRememberActivatedFiles.get(NON_USER_SYSTEM), true));
+                BackupManagerServiceTestable.sRememberActivatedFiles.get(NON_USER_SYSTEM), true));
     }
 
     @Test
     public void setBackupServiceActiveTwice_forNonSystemUser_remembersLastActivated() {
-        mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
-        mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, false);
+        mService.setBackupServiceActive(NON_USER_SYSTEM, true);
+        mService.setBackupServiceActive(NON_USER_SYSTEM, false);
 
         assertFalse(RandomAccessFileUtils.readBoolean(
-                TrampolineTestable.sRememberActivatedFiles.get(NON_USER_SYSTEM), true));
+                BackupManagerServiceTestable.sRememberActivatedFiles.get(NON_USER_SYSTEM), true));
     }
 
     @Test
@@ -497,7 +500,7 @@
                     }
                 };
 
-        mTrampoline.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, listener);
+        mService.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, listener);
 
         assertEquals(BackupManager.ERROR_BACKUP_NOT_ALLOWED, (int) future.get(5, TimeUnit.SECONDS));
     }
@@ -505,14 +508,14 @@
     @Test
     public void selectBackupTransportAsyncForUser_beforeUserUnlockedWithNullListener_doesNotThrow()
             throws Exception {
-        mTrampoline.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, null);
+        mService.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, null);
 
         // No crash.
     }
 
     @Test
     public void
-            selectBackupTransportAsyncForUser_beforeUserUnlockedWithThrowingListener_doesNotThrow()
+            selectBackupTransportAsyncForUser_beforeUserUnlockedListenerThrowing_doesNotThrow()
             throws Exception {
         ISelectBackupTransportCallback.Stub listener =
                 new ISelectBackupTransportCallback.Stub() {
@@ -524,7 +527,7 @@
                     }
                 };
 
-        mTrampoline.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, listener);
+        mService.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, listener);
 
         // No crash.
     }
@@ -535,44 +538,45 @@
                 android.Manifest.permission.DUMP)).thenReturn(
                 PackageManager.PERMISSION_DENIED);
 
-        mTrampoline.dump(mFileDescriptorStub, mPrintWriterMock, new String[0]);
+        mService.dump(mFileDescriptorStub, mPrintWriterMock, new String[0]);
 
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
+        verifyNoMoreInteractions(mUserBackupManagerService);
     }
 
     public void testGetUserForAncestralSerialNumber() {
-        TrampolineTestable.sBackupDisabled = false;
-        Trampoline trampoline = new TrampolineTestable(mContextMock, mUserServices);
+        BackupManagerServiceTestable.sBackupDisabled = false;
+        BackupManagerService backupManagerService =
+                new BackupManagerServiceTestable(mContextMock, mUserServices);
         when(mUserBackupManagerService.getAncestralSerialNumber()).thenReturn(11L);
 
-        UserHandle user = trampoline.getUserForAncestralSerialNumber(11L);
+        UserHandle user = backupManagerService.getUserForAncestralSerialNumber(11L);
 
         assertThat(user).isEqualTo(UserHandle.of(1));
     }
 
     public void testGetUserForAncestralSerialNumber_whenDisabled() {
-        TrampolineTestable.sBackupDisabled = true;
-        Trampoline trampoline = new TrampolineTestable(mContextMock, mUserServices);
+        BackupManagerServiceTestable.sBackupDisabled = true;
+        BackupManagerService backupManagerService =
+                new BackupManagerServiceTestable(mContextMock, mUserServices);
         when(mUserBackupManagerService.getAncestralSerialNumber()).thenReturn(11L);
 
-        UserHandle user = trampoline.getUserForAncestralSerialNumber(11L);
+        UserHandle user = backupManagerService.getUserForAncestralSerialNumber(11L);
 
         assertThat(user).isNull();
     }
 
-    private static class TrampolineTestable extends Trampoline {
+    private static class BackupManagerServiceTestable extends BackupManagerService {
         static boolean sBackupDisabled = false;
         static int sCallingUserId = -1;
         static int sCallingUid = -1;
-        static BackupManagerService sBackupManagerServiceMock = null;
         static File sSuppressFile = null;
         static SparseArray<File> sActivatedFiles = new SparseArray<>();
         static SparseArray<File> sRememberActivatedFiles = new SparseArray<>();
         static UserManager sUserManagerMock = null;
 
-        TrampolineTestable(Context context, SparseArray<UserBackupManagerService> userServices) {
+        BackupManagerServiceTestable(
+                Context context, SparseArray<UserBackupManagerService> userServices) {
             super(context, userServices);
-            mService = sBackupManagerServiceMock;
         }
 
         @Override
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
new file mode 100644
index 0000000..ccf3a90
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -0,0 +1,748 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.biometrics;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.TestCase.assertNotNull;
+
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.AppOpsManager;
+import android.app.IActivityManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.biometrics.BiometricConstants;
+import android.hardware.biometrics.BiometricPrompt;
+import android.hardware.biometrics.IBiometricService;
+import android.hardware.biometrics.IBiometricServiceReceiver;
+import android.hardware.biometrics.IBiometricServiceReceiverInternal;
+import android.hardware.face.FaceManager;
+import android.hardware.face.IFaceService;
+import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.IFingerprintService;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.security.KeyStore;
+
+import com.android.internal.R;
+import com.android.internal.statusbar.IStatusBarService;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.List;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
+@SmallTest
+public class BiometricServiceTest {
+
+    private static final String TAG = "BiometricServiceTest";
+
+    private static final String TEST_PACKAGE_NAME = "test_package";
+
+    private static final String ERROR_HW_UNAVAILABLE = "hw_unavailable";
+    private static final String ERROR_NOT_RECOGNIZED = "not_recognized";
+    private static final String ERROR_TIMEOUT = "error_timeout";
+    private static final String ERROR_CANCELED = "error_canceled";
+    private static final String ERROR_UNABLE_TO_PROCESS = "error_unable_to_process";
+    private static final String ERROR_USER_CANCELED = "error_user_canceled";
+
+    private static final String FINGERPRINT_ACQUIRED_SENSOR_DIRTY = "sensor_dirty";
+
+    private BiometricService mBiometricService;
+
+    @Mock
+    private Context mContext;
+    @Mock
+    private ContentResolver mContentResolver;
+    @Mock
+    private Resources mResources;
+    @Mock
+    private PackageManager mPackageManager;
+    @Mock
+    private AppOpsManager mAppOpsManager;
+    @Mock
+    IBiometricServiceReceiver mReceiver1;
+    @Mock
+    IBiometricServiceReceiver mReceiver2;
+    @Mock
+    FingerprintManager mFingerprintManager;
+    @Mock
+    FaceManager mFaceManager;
+
+    private static class MockInjector extends BiometricService.Injector {
+        @Override
+        IActivityManager getActivityManagerService() {
+            return mock(IActivityManager.class);
+        }
+
+        @Override
+        IStatusBarService getStatusBarService() {
+            return mock(IStatusBarService.class);
+        }
+
+        @Override
+        IFingerprintService getFingerprintService() {
+            return mock(IFingerprintService.class);
+        }
+
+        @Override
+        IFaceService getFaceService() {
+            return mock(IFaceService.class);
+        }
+
+        @Override
+        BiometricService.SettingObserver getSettingObserver(Context context, Handler handler,
+                List<BiometricService.EnabledOnKeyguardCallback> callbacks) {
+            return mock(BiometricService.SettingObserver.class);
+        }
+
+        @Override
+        KeyStore getKeyStore() {
+            return mock(KeyStore.class);
+        }
+
+        @Override
+        boolean isDebugEnabled(Context context, int userId) {
+            return false;
+        }
+
+        @Override
+        void publishBinderService(BiometricService service, IBiometricService.Stub impl) {
+            // no-op for test
+        }
+    }
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
+        when(mContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager);
+        when(mContext.getSystemService(Context.FINGERPRINT_SERVICE))
+                .thenReturn(mFingerprintManager);
+        when(mContext.getSystemService(Context.FACE_SERVICE)).thenReturn(mFaceManager);
+        when(mContext.getContentResolver()).thenReturn(mContentResolver);
+        when(mContext.getResources()).thenReturn(mResources);
+
+        when(mResources.getString(R.string.biometric_error_hw_unavailable))
+                .thenReturn(ERROR_HW_UNAVAILABLE);
+        when(mResources.getString(R.string.biometric_not_recognized))
+                .thenReturn(ERROR_NOT_RECOGNIZED);
+        when(mResources.getString(R.string.biometric_error_user_canceled))
+                .thenReturn(ERROR_USER_CANCELED);
+    }
+
+    @Test
+    public void testAuthenticate_withoutHardware_returnsErrorHardwareNotPresent() throws Exception {
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
+                .thenReturn(false);
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_IRIS)).thenReturn(false);
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(false);
+
+        mBiometricService = new BiometricService(mContext, new MockInjector());
+        mBiometricService.onStart();
+
+        invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */);
+        waitForIdle();
+        verify(mReceiver1).onError(
+                eq(BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT), eq(ERROR_HW_UNAVAILABLE));
+    }
+
+    @Test
+    public void testAuthenticate_withoutEnrolled_returnsErrorNoBiometrics() throws Exception {
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)).thenReturn(true);
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+
+        mBiometricService = new BiometricService(mContext, new MockInjector());
+        mBiometricService.onStart();
+
+        invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */);
+        waitForIdle();
+        verify(mReceiver1).onError(
+                eq(BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS), any());
+    }
+
+    @Test
+    public void testAuthenticate_whenHalIsDead_returnsErrorHardwareUnavailable() throws Exception {
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)).thenReturn(true);
+        when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+        when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
+
+        mBiometricService = new BiometricService(mContext, new MockInjector());
+        mBiometricService.onStart();
+
+        invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */);
+        waitForIdle();
+        verify(mReceiver1).onError(
+                eq(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE), eq(ERROR_HW_UNAVAILABLE));
+    }
+
+    @Test
+    public void testAuthenticateFace_respectsUserSetting()
+            throws Exception {
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true);
+        when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+        when(mFaceManager.isHardwareDetected()).thenReturn(true);
+
+        mBiometricService = new BiometricService(mContext, new MockInjector());
+        mBiometricService.onStart();
+
+        // Disabled in user settings receives onError
+        when(mBiometricService.mSettingObserver.getFaceEnabledForApps(anyInt())).thenReturn(false);
+        invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */);
+        waitForIdle();
+        verify(mReceiver1).onError(
+                eq(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE), eq(ERROR_HW_UNAVAILABLE));
+
+        // Enrolled, not disabled in settings, user requires confirmation in settings
+        resetReceiver();
+        when(mBiometricService.mSettingObserver.getFaceEnabledForApps(anyInt())).thenReturn(true);
+        when(mBiometricService.mSettingObserver.getFaceAlwaysRequireConfirmation(anyInt()))
+                .thenReturn(true);
+        invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */);
+        waitForIdle();
+        verify(mReceiver1, never()).onError(anyInt(), any(String.class));
+        verify(mBiometricService.mFaceService).prepareForAuthentication(
+                eq(true) /* requireConfirmation */,
+                any(IBinder.class),
+                anyLong() /* sessionId */,
+                anyInt() /* userId */,
+                any(IBiometricServiceReceiverInternal.class),
+                anyString() /* opPackageName */,
+                anyInt() /* cookie */,
+                anyInt() /* callingUid */,
+                anyInt() /* callingPid */,
+                anyInt() /* callingUserId */);
+
+        // Enrolled, not disabled in settings, user doesn't require confirmation in settings
+        resetReceiver();
+        when(mBiometricService.mSettingObserver.getFaceAlwaysRequireConfirmation(anyInt()))
+                .thenReturn(false);
+        invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */);
+        waitForIdle();
+        verify(mBiometricService.mFaceService).prepareForAuthentication(
+                eq(false) /* requireConfirmation */,
+                any(IBinder.class),
+                anyLong() /* sessionId */,
+                anyInt() /* userId */,
+                any(IBiometricServiceReceiverInternal.class),
+                anyString() /* opPackageName */,
+                anyInt() /* cookie */,
+                anyInt() /* callingUid */,
+                anyInt() /* callingPid */,
+                anyInt() /* callingUserId */);
+    }
+
+    @Test
+    public void testAuthenticate_happyPathWithoutConfirmation() throws Exception {
+        setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT);
+        mBiometricService = new BiometricService(mContext, new MockInjector());
+        mBiometricService.onStart();
+
+        // Start testing the happy path
+        invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */);
+        waitForIdle();
+
+        // Creates a pending auth session with the correct initial states
+        assertEquals(mBiometricService.mPendingAuthSession.mState,
+                BiometricService.STATE_AUTH_CALLED);
+
+        // Invokes <Modality>Service#prepareForAuthentication
+        ArgumentCaptor<Integer> cookieCaptor = ArgumentCaptor.forClass(Integer.class);
+        verify(mReceiver1, never()).onError(anyInt(), any(String.class));
+        verify(mBiometricService.mFingerprintService).prepareForAuthentication(
+                any(IBinder.class),
+                anyLong() /* sessionId */,
+                anyInt() /* userId */,
+                any(IBiometricServiceReceiverInternal.class),
+                anyString() /* opPackageName */,
+                cookieCaptor.capture() /* cookie */,
+                anyInt() /* callingUid */,
+                anyInt() /* callingPid */,
+                anyInt() /* callingUserId */);
+
+        // onReadyForAuthentication, mCurrentAuthSession state OK
+        mBiometricService.mImpl.onReadyForAuthentication(cookieCaptor.getValue(),
+                anyBoolean() /* requireConfirmation */, anyInt() /* userId */);
+        waitForIdle();
+        assertNull(mBiometricService.mPendingAuthSession);
+        assertEquals(mBiometricService.mCurrentAuthSession.mState,
+                BiometricService.STATE_AUTH_STARTED);
+
+        // startPreparedClient invoked
+        verify(mBiometricService.mFingerprintService)
+                .startPreparedClient(cookieCaptor.getValue());
+
+        // StatusBar showBiometricDialog invoked
+        verify(mBiometricService.mStatusBarService).showBiometricDialog(
+                eq(mBiometricService.mCurrentAuthSession.mBundle),
+                any(IBiometricServiceReceiverInternal.class),
+                eq(BiometricAuthenticator.TYPE_FINGERPRINT),
+                anyBoolean() /* requireConfirmation */,
+                anyInt() /* userId */,
+                eq(TEST_PACKAGE_NAME));
+
+        // Hardware authenticated
+        mBiometricService.mInternalReceiver.onAuthenticationSucceeded(
+                false /* requireConfirmation */,
+                new byte[69] /* HAT */);
+        waitForIdle();
+        // Waiting for SystemUI to send dismissed callback
+        assertEquals(mBiometricService.mCurrentAuthSession.mState,
+                BiometricService.STATE_AUTHENTICATED_PENDING_SYSUI);
+        // Notify SystemUI hardware authenticated
+        verify(mBiometricService.mStatusBarService).onBiometricAuthenticated(
+                eq(true) /* authenticated */, eq(null) /* failureReason */);
+
+        // SystemUI sends callback with dismissed reason
+        mBiometricService.mInternalReceiver.onDialogDismissed(
+                BiometricPrompt.DISMISSED_REASON_CONFIRM_NOT_REQUIRED);
+        waitForIdle();
+        // HAT sent to keystore
+        verify(mBiometricService.mKeyStore).addAuthToken(any(byte[].class));
+        // Send onAuthenticated to client
+        verify(mReceiver1).onAuthenticationSucceeded();
+        // Current session becomes null
+        assertNull(mBiometricService.mCurrentAuthSession);
+    }
+
+    @Test
+    public void testAuthenticate_happyPathWithConfirmation() throws Exception {
+        setupAuthForOnly(BiometricAuthenticator.TYPE_FACE);
+        invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
+                true /* requireConfirmation */);
+
+        // Test authentication succeeded goes to PENDING_CONFIRMATION and that the HAT is not
+        // sent to KeyStore yet
+        mBiometricService.mInternalReceiver.onAuthenticationSucceeded(
+                true /* requireConfirmation */,
+                new byte[69] /* HAT */);
+        waitForIdle();
+        // Waiting for SystemUI to send confirmation callback
+        assertEquals(mBiometricService.mCurrentAuthSession.mState,
+                BiometricService.STATE_AUTH_PENDING_CONFIRM);
+        verify(mBiometricService.mKeyStore, never()).addAuthToken(any(byte[].class));
+
+        // SystemUI sends confirm, HAT is sent to keystore and client is notified.
+        mBiometricService.mInternalReceiver.onDialogDismissed(
+                BiometricPrompt.DISMISSED_REASON_CONFIRMED);
+        waitForIdle();
+        verify(mBiometricService.mKeyStore).addAuthToken(any(byte[].class));
+        verify(mReceiver1).onAuthenticationSucceeded();
+    }
+
+    @Test
+    public void testRejectFace_whenAuthenticating_notifiesSystemUIAndClient_thenPaused()
+            throws Exception {
+        setupAuthForOnly(BiometricAuthenticator.TYPE_FACE);
+        invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
+                false /* requireConfirmation */);
+
+        mBiometricService.mInternalReceiver.onAuthenticationFailed();
+        waitForIdle();
+
+        verify(mBiometricService.mStatusBarService)
+                .onBiometricAuthenticated(eq(false), eq(ERROR_NOT_RECOGNIZED));
+        verify(mReceiver1).onAuthenticationFailed();
+        assertEquals(mBiometricService.mCurrentAuthSession.mState,
+                BiometricService.STATE_AUTH_PAUSED);
+    }
+
+    @Test
+    public void testRejectFingerprint_whenAuthenticating_notifiesAndKeepsAuthenticating()
+            throws Exception {
+        setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT);
+        invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
+                false /* requireConfirmation */);
+
+        mBiometricService.mInternalReceiver.onAuthenticationFailed();
+        waitForIdle();
+
+        verify(mBiometricService.mStatusBarService)
+                .onBiometricAuthenticated(eq(false), eq(ERROR_NOT_RECOGNIZED));
+        verify(mReceiver1).onAuthenticationFailed();
+        assertEquals(mBiometricService.mCurrentAuthSession.mState,
+                BiometricService.STATE_AUTH_STARTED);
+    }
+
+    @Test
+    public void testErrorCanceled_whenAuthenticating_notifiesSystemUIAndClient() throws Exception {
+        setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT);
+        invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
+                false /* requireConfirmation */);
+
+        // Create a new pending auth session but don't start it yet. HAL contract is that previous
+        // one must get ERROR_CANCELED. Simulate that here by creating the pending auth session,
+        // sending ERROR_CANCELED to the current auth session, and then having the second one
+        // onReadyForAuthentication.
+        invokeAuthenticate(mBiometricService.mImpl, mReceiver2, false /* requireConfirmation */);
+        waitForIdle();
+
+        assertEquals(mBiometricService.mCurrentAuthSession.mState,
+                BiometricService.STATE_AUTH_STARTED);
+        mBiometricService.mInternalReceiver.onError(
+                getCookieForCurrentSession(mBiometricService.mCurrentAuthSession),
+                BiometricConstants.BIOMETRIC_ERROR_CANCELED, ERROR_CANCELED);
+        waitForIdle();
+
+        // Auth session doesn't become null until SystemUI responds that the animation is completed
+        assertNotNull(mBiometricService.mCurrentAuthSession);
+        // ERROR_CANCELED is not sent until SystemUI responded that animation is completed
+        verify(mReceiver1, never()).onError(
+                anyInt(), anyString());
+        verify(mReceiver2, never()).onError(anyInt(), any(String.class));
+
+        // SystemUI dialog closed
+        verify(mBiometricService.mStatusBarService).hideBiometricDialog();
+
+        // After SystemUI notifies that the animation has completed
+        mBiometricService.mInternalReceiver
+                .onDialogDismissed(BiometricPrompt.DISMISSED_REASON_SERVER_REQUESTED);
+        waitForIdle();
+        verify(mReceiver1).onError(
+                eq(BiometricConstants.BIOMETRIC_ERROR_CANCELED),
+                eq(ERROR_CANCELED));
+        assertNull(mBiometricService.mCurrentAuthSession);
+    }
+
+    @Test
+    public void testErrorHalTimeout_whenAuthenticating_entersPausedState() throws Exception {
+        setupAuthForOnly(BiometricAuthenticator.TYPE_FACE);
+        invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
+                false /* requireConfirmation */);
+
+        mBiometricService.mInternalReceiver.onError(
+                getCookieForCurrentSession(mBiometricService.mCurrentAuthSession),
+                BiometricConstants.BIOMETRIC_ERROR_TIMEOUT,
+                ERROR_TIMEOUT);
+        waitForIdle();
+
+        assertEquals(mBiometricService.mCurrentAuthSession.mState,
+                BiometricService.STATE_AUTH_PAUSED);
+        verify(mBiometricService.mStatusBarService)
+                .onBiometricAuthenticated(eq(false), eq(ERROR_TIMEOUT));
+        // Timeout does not count as fail as per BiometricPrompt documentation.
+        verify(mReceiver1, never()).onAuthenticationFailed();
+
+        // No pending auth session. Pressing try again will create one.
+        assertNull(mBiometricService.mPendingAuthSession);
+
+        // Pressing "Try again" on SystemUI starts a new auth session.
+        mBiometricService.mInternalReceiver.onTryAgainPressed();
+        waitForIdle();
+
+        // The last one is still paused, and a new one has been created.
+        assertEquals(mBiometricService.mCurrentAuthSession.mState,
+                BiometricService.STATE_AUTH_PAUSED);
+        assertEquals(mBiometricService.mPendingAuthSession.mState,
+                BiometricService.STATE_AUTH_CALLED);
+
+        // Test resuming when hardware becomes ready. SystemUI should not be requested to
+        // show another dialog since it's already showing.
+        resetStatusBar();
+        startPendingAuthSession(mBiometricService);
+        waitForIdle();
+        verify(mBiometricService.mStatusBarService, never()).showBiometricDialog(
+                any(Bundle.class),
+                any(IBiometricServiceReceiverInternal.class),
+                anyInt(),
+                anyBoolean() /* requireConfirmation */,
+                anyInt() /* userId */,
+                anyString());
+    }
+
+    @Test
+    public void testErrorFromHal_whenPaused_notifiesSystemUIAndClient() throws Exception {
+        setupAuthForOnly(BiometricAuthenticator.TYPE_FACE);
+        invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
+                false /* requireCOnfirmation */);
+
+        mBiometricService.mInternalReceiver.onError(
+                getCookieForCurrentSession(mBiometricService.mCurrentAuthSession),
+                BiometricConstants.BIOMETRIC_ERROR_TIMEOUT,
+                ERROR_TIMEOUT);
+        mBiometricService.mInternalReceiver.onError(
+                getCookieForCurrentSession(mBiometricService.mCurrentAuthSession),
+                BiometricConstants.BIOMETRIC_ERROR_CANCELED,
+                ERROR_CANCELED);
+        waitForIdle();
+
+        // Client receives error immediately
+        verify(mReceiver1).onError(
+                eq(BiometricConstants.BIOMETRIC_ERROR_CANCELED),
+                eq(ERROR_CANCELED));
+        // Dialog is hidden immediately
+        verify(mBiometricService.mStatusBarService).hideBiometricDialog();
+        // Auth session is over
+        assertNull(mBiometricService.mCurrentAuthSession);
+    }
+
+    @Test
+    public void testErrorFromHal_whileAuthenticating_waitsForSysUIBeforeNotifyingClient()
+            throws Exception {
+        // For errors that show in SystemUI, BiometricService stays in STATE_ERROR_PENDING_SYSUI
+        // until SystemUI notifies us that the dialog is dismissed at which point the current
+        // session is done.
+        setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT);
+        invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
+                false /* requireConfirmation */);
+
+        mBiometricService.mInternalReceiver.onError(
+                getCookieForCurrentSession(mBiometricService.mCurrentAuthSession),
+                BiometricConstants.BIOMETRIC_ERROR_UNABLE_TO_PROCESS,
+                ERROR_UNABLE_TO_PROCESS);
+        waitForIdle();
+
+        // Sends error to SystemUI and does not notify client yet
+        assertEquals(mBiometricService.mCurrentAuthSession.mState,
+                BiometricService.STATE_ERROR_PENDING_SYSUI);
+        verify(mBiometricService.mStatusBarService)
+                .onBiometricError(eq(ERROR_UNABLE_TO_PROCESS));
+        verify(mBiometricService.mStatusBarService, never()).hideBiometricDialog();
+        verify(mReceiver1, never()).onError(anyInt(), anyString());
+
+        // SystemUI animation completed, client is notified, auth session is over
+        mBiometricService.mInternalReceiver
+                .onDialogDismissed(BiometricPrompt.DISMISSED_REASON_ERROR);
+        waitForIdle();
+        verify(mReceiver1).onError(
+                eq(BiometricConstants.BIOMETRIC_ERROR_UNABLE_TO_PROCESS),
+                eq(ERROR_UNABLE_TO_PROCESS));
+        assertNull(mBiometricService.mCurrentAuthSession);
+    }
+
+    @Test
+    public void testDismissedReasonUserCancel_whileAuthenticating_cancelsHalAuthentication()
+            throws Exception {
+        setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT);
+        invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
+                false /* requireConfirmation */);
+
+        mBiometricService.mInternalReceiver
+                .onDialogDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
+        waitForIdle();
+        verify(mReceiver1).onError(
+                eq(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED),
+                eq(ERROR_USER_CANCELED));
+        verify(mBiometricService.mFingerprintService).cancelAuthenticationFromService(
+                any(),
+                any(),
+                anyInt(),
+                anyInt(),
+                anyInt(),
+                eq(false) /* fromClient */);
+        assertNull(mBiometricService.mCurrentAuthSession);
+    }
+
+    @Test
+    public void testDismissedReasonNegative_whilePaused_doesntInvokeHalCancel() throws Exception {
+        setupAuthForOnly(BiometricAuthenticator.TYPE_FACE);
+        invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
+                false /* requireConfirmation */);
+
+        mBiometricService.mInternalReceiver.onError(
+                getCookieForCurrentSession(mBiometricService.mCurrentAuthSession),
+                BiometricConstants.BIOMETRIC_ERROR_TIMEOUT,
+                ERROR_TIMEOUT);
+        mBiometricService.mInternalReceiver.onDialogDismissed(
+                BiometricPrompt.DISMISSED_REASON_NEGATIVE);
+        waitForIdle();
+
+        verify(mBiometricService.mFaceService, never()).cancelAuthenticationFromService(
+                any(),
+                any(),
+                anyInt(),
+                anyInt(),
+                anyInt(),
+                anyBoolean());
+    }
+
+    @Test
+    public void testDismissedReasonUserCancel_whilePaused_doesntInvokeHalCancel() throws Exception {
+        setupAuthForOnly(BiometricAuthenticator.TYPE_FACE);
+        invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
+                false /* requireConfirmation */);
+
+        mBiometricService.mInternalReceiver.onError(
+                getCookieForCurrentSession(mBiometricService.mCurrentAuthSession),
+                BiometricConstants.BIOMETRIC_ERROR_TIMEOUT,
+                ERROR_TIMEOUT);
+        mBiometricService.mInternalReceiver.onDialogDismissed(
+                BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
+        waitForIdle();
+
+        verify(mBiometricService.mFaceService, never()).cancelAuthenticationFromService(
+                any(),
+                any(),
+                anyInt(),
+                anyInt(),
+                anyInt(),
+                anyBoolean());
+    }
+
+    @Test
+    public void testDismissedReasonUserCancel_whenPendingConfirmation() throws Exception {
+        setupAuthForOnly(BiometricAuthenticator.TYPE_FACE);
+        invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
+                true /* requireConfirmation */);
+
+        mBiometricService.mInternalReceiver.onAuthenticationSucceeded(
+                true /* requireConfirmation */,
+                new byte[69] /* HAT */);
+        mBiometricService.mInternalReceiver.onDialogDismissed(
+                BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
+        waitForIdle();
+
+        // doesn't send cancel to HAL
+        verify(mBiometricService.mFaceService, never()).cancelAuthenticationFromService(
+                any(),
+                any(),
+                anyInt(),
+                anyInt(),
+                anyInt(),
+                anyBoolean());
+        verify(mReceiver1).onError(
+                eq(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED),
+                eq(ERROR_USER_CANCELED));
+        assertNull(mBiometricService.mCurrentAuthSession);
+    }
+
+    @Test
+    public void testAcquire_whenAuthenticating_sentToSystemUI() throws Exception {
+        setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT);
+        invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
+                false /* requireConfirmation */);
+
+        mBiometricService.mInternalReceiver.onAcquired(
+                FingerprintManager.FINGERPRINT_ACQUIRED_IMAGER_DIRTY,
+                FINGERPRINT_ACQUIRED_SENSOR_DIRTY);
+        waitForIdle();
+
+        // Sends to SysUI and stays in authenticating state
+        verify(mBiometricService.mStatusBarService)
+                .onBiometricHelp(eq(FINGERPRINT_ACQUIRED_SENSOR_DIRTY));
+        assertEquals(mBiometricService.mCurrentAuthSession.mState,
+                BiometricService.STATE_AUTH_STARTED);
+    }
+
+    // Helper methods
+
+    private void setupAuthForOnly(int modality) {
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
+                .thenReturn(false);
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(false);
+
+        if (modality == BiometricAuthenticator.TYPE_FINGERPRINT) {
+            when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
+                    .thenReturn(true);
+            when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+            when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+        } else if (modality == BiometricAuthenticator.TYPE_FACE) {
+            when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true);
+            when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+            when(mFaceManager.isHardwareDetected()).thenReturn(true);
+        } else {
+            fail("Unknown modality: " + modality);
+        }
+
+        mBiometricService = new BiometricService(mContext, new MockInjector());
+        mBiometricService.onStart();
+
+        when(mBiometricService.mSettingObserver.getFaceEnabledForApps(anyInt())).thenReturn(true);
+    }
+
+    private void resetReceiver() {
+        mReceiver1 = mock(IBiometricServiceReceiver.class);
+        mReceiver2 = mock(IBiometricServiceReceiver.class);
+    }
+
+    private void resetStatusBar() {
+        mBiometricService.mStatusBarService = mock(IStatusBarService.class);
+    }
+
+    private void invokeAuthenticateAndStart(IBiometricService.Stub service,
+            IBiometricServiceReceiver receiver, boolean requireConfirmation) throws Exception {
+        // Request auth, creates a pending session
+        invokeAuthenticate(service, receiver, requireConfirmation);
+        waitForIdle();
+
+        startPendingAuthSession(mBiometricService);
+        waitForIdle();
+    }
+
+    private static void startPendingAuthSession(BiometricService service) throws Exception {
+        // Get the cookie so we can pretend the hardware is ready to authenticate
+        // Currently we only support single modality per auth
+        assertEquals(service.mPendingAuthSession.mModalitiesWaiting.values().size(), 1);
+        final int cookie = service.mPendingAuthSession.mModalitiesWaiting.values()
+                .iterator().next();
+        assertNotEquals(cookie, 0);
+
+        service.mImpl.onReadyForAuthentication(cookie,
+                anyBoolean() /* requireConfirmation */, anyInt() /* userId */);
+    }
+
+    private static void invokeAuthenticate(IBiometricService.Stub service,
+            IBiometricServiceReceiver receiver, boolean requireConfirmation) throws Exception {
+        service.authenticate(
+                new Binder() /* token */,
+                0 /* sessionId */,
+                0 /* userId */,
+                receiver,
+                TEST_PACKAGE_NAME /* packageName */,
+                createTestBiometricPromptBundle(requireConfirmation),
+                null /* IBiometricConfirmDeviceCredentialCallback */);
+    }
+
+    private static Bundle createTestBiometricPromptBundle(boolean requireConfirmation) {
+        final Bundle bundle = new Bundle();
+        bundle.putBoolean(BiometricPrompt.KEY_REQUIRE_CONFIRMATION, requireConfirmation);
+        return bundle;
+    }
+
+    private static int getCookieForCurrentSession(BiometricService.AuthSession session) {
+        assertEquals(session.mModalitiesMatched.values().size(), 1);
+        return session.mModalitiesMatched.values().iterator().next();
+    }
+
+    private static void waitForIdle() {
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+    }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
index 63b9198..6c78f6f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
@@ -28,6 +28,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
 
@@ -140,7 +141,8 @@
     public void testNotResumeHomeStackOnRemovingDisplay() {
         // Create a display which supports system decoration and allows reparenting stacks to
         // another display when the display is removed.
-        final ActivityDisplay display = spy(createNewActivityDisplay());
+        final ActivityDisplay display = createNewActivityDisplay();
+        spyOn(display);
         doReturn(false).when(display).shouldDestroyContentOnRemove();
         doReturn(true).when(display).supportsSystemDecorations();
         mRootActivityContainer.addChild(display, ActivityDisplay.POSITION_TOP);
@@ -304,14 +306,18 @@
                 ACTIVITY_TYPE_STANDARD, ON_TOP);
         final ActivityStack stack4 = display.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, ON_TOP);
-        final TaskRecord task1 = new TaskBuilder(mService.mStackSupervisor).setStack(
-                stack1).setTaskId(1).build();
-        final TaskRecord task2 = new TaskBuilder(mService.mStackSupervisor).setStack(
-                stack2).setTaskId(2).build();
-        final TaskRecord task3 = new TaskBuilder(mService.mStackSupervisor).setStack(
-                stack3).setTaskId(3).build();
-        final TaskRecord task4 = new TaskBuilder(mService.mStackSupervisor).setStack(
-                stack4).setTaskId(4).build();
+        final TaskRecord task1 = new TaskBuilder(mService.mStackSupervisor)
+                .setStack(stack1)
+                .build();
+        final TaskRecord task2 = new TaskBuilder(mService.mStackSupervisor)
+                .setStack(stack2)
+                .build();
+        final TaskRecord task3 = new TaskBuilder(mService.mStackSupervisor)
+                .setStack(stack3)
+                .build();
+        final TaskRecord task4 = new TaskBuilder(mService.mStackSupervisor)
+                .setStack(stack4)
+                .build();
 
         // Reordering stacks while removing stacks.
         doAnswer(invocation -> {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index 23bae88..977dd8e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -61,13 +61,13 @@
     private ActivityMetricsLaunchObserver mLaunchObserver;
     private ActivityMetricsLaunchObserverRegistry mLaunchObserverRegistry;
 
-    private TestActivityStack mStack;
+    private ActivityStack mStack;
     private TaskRecord mTask;
     private ActivityRecord mActivityRecord;
     private ActivityRecord mActivityRecordTrampoline;
 
     @Before
-    public void setUpAMLO() throws Exception {
+    public void setUpAMLO() {
         mLaunchObserver = mock(ActivityMetricsLaunchObserver.class);
 
         // ActivityStackSupervisor always creates its own instance of ActivityMetricsLogger.
@@ -78,15 +78,19 @@
 
         // Sometimes we need an ActivityRecord for ActivityMetricsLogger to do anything useful.
         // This seems to be the easiest way to create an ActivityRecord.
-        mStack = mRootActivityContainer.getDefaultDisplay().createStack(
-                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
-        mTask = new TaskBuilder(mSupervisor).setStack(mStack).build();
-        mActivityRecord = new ActivityBuilder(mService).setTask(mTask).build();
+        mStack = new StackBuilder(mRootActivityContainer)
+                .setActivityType(ACTIVITY_TYPE_STANDARD)
+                .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
+                .setOnTop(true)
+                .setCreateActivity(true)
+                .build();
+        mTask = mStack.topTask();
+        mActivityRecord = mTask.getTopActivity();
         mActivityRecordTrampoline = new ActivityBuilder(mService).setTask(mTask).build();
     }
 
     @After
-    public void tearDownAMLO() throws Exception {
+    public void tearDownAMLO() {
         if (mLaunchObserverRegistry != null) {  // Don't NPE if setUp failed.
             mLaunchObserverRegistry.unregisterLaunchObserver(mLaunchObserver);
         }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 7b252cb..0f04788 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -16,6 +16,12 @@
 
 package com.android.server.wm;
 
+import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
+import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 import static android.os.Process.NOBODY_UID;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Surface.ROTATION_0;
@@ -29,6 +35,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 import static com.android.server.wm.ActivityRecord.FINISH_RESULT_CANCELLED;
@@ -71,6 +78,7 @@
 import android.platform.test.annotations.Presubmit;
 import android.util.MergedConfiguration;
 import android.util.MutableBoolean;
+import android.view.DisplayInfo;
 import android.view.IRemoteAnimationFinishedCallback;
 import android.view.IRemoteAnimationRunner.Stub;
 import android.view.RemoteAnimationAdapter;
@@ -79,7 +87,6 @@
 import androidx.test.filters.MediumTest;
 
 import com.android.internal.R;
-import com.android.server.wm.utils.WmDisplayCutout;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -96,13 +103,13 @@
 @MediumTest
 @Presubmit
 public class ActivityRecordTests extends ActivityTestsBase {
-    private TestActivityStack mStack;
+    private ActivityStack mStack;
     private TaskRecord mTask;
     private ActivityRecord mActivity;
 
     @Before
     public void setUp() throws Exception {
-        mStack = (TestActivityStack) new StackBuilder(mRootActivityContainer).build();
+        mStack = new StackBuilder(mRootActivityContainer).build();
         mTask = mStack.getChildAt(0);
         mActivity = mTask.getTopActivity();
 
@@ -113,13 +120,13 @@
     @Test
     public void testStackCleanupOnClearingTask() {
         mActivity.setTask(null);
-        assertEquals(mStack.onActivityRemovedFromStackInvocationCount(), 1);
+        verify(mStack, times(1)).onActivityRemovedFromStack(any());
     }
 
     @Test
     public void testStackCleanupOnActivityRemoval() {
         mTask.removeActivity(mActivity);
-        assertEquals(mStack.onActivityRemovedFromStackInvocationCount(),  1);
+        verify(mStack, times(1)).onActivityRemovedFromStack(any());
     }
 
     @Test
@@ -134,7 +141,7 @@
         final TaskRecord newTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack)
                 .build();
         mActivity.reparent(newTask, 0, null /*reason*/);
-        assertEquals(mStack.onActivityRemovedFromStackInvocationCount(), 0);
+        verify(mStack, times(0)).onActivityRemovedFromStack(any());
     }
 
     @Test
@@ -181,7 +188,7 @@
         assertTrue(mActivity.isState(STARTED));
 
         mStack.mTranslucentActivityWaiting = null;
-        topActivity.changeWindowTranslucency(false);
+        topActivity.setOccludesParent(false);
         mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped behind non-opaque");
         mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
         assertTrue(mActivity.isState(STARTED));
@@ -261,8 +268,8 @@
     public void testNewParentConfigurationIncrementsSeq() {
         final Configuration newConfig = new Configuration(
                 mTask.getRequestedOverrideConfiguration());
-        newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
-                ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT;
+        newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
+                ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
 
         final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
         mTask.onRequestedOverrideConfigurationChanged(newConfig);
@@ -277,7 +284,7 @@
                 .getRequestedOverrideConfiguration();
 
         final Configuration newConfig = new Configuration();
-        newConfig.orientation = Configuration.ORIENTATION_PORTRAIT;
+        newConfig.orientation = ORIENTATION_PORTRAIT;
 
         final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
         mActivity.onRequestedOverrideConfigurationChanged(newConfig);
@@ -293,10 +300,11 @@
         mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
                 mActivity.getConfiguration()));
 
-        mActivity.info.configChanges &= ~ActivityInfo.CONFIG_ORIENTATION;
+        mActivity.info.configChanges &= ~CONFIG_ORIENTATION;
         final Configuration newConfig = new Configuration(mTask.getConfiguration());
-        newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
-                ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT;
+        newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
+                ? ORIENTATION_LANDSCAPE
+                : ORIENTATION_PORTRAIT;
         mTask.onRequestedOverrideConfigurationChanged(newConfig);
 
         mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
@@ -315,13 +323,14 @@
         mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
                 mActivity.getConfiguration()));
 
-        mActivity.info.configChanges &= ~ActivityInfo.CONFIG_ORIENTATION;
+        mActivity.info.configChanges &= ~CONFIG_ORIENTATION;
         final Configuration newConfig = new Configuration(mTask.getConfiguration());
-        newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
-                ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT;
+        newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
+                ? ORIENTATION_LANDSCAPE
+                : ORIENTATION_PORTRAIT;
         mTask.onRequestedOverrideConfigurationChanged(newConfig);
 
-        doReturn(true).when(mTask.getTask()).isDragResizing();
+        doReturn(true).when(mTask.mTask).isDragResizing();
 
         mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
 
@@ -355,30 +364,39 @@
 
     @Test
     public void testSetRequestedOrientationUpdatesConfiguration() throws Exception {
+        mActivity = new ActivityBuilder(mService)
+                .setTask(mTask)
+                .setConfigChanges(CONFIG_ORIENTATION | CONFIG_SCREEN_LAYOUT)
+                .build();
         mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
 
-        mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
         mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
                 mActivity.getConfiguration()));
 
-        mActivity.info.configChanges |= ActivityInfo.CONFIG_ORIENTATION;
         final Configuration newConfig = new Configuration(mActivity.getConfiguration());
-        newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
-                ? Configuration.ORIENTATION_LANDSCAPE
-                : Configuration.ORIENTATION_PORTRAIT;
+        final int shortSide = Math.min(newConfig.screenWidthDp, newConfig.screenHeightDp);
+        final int longSide = Math.max(newConfig.screenWidthDp, newConfig.screenHeightDp);
+        if (newConfig.orientation == ORIENTATION_PORTRAIT) {
+            newConfig.orientation = ORIENTATION_LANDSCAPE;
+            newConfig.screenWidthDp = longSide;
+            newConfig.screenHeightDp = shortSide;
+        } else {
+            newConfig.orientation = ORIENTATION_PORTRAIT;
+            newConfig.screenWidthDp = shortSide;
+            newConfig.screenHeightDp = longSide;
+        }
 
         // Mimic the behavior that display doesn't handle app's requested orientation.
-        doAnswer(invocation -> {
-            mTask.onConfigurationChanged(newConfig);
-            return null;
-        }).when(mActivity.mAppWindowToken).setOrientation(anyInt(), any(), any());
+        final DisplayContent dc = mTask.mTask.getDisplayContent();
+        doReturn(false).when(dc).onDescendantOrientationChanged(any(), any());
+        doReturn(false).when(dc).handlesOrientationChangeFromDescendant();
 
         final int requestedOrientation;
         switch (newConfig.orientation) {
-            case Configuration.ORIENTATION_LANDSCAPE:
-                requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+            case ORIENTATION_LANDSCAPE:
+                requestedOrientation = SCREEN_ORIENTATION_LANDSCAPE;
                 break;
-            case Configuration.ORIENTATION_PORTRAIT:
+            case ORIENTATION_PORTRAIT:
                 requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
                 break;
             default:
@@ -421,24 +439,33 @@
 
     @Test
     public void testPushConfigurationWhenLaunchTaskBehind() throws Exception {
+        mActivity = new ActivityBuilder(mService)
+                .setTask(mTask)
+                .setLaunchTaskBehind(true)
+                .setConfigChanges(CONFIG_ORIENTATION)
+                .build();
         mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
 
-        final TestActivityStack stack = (TestActivityStack) new StackBuilder(mRootActivityContainer)
-                .build();
+        final ActivityStack stack = new StackBuilder(mRootActivityContainer).build();
         try {
-            stack.setIsTranslucent(false);
+            doReturn(false).when(stack).isStackTranslucent(any());
             assertFalse(mStack.shouldBeVisible(null /* starting */));
 
-            mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
             mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
                     mActivity.getConfiguration()));
 
-            mActivity.mLaunchTaskBehind = true;
-            mActivity.info.configChanges |= ActivityInfo.CONFIG_ORIENTATION;
             final Configuration newConfig = new Configuration(mActivity.getConfiguration());
-            newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
-                    ? Configuration.ORIENTATION_LANDSCAPE
-                    : Configuration.ORIENTATION_PORTRAIT;
+            final int shortSide = Math.min(newConfig.screenWidthDp, newConfig.screenHeightDp);
+            final int longSide = Math.max(newConfig.screenWidthDp, newConfig.screenHeightDp);
+            if (newConfig.orientation == ORIENTATION_PORTRAIT) {
+                newConfig.orientation = ORIENTATION_LANDSCAPE;
+                newConfig.screenWidthDp = longSide;
+                newConfig.screenHeightDp = shortSide;
+            } else {
+                newConfig.orientation = ORIENTATION_PORTRAIT;
+                newConfig.screenWidthDp = shortSide;
+                newConfig.screenHeightDp = longSide;
+            }
 
             mTask.onConfigurationChanged(newConfig);
 
@@ -457,7 +484,7 @@
     @Test
     public void testShouldPauseWhenMakeClientVisible() {
         ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
-        topActivity.changeWindowTranslucency(false);
+        topActivity.setOccludesParent(false);
         mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
         mActivity.makeClientVisible();
         assertEquals(STARTED, mActivity.getState());
@@ -468,6 +495,7 @@
         setupDisplayContentForCompatDisplayInsets();
         final int decorHeight = 200; // e.g. The device has cutout.
         final DisplayPolicy policy = setupDisplayAndParentSize(600, 800).getDisplayPolicy();
+        spyOn(policy);
         doAnswer(invocationOnMock -> {
             final int rotation = invocationOnMock.<Integer>getArgument(0);
             final Rect insets = invocationOnMock.<Rect>getArgument(4);
@@ -482,7 +510,7 @@
 
         doReturn(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)
                 .when(mActivity.mAppWindowToken).getOrientationIgnoreVisibility();
-        mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+        mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
         mActivity.info.minAspectRatio = mActivity.info.maxAspectRatio = 1;
         ensureActivityConfiguration();
         // The parent configuration doesn't change since the first resolved configuration, so the
@@ -506,19 +534,28 @@
     @Test
     public void testSizeCompatMode_FixedScreenConfigurationWhenMovingToDisplay() {
         // Initialize different bounds on a new display.
-        final ActivityDisplay newDisplay = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
-        newDisplay.getWindowConfiguration().setAppBounds(new Rect(0, 0, 1000, 2000));
-        newDisplay.getConfiguration().densityDpi = 300;
+        final Rect newDisplayBounds = new Rect(0, 0, 1000, 2000);
+        DisplayInfo info = new DisplayInfo();
+        mService.mContext.getDisplay().getDisplayInfo(info);
+        info.logicalWidth = newDisplayBounds.width();
+        info.logicalHeight = newDisplayBounds.height();
+        info.logicalDensityDpi = 300;
+
+        final ActivityDisplay newDisplay =
+                addNewActivityDisplayAt(info, ActivityDisplay.POSITION_TOP);
 
         mTask.getConfiguration().densityDpi = 200;
-        prepareFixedAspectRatioUnresizableActivity();
+        mActivity = new ActivityBuilder(mService)
+                .setTask(mTask)
+                .setResizeMode(RESIZE_MODE_UNRESIZEABLE)
+                .setMaxAspectRatio(1.5f)
+                .build();
 
         final Rect originalBounds = new Rect(mActivity.getBounds());
         final int originalDpi = mActivity.getConfiguration().densityDpi;
 
         // Move the non-resizable activity to the new display.
         mStack.reparent(newDisplay, true /* onTop */, false /* displayRemoved */);
-        ensureActivityConfiguration();
 
         assertEquals(originalBounds, mActivity.getBounds());
         assertEquals(originalDpi, mActivity.getConfiguration().densityDpi);
@@ -531,9 +568,9 @@
         when(mActivity.mAppWindowToken.getOrientationIgnoreVisibility()).thenReturn(
                 ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
         mTask.getWindowConfiguration().setAppBounds(mStack.getDisplay().getBounds());
-        mTask.getConfiguration().orientation = Configuration.ORIENTATION_PORTRAIT;
+        mTask.getConfiguration().orientation = ORIENTATION_PORTRAIT;
         mActivity.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
-        mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+        mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
         ensureActivityConfiguration();
         final Rect originalBounds = new Rect(mActivity.getBounds());
 
@@ -579,7 +616,7 @@
         mTask.getWindowConfiguration().setAppBounds(new Rect(0, 0, 600, 1200));
 
         // Simulate the display changes orientation.
-        doReturn(ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION
+        doReturn(ActivityInfo.CONFIG_SCREEN_SIZE | CONFIG_ORIENTATION
                 | ActivityInfo.CONFIG_WINDOW_CONFIGURATION)
                         .when(display).getLastOverrideConfigurationChanges();
         mActivity.onConfigurationChanged(mTask.getConfiguration());
@@ -754,24 +791,17 @@
     /** Setup {@link #mActivity} as a size-compat-mode-able activity without fixed orientation. */
     private void prepareFixedAspectRatioUnresizableActivity() {
         setupDisplayContentForCompatDisplayInsets();
-        when(mActivity.mAppWindowToken.getOrientationIgnoreVisibility()).thenReturn(
-                ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
-        mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+        mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
         mActivity.info.maxAspectRatio = 1.5f;
         ensureActivityConfiguration();
     }
 
     private void setupDisplayContentForCompatDisplayInsets() {
         final Rect displayBounds = mStack.getDisplay().getBounds();
-        final DisplayContent displayContent = setupDisplayAndParentSize(
-                displayBounds.width(), displayBounds.height());
-        doReturn(mock(DisplayPolicy.class)).when(displayContent).getDisplayPolicy();
-        doReturn(mock(WmDisplayCutout.class)).when(displayContent)
-                .calculateDisplayCutoutForRotation(anyInt());
+        setupDisplayAndParentSize(displayBounds.width(), displayBounds.height());
     }
 
     private DisplayContent setupDisplayAndParentSize(int width, int height) {
-        // The DisplayContent is already a mocked object.
         final DisplayContent displayContent = mStack.getDisplay().mDisplayContent;
         displayContent.mBaseDisplayWidth = width;
         displayContent.mBaseDisplayHeight = height;
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index e5278d8..ff7b1fa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -29,7 +29,7 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING;
 import static com.android.server.wm.ActivityStack.ActivityState.FINISHING;
@@ -44,6 +44,7 @@
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
+import static com.android.server.wm.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -83,8 +84,9 @@
     @Before
     public void setUp() throws Exception {
         mDefaultDisplay = mRootActivityContainer.getDefaultDisplay();
-        mStack = spy(mDefaultDisplay.createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD,
-                true /* onTop */));
+        mStack = mDefaultDisplay.createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD,
+                true /* onTop */);
+        spyOn(mStack);
         mTask = new TaskBuilder(mSupervisor).setStack(mStack).build();
     }
 
@@ -140,10 +142,8 @@
 
         final ActivityStack destStack = mRootActivityContainer.getDefaultDisplay().createStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
-        final TaskRecord destTask = new TaskBuilder(mSupervisor).setStack(destStack).build();
-
-        mTask.removeActivity(r);
-        destTask.addActivityToTop(r);
+        mTask.reparent(destStack, true /*toTop*/, REPARENT_MOVE_STACK_TO_FRONT, false, false,
+                "testResumedActivityFromActivityReparenting");
 
         assertNull(mStack.getResumedActivity());
         assertEquals(r, destStack.getResumedActivity());
@@ -313,45 +313,50 @@
 
     @Test
     public void testShouldBeVisible_Fullscreen() {
-        final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+        final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
         final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+        // Add an activity to the pinned stack so it isn't considered empty for visibility check.
+        final ActivityRecord pinnedActivity = new ActivityBuilder(mService)
+                .setCreateTask(true)
+                .setStack(pinnedStack)
+                .build();
 
         assertTrue(homeStack.shouldBeVisible(null /* starting */));
         assertTrue(pinnedStack.shouldBeVisible(null /* starting */));
 
-        final TestActivityStack fullscreenStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+        final ActivityStack fullscreenStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
         // Home stack shouldn't be visible behind an opaque fullscreen stack, but pinned stack
         // should be visible since it is always on-top.
-        fullscreenStack.setIsTranslucent(false);
+        doReturn(false).when(fullscreenStack).isStackTranslucent(any());
         assertFalse(homeStack.shouldBeVisible(null /* starting */));
         assertTrue(pinnedStack.shouldBeVisible(null /* starting */));
         assertTrue(fullscreenStack.shouldBeVisible(null /* starting */));
 
         // Home stack should be visible behind a translucent fullscreen stack.
-        fullscreenStack.setIsTranslucent(true);
+        doReturn(true).when(fullscreenStack).isStackTranslucent(any());
         assertTrue(homeStack.shouldBeVisible(null /* starting */));
         assertTrue(pinnedStack.shouldBeVisible(null /* starting */));
     }
 
     @Test
     public void testShouldBeVisible_SplitScreen() {
-        final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+        final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
         // Home stack should always be fullscreen for this test.
-        homeStack.setSupportsSplitScreen(false);
-        final TestActivityStack splitScreenPrimary =
+        doReturn(false).when(homeStack).supportsSplitScreenWindowingMode();
+        final ActivityStack splitScreenPrimary =
                 createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
-        final TestActivityStack splitScreenSecondary =
+        final ActivityStack splitScreenSecondary =
                 createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
 
         // Home stack shouldn't be visible if both halves of split-screen are opaque.
-        splitScreenPrimary.setIsTranslucent(false);
-        splitScreenSecondary.setIsTranslucent(false);
+        doReturn(false).when(splitScreenPrimary).isStackTranslucent(any());
+        doReturn(false).when(splitScreenSecondary).isStackTranslucent(any());
         assertFalse(homeStack.shouldBeVisible(null /* starting */));
         assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
         assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
@@ -362,7 +367,7 @@
                 splitScreenSecondary.getVisibility(null /* starting */));
 
         // Home stack should be visible if one of the halves of split-screen is translucent.
-        splitScreenPrimary.setIsTranslucent(true);
+        doReturn(true).when(splitScreenPrimary).isStackTranslucent(any());
         assertTrue(homeStack.shouldBeVisible(null /* starting */));
         assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
         assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
@@ -373,12 +378,12 @@
         assertEquals(STACK_VISIBILITY_VISIBLE,
                 splitScreenSecondary.getVisibility(null /* starting */));
 
-        final TestActivityStack splitScreenSecondary2 =
+        final ActivityStack splitScreenSecondary2 =
                 createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
         // First split-screen secondary shouldn't be visible behind another opaque split-split
         // secondary.
-        splitScreenSecondary2.setIsTranslucent(false);
+        doReturn(false).when(splitScreenSecondary2).isStackTranslucent(any());
         assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */));
         assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
         assertEquals(STACK_VISIBILITY_INVISIBLE,
@@ -388,7 +393,7 @@
 
         // First split-screen secondary should be visible behind another translucent split-screen
         // secondary.
-        splitScreenSecondary2.setIsTranslucent(true);
+        doReturn(true).when(splitScreenSecondary2).isStackTranslucent(any());
         assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
         assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
         assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
@@ -396,11 +401,11 @@
         assertEquals(STACK_VISIBILITY_VISIBLE,
                 splitScreenSecondary2.getVisibility(null /* starting */));
 
-        final TestActivityStack assistantStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+        final ActivityStack assistantStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, true /* onTop */);
 
         // Split-screen stacks shouldn't be visible behind an opaque fullscreen stack.
-        assistantStack.setIsTranslucent(false);
+        doReturn(false).when(assistantStack).isStackTranslucent(any());
         assertTrue(assistantStack.shouldBeVisible(null /* starting */));
         assertFalse(splitScreenPrimary.shouldBeVisible(null /* starting */));
         assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */));
@@ -415,7 +420,7 @@
                 splitScreenSecondary2.getVisibility(null /* starting */));
 
         // Split-screen stacks should be visible behind a translucent fullscreen stack.
-        assistantStack.setIsTranslucent(true);
+        doReturn(true).when(assistantStack).isStackTranslucent(any());
         assertTrue(assistantStack.shouldBeVisible(null /* starting */));
         assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
         assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
@@ -430,9 +435,9 @@
                 splitScreenSecondary2.getVisibility(null /* starting */));
 
         // Assistant stack shouldn't be visible behind translucent split-screen stack
-        assistantStack.setIsTranslucent(false);
-        splitScreenPrimary.setIsTranslucent(true);
-        splitScreenSecondary2.setIsTranslucent(true);
+        doReturn(false).when(assistantStack).isStackTranslucent(any());
+        doReturn(true).when(splitScreenPrimary).isStackTranslucent(any());
+        doReturn(true).when(splitScreenSecondary2).isStackTranslucent(any());
         splitScreenSecondary2.moveToFront("testShouldBeVisible_SplitScreen");
         splitScreenPrimary.moveToFront("testShouldBeVisible_SplitScreen");
         assertFalse(assistantStack.shouldBeVisible(null /* starting */));
@@ -450,10 +455,10 @@
 
     @Test
     public void testGetVisibility_FullscreenBehindTranslucent() {
-        final TestActivityStack bottomStack =
+        final ActivityStack bottomStack =
                 createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
                         false /* translucent */);
-        final TestActivityStack translucentStack =
+        final ActivityStack translucentStack =
                 createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
                         true /* translucent */);
 
@@ -465,13 +470,13 @@
 
     @Test
     public void testGetVisibility_FullscreenBehindTranslucentAndOpaque() {
-        final TestActivityStack bottomStack =
+        final ActivityStack bottomStack =
                 createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
                         false /* translucent */);
-        final TestActivityStack translucentStack =
+        final ActivityStack translucentStack =
                 createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
                         true /* translucent */);
-        final TestActivityStack opaqueStack =
+        final ActivityStack opaqueStack =
                 createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
                         false /* translucent */);
 
@@ -483,13 +488,13 @@
 
     @Test
     public void testGetVisibility_FullscreenBehindOpaqueAndTranslucent() {
-        final TestActivityStack bottomStack =
+        final ActivityStack bottomStack =
                 createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
                         false /* translucent */);
-        final TestActivityStack opaqueStack =
+        final ActivityStack opaqueStack =
                 createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
                         false /* translucent */);
-        final TestActivityStack translucentStack =
+        final ActivityStack translucentStack =
                 createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
                         true /* translucent */);
 
@@ -502,10 +507,10 @@
 
     @Test
     public void testGetVisibility_FullscreenTranslucentBehindTranslucent() {
-        final TestActivityStack bottomTranslucentStack =
+        final ActivityStack bottomTranslucentStack =
                 createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
                         true /* translucent */);
-        final TestActivityStack translucentStack =
+        final ActivityStack translucentStack =
                 createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
                         true /* translucent */);
 
@@ -517,10 +522,10 @@
 
     @Test
     public void testGetVisibility_FullscreenTranslucentBehindOpaque() {
-        final TestActivityStack bottomTranslucentStack =
+        final ActivityStack bottomTranslucentStack =
                 createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
                         true /* translucent */);
-        final TestActivityStack opaqueStack =
+        final ActivityStack opaqueStack =
                 createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
                         false /* translucent */);
 
@@ -531,10 +536,10 @@
 
     @Test
     public void testGetVisibility_FullscreenBehindTranslucentAndPip() {
-        final TestActivityStack bottomStack =
+        final ActivityStack bottomStack =
                 createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
                         false /* translucent */);
-        final TestActivityStack translucentStack =
+        final ActivityStack translucentStack =
                 createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
                         true /* translucent */);
         final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
@@ -544,22 +549,34 @@
                 bottomStack.getVisibility(null /* starting */));
         assertEquals(STACK_VISIBILITY_VISIBLE,
                 translucentStack.getVisibility(null /* starting */));
+        // Add an activity to the pinned stack so it isn't considered empty for visibility check.
+        final ActivityRecord pinnedActivity = new ActivityBuilder(mService)
+                .setCreateTask(true)
+                .setStack(pinnedStack)
+                .build();
         assertEquals(STACK_VISIBILITY_VISIBLE, pinnedStack.getVisibility(null /* starting */));
     }
 
     @Test
     public void testShouldBeVisible_Finishing() {
-        final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+        final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
-        final TestActivityStack translucentStack = createStackForShouldBeVisibleTest(
+        ActivityRecord topRunningHomeActivity = homeStack.topRunningActivityLocked();
+        if (topRunningHomeActivity == null) {
+            topRunningHomeActivity = new ActivityBuilder(mService)
+                    .setStack(homeStack)
+                    .setCreateTask(true)
+                    .build();
+        }
+
+        final ActivityStack translucentStack = createStackForShouldBeVisibleTest(
                 mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
                 true /* onTop */);
-        translucentStack.setIsTranslucent(true);
+        doReturn(true).when(translucentStack).isStackTranslucent(any());
 
         assertTrue(homeStack.shouldBeVisible(null /* starting */));
         assertTrue(translucentStack.shouldBeVisible(null /* starting */));
 
-        final ActivityRecord topRunningHomeActivity = homeStack.topRunningActivityLocked();
         topRunningHomeActivity.finishing = true;
         final ActivityRecord topRunningTranslucentActivity =
                 translucentStack.topRunningActivityLocked();
@@ -577,13 +594,13 @@
     public void testMoveHomeStackBehindBottomMostVisibleStack_NoMoveHomeBehindFullscreen() {
         mDefaultDisplay.removeChild(mStack);
 
-        final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+        final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
-        final TestActivityStack fullscreenStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+        final ActivityStack fullscreenStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
 
-        homeStack.setIsTranslucent(false);
-        fullscreenStack.setIsTranslucent(false);
+        doReturn(false).when(homeStack).isStackTranslucent(any());
+        doReturn(false).when(fullscreenStack).isStackTranslucent(any());
 
         // Ensure that we don't move the home stack if it is already behind the top fullscreen stack
         int homeStackIndex = mDefaultDisplay.getIndexOf(homeStack);
@@ -596,13 +613,13 @@
     public void testMoveHomeStackBehindBottomMostVisibleStack_NoMoveHomeBehindTranslucent() {
         mDefaultDisplay.removeChild(mStack);
 
-        final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+        final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
-        final TestActivityStack fullscreenStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+        final ActivityStack fullscreenStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
 
-        homeStack.setIsTranslucent(false);
-        fullscreenStack.setIsTranslucent(true);
+        doReturn(false).when(homeStack).isStackTranslucent(any());
+        doReturn(true).when(fullscreenStack).isStackTranslucent(any());
 
         // Ensure that we don't move the home stack if it is already behind the top fullscreen stack
         int homeStackIndex = mDefaultDisplay.getIndexOf(homeStack);
@@ -615,13 +632,13 @@
     public void testMoveHomeStackBehindBottomMostVisibleStack_NoMoveHomeOnTop() {
         mDefaultDisplay.removeChild(mStack);
 
-        final TestActivityStack fullscreenStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+        final ActivityStack fullscreenStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
-        final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+        final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
 
-        homeStack.setIsTranslucent(false);
-        fullscreenStack.setIsTranslucent(false);
+        doReturn(false).when(homeStack).isStackTranslucent(any());
+        doReturn(false).when(fullscreenStack).isStackTranslucent(any());
 
         // Ensure we don't move the home stack if it is already on top
         int homeStackIndex = mDefaultDisplay.getIndexOf(homeStack);
@@ -634,20 +651,20 @@
     public void testMoveHomeStackBehindBottomMostVisibleStack_MoveHomeBehindFullscreen() {
         mDefaultDisplay.removeChild(mStack);
 
-        final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+        final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
-        final TestActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest(
+        final ActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest(
                 mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
                 true /* onTop */);
-        final TestActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest(
+        final ActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest(
                 mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
                 true /* onTop */);
         final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
 
-        homeStack.setIsTranslucent(false);
-        fullscreenStack1.setIsTranslucent(false);
-        fullscreenStack2.setIsTranslucent(false);
+        doReturn(false).when(homeStack).isStackTranslucent(any());
+        doReturn(false).when(fullscreenStack1).isStackTranslucent(any());
+        doReturn(false).when(fullscreenStack2).isStackTranslucent(any());
 
         // Ensure that we move the home stack behind the bottom most fullscreen stack, ignoring the
         // pinned stack
@@ -661,18 +678,18 @@
             testMoveHomeStackBehindBottomMostVisibleStack_MoveHomeBehindFullscreenAndTranslucent() {
         mDefaultDisplay.removeChild(mStack);
 
-        final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+        final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
-        final TestActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest(
+        final ActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest(
                 mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
                 true /* onTop */);
-        final TestActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest(
+        final ActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest(
                 mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
                 true /* onTop */);
 
-        homeStack.setIsTranslucent(false);
-        fullscreenStack1.setIsTranslucent(false);
-        fullscreenStack2.setIsTranslucent(true);
+        doReturn(false).when(homeStack).isStackTranslucent(any());
+        doReturn(false).when(fullscreenStack1).isStackTranslucent(any());
+        doReturn(true).when(fullscreenStack2).isStackTranslucent(any());
 
         // Ensure that we move the home stack behind the bottom most non-translucent fullscreen
         // stack
@@ -685,18 +702,18 @@
     public void testMoveHomeStackBehindStack_BehindHomeStack() {
         mDefaultDisplay.removeChild(mStack);
 
-        final TestActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest(
+        final ActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest(
                 mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
                 true /* onTop */);
-        final TestActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest(
+        final ActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest(
                 mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
                 true /* onTop */);
-        final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+        final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
 
-        homeStack.setIsTranslucent(false);
-        fullscreenStack1.setIsTranslucent(false);
-        fullscreenStack2.setIsTranslucent(false);
+        doReturn(false).when(homeStack).isStackTranslucent(any());
+        doReturn(false).when(fullscreenStack1).isStackTranslucent(any());
+        doReturn(false).when(fullscreenStack2).isStackTranslucent(any());
 
         // Ensure we don't move the home stack behind itself
         int homeStackIndex = mDefaultDisplay.getIndexOf(homeStack);
@@ -708,19 +725,19 @@
     public void testMoveHomeStackBehindStack() {
         mDefaultDisplay.removeChild(mStack);
 
-        final TestActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest(
+        final ActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest(
                 mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
                 true /* onTop */);
-        final TestActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest(
+        final ActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest(
                 mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
                 true /* onTop */);
-        final TestActivityStack fullscreenStack3 = createStackForShouldBeVisibleTest(
+        final ActivityStack fullscreenStack3 = createStackForShouldBeVisibleTest(
                 mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
                 true /* onTop */);
-        final TestActivityStack fullscreenStack4 = createStackForShouldBeVisibleTest(
+        final ActivityStack fullscreenStack4 = createStackForShouldBeVisibleTest(
                 mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
                 true /* onTop */);
-        final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+        final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
 
         mDefaultDisplay.moveStackBehindStack(homeStack, fullscreenStack1);
@@ -735,13 +752,13 @@
 
     @Test
     public void testSetAlwaysOnTop() {
-        final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+        final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
         final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
         assertEquals(pinnedStack, mDefaultDisplay.getStackAbove(homeStack));
 
-        final TestActivityStack alwaysOnTopStack = createStackForShouldBeVisibleTest(
+        final ActivityStack alwaysOnTopStack = createStackForShouldBeVisibleTest(
                 mDefaultDisplay, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD,
                 true /* onTop */);
         alwaysOnTopStack.setAlwaysOnTop(true);
@@ -749,13 +766,13 @@
         // Ensure (non-pinned) always on top stack is put below pinned stack.
         assertEquals(pinnedStack, mDefaultDisplay.getStackAbove(alwaysOnTopStack));
 
-        final TestActivityStack nonAlwaysOnTopStack = createStackForShouldBeVisibleTest(
+        final ActivityStack nonAlwaysOnTopStack = createStackForShouldBeVisibleTest(
                 mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
                 true /* onTop */);
         // Ensure non always on top stack is put below always on top stacks.
         assertEquals(alwaysOnTopStack, mDefaultDisplay.getStackAbove(nonAlwaysOnTopStack));
 
-        final TestActivityStack alwaysOnTopStack2 = createStackForShouldBeVisibleTest(
+        final ActivityStack alwaysOnTopStack2 = createStackForShouldBeVisibleTest(
                 mDefaultDisplay, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD,
                 true /* onTop */);
         alwaysOnTopStack2.setAlwaysOnTop(true);
@@ -780,18 +797,18 @@
 
     @Test
     public void testSplitScreenMoveToFront() {
-        final TestActivityStack splitScreenPrimary = createStackForShouldBeVisibleTest(
+        final ActivityStack splitScreenPrimary = createStackForShouldBeVisibleTest(
                 mDefaultDisplay, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD,
                 true /* onTop */);
-        final TestActivityStack splitScreenSecondary = createStackForShouldBeVisibleTest(
+        final ActivityStack splitScreenSecondary = createStackForShouldBeVisibleTest(
                 mDefaultDisplay, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD,
                 true /* onTop */);
-        final TestActivityStack assistantStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+        final ActivityStack assistantStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, true /* onTop */);
 
-        splitScreenPrimary.setIsTranslucent(false);
-        splitScreenSecondary.setIsTranslucent(false);
-        assistantStack.setIsTranslucent(false);
+        doReturn(false).when(splitScreenPrimary).isStackTranslucent(any());
+        doReturn(false).when(splitScreenSecondary).isStackTranslucent(any());
+        doReturn(false).when(assistantStack).isStackTranslucent(any());
 
         assertFalse(splitScreenPrimary.shouldBeVisible(null /* starting */));
         assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */));
@@ -804,18 +821,18 @@
         assertFalse(assistantStack.shouldBeVisible(null /* starting */));
     }
 
-    private TestActivityStack createStandardStackForVisibilityTest(int windowingMode,
+    private ActivityStack createStandardStackForVisibilityTest(int windowingMode,
             boolean translucent) {
-        final TestActivityStack stack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+        final ActivityStack stack = createStackForShouldBeVisibleTest(mDefaultDisplay,
                 windowingMode, ACTIVITY_TYPE_STANDARD, true /* onTop */);
-        stack.setIsTranslucent(translucent);
+        doReturn(translucent).when(stack).isStackTranslucent(any());
         return stack;
     }
 
     @SuppressWarnings("TypeParameterUnusedInFormals")
     private <T extends ActivityStack> T createStackForShouldBeVisibleTest(
             ActivityDisplay display, int windowingMode, int activityType, boolean onTop) {
-        final T stack;
+        final ActivityStack stack;
         if (activityType == ACTIVITY_TYPE_HOME) {
             // Home stack and activity are created in ActivityTestsBase#setupActivityManagerService
             stack = mDefaultDisplay.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
@@ -825,11 +842,15 @@
                 mDefaultDisplay.positionChildAtBottom(stack);
             }
         } else {
-            stack = display.createStack(windowingMode, activityType, onTop);
-            final ActivityRecord r = new ActivityBuilder(mService).setUid(0).setStack(stack)
-                    .setCreateTask(true).build();
+            stack = new StackBuilder(mRootActivityContainer)
+                    .setDisplay(display)
+                    .setWindowingMode(windowingMode)
+                    .setActivityType(activityType)
+                    .setOnTop(onTop)
+                    .setCreateActivity(true)
+                    .build();
         }
-        return stack;
+        return (T) stack;
     }
 
     @Test
@@ -961,11 +982,16 @@
 
     @Test
     public void testAdjustFocusedStackToHomeWhenNoActivity() {
+        final ActivityStack homeStask = mDefaultDisplay.getHomeStack();
+        TaskRecord homeTask = homeStask.topTask();
+        if (homeTask == null) {
+            // Create home task if there isn't one.
+            homeTask = new TaskBuilder(mSupervisor).setStack(homeStask).build();
+        }
+
         final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
         mStack.moveToFront("testAdjustFocusedStack");
 
-        final ActivityStack homeStask = mDefaultDisplay.getHomeStack();
-        final TaskRecord homeTask = homeStask.topTask();
         // Simulate that home activity has not been started or is force-stopped.
         homeStask.removeTask(homeTask, "testAdjustFocusedStack", REMOVE_TASK_MODE_DESTROYING);
 
@@ -981,6 +1007,14 @@
         final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
 
+        ActivityRecord activity = homeStack.topRunningActivityLocked();
+        if (activity == null) {
+            activity = new ActivityBuilder(mService)
+                    .setStack(homeStack)
+                    .setCreateTask(true)
+                    .build();
+        }
+
         // Home stack should not be destroyed immediately.
         final ActivityRecord activity1 = finishCurrentActivity(homeStack);
         assertEquals(FINISHING, activity1.getState());
@@ -1068,7 +1102,7 @@
     public void testStackOrderChangedOnPositionStack() {
         StackOrderChangedListener listener = new StackOrderChangedListener();
         try {
-            final TestActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest(
+            final ActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest(
                     mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
                     true /* onTop */);
             mDefaultDisplay.registerStackOrderChangedListener(listener);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 3d94467..81fbfe4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -79,6 +79,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.server.wm.LaunchParamsController.LaunchParamsModifier;
+import com.android.server.wm.utils.MockTracker;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -186,6 +187,19 @@
         verifyStartActivityPreconditions(preconditions, 0 /*launchFlags*/, expectedResult);
     }
 
+    private void verifyStartActivityPreconditions(int preconditions, int launchFlags,
+            int expectedResult) {
+        // We track mocks created here because this is used in a single test
+        // (testStartActivityPreconditions) as a specific case, and mocks created inside it won't be
+        // used for other cases. To avoid extensive memory usage, we clean up all used mocks after
+        // each case. This is necessary because usually we only clean up mocks after a test
+        // finishes, but this test creates too many mocks that the intermediate memory usage can be
+        // ~0.8 GiB and thus very susceptible to OutOfMemoryException.
+        try (MockTracker tracker = new MockTracker()) {
+            verifyStartActivityPreconditionsUntracked(preconditions, launchFlags, expectedResult);
+        }
+    }
+
     /**
      * Excercises how the {@link ActivityStarter} reacts to various preconditions. The caller
      * provides a bitmask of all the set conditions (such as {@link #PRECONDITION_NO_CALLER_APP})
@@ -197,7 +211,7 @@
      * @param launchFlags The launch flags to be provided by the launch {@link Intent}.
      * @param expectedResult The expected result from the launch.
      */
-    private void verifyStartActivityPreconditions(int preconditions, int launchFlags,
+    private void verifyStartActivityPreconditionsUntracked(int preconditions, int launchFlags,
             int expectedResult) {
         final ActivityTaskManagerService service = mService;
         final IPackageManager packageManager = mock(IPackageManager.class);
@@ -329,9 +343,6 @@
                 any(), any(), any(), anyInt(), anyInt(), anyInt(), any(),
                 anyBoolean(), anyBoolean(), any(), any(), any());
 
-        // Use factory that only returns spy task.
-        mockTaskRecordFactory();
-
         if (mockGetLaunchStack) {
             // Instrument the stack and task used.
             final ActivityStack stack = mRootActivityContainer.getDefaultDisplay().createStack(
@@ -482,7 +493,7 @@
     @Test
     public void testTaskModeViolation() {
         final ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
-        ((TestActivityDisplay) display).removeAllTasks();
+        display.removeAllTasks();
         assertNoTasks(display);
 
         final ActivityStarter starter = prepareStarter(0);
@@ -676,18 +687,27 @@
         doReturn(isCallingUidDeviceOwner).when(mService).isDeviceOwner(callingUid);
 
         final ActivityOptions options = spy(ActivityOptions.makeBasic());
+        ActivityRecord[] outActivity = new ActivityRecord[1];
         ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK)
                 .setCallingPackage("com.whatever.dude")
                 .setCaller(caller)
                 .setCallingUid(callingUid)
                 .setRealCallingUid(realCallingUid)
-                .setActivityOptions(new SafeActivityOptions(options));
+                .setActivityOptions(new SafeActivityOptions(options))
+                .setOutActivity(outActivity);
 
         final int result = starter.setReason("testBackgroundActivityStarts_" + name).execute();
 
         assertEquals(ActivityStarter.getExternalResult(
                 shouldHaveAborted ? START_ABORTED : START_SUCCESS), result);
         verify(options, times(shouldHaveAborted ? 1 : 0)).abort();
+
+        final ActivityRecord startedActivity = outActivity[0];
+        if (startedActivity != null && startedActivity.getTaskRecord() != null) {
+            // Remove the activity so it doesn't interfere with with subsequent activity launch
+            // tests from this method.
+            startedActivity.getTaskRecord().removeActivity(startedActivity);
+        }
     }
 
     /**
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index d8a9bb0..297aa7e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -45,8 +45,7 @@
     /** Verify that activity is finished correctly upon request. */
     @Test
     public void testActivityFinish() {
-        final TestActivityStack stack =
-                (TestActivityStack) new StackBuilder(mRootActivityContainer).build();
+        final ActivityStack stack = new StackBuilder(mRootActivityContainer).build();
         final ActivityRecord activity = stack.getChildAt(0).getTopActivity();
         assertTrue("Activity must be finished", mService.finishActivity(activity.appToken,
                 0 /* resultCode */, null /* resultData */,
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index ab2da2b..a5dc241 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -16,96 +16,58 @@
 
 package com.android.server.wm;
 
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
-import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
-import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
 
-import android.app.ActivityManagerInternal;
 import android.app.ActivityOptions;
-import android.app.AppOpsManager;
 import android.app.IApplicationThread;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageManager;
-import android.content.pm.PackageManagerInternal;
 import android.content.res.Configuration;
 import android.graphics.Rect;
-import android.hardware.display.DisplayManager;
-import android.hardware.display.DisplayManagerGlobal;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.PowerManager;
-import android.os.Process;
 import android.os.UserHandle;
 import android.service.voice.IVoiceInteractionSession;
 import android.testing.DexmakerShareClassLoaderRule;
-import android.view.Display;
 import android.view.DisplayInfo;
 
-import com.android.internal.app.IVoiceInteractor;
 import com.android.server.AttributeCache;
-import com.android.server.ServiceThread;
-import com.android.server.am.ActivityManagerService;
-import com.android.server.am.PendingIntentController;
-import com.android.server.appop.AppOpsService;
-import com.android.server.firewall.IntentFirewall;
-import com.android.server.policy.PermissionPolicyInternal;
-import com.android.server.uri.UriGrantsManagerInternal;
-import com.android.server.wm.TaskRecord.TaskRecordFactory;
-import com.android.server.wm.utils.MockTracker;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Rule;
-import org.mockito.invocation.InvocationOnMock;
-
-import java.io.File;
-import java.util.List;
-import java.util.function.Consumer;
 
 /**
  * A base class to handle common operations in activity related unit tests.
  */
 class ActivityTestsBase {
-    private static int sNextDisplayId = DEFAULT_DISPLAY + 1;
 
     @Rule
     public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
             new DexmakerShareClassLoaderRule();
 
+    @Rule
+    public final SystemServicesTestRule mSystemServicesTestRule = new SystemServicesTestRule();
+
     final Context mContext = getInstrumentation().getTargetContext();
-    final TestInjector mTestInjector = new TestInjector(mContext);
 
     ActivityTaskManagerService mService;
     RootActivityContainer mRootActivityContainer;
     ActivityStackSupervisor mSupervisor;
 
-    private MockTracker mMockTracker;
-
     // Default package name
     static final String DEFAULT_COMPONENT_PACKAGE_NAME = "com.foo";
 
@@ -119,37 +81,18 @@
 
     @Before
     public void setUpBase() {
-        mMockTracker = new MockTracker();
-
-        mTestInjector.setUp();
-
-        mService = new TestActivityTaskManagerService(mContext);
+        mService = mSystemServicesTestRule.getActivityTaskManagerService();
         mSupervisor = mService.mStackSupervisor;
         mRootActivityContainer = mService.mRootActivityContainer;
     }
 
-    @After
-    public void tearDownBase() {
-        mTestInjector.tearDown();
-        if (mService != null) {
-            mService.setWindowManager(null);
-            mService = null;
-        }
-        if (sMockWindowManagerService != null) {
-            reset(sMockWindowManagerService);
-        }
-
-        mMockTracker.close();
-        mMockTracker = null;
-    }
-
     /** Creates a {@link TestActivityDisplay}. */
     TestActivityDisplay createNewActivityDisplay() {
-        return TestActivityDisplay.create(mSupervisor, sNextDisplayId++);
+        return TestActivityDisplay.create(mSupervisor);
     }
 
     TestActivityDisplay createNewActivityDisplay(DisplayInfo info) {
-        return TestActivityDisplay.create(mSupervisor, sNextDisplayId++, info);
+        return TestActivityDisplay.create(mSupervisor, info);
     }
 
     /** Creates and adds a {@link TestActivityDisplay} to supervisor at the given position. */
@@ -166,25 +109,9 @@
         return display;
     }
 
-    /**
-     * Delegates task creation to {@link #TaskBuilder} to avoid the dependency of window hierarchy
-     * when starting activity in unit tests.
-     */
-    void mockTaskRecordFactory(Consumer<TaskBuilder> taskBuilderSetup) {
-        final TaskBuilder taskBuilder = new TaskBuilder(mSupervisor).setCreateStack(false);
-        if (taskBuilderSetup != null) {
-            taskBuilderSetup.accept(taskBuilder);
-        }
-        final TaskRecord task = taskBuilder.build();
-        final TaskRecordFactory factory = mock(TaskRecordFactory.class);
-        TaskRecord.setTaskRecordFactory(factory);
-        doReturn(task).when(factory).create(any() /* service */, anyInt() /* taskId */,
-                any() /* info */, any() /* intent */, any() /* voiceSession */,
-                any() /* voiceInteractor */);
-    }
-
-    void mockTaskRecordFactory() {
-        mockTaskRecordFactory(null /* taskBuilderSetup */);
+    /** Sets the default minimum task size to 1 so that tests can use small task sizes */
+    public void removeGlobalMinSizeRestriction() {
+        mService.mRootActivityContainer.mDefaultMinSizeOfResizeableTaskDp = 1;
     }
 
     /**
@@ -204,6 +131,11 @@
         private ActivityStack mStack;
         private int mActivityFlags;
         private int mLaunchMode;
+        private int mResizeMode = RESIZE_MODE_RESIZEABLE;
+        private float mMaxAspectRatio;
+        private int mScreenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
+        private boolean mLaunchTaskBehind;
+        private int mConfigChanges;
 
         ActivityBuilder(ActivityTaskManagerService service) {
             mService = service;
@@ -254,6 +186,31 @@
             return this;
         }
 
+        ActivityBuilder setResizeMode(int resizeMode) {
+            mResizeMode = resizeMode;
+            return this;
+        }
+
+        ActivityBuilder setMaxAspectRatio(float maxAspectRatio) {
+            mMaxAspectRatio = maxAspectRatio;
+            return this;
+        }
+
+        ActivityBuilder setScreenOrientation(int screenOrientation) {
+            mScreenOrientation = screenOrientation;
+            return this;
+        }
+
+        ActivityBuilder setLaunchTaskBehind(boolean launchTaskBehind) {
+            mLaunchTaskBehind = launchTaskBehind;
+            return this;
+        }
+
+        ActivityBuilder setConfigChanges(int configChanges) {
+            mConfigChanges = configChanges;
+            return this;
+        }
+
         ActivityRecord build() {
             if (mComponent == null) {
                 final int id = sCurrentActivityId++;
@@ -279,24 +236,31 @@
             }
             aInfo.flags |= mActivityFlags;
             aInfo.launchMode = mLaunchMode;
+            aInfo.resizeMode = mResizeMode;
+            aInfo.maxAspectRatio = mMaxAspectRatio;
+            aInfo.screenOrientation = mScreenOrientation;
+            aInfo.configChanges |= mConfigChanges;
+
+            ActivityOptions options = null;
+            if (mLaunchTaskBehind) {
+                options =  ActivityOptions.makeTaskLaunchBehind();
+            }
 
             final ActivityRecord activity = new ActivityRecord(mService, null /* caller */,
                     0 /* launchedFromPid */, 0, null, intent, null,
                     aInfo /*aInfo*/, new Configuration(), null /* resultTo */, null /* resultWho */,
                     0 /* reqCode */, false /*componentSpecified*/, false /* rootVoiceInteraction */,
-                    mService.mStackSupervisor, null /* options */, null /* sourceRecord */);
+                    mService.mStackSupervisor, options, null /* sourceRecord */);
             spyOn(activity);
-            activity.mAppWindowToken = mock(AppWindowToken.class);
-            doCallRealMethod().when(activity.mAppWindowToken).getOrientationIgnoreVisibility();
-            doCallRealMethod().when(activity.mAppWindowToken)
-                    .setOrientation(anyInt(), any(), any());
-            doCallRealMethod().when(activity.mAppWindowToken).setOrientation(anyInt());
-            doNothing().when(activity).removeWindowContainer();
-            doReturn(mock(Configuration.class)).when(activity.mAppWindowToken)
-                    .getRequestedOverrideConfiguration();
-
             if (mTaskRecord != null) {
-                mTaskRecord.addActivityToTop(activity);
+                // fullscreen value is normally read from resources in ctor, so for testing we need
+                // to set it somewhere else since we can't mock resources.
+                activity.fullscreen = true;
+                activity.setTask(mTaskRecord);
+                activity.createAppWindowToken();
+                spyOn(activity.mAppWindowToken);
+                // Make visible by default...
+                activity.mAppWindowToken.setHidden(false);
             }
 
             final WindowProcessController wpc = new WindowProcessController(mService,
@@ -305,6 +269,9 @@
                     mock(WindowProcessListener.class));
             wpc.setThread(mock(IApplicationThread.class));
             activity.setProcess(wpc);
+
+            // Resume top activities to make sure all other signals in the system are connected.
+            mService.mRootActivityContainer.resumeFocusedStacksTopActivities();
             return activity;
         }
     }
@@ -313,16 +280,13 @@
      * Builder for creating new tasks.
      */
     protected static class TaskBuilder {
-        // Default package name
-        static final String DEFAULT_PACKAGE = "com.bar";
-
         private final ActivityStackSupervisor mSupervisor;
 
         private ComponentName mComponent;
         private String mPackage;
         private int mFlags = 0;
         // Task id 0 is reserved in ARC for the home app.
-        private int mTaskId = 1;
+        private int mTaskId = SystemServicesTestRule.sNextTaskId++;
         private int mUserId = 0;
         private IVoiceInteractionSession mVoiceSession;
         private boolean mCreateStack = true;
@@ -381,6 +345,7 @@
             if (mStack == null && mCreateStack) {
                 mStack = mSupervisor.mRootActivityContainer.getDefaultDisplay().createStack(
                         WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+                spyOn(mStack);
             }
 
             final ActivityInfo aInfo = new ActivityInfo();
@@ -396,450 +361,22 @@
             intent.setComponent(mComponent);
             intent.setFlags(mFlags);
 
-            final TestTaskRecord task = new TestTaskRecord(mSupervisor.mService, mTaskId, aInfo,
+            final TaskRecord task = new TaskRecord(mSupervisor.mService, mTaskId, aInfo,
                     intent /*intent*/, mVoiceSession, null /*_voiceInteractor*/);
+            spyOn(task);
             task.userId = mUserId;
 
             if (mStack != null) {
                 mStack.moveToFront("test");
                 mStack.addTask(task, true, "creating test task");
-                task.setStack(mStack);
-                task.setTask();
-                mStack.getTaskStack().addChild(task.mTask, 0);
+                task.createTask(true, true);
+                spyOn(task.mTask);
             }
 
             task.touchActiveTime();
 
             return task;
         }
-
-        private static class TestTaskRecord extends TaskRecord {
-            TestTaskRecord(ActivityTaskManagerService service, int taskId, ActivityInfo info,
-                       Intent intent, IVoiceInteractionSession voiceSession,
-                       IVoiceInteractor voiceInteractor) {
-                super(service, taskId, info, intent, voiceSession, voiceInteractor);
-            }
-
-            @Override
-            void createTask(boolean onTop, boolean showForAllUsers) {
-                setTask();
-            }
-
-            void setTask() {
-                Task mockTask = mock(Task.class);
-                mockTask.mTaskRecord = this;
-                doCallRealMethod().when(mockTask).onDescendantOrientationChanged(any(), any());
-                setTask(mock(Task.class));
-            }
-        }
-    }
-
-    protected class TestActivityTaskManagerService extends ActivityTaskManagerService {
-        private PackageManagerInternal mPmInternal;
-        private PermissionPolicyInternal mPermissionPolicyInternal;
-
-        // ActivityStackSupervisor may be created more than once while setting up AMS and ATMS.
-        // We keep the reference in order to prevent creating it twice.
-        ActivityStackSupervisor mTestStackSupervisor;
-
-        ActivityDisplay mDefaultDisplay;
-        AppOpsService mAppOpsService;
-
-        TestActivityTaskManagerService(Context context) {
-            super(context);
-            spyOn(this);
-
-            mUgmInternal = mock(UriGrantsManagerInternal.class);
-            mAppOpsService = mock(AppOpsService.class);
-
-            // Make sure permission checks aren't overridden.
-            doReturn(AppOpsManager.MODE_DEFAULT)
-                    .when(mAppOpsService).noteOperation(anyInt(), anyInt(), anyString());
-
-            mSupportsMultiWindow = true;
-            mSupportsMultiDisplay = true;
-            mSupportsSplitScreenMultiWindow = true;
-            mSupportsFreeformWindowManagement = true;
-            mSupportsPictureInPicture = true;
-
-            final TestActivityManagerService am =
-                    new TestActivityManagerService(mTestInjector, this);
-
-            spyOn(getLifecycleManager());
-            spyOn(getLockTaskController());
-            spyOn(getTaskChangeNotificationController());
-            doReturn(mock(IPackageManager.class)).when(this).getPackageManager();
-            // allow background activity starts by default
-            doReturn(true).when(this).isBackgroundActivityStartsEnabled();
-            doNothing().when(this).updateCpuStats();
-        }
-
-        void setup(IntentFirewall intentFirewall, PendingIntentController intentController,
-                ActivityManagerInternal amInternal, WindowManagerService wm, Looper looper) {
-            mAmInternal = amInternal;
-            initialize(intentFirewall, intentController, looper);
-            initRootActivityContainerMocks(wm);
-            setWindowManager(wm);
-            createDefaultDisplay();
-        }
-
-        void initRootActivityContainerMocks(WindowManagerService wm) {
-            spyOn(mRootActivityContainer);
-            mRootActivityContainer.setWindowContainer(mock(RootWindowContainer.class));
-            mRootActivityContainer.mWindowManager = wm;
-            mRootActivityContainer.mDisplayManager =
-                    (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
-            doNothing().when(mRootActivityContainer).setWindowManager(any());
-            // Invoked during {@link ActivityStack} creation.
-            doNothing().when(mRootActivityContainer).updateUIDsPresentOnDisplay();
-            // Always keep things awake.
-            doReturn(true).when(mRootActivityContainer).hasAwakeDisplay();
-            // Called when moving activity to pinned stack.
-            doNothing().when(mRootActivityContainer).ensureActivitiesVisible(any(), anyInt(),
-                    anyBoolean());
-        }
-
-        void createDefaultDisplay() {
-            // Create a default display and put a home stack on it so that we'll always have
-            // something focusable.
-            mDefaultDisplay = TestActivityDisplay.create(mStackSupervisor, DEFAULT_DISPLAY);
-            spyOn(mDefaultDisplay);
-            mRootActivityContainer.addChild(mDefaultDisplay, ActivityDisplay.POSITION_TOP);
-            mDefaultDisplay.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
-            final TaskRecord task = new TaskBuilder(mStackSupervisor)
-                    .setStack(mDefaultDisplay.getHomeStack()).build();
-            new ActivityBuilder(this).setTask(task).build();
-
-            doReturn(mDefaultDisplay).when(mRootActivityContainer).getDefaultDisplay();
-        }
-
-        @Override
-        int handleIncomingUser(int callingPid, int callingUid, int userId, String name) {
-            return userId;
-        }
-
-        @Override
-        AppOpsService getAppOpsService() {
-            return mAppOpsService;
-        }
-
-        @Override
-        void updateCpuStats() {
-        }
-
-        @Override
-        void updateBatteryStats(ActivityRecord component, boolean resumed) {
-        }
-
-        @Override
-        void updateActivityUsageStats(ActivityRecord activity, int event) {
-        }
-
-        @Override
-        protected ActivityStackSupervisor createStackSupervisor() {
-            if (mTestStackSupervisor == null) {
-                mTestStackSupervisor = new TestActivityStackSupervisor(this, mH.getLooper());
-            }
-            return mTestStackSupervisor;
-        }
-
-        @Override
-        PackageManagerInternal getPackageManagerInternalLocked() {
-            if (mPmInternal == null) {
-                mPmInternal = mock(PackageManagerInternal.class);
-                doReturn(false)
-                        .when(mPmInternal)
-                        .isPermissionsReviewRequired(anyString(), anyInt());
-            }
-            return mPmInternal;
-        }
-
-        @Override
-        PermissionPolicyInternal getPermissionPolicyInternal() {
-            if (mPermissionPolicyInternal == null) {
-                mPermissionPolicyInternal = mock(PermissionPolicyInternal.class);
-                doReturn(true).when(mPermissionPolicyInternal).checkStartActivity(any(), anyInt(),
-                        any());
-            }
-            return mPermissionPolicyInternal;
-        }
-    }
-
-    private static class TestInjector extends ActivityManagerService.Injector {
-        private ServiceThread mHandlerThread;
-
-        TestInjector(Context context) {
-            super(context);
-        }
-
-        @Override
-        public AppOpsService getAppOpsService(File file, Handler handler) {
-            return null;
-        }
-
-        @Override
-        public Handler getUiHandler(ActivityManagerService service) {
-            return mHandlerThread.getThreadHandler();
-        }
-
-        @Override
-        public boolean isNetworkRestrictedForUid(int uid) {
-            return false;
-        }
-
-        void setUp() {
-            mHandlerThread = new ServiceThread("ActivityTestsThread",
-                    Process.THREAD_PRIORITY_DEFAULT, true /* allowIo */);
-            mHandlerThread.start();
-        }
-
-        void tearDown() {
-            // Make sure there are no running messages and then quit the thread so the next test
-            // won't be affected.
-            mHandlerThread.getThreadHandler().runWithScissors(mHandlerThread::quit,
-                    0 /* timeout */);
-        }
-    }
-
-    // TODO: Replace this with a mock object since we are no longer in AMS package.
-    /**
-     * An {@link ActivityManagerService} subclass which provides a test
-     * {@link ActivityStackSupervisor}.
-     */
-    class TestActivityManagerService extends ActivityManagerService {
-
-        TestActivityManagerService(TestInjector testInjector, TestActivityTaskManagerService atm) {
-            super(testInjector, testInjector.mHandlerThread);
-            spyOn(this);
-
-            mWindowManager = prepareMockWindowManager();
-            mUgmInternal = mock(UriGrantsManagerInternal.class);
-
-            atm.setup(mIntentFirewall, mPendingIntentController, new LocalService(), mWindowManager,
-                    testInjector.mHandlerThread.getLooper());
-
-            mActivityTaskManager = atm;
-            mAtmInternal = atm.mInternal;
-
-            doReturn(mock(IPackageManager.class)).when(this).getPackageManager();
-            PackageManagerInternal mockPackageManager = mock(PackageManagerInternal.class);
-            doReturn(mockPackageManager).when(this).getPackageManagerInternalLocked();
-            doReturn(null).when(mockPackageManager).getDefaultHomeActivity(anyInt());
-            doNothing().when(this).grantEphemeralAccessLocked(anyInt(), any(), anyInt(), anyInt());
-        }
-    }
-
-    /**
-     * An {@link ActivityStackSupervisor} which stubs out certain methods that depend on
-     * setup not available in the test environment. Also specifies an injector for
-     */
-    protected class TestActivityStackSupervisor extends ActivityStackSupervisor {
-        private KeyguardController mKeyguardController;
-
-        TestActivityStackSupervisor(ActivityTaskManagerService service, Looper looper) {
-            super(service, looper);
-            spyOn(this);
-            mWindowManager = prepareMockWindowManager();
-            mKeyguardController = mock(KeyguardController.class);
-
-            // Do not schedule idle that may touch methods outside the scope of the test.
-            doNothing().when(this).scheduleIdleLocked();
-            doNothing().when(this).scheduleIdleTimeoutLocked(any());
-            // unit test version does not handle launch wake lock
-            doNothing().when(this).acquireLaunchWakelock();
-            doReturn(mKeyguardController).when(this).getKeyguardController();
-
-            mLaunchingActivityWakeLock = mock(PowerManager.WakeLock.class);
-
-            initialize();
-        }
-
-        @Override
-        public KeyguardController getKeyguardController() {
-            return mKeyguardController;
-        }
-
-        @Override
-        void setWindowManager(WindowManagerService wm) {
-            mWindowManager = wm;
-        }
-    }
-
-    protected static class TestActivityDisplay extends ActivityDisplay {
-        private final ActivityStackSupervisor mSupervisor;
-
-        static TestActivityDisplay create(ActivityStackSupervisor supervisor, int displayId) {
-            return create(supervisor, displayId, new DisplayInfo());
-        }
-
-        static TestActivityDisplay create(ActivityStackSupervisor supervisor, int displayId,
-                DisplayInfo info) {
-            if (displayId == DEFAULT_DISPLAY) {
-                return new TestActivityDisplay(supervisor,
-                        supervisor.mRootActivityContainer.mDisplayManager.getDisplay(displayId));
-            }
-            final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
-                    info, DEFAULT_DISPLAY_ADJUSTMENTS);
-            return new TestActivityDisplay(supervisor, display);
-        }
-
-        TestActivityDisplay(ActivityStackSupervisor supervisor, Display display) {
-            super(supervisor.mService.mRootActivityContainer, display);
-            // Normally this comes from display-properties as exposed by WM. Without that, just
-            // hard-code to FULLSCREEN for tests.
-            setWindowingMode(WINDOWING_MODE_FULLSCREEN);
-            mSupervisor = supervisor;
-        }
-
-        @SuppressWarnings("TypeParameterUnusedInFormals")
-        @Override
-        ActivityStack createStackUnchecked(int windowingMode, int activityType,
-                int stackId, boolean onTop) {
-            return new StackBuilder(mSupervisor.mRootActivityContainer).setDisplay(this)
-                    .setWindowingMode(windowingMode).setActivityType(activityType)
-                    .setStackId(stackId).setOnTop(onTop).setCreateActivity(false).build();
-        }
-
-        @Override
-        protected DisplayContent createDisplayContent() {
-            final DisplayContent displayContent = mock(DisplayContent.class);
-            DockedStackDividerController divider = mock(DockedStackDividerController.class);
-            doReturn(divider).when(displayContent).getDockedDividerController();
-            return displayContent;
-        }
-
-        void removeAllTasks() {
-            for (int i = 0; i < getChildCount(); i++) {
-                final ActivityStack stack = getChildAt(i);
-                for (TaskRecord task : (List<TaskRecord>) stack.getAllTasks()) {
-                    stack.removeTask(task, "removeAllTasks", REMOVE_TASK_MODE_DESTROYING);
-                }
-            }
-        }
-    }
-
-    private static WindowManagerService sMockWindowManagerService;
-
-    private static WindowManagerService prepareMockWindowManager() {
-        if (sMockWindowManagerService == null) {
-            sMockWindowManagerService = mock(WindowManagerService.class);
-        }
-
-        sMockWindowManagerService.mRoot = mock(RootWindowContainer.class);
-
-        doAnswer((InvocationOnMock invocationOnMock) -> {
-            final Runnable runnable = invocationOnMock.<Runnable>getArgument(0);
-            if (runnable != null) {
-                runnable.run();
-            }
-            return null;
-        }).when(sMockWindowManagerService).inSurfaceTransaction(any());
-
-        return sMockWindowManagerService;
-    }
-
-    /**
-     * Overridden {@link ActivityStack} that tracks test metrics, such as the number of times a
-     * method is called. Note that its functionality depends on the implementations of the
-     * construction arguments.
-     */
-    protected static class TestActivityStack
-            extends ActivityStack {
-        private int mOnActivityRemovedFromStackCount = 0;
-
-        static final int IS_TRANSLUCENT_UNSET = 0;
-        static final int IS_TRANSLUCENT_FALSE = 1;
-        static final int IS_TRANSLUCENT_TRUE = 2;
-        private int mIsTranslucent = IS_TRANSLUCENT_UNSET;
-
-        static final int SUPPORTS_SPLIT_SCREEN_UNSET = 0;
-        static final int SUPPORTS_SPLIT_SCREEN_FALSE = 1;
-        static final int SUPPORTS_SPLIT_SCREEN_TRUE = 2;
-        private int mSupportsSplitScreen = SUPPORTS_SPLIT_SCREEN_UNSET;
-
-        TestActivityStack(ActivityDisplay display, int stackId, ActivityStackSupervisor supervisor,
-                int windowingMode, int activityType, boolean onTop, boolean createActivity) {
-            super(display, stackId, supervisor, windowingMode, activityType, onTop);
-            if (createActivity) {
-                new ActivityBuilder(mService).setCreateTask(true).setStack(this).build();
-                if (onTop) {
-                    // We move the task to front again in order to regain focus after activity
-                    // added to the stack. Or {@link ActivityDisplay#mPreferredTopFocusableStack}
-                    // could be other stacks (e.g. home stack).
-                    moveToFront("createActivityStack");
-                } else {
-                    moveToBack("createActivityStack", null);
-                }
-            }
-        }
-
-        @Override
-        void onActivityRemovedFromStack(ActivityRecord r) {
-            mOnActivityRemovedFromStackCount++;
-            super.onActivityRemovedFromStack(r);
-        }
-
-        // Returns the number of times {@link #onActivityRemovedFromStack} has been called
-        int onActivityRemovedFromStackInvocationCount() {
-            return mOnActivityRemovedFromStackCount;
-        }
-
-        @Override
-        protected void createTaskStack(int displayId, boolean onTop, Rect outBounds) {
-            mTaskStack = mock(TaskStack.class);
-
-            // Primary pinned stacks require a non-empty out bounds to be set or else all tasks
-            // will be moved to the full screen stack.
-            if (getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
-                outBounds.set(0, 0, 100, 100);
-            }
-        }
-
-        @Override
-        TaskStack getTaskStack() {
-            return mTaskStack;
-        }
-
-        void setIsTranslucent(boolean isTranslucent) {
-            mIsTranslucent = isTranslucent ? IS_TRANSLUCENT_TRUE : IS_TRANSLUCENT_FALSE;
-        }
-
-        @Override
-        boolean isStackTranslucent(ActivityRecord starting) {
-            switch (mIsTranslucent) {
-                case IS_TRANSLUCENT_TRUE:
-                    return true;
-                case IS_TRANSLUCENT_FALSE:
-                    return false;
-                case IS_TRANSLUCENT_UNSET:
-                default:
-                    return super.isStackTranslucent(starting);
-            }
-        }
-
-        void setSupportsSplitScreen(boolean supportsSplitScreen) {
-            mSupportsSplitScreen = supportsSplitScreen
-                    ? SUPPORTS_SPLIT_SCREEN_TRUE : SUPPORTS_SPLIT_SCREEN_FALSE;
-        }
-
-        @Override
-        public boolean supportsSplitScreenWindowingMode() {
-            switch (mSupportsSplitScreen) {
-                case SUPPORTS_SPLIT_SCREEN_TRUE:
-                    return true;
-                case SUPPORTS_SPLIT_SCREEN_FALSE:
-                    return false;
-                case SUPPORTS_SPLIT_SCREEN_UNSET:
-                default:
-                    return super.supportsSplitScreenWindowingMode();
-            }
-        }
-
-        @Override
-        void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
-                                 boolean newTask, boolean keepCurTransition,
-                                 ActivityOptions options) {
-        }
     }
 
     static class StackBuilder {
@@ -886,27 +423,45 @@
             return this;
         }
 
-        @SuppressWarnings("TypeParameterUnusedInFormals")
         ActivityStack build() {
             final int stackId = mStackId >= 0 ? mStackId : mDisplay.getNextStackId();
+            final ActivityStack stack;
+            final ActivityStackSupervisor supervisor = mRootActivityContainer.mStackSupervisor;
             if (mWindowingMode == WINDOWING_MODE_PINNED) {
-                return new ActivityStack(mDisplay, stackId, mRootActivityContainer.mStackSupervisor,
+                stack = new ActivityStack(mDisplay, stackId, supervisor,
                         mWindowingMode, ACTIVITY_TYPE_STANDARD, mOnTop) {
                     @Override
                     Rect getDefaultPictureInPictureBounds(float aspectRatio) {
                         return new Rect(50, 50, 100, 100);
                     }
-
-                    @Override
-                    void createTaskStack(int displayId, boolean onTop, Rect outBounds) {
-                        mTaskStack = mock(TaskStack.class);
-                    }
                 };
             } else {
-                return new TestActivityStack(mDisplay, stackId,
-                        mRootActivityContainer.mStackSupervisor, mWindowingMode,
-                        mActivityType, mOnTop, mCreateActivity);
+                stack = new ActivityStack(mDisplay, stackId, supervisor,
+                        mWindowingMode, mActivityType, mOnTop);
+
+                if (mCreateActivity) {
+                    new ActivityBuilder(supervisor.mService)
+                            .setCreateTask(true)
+                            .setStack(stack)
+                            .build();
+                    if (mOnTop) {
+                        // We move the task to front again in order to regain focus after activity
+                        // added to the stack.
+                        // Or {@link ActivityDisplay#mPreferredTopFocusableStack} could be other
+                        // stacks (e.g. home stack).
+                        stack.moveToFront("createActivityStack");
+                    } else {
+                        stack.moveToBack("createActivityStack", null);
+                    }
+                }
             }
+
+            spyOn(stack);
+            spyOn(stack.mTaskStack);
+            doNothing().when(stack).startActivityLocked(
+                    any(), any(), anyBoolean(), anyBoolean(), any());
+
+            return stack;
         }
 
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index 20379a2..e71c8f4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -60,7 +60,7 @@
                     WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
             final AppWindowToken translucentOpening = createAppWindowToken(mDisplayContent,
                     WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
-            translucentOpening.setFillsParent(false);
+            translucentOpening.setOccludesParent(false);
             translucentOpening.setHidden(true);
             mDisplayContent.mOpeningApps.add(behind);
             mDisplayContent.mOpeningApps.add(translucentOpening);
@@ -78,7 +78,7 @@
                     WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
             final AppWindowToken translucentClosing = createAppWindowToken(mDisplayContent,
                     WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
-            translucentClosing.setFillsParent(false);
+            translucentClosing.setOccludesParent(false);
             mDisplayContent.mClosingApps.add(translucentClosing);
             assertEquals(WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE,
                     mAppTransitionController.maybeUpdateTransitToTranslucentAnim(
@@ -94,7 +94,7 @@
                     WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
             final AppWindowToken translucentOpening = createAppWindowToken(mDisplayContent,
                     WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
-            translucentOpening.setFillsParent(false);
+            translucentOpening.setOccludesParent(false);
             translucentOpening.setHidden(true);
             mDisplayContent.mOpeningApps.add(behind);
             mDisplayContent.mOpeningApps.add(translucentOpening);
@@ -110,10 +110,10 @@
         synchronized (mWm.mGlobalLock) {
             final AppWindowToken opening = createAppWindowToken(mDisplayContent,
                     WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
-            opening.setFillsParent(false);
+            opening.setOccludesParent(false);
             final AppWindowToken closing = createAppWindowToken(mDisplayContent,
                     WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
-            closing.setFillsParent(false);
+            closing.setOccludesParent(false);
             Task task = opening.getTask();
             mDisplayContent.mOpeningApps.add(opening);
             mDisplayContent.mClosingApps.add(closing);
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index d1dc382..c162b6a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -30,12 +30,14 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
 
 import android.graphics.Rect;
 import android.os.IBinder;
@@ -195,6 +197,7 @@
     @Test
     public void testCancelRemoteAnimationWhenFreeze() {
         final DisplayContent dc = createNewDisplay(Display.STATE_ON);
+        doReturn(false).when(dc).onDescendantOrientationChanged(any(), any());
         final WindowState exitingAppWindow = createWindow(null /* parent */, TYPE_BASE_APPLICATION,
                 dc, "exiting app");
         final AppWindowToken exitingAppToken = exitingAppWindow.mAppToken;
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index d9566a3..e387e18 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -36,7 +36,7 @@
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
@@ -152,10 +152,6 @@
     @Test
     @FlakyTest(bugId = 131005232)
     public void testLandscapeSeascapeRotationByApp() {
-        // Some plumbing to get the service ready for rotation updates.
-        mWm.mDisplayReady = true;
-        mWm.mDisplayEnabled = true;
-
         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
                 TYPE_BASE_APPLICATION);
         attrs.setTitle("AppWindow");
@@ -185,25 +181,21 @@
 
     @Test
     public void testLandscapeSeascapeRotationByPolicy() {
-        // Some plumbing to get the service ready for rotation updates.
-        mWm.mDisplayReady = true;
-        mWm.mDisplayEnabled = true;
-
-        final DisplayRotation spiedRotation = spy(mDisplayContent.getDisplayRotation());
-        mDisplayContent.setDisplayRotation(spiedRotation);
+        final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
+        spyOn(displayRotation);
 
         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
                 TYPE_BASE_APPLICATION);
-        attrs.setTitle("AppWindow");
+        attrs.setTitle("RotationByPolicy");
         final WindowTestUtils.TestWindowState appWindow = createWindowState(attrs, mToken);
         mToken.addWindow(appWindow);
 
         // Set initial orientation and update.
-        performRotation(spiedRotation, Surface.ROTATION_90);
+        performRotation(displayRotation, Surface.ROTATION_90);
         appWindow.mResizeReported = false;
 
         // Update the rotation to perform 180 degree rotation and check that resize was reported.
-        performRotation(spiedRotation, Surface.ROTATION_270);
+        performRotation(displayRotation, Surface.ROTATION_270);
         assertTrue(appWindow.mResizeReported);
 
         appWindow.removeImmediately();
@@ -211,14 +203,7 @@
 
     private void performRotation(DisplayRotation spiedRotation, int rotationToReport) {
         doReturn(rotationToReport).when(spiedRotation).rotationForOrientation(anyInt(), anyInt());
-        int oldRotation = mDisplayContent.getRotation();
         mWm.updateRotation(false, false);
-        // Must manually apply here since ATM doesn't know about the display during this test
-        // (meaning it can't perform the normal sendNewConfiguration flow).
-        mDisplayContent.applyRotationLocked(oldRotation, mDisplayContent.getRotation());
-        // Prevent the next rotation from being deferred by animation.
-        mWm.mAnimator.setScreenRotationAnimationLocked(mDisplayContent.getDisplayId(), null);
-        mWm.mRoot.performSurfacePlacement(false /* recoveringMemory */);
     }
 
     @Test
@@ -266,14 +251,14 @@
     public void testGetOrientation() {
         mToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
 
-        mToken.setFillsParent(false);
-        // Can specify orientation if app doesn't fill parent.
+        mToken.setOccludesParent(false);
+        // Can specify orientation if app doesn't occludes parent.
         assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mToken.getOrientation());
 
-        mToken.setFillsParent(true);
+        mToken.setOccludesParent(true);
         mToken.setHidden(true);
         mToken.sendingToBottom = true;
-        // Can not specify orientation if app isn't visible even though it fills parent.
+        // Can not specify orientation if app isn't visible even though it occludes parent.
         assertEquals(SCREEN_ORIENTATION_UNSET, mToken.getOrientation());
         // Can specify orientation if the current orientation candidate is orientation behind.
         assertEquals(SCREEN_ORIENTATION_LANDSCAPE,
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 388658d..6289768 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -83,7 +83,6 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.dx.mockito.inline.extended.ExtendedMockito;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.server.wm.utils.WmDisplayCutout;
@@ -653,25 +652,27 @@
     @Test
     public void testOnDescendantOrientationRequestChanged() {
         final DisplayContent dc = createNewDisplay();
-        mWm.mAtmService.mRootActivityContainer = mock(RootActivityContainer.class);
+        dc.getDisplayRotation().setFixedToUserRotation(
+                DisplayRotation.FIXED_TO_USER_ROTATION_DISABLED);
         final int newOrientation = dc.getLastOrientation() == SCREEN_ORIENTATION_LANDSCAPE
                 ? SCREEN_ORIENTATION_PORTRAIT
                 : SCREEN_ORIENTATION_LANDSCAPE;
 
-        final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
-        window.getTask().mTaskRecord = mock(TaskRecord.class, ExtendedMockito.RETURNS_DEEP_STUBS);
-        window.mAppToken.setOrientation(newOrientation);
+        final ActivityStack stack =
+                new ActivityTestsBase.StackBuilder(mWm.mAtmService.mRootActivityContainer)
+                        .setDisplay(dc.mAcitvityDisplay).build();
+        final ActivityRecord activity = stack.topTask().getTopActivity();
 
-        ActivityRecord activityRecord = mock(ActivityRecord.class);
-
-        assertTrue("Display should rotate to handle orientation request by default.",
-                dc.onDescendantOrientationChanged(window.mToken.token, activityRecord));
+        activity.setRequestedOrientation(newOrientation);
 
         final ArgumentCaptor<Configuration> captor = ArgumentCaptor.forClass(Configuration.class);
         verify(dc.mAcitvityDisplay).updateDisplayOverrideConfigurationLocked(captor.capture(),
-                same(activityRecord), anyBoolean(), same(null));
+                same(activity), anyBoolean(), same(null));
         final Configuration newDisplayConfig = captor.getValue();
-        assertEquals(Configuration.ORIENTATION_PORTRAIT, newDisplayConfig.orientation);
+        final int expectedOrientation = newOrientation == SCREEN_ORIENTATION_PORTRAIT
+                ? Configuration.ORIENTATION_PORTRAIT
+                : Configuration.ORIENTATION_LANDSCAPE;
+        assertEquals(expectedOrientation, newDisplayConfig.orientation);
     }
 
     @Test
@@ -679,22 +680,20 @@
         final DisplayContent dc = createNewDisplay();
         dc.getDisplayRotation().setFixedToUserRotation(
                 DisplayRotation.FIXED_TO_USER_ROTATION_ENABLED);
-        mWm.mAtmService.mRootActivityContainer = mock(RootActivityContainer.class);
         final int newOrientation = dc.getLastOrientation() == SCREEN_ORIENTATION_LANDSCAPE
                 ? SCREEN_ORIENTATION_PORTRAIT
                 : SCREEN_ORIENTATION_LANDSCAPE;
 
-        final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
-        window.getTask().mTaskRecord = mock(TaskRecord.class, ExtendedMockito.RETURNS_DEEP_STUBS);
-        window.mAppToken.setOrientation(newOrientation);
+        final ActivityStack stack =
+                new ActivityTestsBase.StackBuilder(mWm.mAtmService.mRootActivityContainer)
+                        .setDisplay(dc.mAcitvityDisplay).build();
+        final ActivityRecord activity = stack.topTask().getTopActivity();
 
-        ActivityRecord activityRecord = mock(ActivityRecord.class);
+        activity.setRequestedOrientation(newOrientation);
 
-        assertFalse("Display shouldn't rotate to handle orientation request if fixed to"
-                        + " user rotation.",
-                dc.onDescendantOrientationChanged(window.mToken.token, activityRecord));
         verify(dc.mAcitvityDisplay, never()).updateDisplayOverrideConfigurationLocked(any(),
-                eq(activityRecord), anyBoolean(), same(null));
+                eq(activity), anyBoolean(), same(null));
+        assertEquals(dc.getDisplayRotation().getUserRotation(), dc.getRotation());
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
index bfede51..f6f8811 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
@@ -95,7 +95,7 @@
     public void setUp() throws Exception {
         deleteRecursively(TEST_FOLDER);
 
-        mWm.setSupportsFreeformWindowManagement(false);
+        mWm.mAtmService.mSupportsFreeformWindowManagement = false;
         mWm.setIsPc(false);
         mWm.setForceDesktopModeOnExternalDisplays(false);
 
@@ -134,7 +134,7 @@
 
     @Test
     public void testPrimaryDisplayDefaultToFullscreen_HasFreeformSupport_NonPc_NoDesktopMode() {
-        mWm.setSupportsFreeformWindowManagement(true);
+        mWm.mAtmService.mSupportsFreeformWindowManagement = true;
 
         mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
 
@@ -144,7 +144,7 @@
 
     @Test
     public void testPrimaryDisplayDefaultToFullscreen_HasFreeformSupport_NonPc_HasDesktopMode() {
-        mWm.setSupportsFreeformWindowManagement(true);
+        mWm.mAtmService.mSupportsFreeformWindowManagement = true;
         mWm.setForceDesktopModeOnExternalDisplays(true);
 
         mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
@@ -155,7 +155,7 @@
 
     @Test
     public void testPrimaryDisplayDefaultToFreeform_HasFreeformSupport_IsPc() {
-        mWm.setSupportsFreeformWindowManagement(true);
+        mWm.mAtmService.mSupportsFreeformWindowManagement = true;
         mWm.setIsPc(true);
 
         mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
@@ -168,7 +168,7 @@
     public void testPrimaryDisplayUpdateToFreeform_HasFreeformSupport_IsPc() {
         mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
 
-        mWm.setSupportsFreeformWindowManagement(true);
+        mWm.mAtmService.mSupportsFreeformWindowManagement = true;
         mWm.setIsPc(true);
 
         mTarget.updateSettingsForDisplay(mPrimaryDisplay);
@@ -187,7 +187,7 @@
 
     @Test
     public void testSecondaryDisplayDefaultToFreeform_HasFreeformSupport_NonPc_NoDesktopMode() {
-        mWm.setSupportsFreeformWindowManagement(true);
+        mWm.mAtmService.mSupportsFreeformWindowManagement = true;
 
         mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
 
@@ -197,7 +197,7 @@
 
     @Test
     public void testSecondaryDisplayDefaultToFreeform_HasFreeformSupport_NonPc_HasDesktopMode() {
-        mWm.setSupportsFreeformWindowManagement(true);
+        mWm.mAtmService.mSupportsFreeformWindowManagement = true;
         mWm.setForceDesktopModeOnExternalDisplays(true);
 
         mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
@@ -208,7 +208,7 @@
 
     @Test
     public void testSecondaryDisplayDefaultToFreeform_HasFreeformSupport_IsPc() {
-        mWm.setSupportsFreeformWindowManagement(true);
+        mWm.mAtmService.mSupportsFreeformWindowManagement = true;
         mWm.setIsPc(true);
 
         mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
index b28ae40..be2ee29 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
@@ -331,7 +331,9 @@
 
         mController.layoutTask(task, null /* windowLayout */);
 
-        assertEquals(expected, task.getBounds());
+        // TaskRecord will make adjustments to requested bounds. We only need to guarantee that the
+        // reuqested bounds are expected.
+        assertEquals(expected, task.getRequestedOverrideBounds());
     }
 
     /**
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
index e4d3770..49d778f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
@@ -104,6 +104,7 @@
 
         mDisplayUniqueId = "test:" + Integer.toString(sNextUniqueId++);
         final DisplayInfo info = new DisplayInfo();
+        mService.mContext.getDisplay().getDisplayInfo(info);
         info.uniqueId = mDisplayUniqueId;
         mTestDisplay = createNewActivityDisplay(info);
         mRootActivityContainer.addChild(mTestDisplay, ActivityDisplay.POSITION_TOP);
diff --git a/services/tests/wmtests/src/com/android/server/wm/PinnedStackControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/PinnedStackControllerTest.java
index 63d9fb9..efd468f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/PinnedStackControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/PinnedStackControllerTest.java
@@ -61,7 +61,7 @@
 
     @Test
     public void setShelfHeight_shelfVisibilityChangedTriggered() throws RemoteException {
-        mWm.mSupportsPictureInPicture = true;
+        mWm.mAtmService.mSupportsPictureInPicture = true;
         mWm.registerPinnedStackListener(DEFAULT_DISPLAY, mIPinnedStackListener);
 
         verify(mIPinnedStackListener).onImeVisibilityChanged(false, 0);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index b7a85d7..fb4e330 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -32,7 +32,7 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
@@ -53,14 +53,12 @@
 import android.app.ActivityTaskManager;
 import android.app.WindowConfiguration;
 import android.content.ComponentName;
-import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Bundle;
-import android.os.Looper;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
@@ -93,11 +91,8 @@
     private static final int TEST_QUIET_USER_ID = 20;
     private static final UserInfo DEFAULT_USER_INFO = new UserInfo();
     private static final UserInfo QUIET_USER_INFO = new UserInfo();
-    private static int sLastTaskId = 1;
-    private static int sLastStackId = 1;
     private static final int INVALID_STACK_ID = 999;
 
-    private TestActivityTaskManagerService mTestService;
     private ActivityDisplay mDisplay;
     private ActivityDisplay mOtherDisplay;
     private ActivityDisplay mSingleTaskDisplay;
@@ -115,13 +110,29 @@
     @Before
     public void setUp() throws Exception {
         mTaskPersister = new TestTaskPersister(mContext.getFilesDir());
-        mTestService = new MyTestActivityTaskManagerService(mContext);
-        mRecentTasks = (TestRecentTasks) mTestService.getRecentTasks();
+
+        // Set testing displays
+        mDisplay = mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY);
+        mOtherDisplay = createNewActivityDisplay();
+        mSingleTaskDisplay = createNewActivityDisplay();
+        mSingleTaskDisplay.setDisplayToSingleTaskInstance();
+        mRootActivityContainer.addChild(mOtherDisplay, ActivityDisplay.POSITION_TOP);
+        mRootActivityContainer.addChild(mDisplay, ActivityDisplay.POSITION_TOP);
+        mRootActivityContainer.addChild(mSingleTaskDisplay, ActivityDisplay.POSITION_TOP);
+
+        // Set the recent tasks we should use for testing in this class.
+        mRecentTasks = new TestRecentTasks(mService, mTaskPersister);
+        spyOn(mRecentTasks);
+        mService.setRecentTasks(mRecentTasks);
         mRecentTasks.loadParametersFromResources(mContext.getResources());
-        mRunningTasks = (TestRunningTasks) mTestService.mStackSupervisor.mRunningTasks;
-        mHomeStack = mTestService.mRootActivityContainer.getDefaultDisplay().getOrCreateStack(
+
+        // Set the running tasks we should use for testing in this class.
+        mRunningTasks = new TestRunningTasks();
+        mService.mStackSupervisor.setRunningTasks(mRunningTasks);
+
+        mHomeStack = mDisplay.getOrCreateStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
-        mStack = mTestService.mRootActivityContainer.getDefaultDisplay().createStack(
+        mStack = mDisplay.createStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
         mCallbacksRecorder = new CallbacksRecorder();
         mRecentTasks.registerCallback(mCallbacksRecorder);
@@ -723,7 +734,7 @@
 
         ActivityStack stack = mTasks.get(2).getStack();
         stack.moveToFront("", mTasks.get(2));
-        doReturn(stack).when(mTestService.mRootActivityContainer).getTopDisplayFocusedStack();
+        doReturn(stack).when(mService.mRootActivityContainer).getTopDisplayFocusedStack();
 
         // Simulate the reset from the timeout
         mRecentTasks.resetFreezeTaskListReorderingOnTimeout();
@@ -742,10 +753,9 @@
     public void testBackStackTasks_expectNoTrim() {
         mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */);
 
-        final MyTestActivityStackSupervisor supervisor =
-                (MyTestActivityStackSupervisor) mTestService.mStackSupervisor;
         final ActivityStack homeStack = mDisplay.getHomeStack();
-        final ActivityStack aboveHomeStack = new MyTestActivityStack(mDisplay, supervisor);
+        final ActivityStack aboveHomeStack = mDisplay.createStack(
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
 
         // Add a number of tasks (beyond the max) but ensure that nothing is trimmed because all
         // the tasks belong in stacks above the home stack
@@ -761,11 +771,11 @@
     public void testBehindHomeStackTasks_expectTaskTrimmed() {
         mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */);
 
-        final MyTestActivityStackSupervisor supervisor =
-                (MyTestActivityStackSupervisor) mTestService.mStackSupervisor;
-        final ActivityStack behindHomeStack = new MyTestActivityStack(mDisplay, supervisor);
+        final ActivityStack behindHomeStack = mDisplay.createStack(
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
         final ActivityStack homeStack = mDisplay.getHomeStack();
-        final ActivityStack aboveHomeStack = new MyTestActivityStack(mDisplay, supervisor);
+        final ActivityStack aboveHomeStack = mDisplay.createStack(
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
 
         // Add a number of tasks (beyond the max) but ensure that only the task in the stack behind
         // the home stack is trimmed once a new task is added
@@ -783,10 +793,9 @@
     public void testOtherDisplayTasks_expectNoTrim() {
         mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */);
 
-        final MyTestActivityStackSupervisor supervisor =
-                (MyTestActivityStackSupervisor) mTestService.mStackSupervisor;
         final ActivityStack homeStack = mDisplay.getHomeStack();
-        final ActivityStack otherDisplayStack = new MyTestActivityStack(mOtherDisplay, supervisor);
+        final ActivityStack otherDisplayStack = mOtherDisplay.createStack(
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
 
         // Add a number of tasks (beyond the max) on each display, ensure that the tasks are not
         // removed
@@ -887,16 +896,16 @@
         mStack.remove();
 
         // The following APIs should not restore task from recents to the active list.
-        assertNotRestoreTask(() -> mTestService.setFocusedTask(taskId));
-        assertNotRestoreTask(() -> mTestService.startSystemLockTaskMode(taskId));
-        assertNotRestoreTask(() -> mTestService.cancelTaskWindowTransition(taskId));
+        assertNotRestoreTask(() -> mService.setFocusedTask(taskId));
+        assertNotRestoreTask(() -> mService.startSystemLockTaskMode(taskId));
+        assertNotRestoreTask(() -> mService.cancelTaskWindowTransition(taskId));
         assertNotRestoreTask(
-                () -> mTestService.resizeTask(taskId, null /* bounds */, 0 /* resizeMode */));
+                () -> mService.resizeTask(taskId, null /* bounds */, 0 /* resizeMode */));
         assertNotRestoreTask(
-                () -> mTestService.setTaskWindowingMode(taskId, WINDOWING_MODE_FULLSCREEN,
+                () -> mService.setTaskWindowingMode(taskId, WINDOWING_MODE_FULLSCREEN,
                         false/* toTop */));
         assertNotRestoreTask(
-                () -> mTestService.setTaskWindowingModeSplitScreenPrimary(taskId,
+                () -> mService.setTaskWindowingModeSplitScreenPrimary(taskId,
                         SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT,
                         false /* toTop */, false /* animate */, null /* initialBounds */,
                         true /* showRecents */));
@@ -910,7 +919,7 @@
         mRecentTasks.remove(task);
 
         TaskChangeNotificationController controller =
-                mTestService.getTaskChangeNotificationController();
+                mService.getTaskChangeNotificationController();
         verify(controller, times(2)).notifyTaskListUpdated();
     }
 
@@ -923,7 +932,7 @@
 
         // 2 calls - Once for add and once for remove
         TaskChangeNotificationController controller =
-                mTestService.getTaskChangeNotificationController();
+                mService.getTaskChangeNotificationController();
         verify(controller, times(2)).notifyTaskListUpdated();
     }
 
@@ -938,7 +947,7 @@
 
         // 4 calls - Twice for add and twice for remove
         TaskChangeNotificationController controller =
-                mTestService.getTaskChangeNotificationController();
+                mService.getTaskChangeNotificationController();
         verify(controller, times(4)).notifyTaskListUpdated();
     }
 
@@ -980,7 +989,7 @@
 
     @Test
     public void testNotRecentsComponent_denyApiAccess() throws Exception {
-        doReturn(PackageManager.PERMISSION_DENIED).when(mTestService)
+        doReturn(PackageManager.PERMISSION_DENIED).when(mService)
                 .checkGetTasksPermission(anyString(), anyInt(), anyInt());
         // Expect the following methods to fail due to recents component not being set
         mRecentTasks.setIsCallerRecentsOverride(TestRecentTasks.DENY_THROW_SECURITY_EXCEPTION);
@@ -992,7 +1001,7 @@
 
     @Test
     public void testRecentsComponent_allowApiAccessWithoutPermissions() {
-        doReturn(PackageManager.PERMISSION_DENIED).when(mTestService)
+        doReturn(PackageManager.PERMISSION_DENIED).when(mService)
                 .checkGetTasksPermission(anyString(), anyInt(), anyInt());
 
         // Set the recents component and ensure that the following calls do not fail
@@ -1002,62 +1011,62 @@
     }
 
     private void doTestRecentTasksApis(boolean expectCallable) {
-        assertSecurityException(expectCallable, () -> mTestService.removeStack(INVALID_STACK_ID));
+        assertSecurityException(expectCallable, () -> mService.removeStack(INVALID_STACK_ID));
         assertSecurityException(expectCallable,
-                () -> mTestService.removeStacksInWindowingModes(
+                () -> mService.removeStacksInWindowingModes(
                         new int[]{WINDOWING_MODE_UNDEFINED}));
         assertSecurityException(expectCallable,
-                () -> mTestService.removeStacksWithActivityTypes(
+                () -> mService.removeStacksWithActivityTypes(
                         new int[]{ACTIVITY_TYPE_UNDEFINED}));
-        assertSecurityException(expectCallable, () -> mTestService.removeTask(0));
+        assertSecurityException(expectCallable, () -> mService.removeTask(0));
         assertSecurityException(expectCallable,
-                () -> mTestService.setTaskWindowingMode(0, WINDOWING_MODE_UNDEFINED, true));
+                () -> mService.setTaskWindowingMode(0, WINDOWING_MODE_UNDEFINED, true));
         assertSecurityException(expectCallable,
-                () -> mTestService.moveTaskToStack(0, INVALID_STACK_ID, true));
+                () -> mService.moveTaskToStack(0, INVALID_STACK_ID, true));
         assertSecurityException(expectCallable,
-                () -> mTestService.setTaskWindowingModeSplitScreenPrimary(0,
+                () -> mService.setTaskWindowingModeSplitScreenPrimary(0,
                         SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, true, true, new Rect(), true));
-        assertSecurityException(expectCallable, () -> mTestService.dismissSplitScreenMode(true));
-        assertSecurityException(expectCallable, () -> mTestService.dismissPip(true, 0));
+        assertSecurityException(expectCallable, () -> mService.dismissSplitScreenMode(true));
+        assertSecurityException(expectCallable, () -> mService.dismissPip(true, 0));
         assertSecurityException(expectCallable,
-                () -> mTestService.moveTopActivityToPinnedStack(INVALID_STACK_ID, new Rect()));
+                () -> mService.moveTopActivityToPinnedStack(INVALID_STACK_ID, new Rect()));
         assertSecurityException(expectCallable,
-                () -> mTestService.resizeStack(INVALID_STACK_ID, new Rect(), true, true, true, 0));
+                () -> mService.resizeStack(INVALID_STACK_ID, new Rect(), true, true, true, 0));
         assertSecurityException(expectCallable,
-                () -> mTestService.resizeDockedStack(new Rect(), new Rect(), new Rect(), new Rect(),
+                () -> mService.resizeDockedStack(new Rect(), new Rect(), new Rect(), new Rect(),
                         new Rect()));
         assertSecurityException(expectCallable,
-                () -> mTestService.resizePinnedStack(new Rect(), new Rect()));
-        assertSecurityException(expectCallable, () -> mTestService.getAllStackInfos());
+                () -> mService.resizePinnedStack(new Rect(), new Rect()));
+        assertSecurityException(expectCallable, () -> mService.getAllStackInfos());
         assertSecurityException(expectCallable,
-                () -> mTestService.getStackInfo(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_UNDEFINED));
+                () -> mService.getStackInfo(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_UNDEFINED));
         assertSecurityException(expectCallable, () -> {
             try {
-                mTestService.getFocusedStackInfo();
+                mService.getFocusedStackInfo();
             } catch (RemoteException e) {
                 // Ignore
             }
         });
         assertSecurityException(expectCallable,
-                () -> mTestService.moveTasksToFullscreenStack(INVALID_STACK_ID, true));
+                () -> mService.moveTasksToFullscreenStack(INVALID_STACK_ID, true));
         assertSecurityException(expectCallable,
-                () -> mTestService.startActivityFromRecents(0, new Bundle()));
-        assertSecurityException(expectCallable, () -> mTestService.getTaskSnapshot(0, true));
-        assertSecurityException(expectCallable, () -> mTestService.registerTaskStackListener(null));
+                () -> mService.startActivityFromRecents(0, new Bundle()));
+        assertSecurityException(expectCallable, () -> mService.getTaskSnapshot(0, true));
+        assertSecurityException(expectCallable, () -> mService.registerTaskStackListener(null));
         assertSecurityException(expectCallable,
-                () -> mTestService.unregisterTaskStackListener(null));
-        assertSecurityException(expectCallable, () -> mTestService.getTaskDescription(0));
-        assertSecurityException(expectCallable, () -> mTestService.cancelTaskWindowTransition(0));
-        assertSecurityException(expectCallable, () -> mTestService.startRecentsActivity(null, null,
+                () -> mService.unregisterTaskStackListener(null));
+        assertSecurityException(expectCallable, () -> mService.getTaskDescription(0));
+        assertSecurityException(expectCallable, () -> mService.cancelTaskWindowTransition(0));
+        assertSecurityException(expectCallable, () -> mService.startRecentsActivity(null, null,
                 null));
-        assertSecurityException(expectCallable, () -> mTestService.cancelRecentsAnimation(true));
-        assertSecurityException(expectCallable, () -> mTestService.stopAppSwitches());
-        assertSecurityException(expectCallable, () -> mTestService.resumeAppSwitches());
+        assertSecurityException(expectCallable, () -> mService.cancelRecentsAnimation(true));
+        assertSecurityException(expectCallable, () -> mService.stopAppSwitches());
+        assertSecurityException(expectCallable, () -> mService.resumeAppSwitches());
     }
 
     private void testGetTasksApis(boolean expectCallable) {
-        mTestService.getRecentTasks(MAX_VALUE, 0, TEST_USER_0_ID);
-        mTestService.getTasks(MAX_VALUE);
+        mService.getRecentTasks(MAX_VALUE, 0, TEST_USER_0_ID);
+        mService.getTasks(MAX_VALUE);
         if (expectCallable) {
             assertTrue(mRecentTasks.mLastAllowed);
             assertTrue(mRunningTasks.mLastAllowed);
@@ -1072,10 +1081,9 @@
     }
 
     private TaskBuilder createTaskBuilder(String packageName, String className) {
-        return new TaskBuilder(mTestService.mStackSupervisor)
+        return new TaskBuilder(mService.mStackSupervisor)
                 .setComponent(new ComponentName(packageName, className))
                 .setStack(mStack)
-                .setTaskId(sLastTaskId++)
                 .setUserId(TEST_USER_0_ID);
     }
 
@@ -1140,68 +1148,6 @@
         }
     }
 
-    private class MyTestActivityTaskManagerService extends TestActivityTaskManagerService {
-        MyTestActivityTaskManagerService(Context context) {
-            super(context);
-        }
-
-        @Override
-        protected RecentTasks createRecentTasks() {
-            return spy(new TestRecentTasks(this, mTaskPersister));
-        }
-
-        @Override
-        protected ActivityStackSupervisor createStackSupervisor() {
-            if (mTestStackSupervisor == null) {
-                mTestStackSupervisor = new MyTestActivityStackSupervisor(this, mH.getLooper());
-            }
-            return mTestStackSupervisor;
-        }
-
-        @Override
-        void createDefaultDisplay() {
-            super.createDefaultDisplay();
-            mDisplay = mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY);
-            mOtherDisplay = TestActivityDisplay.create(mTestStackSupervisor, DEFAULT_DISPLAY + 1);
-            mSingleTaskDisplay = TestActivityDisplay.create(mTestStackSupervisor,
-                    DEFAULT_DISPLAY + 2);
-            mSingleTaskDisplay.setDisplayToSingleTaskInstance();
-            mRootActivityContainer.addChild(mOtherDisplay, ActivityDisplay.POSITION_TOP);
-            mRootActivityContainer.addChild(mDisplay, ActivityDisplay.POSITION_TOP);
-            mRootActivityContainer.addChild(mSingleTaskDisplay, ActivityDisplay.POSITION_TOP);
-        }
-    }
-
-    private class MyTestActivityStackSupervisor extends TestActivityStackSupervisor {
-        MyTestActivityStackSupervisor(ActivityTaskManagerService service, Looper looper) {
-            super(service, looper);
-        }
-
-        @Override
-        RunningTasks createRunningTasks() {
-            mRunningTasks = new TestRunningTasks();
-            return mRunningTasks;
-        }
-    }
-
-    private static class MyTestActivityStack extends TestActivityStack {
-        private ActivityDisplay mDisplay = null;
-
-        MyTestActivityStack(ActivityDisplay display, ActivityStackSupervisor supervisor) {
-            super(display, sLastStackId++, supervisor, WINDOWING_MODE_FULLSCREEN,
-                    ACTIVITY_TYPE_STANDARD, true /* onTop */, false /* createActivity */);
-            mDisplay = display;
-        }
-
-        @Override
-        ActivityDisplay getDisplay() {
-            if (mDisplay != null) {
-                return mDisplay;
-            }
-            return super.getDisplay();
-        }
-    }
-
     private static class CallbacksRecorder implements Callbacks {
         public final ArrayList<TaskRecord> mAdded = new ArrayList<>();
         public final ArrayList<TaskRecord> mTrimmed = new ArrayList<>();
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index f5a1d75..9ca0180 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -30,6 +30,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMoreInteractions;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
 import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
 import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
 
@@ -132,8 +133,14 @@
     @Test
     public void testIncludedApps_expectTargetAndVisible() {
         mWm.setRecentsAnimationController(mController);
-        final AppWindowToken homeAppWindow = createAppWindowToken(mDisplayContent,
-                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
+        final ActivityStack homStack = mDisplayContent.mAcitvityDisplay.getOrCreateStack(
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
+        final AppWindowToken homeAppWindow =
+                new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
+                        .setStack(homStack)
+                        .setCreateTask(true)
+                        .build()
+                        .mAppWindowToken;
         final AppWindowToken appWindow = createAppWindowToken(mDisplayContent,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
         final AppWindowToken hiddenAppWindow = createAppWindowToken(mDisplayContent,
@@ -169,7 +176,7 @@
 
         // Simulate the app transition finishing
         mController.mAppTransitionListener.onAppTransitionStartingLocked(0, 0, 0, 0);
-        verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, true, false);
+        verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, false);
     }
 
     @Test
@@ -201,7 +208,7 @@
         spyOn(mController.mRecentScreenshotAnimator.mAnimatable);
         mController.mRecentScreenshotAnimator.cancelAnimation();
         verify(mController.mRecentScreenshotAnimator.mAnimatable).onAnimationLeashLost(any());
-        verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, true, false);
+        verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, false);
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index 0e119e3..dcc295c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -74,8 +74,9 @@
     @Before
     public void setUp() throws Exception {
         mRecentsAnimationController = mock(RecentsAnimationController.class);
-        doReturn(mRecentsAnimationController).when(
-                mService.mWindowManager).getRecentsAnimationController();
+        mService.mWindowManager.setRecentsAnimationController(mRecentsAnimationController);
+        doNothing().when(mService.mWindowManager).initializeRecentsAnimation(
+                anyInt(), any(), any(), anyInt(), any());
         doReturn(true).when(mService.mWindowManager).canStartRecentsAnimation();
 
         final RecentTasks recentTasks = mService.getRecentTasks();
@@ -107,16 +108,25 @@
         assertTrue(recentActivity.visible);
 
         // Simulate the animation is cancelled without changing the stack order.
-        recentsAnimation.onAnimationFinished(REORDER_KEEP_IN_PLACE, true /* runSychronously */,
-                false /* sendUserLeaveHint */);
+        recentsAnimation.onAnimationFinished(REORDER_KEEP_IN_PLACE, false /* sendUserLeaveHint */);
         // The non-top recents activity should be invisible by the restored launch-behind state.
         assertFalse(recentActivity.visible);
     }
 
     @Test
     public void testPreloadRecentsActivity() {
-        // Ensure that the fake recent component can be resolved by the recents intent.
-        mockTaskRecordFactory(builder -> builder.setComponent(mRecentsComponent));
+        final ActivityDisplay defaultDisplay = mRootActivityContainer.getDefaultDisplay();
+        final ActivityStack homeStack =
+                defaultDisplay.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
+        defaultDisplay.positionChildAtTop(homeStack, false /* includingParents */);
+        ActivityRecord topRunningHomeActivity = homeStack.topRunningActivityLocked();
+        if (topRunningHomeActivity == null) {
+            topRunningHomeActivity = new ActivityBuilder(mService)
+                    .setStack(homeStack)
+                    .setCreateTask(true)
+                    .build();
+        }
+
         ActivityInfo aInfo = new ActivityInfo();
         aInfo.applicationInfo = new ApplicationInfo();
         aInfo.applicationInfo.uid = 10001;
@@ -204,6 +214,13 @@
         ActivityStack homeStack = display.getHomeStack();
         // Assume the home activity support recents.
         ActivityRecord targetActivity = homeStack.getTopActivity();
+        if (targetActivity == null) {
+            targetActivity = new ActivityBuilder(mService)
+                    .setCreateTask(true)
+                    .setStack(homeStack)
+                    .build();
+        }
+
         // Put another home activity in home stack.
         ActivityRecord anotherHomeActivity = new ActivityBuilder(mService)
                 .setComponent(new ComponentName(mContext.getPackageName(), "Home2"))
@@ -226,13 +243,12 @@
 
         anotherHomeActivity.moveFocusableActivityToTop("launchAnotherHome");
         // The current top activity is not the recents so the animation should be canceled.
-        verify(mService.mWindowManager, times(1)).cancelRecentsAnimationSynchronously(
+        verify(mService.mWindowManager, times(1)).cancelRecentsAnimation(
                 eq(REORDER_KEEP_IN_PLACE), any() /* reason */);
 
         // The test uses mocked RecentsAnimationController so we have to invoke the callback
         // manually to simulate the flow.
-        recentsAnimation.onAnimationFinished(REORDER_KEEP_IN_PLACE, true /* runSychronously */,
-                false /* sendUserLeaveHint */);
+        recentsAnimation.onAnimationFinished(REORDER_KEEP_IN_PLACE, false /* sendUserLeaveHint */);
         // We should restore the launch-behind of the original target activity.
         assertFalse(targetActivity.mLaunchTaskBehind);
     }
@@ -269,7 +285,7 @@
         fullscreenStack.moveToFront("Activity start");
 
         // Ensure that the recents animation was canceled by cancelAnimationSynchronously().
-        verify(mService.mWindowManager, times(1)).cancelRecentsAnimationSynchronously(
+        verify(mService.mWindowManager, times(1)).cancelRecentsAnimation(
                 eq(REORDER_KEEP_IN_PLACE), any());
 
         // Assume recents animation already started, set a state that cancel recents animation
@@ -314,7 +330,7 @@
         fullscreenStack.remove();
 
         // Ensure that the recents animation was NOT canceled
-        verify(mService.mWindowManager, times(0)).cancelRecentsAnimationSynchronously(
+        verify(mService.mWindowManager, times(0)).cancelRecentsAnimation(
                 eq(REORDER_KEEP_IN_PLACE), any());
         verify(mRecentsAnimationController, times(0)).setCancelOnNextTransitionStart();
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index d4f24f9..539a79c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -97,7 +97,7 @@
      */
     @Test
     public void testRestoringInvalidTask() {
-        ((TestActivityDisplay) mRootActivityContainer.getDefaultDisplay()).removeAllTasks();
+        mRootActivityContainer.getDefaultDisplay().removeAllTasks();
         TaskRecord task = mRootActivityContainer.anyTaskForId(0 /*taskId*/,
                 MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, null, false /* onTop */);
         assertNull(task);
@@ -304,21 +304,23 @@
      */
     @Test
     public void testResizeDockedStackForSplitScreenPrimary() {
-        final Rect taskSize = new Rect(0, 0, 600, 600);
+        final Rect taskSize = new Rect(0, 0, 1000, 1000);
         final Rect stackSize = new Rect(0, 0, 300, 300);
 
         // Create primary split-screen stack with a task.
-        final ActivityStack primaryStack = mRootActivityContainer.getDefaultDisplay()
-                .createStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD,
-                        true /* onTop */);
-        final TaskRecord task = new TaskBuilder(mSupervisor).setStack(primaryStack).build();
+        final ActivityStack primaryStack = new StackBuilder(mRootActivityContainer)
+                .setActivityType(ACTIVITY_TYPE_STANDARD)
+                .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)
+                .setOnTop(true)
+                .build();
+        final TaskRecord task = primaryStack.topTask();
 
         // Resize dock stack.
         mService.resizeDockedStack(stackSize, taskSize, null, null, null);
 
         // Verify dock stack & its task bounds if is equal as resized result.
-        assertEquals(primaryStack.getBounds(), stackSize);
-        assertEquals(task.getBounds(), taskSize);
+        assertEquals(stackSize, primaryStack.getBounds());
+        assertEquals(taskSize, task.getBounds());
     }
 
     /**
@@ -328,8 +330,9 @@
     public void testFindTaskToMoveToFrontWhenRecentsOnTop() {
         // Create stack/task on default display.
         final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
-        final TestActivityStack targetStack = (TestActivityStack) new StackBuilder(
-                mRootActivityContainer).setOnTop(false).build();
+        final ActivityStack targetStack = new StackBuilder(mRootActivityContainer)
+                .setOnTop(false)
+                .build();
         final TaskRecord targetTask = targetStack.getChildAt(0);
 
         // Create Recents on top of the display.
@@ -505,12 +508,10 @@
         mockResolveSecondaryHomeActivity();
 
         // Create secondary displays.
-        final TestActivityDisplay secondDisplay = spy(createNewActivityDisplay());
+        final TestActivityDisplay secondDisplay = createNewActivityDisplay();
         mRootActivityContainer.addChild(secondDisplay, POSITION_TOP);
         doReturn(true).when(secondDisplay).supportsSystemDecorations();
 
-        // Create mock tasks and other necessary mocks.
-        mockTaskRecordFactory();
         doReturn(true).when(mRootActivityContainer)
                 .ensureVisibilityAndConfig(any(), anyInt(), anyBoolean(), anyBoolean());
         doReturn(true).when(mRootActivityContainer).canStartHomeOnDisplay(
@@ -621,7 +622,6 @@
         info.applicationInfo.packageName = "android";
         info.name = ResolverActivity.class.getName();
         doReturn(info).when(mRootActivityContainer).resolveHomeActivity(anyInt(), any());
-        mockTaskRecordFactory();
 
         mRootActivityContainer.startHomeOnDisplay(0 /* userId */, "test", DEFAULT_DISPLAY);
         final ActivityRecord resolverActivity = mRootActivityContainer.topRunningActivity();
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index f51ce13..db105dd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -96,7 +96,7 @@
                     mWm.getDefaultDisplayContentLocked().getWindowingMode());
 
             mWm.mIsPc = true;
-            mWm.mSupportsFreeformWindowManagement = true;
+            mWm.mAtmService.mSupportsFreeformWindowManagement = true;
 
             mWm.mRoot.onSettingsRetrieved();
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index df7c9a4..1ad0e00 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -16,6 +16,9 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.os.Process.THREAD_PRIORITY_DEFAULT;
 import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader;
 import static android.view.Display.DEFAULT_DISPLAY;
 
@@ -25,67 +28,91 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.nullable;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import android.app.ActivityManagerInternal;
 import android.app.AppOpsManager;
+import android.app.usage.UsageStatsManagerInternal;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.IntentFilter;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManagerInternal;
 import android.database.ContentObserver;
+import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManagerInternal;
 import android.net.Uri;
 import android.os.Handler;
+import android.os.Looper;
+import android.os.PowerManager;
 import android.os.PowerManagerInternal;
 import android.os.PowerSaveState;
 import android.os.UserHandle;
-import android.view.Display;
+import android.provider.DeviceConfig;
 import android.view.InputChannel;
+import android.view.Surface;
+import android.view.SurfaceControl;
 
 import com.android.dx.mockito.inline.extended.StaticMockitoSession;
+import com.android.server.AnimationThread;
+import com.android.server.DisplayThread;
 import com.android.server.LocalServices;
 import com.android.server.LockGuard;
+import com.android.server.ServiceThread;
 import com.android.server.Watchdog;
+import com.android.server.am.ActivityManagerService;
+import com.android.server.appop.AppOpsService;
+import com.android.server.display.color.ColorDisplayService;
 import com.android.server.input.InputManagerService;
+import com.android.server.policy.PermissionPolicyInternal;
 import com.android.server.policy.WindowManagerPolicy;
-import com.android.server.wm.utils.MockTracker;
+import com.android.server.statusbar.StatusBarManagerInternal;
+import com.android.server.uri.UriGrantsManagerInternal;
 
 import org.junit.rules.TestRule;
 import org.junit.runner.Description;
 import org.junit.runners.model.Statement;
-import org.mockito.invocation.InvocationOnMock;
+import org.mockito.Mockito;
 import org.mockito.quality.Strictness;
 
+import java.io.File;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
- * JUnit test rule to create a mock {@link WindowManagerService} instance for tests.
+ * JUnit test rule to correctly setting up system services like {@link WindowManagerService}
+ * and {@link ActivityTaskManagerService} for tests.
  */
 public class SystemServicesTestRule implements TestRule {
 
     private static final String TAG = SystemServicesTestRule.class.getSimpleName();
 
+    static int sNextDisplayId = DEFAULT_DISPLAY + 100;
+    static int sNextTaskId = 100;
+
     private final AtomicBoolean mCurrentMessagesProcessed = new AtomicBoolean(false);
 
-    private MockTracker mMockTracker;
+    private Context mContext;
     private StaticMockitoSession mMockitoSession;
-    private WindowManagerService mWindowManagerService;
-    private TestWindowManagerPolicy mWindowManagerPolicy;
-
-    /** {@link MockTracker} to track mocks created by {@link SystemServicesTestRule}. */
-    private static class Tracker extends MockTracker {
-        // This empty extended class is necessary since Mockito distinguishes a listener by it
-        // class.
-    }
+    ServiceThread mHandlerThread;
+    private ActivityManagerService mAmService;
+    private ActivityTaskManagerService mAtmService;
+    private WindowManagerService mWmService;
+    private TestWindowManagerPolicy mWMPolicy;
+    private WindowState.PowerManagerWrapper mPowerManagerWrapper;
+    private InputManagerService mImService;
+    /**
+     * Spied {@link SurfaceControl.Transaction} class than can be used to verify calls.
+     */
+    SurfaceControl.Transaction mTransaction;
 
     @Override
     public Statement apply(Statement base, Description description) {
@@ -103,8 +130,6 @@
     }
 
     private void setUp() {
-        mMockTracker = new Tracker();
-
         mMockitoSession = mockitoSession()
                 .spyStatic(LocalServices.class)
                 .mockStatic(LockGuard.class)
@@ -112,101 +137,220 @@
                 .strictness(Strictness.LENIENT)
                 .startMocking();
 
+        setUpSystemCore();
+        setUpLocalServices();
+        setUpActivityTaskManagerService();
+        setUpWindowManagerService();
+    }
+
+    private void setUpSystemCore() {
+        mHandlerThread = new ServiceThread(
+                "WmTestsThread", THREAD_PRIORITY_DEFAULT, true /* allowIo */);
+        mHandlerThread.start();
+
         doReturn(mock(Watchdog.class)).when(Watchdog::getInstance);
 
-        final Context context = getInstrumentation().getTargetContext();
-        spyOn(context);
+        mContext = getInstrumentation().getTargetContext();
+        spyOn(mContext);
 
-        doReturn(null).when(context)
+        doReturn(null).when(mContext)
                 .registerReceiver(nullable(BroadcastReceiver.class), any(IntentFilter.class));
-        doReturn(null).when(context)
+        doReturn(null).when(mContext)
                 .registerReceiverAsUser(any(BroadcastReceiver.class), any(UserHandle.class),
                         any(IntentFilter.class), nullable(String.class), nullable(Handler.class));
 
-        final ContentResolver contentResolver = context.getContentResolver();
+        final ContentResolver contentResolver = mContext.getContentResolver();
         spyOn(contentResolver);
         doNothing().when(contentResolver)
                 .registerContentObserver(any(Uri.class), anyBoolean(), any(ContentObserver.class),
                         anyInt());
+    }
 
-        final AppOpsManager appOpsManager = mock(AppOpsManager.class);
-        doReturn(appOpsManager).when(context)
-                .getSystemService(eq(Context.APP_OPS_SERVICE));
+    private void setUpLocalServices() {
+        // Tear down any local services just in case.
+        tearDownLocalServices();
 
+        // UriGrantsManagerInternal
+        final UriGrantsManagerInternal ugmi = mock(UriGrantsManagerInternal.class);
+        LocalServices.addService(UriGrantsManagerInternal.class, ugmi);
+
+        // AppOpsManager
+        final AppOpsManager aom = mock(AppOpsManager.class);
+        doReturn(aom).when(mContext).getSystemService(eq(Context.APP_OPS_SERVICE));
+
+        // DisplayManagerInternal
         final DisplayManagerInternal dmi = mock(DisplayManagerInternal.class);
         doReturn(dmi).when(() -> LocalServices.getService(eq(DisplayManagerInternal.class)));
 
+        // ColorDisplayServiceInternal
+        final ColorDisplayService.ColorDisplayServiceInternal cds =
+                mock(ColorDisplayService.ColorDisplayServiceInternal.class);
+        doReturn(cds).when(() -> LocalServices.getService(
+                eq(ColorDisplayService.ColorDisplayServiceInternal.class)));
+
+        final UsageStatsManagerInternal usmi = mock(UsageStatsManagerInternal.class);
+        LocalServices.addService(UsageStatsManagerInternal.class, usmi);
+
+        // PackageManagerInternal
+        final PackageManagerInternal packageManagerInternal = mock(PackageManagerInternal.class);
+        LocalServices.addService(PackageManagerInternal.class, packageManagerInternal);
+        doReturn(false).when(packageManagerInternal).isPermissionsReviewRequired(
+                anyString(), anyInt());
+        doReturn(null).when(packageManagerInternal).getDefaultHomeActivity(anyInt());
+
+        // PowerManagerInternal
         final PowerManagerInternal pmi = mock(PowerManagerInternal.class);
         final PowerSaveState state = new PowerSaveState.Builder().build();
         doReturn(state).when(pmi).getLowPowerState(anyInt());
         doReturn(pmi).when(() -> LocalServices.getService(eq(PowerManagerInternal.class)));
 
-        final ActivityManagerInternal ami = mock(ActivityManagerInternal.class);
-        doReturn(ami).when(() -> LocalServices.getService(eq(ActivityManagerInternal.class)));
+        // PermissionPolicyInternal
+        final PermissionPolicyInternal ppi = mock(PermissionPolicyInternal.class);
+        LocalServices.addService(PermissionPolicyInternal.class, ppi);
+        doReturn(true).when(ppi).checkStartActivity(any(), anyInt(), any());
 
-        final ActivityTaskManagerInternal atmi = mock(ActivityTaskManagerInternal.class);
-        doAnswer((InvocationOnMock invocationOnMock) -> {
-            final Runnable runnable = invocationOnMock.getArgument(0);
-            if (runnable != null) {
-                runnable.run();
-            }
-            return null;
-        }).when(atmi).notifyKeyguardFlagsChanged(nullable(Runnable.class), anyInt());
-        doReturn(atmi).when(() -> LocalServices.getService(eq(ActivityTaskManagerInternal.class)));
-
-        final InputManagerService ims = mock(InputManagerService.class);
+        // InputManagerService
+        mImService = mock(InputManagerService.class);
         // InputChannel is final and can't be mocked.
         final InputChannel[] input = InputChannel.openInputChannelPair(TAG_WM);
         if (input != null && input.length > 1) {
-            doReturn(input[1]).when(ims).monitorInput(anyString(), anyInt());
+            doReturn(input[1]).when(mImService).monitorInput(anyString(), anyInt());
         }
 
-        final ActivityTaskManagerService atms = mock(ActivityTaskManagerService.class);
-        final TaskChangeNotificationController taskChangeNotificationController = mock(
-                TaskChangeNotificationController.class);
-        doReturn(taskChangeNotificationController).when(atms).getTaskChangeNotificationController();
-        final WindowManagerGlobalLock wmLock = new WindowManagerGlobalLock();
-        doReturn(wmLock).when(atms).getGlobalLock();
+        // StatusBarManagerInternal
+        final StatusBarManagerInternal sbmi = mock(StatusBarManagerInternal.class);
+        doReturn(sbmi).when(() -> LocalServices.getService(eq(StatusBarManagerInternal.class)));
+    }
 
-        mWindowManagerPolicy = new TestWindowManagerPolicy(this::getWindowManagerService);
-        mWindowManagerService = WindowManagerService.main(
-                context, ims, false, false, mWindowManagerPolicy, atms, StubTransaction::new);
+    private void setUpActivityTaskManagerService() {
+        // ActivityManagerService
+        mAmService = new ActivityManagerService(
+                new AMTestInjector(mContext, mHandlerThread), mHandlerThread);
+        spyOn(mAmService);
+        doReturn(mock(IPackageManager.class)).when(mAmService).getPackageManager();
+        doNothing().when(mAmService).grantEphemeralAccessLocked(
+                anyInt(), any(), anyInt(), anyInt());
 
-        mWindowManagerService.onInitReady();
+        // ActivityManagerInternal
+        final ActivityManagerInternal amInternal = mAmService.mInternal;
+        spyOn(amInternal);
+        doNothing().when(amInternal).trimApplications();
+        doNothing().when(amInternal).updateCpuStats();
+        doNothing().when(amInternal).updateOomAdj();
+        doNothing().when(amInternal).updateBatteryStats(any(), anyInt(), anyInt(), anyBoolean());
+        doNothing().when(amInternal).updateActivityUsageStats(
+                any(), anyInt(), anyInt(), any(), any());
+        doNothing().when(amInternal).startProcess(
+                any(), any(), anyBoolean(), anyBoolean(), any(), any());
+        doNothing().when(amInternal).updateOomLevelsForDisplay(anyInt());
+        LocalServices.addService(ActivityManagerInternal.class, amInternal);
 
-        final Display display = mWindowManagerService.mDisplayManager.getDisplay(DEFAULT_DISPLAY);
-        // Display creation is driven by the ActivityManagerService via
-        // ActivityStackSupervisor. We emulate those steps here.
-        DisplayContent displayContent = mWindowManagerService.mRoot
-                .createDisplayContent(display, mock(ActivityDisplay.class));
-        displayContent.reconfigureDisplayLocked();
+        mAtmService = new TestActivityTaskManagerService(mContext, mAmService);
+        LocalServices.addService(ActivityTaskManagerInternal.class, mAtmService.getAtmInternal());
+    }
 
-        mMockTracker.stopTracking();
+    private void setUpWindowManagerService() {
+        mPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class);
+        mWMPolicy = new TestWindowManagerPolicy(this::getWindowManagerService,
+                mPowerManagerWrapper);
+        mWmService = WindowManagerService.main(
+                mContext, mImService, false, false, mWMPolicy, mAtmService, StubTransaction::new);
+        spyOn(mWmService);
+
+        // Setup factory classes to prevent calls to native code.
+        mTransaction = spy(StubTransaction.class);
+        // Return a spied Transaction class than can be used to verify calls.
+        mWmService.mTransactionFactory = () -> mTransaction;
+        // Return a SurfaceControl.Builder class that creates mocked SurfaceControl instances.
+        mWmService.mSurfaceBuilderFactory = (unused) -> new MockSurfaceControlBuilder();
+        // Return mocked Surface instances.
+        mWmService.mSurfaceFactory = () -> mock(Surface.class);
+        mWmService.mSurfaceAnimationRunner = new SurfaceAnimationRunner(
+                null, null, mTransaction, mWmService.mPowerManagerInternal);
+
+        mWmService.onInitReady();
+        mAmService.setWindowManager(mWmService);
+        mWmService.mDisplayEnabled = true;
+        mWmService.mDisplayReady = true;
+        // Set configuration for default display
+        mWmService.getDefaultDisplayContentLocked().reconfigureDisplayLocked();
+
+        // Mock root, some default display, and home stack.
+        spyOn(mWmService.mRoot);
+        final ActivityDisplay display = mAtmService.mRootActivityContainer.getDefaultDisplay();
+        spyOn(display);
+        spyOn(display.mDisplayContent);
+        final ActivityStack homeStack = display.getStack(
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
+        spyOn(homeStack);
+        spyOn(homeStack.mTaskStack);
     }
 
     private void tearDown() {
         waitUntilWindowManagerHandlersIdle();
-        removeLocalServices();
-        mWindowManagerService = null;
-        mWindowManagerPolicy = null;
+        // Unregister display listener from root to avoid issues with subsequent tests.
+        mContext.getSystemService(DisplayManager.class)
+                .unregisterDisplayListener(mAtmService.mRootActivityContainer);
+        // ProptertiesChangesListener is registered in the constructor of WindowManagerService to
+        // a static object, so we need to clean it up in tearDown(), even though we didn't set up
+        // in tests.
+        DeviceConfig.removeOnPropertiesChangedListener(mWmService.mPropertiesChangedListener);
+        mWmService = null;
+        mWMPolicy = null;
+        mPowerManagerWrapper = null;
+
+        tearDownLocalServices();
+        tearDownSystemCore();
+
+        // Needs to explicitly dispose current static threads because there could be messages
+        // scheduled at a later time, and all mocks are invalid when it's executed.
+        DisplayThread.dispose();
+        AnimationThread.dispose();
+        // Reset priority booster because animation thread has been changed.
+        WindowManagerService.sThreadPriorityBooster = new WindowManagerThreadPriorityBooster();
+
+        Mockito.framework().clearInlineMocks();
+    }
+
+    private void tearDownSystemCore() {
         if (mMockitoSession != null) {
             mMockitoSession.finishMocking();
             mMockitoSession = null;
         }
 
-        if (mMockTracker != null) {
-            mMockTracker.close();
-            mMockTracker = null;
+        if (mHandlerThread != null) {
+            // Make sure there are no running messages and then quit the thread so the next test
+            // won't be affected.
+            mHandlerThread.getThreadHandler().runWithScissors(mHandlerThread::quit,
+                    0 /* timeout */);
         }
     }
 
-    private static void removeLocalServices() {
+    private static void tearDownLocalServices() {
+        LocalServices.removeServiceForTest(DisplayManagerInternal.class);
+        LocalServices.removeServiceForTest(PowerManagerInternal.class);
+        LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+        LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class);
         LocalServices.removeServiceForTest(WindowManagerInternal.class);
         LocalServices.removeServiceForTest(WindowManagerPolicy.class);
+        LocalServices.removeServiceForTest(PackageManagerInternal.class);
+        LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
+        LocalServices.removeServiceForTest(PermissionPolicyInternal.class);
+        LocalServices.removeServiceForTest(ColorDisplayService.ColorDisplayServiceInternal.class);
+        LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
+        LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
     }
 
     WindowManagerService getWindowManagerService() {
-        return mWindowManagerService;
+        return mWmService;
+    }
+
+    ActivityTaskManagerService getActivityTaskManagerService() {
+        return mAtmService;
+    }
+
+    WindowState.PowerManagerWrapper getPowerManagerWrapper() {
+        return mPowerManagerWrapper;
     }
 
     void cleanupWindowManagerHandlers() {
@@ -229,6 +373,7 @@
         waitHandlerIdle(wm.mH);
         waitHandlerIdle(wm.mAnimationHandler);
         waitHandlerIdle(SurfaceAnimationThread.getHandler());
+        waitHandlerIdle(mHandlerThread.getThreadHandler());
     }
 
     private void waitHandlerIdle(Handler handler) {
@@ -251,4 +396,121 @@
             }
         }
     }
+
+    protected class TestActivityTaskManagerService extends ActivityTaskManagerService {
+        // ActivityStackSupervisor may be created more than once while setting up AMS and ATMS.
+        // We keep the reference in order to prevent creating it twice.
+        ActivityStackSupervisor mTestStackSupervisor;
+
+        TestActivityTaskManagerService(Context context, ActivityManagerService ams) {
+            super(context);
+            spyOn(this);
+
+            mSupportsMultiWindow = true;
+            mSupportsMultiDisplay = true;
+            mSupportsSplitScreenMultiWindow = true;
+            mSupportsFreeformWindowManagement = true;
+            mSupportsPictureInPicture = true;
+
+            doReturn(mock(IPackageManager.class)).when(this).getPackageManager();
+            // allow background activity starts by default
+            doReturn(true).when(this).isBackgroundActivityStartsEnabled();
+            doNothing().when(this).updateCpuStats();
+
+            // AppOpsService
+            final AppOpsService aos = mock(AppOpsService.class);
+            doReturn(aos).when(this).getAppOpsService();
+            // Make sure permission checks aren't overridden.
+            doReturn(AppOpsManager.MODE_DEFAULT)
+                    .when(aos).noteOperation(anyInt(), anyInt(), anyString());
+
+            setUsageStatsManager(LocalServices.getService(UsageStatsManagerInternal.class));
+            ams.mActivityTaskManager = this;
+            ams.mAtmInternal = mInternal;
+            onActivityManagerInternalAdded();
+            initialize(
+                    ams.mIntentFirewall, ams.mPendingIntentController, mHandlerThread.getLooper());
+            spyOn(getLifecycleManager());
+            spyOn(getLockTaskController());
+            spyOn(getTaskChangeNotificationController());
+            initRootActivityContainerMocks();
+        }
+
+        void initRootActivityContainerMocks() {
+            spyOn(mRootActivityContainer);
+            // Invoked during {@link ActivityStack} creation.
+            doNothing().when(mRootActivityContainer).updateUIDsPresentOnDisplay();
+            // Always keep things awake.
+            doReturn(true).when(mRootActivityContainer).hasAwakeDisplay();
+            // Called when moving activity to pinned stack.
+            doNothing().when(mRootActivityContainer).ensureActivitiesVisible(any(), anyInt(),
+                    anyBoolean());
+        }
+
+        @Override
+        int handleIncomingUser(int callingPid, int callingUid, int userId, String name) {
+            return userId;
+        }
+
+        @Override
+        protected ActivityStackSupervisor createStackSupervisor() {
+            if (mTestStackSupervisor == null) {
+                mTestStackSupervisor = new TestActivityStackSupervisor(this, mH.getLooper());
+            }
+            return mTestStackSupervisor;
+        }
+    }
+
+    /**
+     * An {@link ActivityStackSupervisor} which stubs out certain methods that depend on
+     * setup not available in the test environment. Also specifies an injector for
+     */
+    protected class TestActivityStackSupervisor extends ActivityStackSupervisor {
+
+        TestActivityStackSupervisor(ActivityTaskManagerService service, Looper looper) {
+            super(service, looper);
+            spyOn(this);
+
+            // Do not schedule idle that may touch methods outside the scope of the test.
+            doNothing().when(this).scheduleIdleLocked();
+            doNothing().when(this).scheduleIdleTimeoutLocked(any());
+            // unit test version does not handle launch wake lock
+            doNothing().when(this).acquireLaunchWakelock();
+            doReturn(mock(KeyguardController.class)).when(this).getKeyguardController();
+
+            mLaunchingActivityWakeLock = mock(PowerManager.WakeLock.class);
+
+            initialize();
+        }
+    }
+
+    // TODO: Can we just mock this?
+    private static class AMTestInjector extends ActivityManagerService.Injector {
+        private ServiceThread mHandlerThread;
+
+        AMTestInjector(Context context, ServiceThread handlerThread) {
+            super(context);
+            mHandlerThread = handlerThread;
+        }
+
+        @Override
+        public Context getContext() {
+            return getInstrumentation().getTargetContext();
+        }
+
+        @Override
+        public AppOpsService getAppOpsService(File file, Handler handler) {
+            return null;
+        }
+
+        @Override
+        public Handler getUiHandler(ActivityManagerService service) {
+            return mHandlerThread.getThreadHandler();
+        }
+
+        @Override
+        public boolean isNetworkRestrictedForUid(int uid) {
+            return false;
+        }
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index 2cebebf..bcff704 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -1277,17 +1277,18 @@
     }
 
     private ActivityRecord createSourceActivity(TestActivityDisplay display) {
-        final TestActivityStack stack = display.createStack(display.getWindowingMode(),
+        final ActivityStack stack = display.createStack(display.getWindowingMode(),
                 ACTIVITY_TYPE_STANDARD, true);
         return new ActivityBuilder(mService).setStack(stack).setCreateTask(true).build();
     }
 
     private void addFreeformTaskTo(TestActivityDisplay display, Rect bounds) {
-        final TestActivityStack stack = display.createStack(display.getWindowingMode(),
+        final ActivityStack stack = display.createStack(display.getWindowingMode(),
                 ACTIVITY_TYPE_STANDARD, true);
         stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
         final TaskRecord task = new TaskBuilder(mSupervisor).setStack(stack).build();
-        task.setBounds(bounds);
+        // Just work around the unnecessary adjustments for bounds.
+        task.getWindowConfiguration().setBounds(bounds);
     }
 
     private void assertEquivalentWindowingMode(int expected, int actual, int parentWindowingMode) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index a0302f6..c83401b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -28,14 +28,19 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 import static android.util.DisplayMetrics.DENSITY_DEFAULT;
 import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_90;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.policy.WindowManagerPolicy.USER_ROTATION_FREE;
+import static com.android.server.wm.DisplayRotation.FIXED_TO_USER_ROTATION_ENABLED;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.hamcrest.Matchers.not;
 import static org.hamcrest.Matchers.sameInstance;
 import static org.junit.Assert.assertEquals;
@@ -64,6 +69,7 @@
 import android.util.Xml;
 import android.view.DisplayInfo;
 
+import androidx.test.filters.FlakyTest;
 import androidx.test.filters.MediumTest;
 
 import com.android.internal.app.IVoiceInteractor;
@@ -102,6 +108,7 @@
     public void setUp() throws Exception {
         TaskRecord.setTaskRecordFactory(null);
         mParentBounds = new Rect(10 /*left*/, 30 /*top*/, 80 /*right*/, 60 /*bottom*/);
+        removeGlobalMinSizeRestriction();
     }
 
     @Test
@@ -165,6 +172,7 @@
 
     /** Ensures that bounds on freeform stacks are not clipped. */
     @Test
+    @FlakyTest(bugId = 137879065)
     public void testAppBounds_FreeFormBounds() {
         final Rect freeFormBounds = new Rect(mParentBounds);
         freeFormBounds.offset(10, 10);
@@ -174,6 +182,7 @@
 
     /** Ensures that fully contained bounds are not clipped. */
     @Test
+    @FlakyTest(bugId = 137879065)
     public void testAppBounds_ContainedBounds() {
         final Rect insetBounds = new Rect(mParentBounds);
         insetBounds.inset(5, 5, 5, 5);
@@ -182,6 +191,7 @@
     }
 
     @Test
+    @FlakyTest(bugId = 137879065)
     public void testFitWithinBounds() {
         final Rect parentBounds = new Rect(10, 10, 200, 200);
         ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
@@ -221,6 +231,7 @@
 
     /** Tests that the task bounds adjust properly to changes between FULLSCREEN and FREEFORM */
     @Test
+    @FlakyTest(bugId = 137879065)
     public void testBoundsOnModeChangeFreeformToFullscreen() {
         ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
         ActivityStack stack = new StackBuilder(mRootActivityContainer).setDisplay(display)
@@ -248,18 +259,6 @@
     }
 
     /**
-     * This is a temporary hack to trigger an onConfigurationChange at the task level after an
-     * orientation is requested. Normally this is done by the onDescendentOrientationChanged call
-     * up the WM hierarchy, but since the WM hierarchy is mocked out, it doesn't happen here.
-     * TODO: remove this when we either get a WM hierarchy or when hierarchies are merged.
-     */
-    private void setActivityRequestedOrientation(ActivityRecord activity, int orientation) {
-        activity.setRequestedOrientation(orientation);
-        ConfigurationContainer taskRecord = activity.getParent();
-        taskRecord.onConfigurationChanged(taskRecord.getParent().getConfiguration());
-    }
-
-    /**
      * Tests that a task with forced orientation has orientation-consistent bounds within the
      * parent.
      */
@@ -268,49 +267,48 @@
         final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080);
         final Rect fullScreenBoundsPort = new Rect(0, 0, 1080, 1920);
         DisplayInfo info = new DisplayInfo();
+        mService.mContext.getDisplay().getDisplayInfo(info);
         info.logicalWidth = fullScreenBounds.width();
         info.logicalHeight = fullScreenBounds.height();
         ActivityDisplay display = addNewActivityDisplayAt(info, POSITION_TOP);
         assertTrue(mRootActivityContainer.getActivityDisplay(display.mDisplayId) != null);
-        // Override display orientation. Normally this is available via DisplayContent, but DC
-        // is mocked-out.
-        display.getRequestedOverrideConfiguration().orientation =
-                Configuration.ORIENTATION_LANDSCAPE;
-        display.onRequestedOverrideConfigurationChanged(
-                display.getRequestedOverrideConfiguration());
+        // Fix the display orientation to landscape which is the natural rotation (0) for the test
+        // display.
+        final DisplayRotation dr = display.mDisplayContent.getDisplayRotation();
+        dr.setFixedToUserRotation(FIXED_TO_USER_ROTATION_ENABLED);
+        dr.setUserRotation(USER_ROTATION_FREE, ROTATION_0);
+
         ActivityStack stack = new StackBuilder(mRootActivityContainer)
                 .setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
         TaskRecord task = stack.getChildAt(0);
         ActivityRecord root = task.getTopActivity();
-        assertEquals(root, task.getTopActivity());
 
         assertEquals(fullScreenBounds, task.getBounds());
 
         // Setting app to fixed portrait fits within parent
-        setActivityRequestedOrientation(root, SCREEN_ORIENTATION_PORTRAIT);
+        root.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
         assertEquals(root, task.getRootActivity());
         assertEquals(SCREEN_ORIENTATION_PORTRAIT, task.getRootActivity().getOrientation());
-        assertTrue(task.getBounds().width() < task.getBounds().height());
+        assertThat(task.getBounds().width()).isLessThan(task.getBounds().height());
         assertEquals(fullScreenBounds.height(), task.getBounds().height());
 
         // Top activity gets used
         ActivityRecord top = new ActivityBuilder(mService).setTask(task).setStack(stack).build();
         assertEquals(top, task.getTopActivity());
-        setActivityRequestedOrientation(top, SCREEN_ORIENTATION_LANDSCAPE);
-        assertTrue(task.getBounds().width() > task.getBounds().height());
+        top.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+        assertThat(task.getBounds().width()).isGreaterThan(task.getBounds().height());
         assertEquals(task.getBounds().width(), fullScreenBounds.width());
 
         // Setting app to unspecified restores
-        setActivityRequestedOrientation(top, SCREEN_ORIENTATION_UNSPECIFIED);
+        top.setRequestedOrientation(SCREEN_ORIENTATION_UNSPECIFIED);
         assertEquals(fullScreenBounds, task.getBounds());
 
         // Setting app to fixed landscape and changing display
-        setActivityRequestedOrientation(top, SCREEN_ORIENTATION_LANDSCAPE);
-        // simulate display orientation changing (normally done via DisplayContent)
-        display.getRequestedOverrideConfiguration().orientation =
-                Configuration.ORIENTATION_PORTRAIT;
-        display.setBounds(fullScreenBoundsPort);
-        assertTrue(task.getBounds().width() > task.getBounds().height());
+        top.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+        // Fix the display orientation to portrait which is 90 degrees for the test display.
+        dr.setUserRotation(USER_ROTATION_FREE, ROTATION_90);
+
+        assertThat(task.getBounds().width()).isGreaterThan(task.getBounds().height());
         assertEquals(fullScreenBoundsPort.width(), task.getBounds().width());
 
         // in FREEFORM, no constraint
@@ -323,7 +321,7 @@
 
         // FULLSCREEN letterboxes bounds
         stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
-        assertTrue(task.getBounds().width() > task.getBounds().height());
+        assertThat(task.getBounds().width()).isGreaterThan(task.getBounds().height());
         assertEquals(fullScreenBoundsPort.width(), task.getBounds().width());
 
         // FREEFORM restores bounds as before
@@ -335,6 +333,7 @@
     public void testIgnoresForcedOrientationWhenParentHandles() {
         final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080);
         DisplayInfo info = new DisplayInfo();
+        mService.mContext.getDisplay().getDisplayInfo(info);
         info.logicalWidth = fullScreenBounds.width();
         info.logicalHeight = fullScreenBounds.height();
         ActivityDisplay display = addNewActivityDisplayAt(info, POSITION_TOP);
@@ -355,7 +354,7 @@
 
         // Setting app to fixed portrait fits within parent, but TaskRecord shouldn't adjust the
         // bounds because its parent says it will handle it at a later time.
-        setActivityRequestedOrientation(root, SCREEN_ORIENTATION_PORTRAIT);
+        root.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
         assertEquals(root, task.getRootActivity());
         assertEquals(SCREEN_ORIENTATION_PORTRAIT, task.getRootActivity().getOrientation());
         assertEquals(fullScreenBounds, task.getBounds());
@@ -646,7 +645,7 @@
         final ActivityRecord activity0 = task0.getChildAt(0);
 
         final TaskRecord task1 = getTestTask();
-        final ActivityRecord activity1 = task0.getChildAt(0);
+        final ActivityRecord activity1 = task1.getChildAt(0);
 
         assertEquals(task0.taskId,
                 ActivityRecord.getTaskForActivityLocked(activity0.appToken, false /* onlyRoot */));
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java b/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java
new file mode 100644
index 0000000..c143969
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
+import android.hardware.display.DisplayManagerGlobal;
+import android.view.Display;
+import android.view.DisplayInfo;
+
+class TestActivityDisplay extends ActivityDisplay {
+    private final ActivityStackSupervisor mSupervisor;
+
+    static TestActivityDisplay create(ActivityStackSupervisor supervisor) {
+        return create(supervisor, SystemServicesTestRule.sNextDisplayId++);
+    }
+
+    static TestActivityDisplay create(ActivityStackSupervisor supervisor, DisplayInfo info) {
+        return create(supervisor, SystemServicesTestRule.sNextDisplayId++, info);
+    }
+
+    static TestActivityDisplay create(ActivityStackSupervisor supervisor, int displayId) {
+        final DisplayInfo info = new DisplayInfo();
+        supervisor.mService.mContext.getDisplay().getDisplayInfo(info);
+        return create(supervisor, displayId, info);
+    }
+
+    static TestActivityDisplay create(ActivityStackSupervisor supervisor, int displayId,
+            DisplayInfo info) {
+        if (displayId == DEFAULT_DISPLAY) {
+            synchronized (supervisor.mService.mGlobalLock) {
+                return new TestActivityDisplay(supervisor,
+                        supervisor.mRootActivityContainer.mDisplayManager.getDisplay(displayId));
+            }
+        }
+        final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
+                info, DEFAULT_DISPLAY_ADJUSTMENTS);
+
+        synchronized (supervisor.mService.mGlobalLock) {
+            return new TestActivityDisplay(supervisor, display);
+        }
+    }
+
+    private TestActivityDisplay(ActivityStackSupervisor supervisor, Display display) {
+        super(supervisor.mService.mRootActivityContainer, display);
+        // Normally this comes from display-properties as exposed by WM. Without that, just
+        // hard-code to FULLSCREEN for tests.
+        setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+        mSupervisor = supervisor;
+        spyOn(this);
+        spyOn(mDisplayContent);
+        doAnswer(invocation -> {
+            // Bypass all the rotation animation and display freezing stuff for testing and just
+            // set the rotation we want for the display
+            final DisplayContent dc = mDisplayContent;
+            final int oldRotation = dc.getRotation();
+            final int rotation = dc.getDisplayRotation().rotationForOrientation(
+                    dc.getLastOrientation(), oldRotation);
+            if (oldRotation == rotation) {
+                return false;
+            }
+            dc.setLayoutNeeded();
+            dc.setRotation(rotation);
+            return true;
+        }).when(mDisplayContent).updateRotationUnchecked(anyBoolean());
+    }
+
+    @SuppressWarnings("TypeParameterUnusedInFormals")
+    @Override
+    ActivityStack createStackUnchecked(int windowingMode, int activityType,
+            int stackId, boolean onTop) {
+        return new ActivityTestsBase.StackBuilder(mSupervisor.mRootActivityContainer)
+                .setDisplay(this)
+                .setWindowingMode(windowingMode)
+                .setActivityType(activityType)
+                .setStackId(stackId)
+                .setOnTop(onTop)
+                .setCreateActivity(false)
+                .build();
+    }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 2e5ce69..bb89446 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -40,12 +40,14 @@
 import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IShortcutService;
 import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.wm.WindowState.PowerManagerWrapper;
 
 import java.io.PrintWriter;
 import java.util.function.Supplier;
 
 class TestWindowManagerPolicy implements WindowManagerPolicy {
     private final Supplier<WindowManagerService> mWmSupplier;
+    private final PowerManagerWrapper mPowerManagerWrapper;
 
     int mRotationToReport = 0;
     boolean mKeyguardShowingAndNotOccluded = false;
@@ -53,8 +55,10 @@
 
     private Runnable mRunnableWhenAddingSplashScreen;
 
-    TestWindowManagerPolicy(Supplier<WindowManagerService> wmSupplier) {
+    TestWindowManagerPolicy(Supplier<WindowManagerService> wmSupplier,
+            PowerManagerWrapper powerManagerWrapper) {
         mWmSupplier = wmSupplier;
+        mPowerManagerWrapper = powerManagerWrapper;
     }
 
     @Override
@@ -121,7 +125,7 @@
             doReturn(mock(IBinder.class)).when(iWindow).asBinder();
             window = WindowTestsBase.createWindow(null, TYPE_APPLICATION_STARTING, atoken,
                     "Starting window", 0 /* ownerId */, false /* internalWindows */, wm,
-                    mock(Session.class), iWindow);
+                    mock(Session.class), iWindow, mPowerManagerWrapper);
             atoken.startingWindow = window;
         }
         if (mRunnableWhenAddingSplashScreen != null) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index acfc2ea..921f105 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -27,6 +27,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
@@ -113,6 +114,7 @@
 
     @Test
     public void testAddChildSetsSurfacePosition() {
+        reset(mTransaction);
         try (MockSurfaceBuildingContainer top = new MockSurfaceBuildingContainer(mWm)) {
             WindowContainer child = new WindowContainer(mWm);
             child.setBounds(1, 1, 10, 10);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
index 06bcdf8..60cefe8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
@@ -57,6 +57,7 @@
 
     private final IWindow mIWindow = new TestIWindow();
     private final Rect mEmptyRect = new Rect();
+    private DisplayContent mTestDisplayContent;
 
     static class FrameTestWindowState extends WindowState {
         boolean mDockedResizingForTest = false;
@@ -77,6 +78,9 @@
     @Before
     public void setUp() throws Exception {
         mStubStack = mock(TaskStack.class);
+        DisplayInfo testDisplayInfo = new DisplayInfo(mDisplayInfo);
+        testDisplayInfo.displayCutout = null;
+        mTestDisplayContent = createNewDisplay(testDisplayInfo);
     }
 
     // Do not use this function directly in the tests below. Instead, use more explicit function
@@ -100,6 +104,10 @@
         assertRect(w.getStableInsets(), left, top, right, bottom);
     }
 
+    private void assertFrame(WindowState w, Rect frame) {
+        assertEquals(w.getFrameLw(), frame);
+    }
+
     private void assertFrame(WindowState w, int left, int top, int right, int bottom) {
         assertRect(w.getFrameLw(), left, top, right, bottom);
     }
@@ -380,9 +388,10 @@
     }
 
     @Test
+    @FlakyTest(bugId = 137879065)
     public void testLayoutLetterboxedWindow() {
         // First verify task behavior in multi-window mode.
-        final DisplayInfo displayInfo = mWm.getDefaultDisplayContentLocked().getDisplayInfo();
+        final DisplayInfo displayInfo = mTestDisplayContent.getDisplayInfo();
         final int logicalWidth = displayInfo.logicalWidth;
         final int logicalHeight = displayInfo.logicalHeight;
 
@@ -413,13 +422,14 @@
         final Rect cf = new Rect(xInset, 0, logicalWidth - xInset, logicalHeight);
         Configuration config = new Configuration(w.mAppToken.getRequestedOverrideConfiguration());
         config.windowConfiguration.setBounds(cf);
+        config.windowConfiguration.setAppBounds(cf);
         w.mAppToken.onRequestedOverrideConfigurationChanged(config);
         pf.set(0, 0, logicalWidth, logicalHeight);
         task.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
         task.setBounds(null);
         windowFrames.setFrames(pf, pf, pf, cf, cf, pf, cf, mEmptyRect);
         w.computeFrameLw();
-        assertFrame(w, cf.left, cf.top, cf.right, cf.bottom);
+        assertFrame(w, cf);
         assertContentFrame(w, cf);
         assertContentInset(w, 0, 0, 0, 0);
     }
@@ -483,7 +493,7 @@
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
         task.setWindowingMode(WINDOWING_MODE_FREEFORM);
 
-        DisplayContent dc = mWm.getDefaultDisplayContentLocked();
+        DisplayContent dc = mTestDisplayContent;
         dc.mInputMethodTarget = w;
         WindowState mockIme = mock(WindowState.class);
         Mockito.doReturn(true).when(mockIme).isVisibleNow();
@@ -537,7 +547,7 @@
         attrs.width = width;
         attrs.height = height;
 
-        AppWindowToken token = createAppWindowToken(mWm.getDefaultDisplayContentLocked(),
+        AppWindowToken token = createAppWindowToken(mTestDisplayContent,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
 
         FrameTestWindowState ws = new FrameTestWindowState(mWm, mIWindow, token, attrs);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 36698ea..b731628 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -346,24 +346,28 @@
         firstWindow.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
         secondWindow.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
 
-        reset(sPowerManagerWrapper);
+        final WindowState.PowerManagerWrapper powerManagerWrapper =
+                mSystemServicesTestRule.getPowerManagerWrapper();
+        reset(powerManagerWrapper);
         firstWindow.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
-        verify(sPowerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString());
+        verify(powerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString());
 
-        reset(sPowerManagerWrapper);
+        reset(powerManagerWrapper);
         secondWindow.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
-        verify(sPowerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString());
+        verify(powerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString());
     }
 
     private void testPrepareWindowToDisplayDuringRelayout(WindowState appWindow,
             boolean expectedWakeupCalled, boolean expectedCurrentLaunchCanTurnScreenOn) {
-        reset(sPowerManagerWrapper);
+        final WindowState.PowerManagerWrapper powerManagerWrapper =
+                mSystemServicesTestRule.getPowerManagerWrapper();
+        reset(powerManagerWrapper);
         appWindow.prepareWindowToDisplayDuringRelayout(false /* wasVisible */);
 
         if (expectedWakeupCalled) {
-            verify(sPowerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString());
+            verify(powerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString());
         } else {
-            verify(sPowerManagerWrapper, never()).wakeUp(anyLong(), anyInt(), anyString());
+            verify(powerManagerWrapper, never()).wakeUp(anyLong(), anyInt(), anyString());
         }
         // If wakeup is expected to be called, the currentLaunchCanTurnScreenOn should be false
         // because the state will be consumed.
@@ -517,13 +521,19 @@
 
     @Test
     public void testGetTransformationMatrix() {
+        final int PARENT_WINDOW_OFFSET = 1;
+        final int DISPLAY_IN_PARENT_WINDOW_OFFSET = 2;
+        final int WINDOW_OFFSET = 3;
+        final float OFFSET_SUM =
+                PARENT_WINDOW_OFFSET + DISPLAY_IN_PARENT_WINDOW_OFFSET + WINDOW_OFFSET;
+
         synchronized (mWm.mGlobalLock) {
             final WindowState win0 = createWindow(null, TYPE_APPLICATION, "win0");
-            win0.getFrameLw().offsetTo(1, 0);
 
             final DisplayContent dc = createNewDisplay();
+            win0.getFrameLw().offsetTo(PARENT_WINDOW_OFFSET, 0);
             dc.reparentDisplayContent(win0, win0.getSurfaceControl());
-            dc.updateLocation(win0, 2, 0);
+            dc.updateLocation(win0, DISPLAY_IN_PARENT_WINDOW_OFFSET, 0);
 
             final float[] values = new float[9];
             final Matrix matrix = new Matrix();
@@ -531,12 +541,12 @@
             final WindowState win1 = createWindow(null, TYPE_APPLICATION, dc, "win1");
             win1.mHasSurface = true;
             win1.mSurfaceControl = mock(SurfaceControl.class);
-            win1.getFrameLw().offsetTo(3, 0);
+            win1.getFrameLw().offsetTo(WINDOW_OFFSET, 0);
             win1.updateSurfacePosition(t);
             win1.getTransformationMatrix(values, matrix);
 
             matrix.getValues(values);
-            assertEquals(6f, values[Matrix.MTRANS_X], 0f);
+            assertEquals(OFFSET_SUM, values[Matrix.MTRANS_X], 0f);
             assertEquals(0f, values[Matrix.MTRANS_Y], 0f);
         }
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index dc461d1..d1cf1c3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -20,8 +20,6 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.os.Process.SYSTEM_UID;
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
 import static android.view.View.VISIBLE;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
@@ -38,33 +36,27 @@
 
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
+import static com.android.server.wm.ActivityDisplay.POSITION_TOP;
 
 import static org.mockito.Mockito.mock;
 
-
 import android.content.Context;
 import android.content.res.Configuration;
-import android.hardware.display.DisplayManagerGlobal;
 import android.testing.DexmakerShareClassLoaderRule;
 import android.util.Log;
 import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.IWindow;
-import android.view.Surface;
 import android.view.SurfaceControl.Transaction;
 import android.view.WindowManager;
 
 import com.android.server.AttributeCache;
-import com.android.server.wm.utils.MockTracker;
 
 import org.junit.After;
-import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Rule;
 
-import java.io.IOException;
 import java.util.HashSet;
 import java.util.LinkedList;
 
@@ -79,10 +71,6 @@
     WindowManagerService mWm;
     private final IWindow mIWindow = new TestIWindow();
     private Session mMockSession;
-    // The default display is removed in {@link #setUp} and then we iterate over all displays to
-    // make sure we don't collide with any existing display. If we run into no other display, the
-    // added display should be treated as default. This cannot be the default display
-    private static int sNextDisplayId = DEFAULT_DISPLAY + 1;
     static int sNextStackId = 1000;
 
     /** Non-default display. */
@@ -99,8 +87,6 @@
     WindowState mChildAppWindowBelow;
     HashSet<WindowState> mCommonWindows;
 
-    private MockTracker mMockTracker;
-
     /**
      * Spied {@link Transaction} class than can be used to verify calls.
      */
@@ -112,49 +98,27 @@
     @Rule
     public final SystemServicesTestRule mSystemServicesTestRule = new SystemServicesTestRule();
 
-    static WindowState.PowerManagerWrapper sPowerManagerWrapper;
-
     @BeforeClass
     public static void setUpOnceBase() {
         AttributeCache.init(getInstrumentation().getTargetContext());
-
-        sPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class);
-    }
-
-    @AfterClass
-    public static void tearDownOnceBase() throws IOException {
-        sPowerManagerWrapper = null;
     }
 
     @Before
     public void setUpBase() {
-        mMockTracker = new MockTracker();
-
         // If @Before throws an exception, the error isn't logged. This will make sure any failures
         // in the set up are clear. This can be removed when b/37850063 is fixed.
         try {
             mMockSession = mock(Session.class);
-            mTransaction = spy(StubTransaction.class);
 
             final Context context = getInstrumentation().getTargetContext();
 
             mWm = mSystemServicesTestRule.getWindowManagerService();
-
-            // Setup factory classes to prevent calls to native code.
-
-            // Return a spied Transaction class than can be used to verify calls.
-            mWm.mTransactionFactory = () -> mTransaction;
-            // Return a SurfaceControl.Builder class that creates mocked SurfaceControl instances.
-            mWm.mSurfaceBuilderFactory = (unused) -> new MockSurfaceControlBuilder();
-            // Return mocked Surface instances.
-            mWm.mSurfaceFactory = () -> mock(Surface.class);
+            mTransaction = mSystemServicesTestRule.mTransaction;
 
             beforeCreateDisplay();
 
             context.getDisplay().getDisplayInfo(mDisplayInfo);
             mDisplayContent = createNewDisplay();
-            mWm.mDisplayEnabled = true;
-            mWm.mDisplayReady = true;
 
             // Set-up some common windows.
             mCommonWindows = new HashSet<>();
@@ -211,12 +175,6 @@
                     nonCommonWindows.pollLast().removeImmediately();
                 }
 
-                for (int i = mWm.mRoot.mChildren.size() - 1; i >= 0; --i) {
-                    final DisplayContent displayContent = mWm.mRoot.mChildren.get(i);
-                    if (!displayContent.isDefaultDisplay) {
-                        displayContent.removeImmediately();
-                    }
-                }
                 // Remove app transition & window freeze timeout callbacks to prevent unnecessary
                 // actions after test.
                 mWm.getDefaultDisplayContentLocked().mAppTransition
@@ -230,11 +188,7 @@
         } catch (Exception e) {
             Log.e(TAG, "Failed to tear down test", e);
             throw e;
-        } finally {
-            mMockTracker.close();
-            mMockTracker = null;
         }
-
     }
 
     private WindowState createCommonWindow(WindowState parent, int type, String name) {
@@ -356,12 +310,13 @@
     WindowState createWindow(WindowState parent, int type, WindowToken token, String name,
             int ownerId, boolean ownerCanAddInternalSystemWindow) {
         return createWindow(parent, type, token, name, ownerId, ownerCanAddInternalSystemWindow,
-                mWm, mMockSession, mIWindow);
+                mWm, mMockSession, mIWindow, mSystemServicesTestRule.getPowerManagerWrapper());
     }
 
     static WindowState createWindow(WindowState parent, int type, WindowToken token,
             String name, int ownerId, boolean ownerCanAddInternalSystemWindow,
-            WindowManagerService service, Session session, IWindow iWindow) {
+            WindowManagerService service, Session session, IWindow iWindow,
+            WindowState.PowerManagerWrapper powerManagerWrapper) {
         synchronized (service.mGlobalLock) {
             final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
             attrs.setTitle(name);
@@ -369,7 +324,7 @@
             final WindowState w = new WindowState(service, session, iWindow, token, parent,
                     OP_NONE,
                     0, attrs, VISIBLE, ownerId, ownerCanAddInternalSystemWindow,
-                    sPowerManagerWrapper);
+                    powerManagerWrapper);
             // TODO: Probably better to make this call in the WindowState ctor to avoid errors with
             // adding it to the token...
             token.addWindow(w);
@@ -408,13 +363,11 @@
     }
 
     /** Creates a {@link DisplayContent} and adds it to the system. */
-    DisplayContent createNewDisplay(DisplayInfo displayInfo) {
-        final int displayId = sNextDisplayId++;
-        final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
-                displayInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
-        synchronized (mWm.mGlobalLock) {
-            return new DisplayContent(display, mWm, mock(ActivityDisplay.class));
-        }
+    DisplayContent createNewDisplay(DisplayInfo info) {
+        final ActivityDisplay display =
+                TestActivityDisplay.create(mWm.mAtmService.mStackSupervisor, info);
+        mWm.mAtmService.mRootActivityContainer.addChild(display, POSITION_TOP);
+        return display.mDisplayContent;
     }
 
     /**
@@ -428,17 +381,7 @@
         DisplayInfo displayInfo = new DisplayInfo();
         displayInfo.copyFrom(mDisplayInfo);
         displayInfo.state = displayState;
-        final int displayId = sNextDisplayId++;
-        final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
-                displayInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
-        synchronized (mWm.mGlobalLock) {
-            // Display creation is driven by DisplayWindowController via ActivityStackSupervisor.
-            // We skip those steps here.
-            final ActivityDisplay mockAd = mock(ActivityDisplay.class);
-            final DisplayContent displayContent = mWm.mRoot.createDisplayContent(display, mockAd);
-            displayContent.reconfigureDisplayLocked();
-            return displayContent;
-        }
+        return createNewDisplay(displayInfo);
     }
 
     /** Creates a {@link com.android.server.wm.WindowTestUtils.TestWindowState} */
diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java b/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java
index a6e675a..7f09482 100644
--- a/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java
+++ b/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java
@@ -89,7 +89,7 @@
 
         for (final Object mock : mMocks.keySet()) {
             if (MockUtil.isMock(mock)) {
-                Mockito.reset(mock);
+                mMockitoFramework.clearInlineMock(mock);
             }
         }
         mMocks.clear();
diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java
index 258a873..432978d 100644
--- a/telephony/java/android/telephony/CellIdentity.java
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -17,6 +17,7 @@
 package android.telephony;
 
 import android.annotation.CallSuper;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -61,7 +62,7 @@
         mType = type;
 
         // Only allow INT_MAX if unknown string mcc/mnc
-        if (mcc == null || mcc.matches("^[0-9]{3}$")) {
+        if (mcc == null || isMcc(mcc)) {
             mMccStr = mcc;
         } else if (mcc.isEmpty() || mcc.equals(String.valueOf(Integer.MAX_VALUE))) {
             // If the mccStr is empty or unknown, set it as null.
@@ -73,7 +74,7 @@
             log("invalid MCC format: " + mcc);
         }
 
-        if (mnc == null || mnc.matches("^[0-9]{2,3}$")) {
+        if (mnc == null || isMnc(mnc)) {
             mMncStr = mnc;
         } else if (mnc.isEmpty() || mnc.equals(String.valueOf(Integer.MAX_VALUE))) {
             // If the mncStr is empty or unknown, set it as null.
@@ -262,4 +263,30 @@
         if ((value < rangeMin || value > rangeMax) && value != special) return CellInfo.UNAVAILABLE;
         return value;
     }
+
+    /** @hide */
+    private static boolean isMcc(@NonNull String mcc) {
+        // ensure no out of bounds indexing
+        if (mcc.length() != 3) return false;
+
+        // Character.isDigit allows all unicode digits, not just [0-9]
+        for (int i = 0; i < 3; i++) {
+            if (mcc.charAt(i) < '0' || mcc.charAt(i) > '9') return false;
+        }
+
+        return true;
+    }
+
+    /** @hide */
+    private static boolean isMnc(@NonNull String mnc) {
+        // ensure no out of bounds indexing
+        if (mnc.length() < 2 || mnc.length() > 3) return false;
+
+        // Character.isDigit allows all unicode digits, not just [0-9]
+        for (int i = 0; i < mnc.length(); i++) {
+            if (mnc.charAt(i) < '0' || mnc.charAt(i) > '9') return false;
+        }
+
+        return true;
+    }
 }