Merge "Reduce flakiness of TaskStackChangedListenerTest"
diff --git a/cmds/idmap2/tests/ResultTests.cpp b/cmds/idmap2/tests/ResultTests.cpp
index cbced0a..f2f8854 100644
--- a/cmds/idmap2/tests/ResultTests.cpp
+++ b/cmds/idmap2/tests/ResultTests.cpp
@@ -260,7 +260,8 @@
 
 struct NoCopyContainer {
   uint32_t value;  // NOLINT(misc-non-private-member-variables-in-classes)
-  DISALLOW_COPY_AND_ASSIGN(NoCopyContainer);
+  NoCopyContainer(const NoCopyContainer&) = delete;
+  NoCopyContainer& operator=(const NoCopyContainer&) = delete;
 };
 
 Result<std::unique_ptr<NoCopyContainer>> CreateNoCopyContainer(bool succeed) {
diff --git a/core/java/android/app/prediction/AppPredictor.java b/core/java/android/app/prediction/AppPredictor.java
index 7f43640..fa135b1 100644
--- a/core/java/android/app/prediction/AppPredictor.java
+++ b/core/java/android/app/prediction/AppPredictor.java
@@ -83,6 +83,8 @@
     private final AppPredictionSessionId mSessionId;
     private final ArrayMap<Callback, CallbackWrapper> mRegisteredCallbacks = new ArrayMap<>();
 
+    private final IBinder mToken = new Binder();
+
     /**
      * Creates a new Prediction client.
      * <p>
@@ -98,7 +100,7 @@
         mSessionId = new AppPredictionSessionId(
                 context.getPackageName() + ":" + UUID.randomUUID().toString(), context.getUserId());
         try {
-            mPredictionManager.createPredictionSession(predictionContext, mSessionId);
+            mPredictionManager.createPredictionSession(predictionContext, mSessionId, mToken);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to create predictor", e);
             e.rethrowAsRuntimeException();
diff --git a/core/java/android/app/prediction/IPredictionManager.aidl b/core/java/android/app/prediction/IPredictionManager.aidl
index 587e3fd..863fc6f9 100644
--- a/core/java/android/app/prediction/IPredictionManager.aidl
+++ b/core/java/android/app/prediction/IPredictionManager.aidl
@@ -29,7 +29,7 @@
 interface IPredictionManager {
 
     void createPredictionSession(in AppPredictionContext context,
-            in AppPredictionSessionId sessionId);
+            in AppPredictionSessionId sessionId, in IBinder token);
 
     void notifyAppTargetEvent(in AppPredictionSessionId sessionId, in AppTargetEvent event);
 
diff --git a/core/java/android/app/timezonedetector/ITimeZoneConfigurationListener.aidl b/core/java/android/app/timezonedetector/ITimeZoneConfigurationListener.aidl
index af77fe0..6d0fe72 100644
--- a/core/java/android/app/timezonedetector/ITimeZoneConfigurationListener.aidl
+++ b/core/java/android/app/timezonedetector/ITimeZoneConfigurationListener.aidl
@@ -20,5 +20,5 @@
 
 /** {@hide} */
 oneway interface ITimeZoneConfigurationListener {
-    void onChange(in TimeZoneConfiguration configuration);
+    void onChange();
 }
\ No newline at end of file
diff --git a/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl b/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl
index 6e93af6..4f7e1f6 100644
--- a/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl
+++ b/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl
@@ -32,17 +32,15 @@
  * this Binder interface directly. See {@link android.app.timezonedetector.TimeZoneDetectorService}
  * for more complete documentation.
  *
- *
  * {@hide}
  */
 interface ITimeZoneDetectorService {
   TimeZoneCapabilities getCapabilities();
-
-  TimeZoneConfiguration getConfiguration();
-  boolean updateConfiguration(in TimeZoneConfiguration configuration);
   void addConfigurationListener(ITimeZoneConfigurationListener listener);
   void removeConfigurationListener(ITimeZoneConfigurationListener listener);
 
+  boolean updateConfiguration(in TimeZoneConfiguration configuration);
+
   boolean suggestManualTimeZone(in ManualTimeZoneSuggestion timeZoneSuggestion);
   void suggestTelephonyTimeZone(in TelephonyTimeZoneSuggestion timeZoneSuggestion);
 }
diff --git a/core/java/android/app/timezonedetector/TimeZoneCapabilities.java b/core/java/android/app/timezonedetector/TimeZoneCapabilities.java
index cc0af3f..09fffe9 100644
--- a/core/java/android/app/timezonedetector/TimeZoneCapabilities.java
+++ b/core/java/android/app/timezonedetector/TimeZoneCapabilities.java
@@ -16,9 +16,12 @@
 
 package android.app.timezonedetector;
 
+import static android.app.timezonedetector.TimeZoneConfiguration.SETTING_AUTO_DETECTION_ENABLED;
+import static android.app.timezonedetector.TimeZoneConfiguration.SETTING_GEO_DETECTION_ENABLED;
+
 import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.annotation.UserIdInt;
+import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -38,9 +41,9 @@
  *
  * <p>Actions have associated methods, see the documentation for each action for details.
  *
- * <p>For configuration capabilities, the associated current configuration value can be retrieved
- * using {@link TimeZoneDetector#getConfiguration()} and may be changed using
- * {@link TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)}.
+ * <p>For configuration settings capabilities, the associated settings value can be found via
+ * {@link #getConfiguration()} and may be changed using {@link
+ * TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} (if the user's capabilities allow).
  *
  * <p>Note: Capabilities are independent of app permissions required to call the associated APIs.
  *
@@ -60,7 +63,8 @@
     public static final int CAPABILITY_NOT_SUPPORTED = 10;
 
     /**
-     * Indicates that a capability is supported on this device, but not allowed for the user.
+     * Indicates that a capability is supported on this device, but not allowed for the user, e.g.
+     * if the capability relates to the ability to modify settings the user is not able to.
      * This could be because of the user's type (e.g. maybe it applies to the primary user only) or
      * device policy. Depending on the capability, this could mean the associated UI
      * should be hidden, or displayed but disabled.
@@ -68,9 +72,11 @@
     public static final int CAPABILITY_NOT_ALLOWED = 20;
 
     /**
-     * Indicates that a capability is possessed but not applicable, e.g. if it is configuration,
-     * the current configuration or device state renders it irrelevant. The associated UI may be
-     * hidden, disabled, or left visible (but ineffective) depending on requirements.
+     * Indicates that a capability is possessed but not currently applicable, e.g. if the
+     * capability relates to the ability to modify settings, the user has the ability to modify
+     * it, but it is currently rendered irrelevant by other settings or other device state (flags,
+     * resource config, etc.). The associated UI may be hidden, disabled, or left visible (but
+     * ineffective) depending on requirements.
      */
     public static final int CAPABILITY_NOT_APPLICABLE = 30;
 
@@ -89,13 +95,13 @@
             };
 
 
-    private final @UserIdInt int mUserId;
+    @NonNull private final TimeZoneConfiguration mConfiguration;
     private final @CapabilityState int mConfigureAutoDetectionEnabled;
     private final @CapabilityState int mConfigureGeoDetectionEnabled;
     private final @CapabilityState int mSuggestManualTimeZone;
 
     private TimeZoneCapabilities(@NonNull Builder builder) {
-        this.mUserId = builder.mUserId;
+        this.mConfiguration = Objects.requireNonNull(builder.mConfiguration);
         this.mConfigureAutoDetectionEnabled = builder.mConfigureAutoDetectionEnabled;
         this.mConfigureGeoDetectionEnabled = builder.mConfigureGeoDetectionEnabled;
         this.mSuggestManualTimeZone = builder.mSuggestManualTimeZone;
@@ -103,7 +109,8 @@
 
     @NonNull
     private static TimeZoneCapabilities createFromParcel(Parcel in) {
-        return new TimeZoneCapabilities.Builder(in.readInt())
+        return new TimeZoneCapabilities.Builder()
+                .setConfiguration(in.readParcelable(null))
                 .setConfigureAutoDetectionEnabled(in.readInt())
                 .setConfigureGeoDetectionEnabled(in.readInt())
                 .setSuggestManualTimeZone(in.readInt())
@@ -112,21 +119,24 @@
 
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeInt(mUserId);
+        dest.writeParcelable(mConfiguration, flags);
         dest.writeInt(mConfigureAutoDetectionEnabled);
         dest.writeInt(mConfigureGeoDetectionEnabled);
         dest.writeInt(mSuggestManualTimeZone);
     }
 
-    /** Returns the user ID the capabilities are for. */
-    public @UserIdInt int getUserId() {
-        return mUserId;
+    /**
+     * Returns the user's time zone behavior configuration.
+     */
+    public @NonNull TimeZoneConfiguration getConfiguration() {
+        return mConfiguration;
     }
 
     /**
-     * Returns the user's capability state for controlling whether automatic time zone detection is
-     * enabled via {@link TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and {@link
-     * TimeZoneConfiguration#isAutoDetectionEnabled()}.
+     * Returns the capability state associated with the user's ability to modify the automatic time
+     * zone detection setting. The setting can be updated via {@link
+     * TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and accessed via {@link
+     * #getConfiguration()}.
      */
     @CapabilityState
     public int getConfigureAutoDetectionEnabled() {
@@ -134,9 +144,10 @@
     }
 
     /**
-     * Returns the user's capability state for controlling whether geolocation can be used to detect
-     * time zone via {@link TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and {@link
-     * TimeZoneConfiguration#isGeoDetectionEnabled()}.
+     * Returns the capability state associated with the user's ability to modify the geolocation
+     * detection setting. The setting can be updated via {@link
+     * TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and accessed via {@link
+     * #getConfiguration()}.
      */
     @CapabilityState
     public int getConfigureGeoDetectionEnabled() {
@@ -144,8 +155,8 @@
     }
 
     /**
-     * Returns the user's capability state for manually setting the time zone on a device via
-     * {@link TimeZoneDetector#suggestManualTimeZone(ManualTimeZoneSuggestion)}.
+     * Returns the capability state associated with the user's ability to manually set the time zone
+     * on a device via {@link TimeZoneDetector#suggestManualTimeZone(ManualTimeZoneSuggestion)}.
      *
      * <p>The suggestion will be ignored in all cases unless the value is {@link
      * #CAPABILITY_POSSESSED}. See also {@link TimeZoneConfiguration#isAutoDetectionEnabled()}.
@@ -155,6 +166,38 @@
         return mSuggestManualTimeZone;
     }
 
+    /**
+     * Constructs a new {@link TimeZoneConfiguration} from an {@code oldConfiguration} and a set of
+     * {@code requestedChanges}, if the current capabilities allow. The new configuration is
+     * returned and the capabilities are left unchanged. If the capabilities do not permit one or
+     * more of the changes then {@code null} is returned.
+     */
+    @Nullable
+    public TimeZoneConfiguration applyUpdate(TimeZoneConfiguration requestedChanges) {
+        if (requestedChanges.getUserId() != mConfiguration.getUserId()) {
+            throw new IllegalArgumentException("User does not match:"
+                    + " this=" + mConfiguration + ", other=" + requestedChanges);
+        }
+
+        TimeZoneConfiguration.Builder newConfigBuilder =
+                new TimeZoneConfiguration.Builder(mConfiguration);
+        if (requestedChanges.hasSetting(SETTING_AUTO_DETECTION_ENABLED)) {
+            if (getConfigureAutoDetectionEnabled() < CAPABILITY_NOT_APPLICABLE) {
+                return null;
+            }
+            newConfigBuilder.setAutoDetectionEnabled(requestedChanges.isAutoDetectionEnabled());
+        }
+
+        if (requestedChanges.hasSetting(SETTING_GEO_DETECTION_ENABLED)) {
+            if (getConfigureGeoDetectionEnabled() < CAPABILITY_NOT_APPLICABLE) {
+                return null;
+            }
+            newConfigBuilder.setGeoDetectionEnabled(requestedChanges.isGeoDetectionEnabled());
+        }
+
+        return newConfigBuilder.build();
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -169,7 +212,7 @@
             return false;
         }
         TimeZoneCapabilities that = (TimeZoneCapabilities) o;
-        return mUserId == that.mUserId
+        return Objects.equals(mConfiguration, that.mConfiguration)
                 && mConfigureAutoDetectionEnabled == that.mConfigureAutoDetectionEnabled
                 && mConfigureGeoDetectionEnabled == that.mConfigureGeoDetectionEnabled
                 && mSuggestManualTimeZone == that.mSuggestManualTimeZone;
@@ -177,7 +220,7 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(mUserId,
+        return Objects.hash(mConfiguration,
                 mConfigureAutoDetectionEnabled,
                 mConfigureGeoDetectionEnabled,
                 mSuggestManualTimeZone);
@@ -186,7 +229,7 @@
     @Override
     public String toString() {
         return "TimeZoneDetectorCapabilities{"
-                + "mUserId=" + mUserId
+                + "mConfiguration=" + mConfiguration
                 + ", mConfigureAutomaticDetectionEnabled=" + mConfigureAutoDetectionEnabled
                 + ", mConfigureGeoDetectionEnabled=" + mConfigureGeoDetectionEnabled
                 + ", mSuggestManualTimeZone=" + mSuggestManualTimeZone
@@ -196,16 +239,18 @@
     /** @hide */
     public static class Builder {
 
-        private final @UserIdInt int mUserId;
+        private TimeZoneConfiguration mConfiguration;
         private @CapabilityState int mConfigureAutoDetectionEnabled;
         private @CapabilityState int mConfigureGeoDetectionEnabled;
         private @CapabilityState int mSuggestManualTimeZone;
 
-        /**
-         * Creates a new Builder with no properties set.
-         */
-        public Builder(@UserIdInt int userId) {
-            mUserId = userId;
+        /** Sets the user-visible configuration settings. */
+        public Builder setConfiguration(@NonNull TimeZoneConfiguration configuration) {
+            if (!configuration.isComplete()) {
+                throw new IllegalArgumentException(configuration + " is not complete");
+            }
+            this.mConfiguration = configuration;
+            return this;
         }
 
         /** Sets the state for the automatic time zone detection enabled config. */
diff --git a/core/java/android/app/timezonedetector/TimeZoneConfiguration.java b/core/java/android/app/timezonedetector/TimeZoneConfiguration.java
index 6f84ee2..95db0a2 100644
--- a/core/java/android/app/timezonedetector/TimeZoneConfiguration.java
+++ b/core/java/android/app/timezonedetector/TimeZoneConfiguration.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.StringDef;
+import android.annotation.UserIdInt;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -27,21 +28,20 @@
 import java.util.Objects;
 
 /**
- * Configuration that controls the behavior of the time zone detector associated with a specific
- * user.
+ * User visible settings that control the behavior of the time zone detector / manual time zone
+ * entry.
  *
- * <p>Configuration consists of a set of known properties. When reading configuration via
- * {@link TimeZoneDetector#getConfiguration()} values for all known properties will be provided. In
- * some cases, such as when the configuration relies on optional hardware, the values may be
- * meaningless / defaulted to safe values.
+ * <p>When reading the configuration, values for all settings will be provided. In some cases, such
+ * as when the device behavior relies on optional hardware / OEM configuration, or the value of
+ * several settings, the device behavior may not be directly affected by the setting value.
  *
- * <p>Configuration properties can be left absent when updating configuration via {@link
- * TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and those values will not be
- * changed. Not all configuration properties can be modified by all users. See {@link
- * TimeZoneDetector#getCapabilities()} and {@link TimeZoneCapabilities}.
+ * <p>Settings can be left absent when updating configuration via {@link
+ * TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and those settings will not be
+ * changed. Not all configuration settings can be modified by all users: see {@link
+ * TimeZoneDetector#getCapabilities()} and {@link TimeZoneCapabilities} for details.
  *
- * <p>See {@link #isComplete()} to tell if all known properties are present, and {@link
- * #hasProperty(String)} with {@code PROPERTY_} constants for testing individual properties.
+ * <p>See {@link #hasSetting(String)} with {@code PROPERTY_} constants for testing for the presence
+ * of individual settings.
  *
  * @hide
  */
@@ -59,80 +59,82 @@
             };
 
     /** All configuration properties */
-    @StringDef(PROPERTY_AUTO_DETECTION_ENABLED)
+    @StringDef({ SETTING_AUTO_DETECTION_ENABLED, SETTING_GEO_DETECTION_ENABLED })
     @Retention(RetentionPolicy.SOURCE)
-    @interface Property {}
+    @interface Setting {}
 
     /** See {@link TimeZoneConfiguration#isAutoDetectionEnabled()} for details. */
-    @Property
-    public static final String PROPERTY_AUTO_DETECTION_ENABLED = "autoDetectionEnabled";
+    @Setting
+    public static final String SETTING_AUTO_DETECTION_ENABLED = "autoDetectionEnabled";
 
     /** See {@link TimeZoneConfiguration#isGeoDetectionEnabled()} for details. */
-    @Property
-    public static final String PROPERTY_GEO_DETECTION_ENABLED = "geoDetectionEnabled";
+    @Setting
+    public static final String SETTING_GEO_DETECTION_ENABLED = "geoDetectionEnabled";
 
-    private final Bundle mBundle;
+    private final @UserIdInt int mUserId;
+    @NonNull private final Bundle mBundle;
 
     private TimeZoneConfiguration(Builder builder) {
-        this.mBundle = builder.mBundle;
+        this.mUserId = builder.mUserId;
+        this.mBundle = Objects.requireNonNull(builder.mBundle);
     }
 
     private static TimeZoneConfiguration createFromParcel(Parcel in) {
-        return new TimeZoneConfiguration.Builder()
+        return new TimeZoneConfiguration.Builder(in.readInt())
                 .setPropertyBundleInternal(in.readBundle())
                 .build();
     }
 
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mUserId);
         dest.writeBundle(mBundle);
     }
 
-    /** Returns {@code true} if all known properties are set. */
-    public boolean isComplete() {
-        return hasProperty(PROPERTY_AUTO_DETECTION_ENABLED)
-                && hasProperty(PROPERTY_GEO_DETECTION_ENABLED);
+    /** Returns the ID of the user this configuration is associated with. */
+    public @UserIdInt int getUserId() {
+        return mUserId;
     }
 
-    /** Returns true if the specified property is set. */
-    public boolean hasProperty(@Property String property) {
-        return mBundle.containsKey(property);
+    /** Returns {@code true} if all known settings are present. */
+    public boolean isComplete() {
+        return hasSetting(SETTING_AUTO_DETECTION_ENABLED)
+                && hasSetting(SETTING_GEO_DETECTION_ENABLED);
+    }
+
+    /** Returns true if the specified setting is set. */
+    public boolean hasSetting(@Setting String setting) {
+        return mBundle.containsKey(setting);
     }
 
     /**
-     * Returns the value of the {@link #PROPERTY_AUTO_DETECTION_ENABLED} property. This
+     * Returns the value of the {@link #SETTING_AUTO_DETECTION_ENABLED} setting. This
      * controls whether a device will attempt to determine the time zone automatically using
-     * contextual information.
+     * contextual information if the device supports auto detection.
      *
-     * @throws IllegalStateException if the field has not been set
+     * <p>This setting is global and can be updated by some users.
+     *
+     * @throws IllegalStateException if the setting has not been set
      */
     public boolean isAutoDetectionEnabled() {
-        if (!mBundle.containsKey(PROPERTY_AUTO_DETECTION_ENABLED)) {
-            throw new IllegalStateException(PROPERTY_AUTO_DETECTION_ENABLED + " is not set");
-        }
-        return mBundle.getBoolean(PROPERTY_AUTO_DETECTION_ENABLED);
+        enforceSettingPresent(SETTING_AUTO_DETECTION_ENABLED);
+        return mBundle.getBoolean(SETTING_AUTO_DETECTION_ENABLED);
     }
 
     /**
-     * Returns the value of the {@link #PROPERTY_GEO_DETECTION_ENABLED} property. This
-     * controls whether a device can use location to determine time zone. Only used when
-     * {@link #isAutoDetectionEnabled()} is true.
+     * Returns the value of the {@link #SETTING_GEO_DETECTION_ENABLED} setting. This
+     * controls whether a device can use geolocation to determine time zone. Only used when
+     * {@link #isAutoDetectionEnabled()} is {@code true} and when the user has allowed their
+     * location to be used.
      *
-     * @throws IllegalStateException if the field has not been set
+     * <p>This setting is user-scoped and can be updated by some users.
+     * See {@link TimeZoneCapabilities#getConfigureGeoDetectionEnabled()}.
+     *
+     * @throws IllegalStateException if the setting has not been set
      */
     public boolean isGeoDetectionEnabled() {
-        if (!mBundle.containsKey(PROPERTY_GEO_DETECTION_ENABLED)) {
-            throw new IllegalStateException(PROPERTY_GEO_DETECTION_ENABLED + " is not set");
-        }
-        return mBundle.getBoolean(PROPERTY_GEO_DETECTION_ENABLED);
-    }
-
-    /**
-     * Convenience method to merge this with another. The argument configuration properties have
-     * precedence.
-     */
-    public TimeZoneConfiguration with(TimeZoneConfiguration other) {
-        return new Builder(this).mergeProperties(other).build();
+        enforceSettingPresent(SETTING_GEO_DETECTION_ENABLED);
+        return mBundle.getBoolean(SETTING_GEO_DETECTION_ENABLED);
     }
 
     @Override
@@ -149,43 +151,61 @@
             return false;
         }
         TimeZoneConfiguration that = (TimeZoneConfiguration) o;
-        return mBundle.kindofEquals(that.mBundle);
+        return mUserId == that.mUserId
+                && mBundle.kindofEquals(that.mBundle);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mBundle);
+        return Objects.hash(mUserId, mBundle);
     }
 
     @Override
     public String toString() {
         return "TimeZoneDetectorConfiguration{"
+                + "mUserId=" + mUserId
                 + "mBundle=" + mBundle
                 + '}';
     }
 
+    private void enforceSettingPresent(@Setting String setting) {
+        if (!mBundle.containsKey(setting)) {
+            throw new IllegalStateException(setting + " is not set");
+        }
+    }
+
     /** @hide */
     public static class Builder {
 
-        private Bundle mBundle = new Bundle();
+        private final @UserIdInt int mUserId;
+        private final Bundle mBundle = new Bundle();
 
         /**
-         * Creates a new Builder with no properties set.
+         * Creates a new Builder for a userId with no settings held.
          */
-        public Builder() {}
+        public Builder(@UserIdInt int userId) {
+            mUserId = userId;
+        }
 
         /**
-         * Creates a new Builder by copying properties from an existing instance.
+         * Creates a new Builder by copying the user ID and settings from an existing instance.
          */
         public Builder(TimeZoneConfiguration toCopy) {
+            this.mUserId = toCopy.mUserId;
             mergeProperties(toCopy);
         }
 
         /**
-         * Merges {@code other} properties into this instances, replacing existing values in this
-         * where the properties appear in both.
+         * Merges {@code other} settings into this instances, replacing existing values in this
+         * where the settings appear in both.
          */
         public Builder mergeProperties(TimeZoneConfiguration other) {
+            if (mUserId != other.mUserId) {
+                throw new IllegalArgumentException(
+                        "Cannot merge configurations for different user IDs."
+                                + " this.mUserId=" + this.mUserId
+                                + ", other.mUserId=" + other.mUserId);
+            }
             this.mBundle.putAll(other.mBundle);
             return this;
         }
@@ -195,15 +215,19 @@
             return this;
         }
 
-        /** Sets the desired state of the automatic time zone detection property. */
+        /**
+         * Sets the state of the {@link #SETTING_AUTO_DETECTION_ENABLED} setting.
+         */
         public Builder setAutoDetectionEnabled(boolean enabled) {
-            this.mBundle.putBoolean(PROPERTY_AUTO_DETECTION_ENABLED, enabled);
+            this.mBundle.putBoolean(SETTING_AUTO_DETECTION_ENABLED, enabled);
             return this;
         }
 
-        /** Sets the desired state of the geolocation time zone detection enabled property. */
+        /**
+         * Sets the state of the {@link #SETTING_GEO_DETECTION_ENABLED} setting.
+         */
         public Builder setGeoDetectionEnabled(boolean enabled) {
-            this.mBundle.putBoolean(PROPERTY_GEO_DETECTION_ENABLED, enabled);
+            this.mBundle.putBoolean(SETTING_GEO_DETECTION_ENABLED, enabled);
             return this;
         }
 
diff --git a/core/java/android/app/timezonedetector/TimeZoneDetector.java b/core/java/android/app/timezonedetector/TimeZoneDetector.java
index 7885613..2b1cbf2 100644
--- a/core/java/android/app/timezonedetector/TimeZoneDetector.java
+++ b/core/java/android/app/timezonedetector/TimeZoneDetector.java
@@ -37,37 +37,29 @@
     TimeZoneCapabilities getCapabilities();
 
     /**
-     * Returns the current user's complete time zone configuration. See {@link
-     * TimeZoneConfiguration}.
-     */
-    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
-    @NonNull
-    TimeZoneConfiguration getConfiguration();
-
-    /**
      * Modifies the time zone detection configuration.
      *
-     * <p>Configuration properties vary in scope: some may be device-wide, others may be specific to
-     * the current user.
+     * <p>Configuration settings vary in scope: some may be global (affect all users), others may be
+     * specific to the current user.
      *
-     * <p>The ability to modify configuration properties can be subject to restrictions. For
+     * <p>The ability to modify configuration settings can be subject to restrictions. For
      * example, they may be determined by device hardware, general policy (i.e. only the primary
-     * user can set them), or by a managed device policy. See {@link #getCapabilities()} to obtain
+     * user can set them), or by a managed device policy. Use {@link #getCapabilities()} to obtain
      * information at runtime about the user's capabilities.
      *
-     * <p>Attempts to set configuration with capabilities that are {@link
+     * <p>Attempts to modify configuration settings with capabilities that are {@link
      * TimeZoneCapabilities#CAPABILITY_NOT_SUPPORTED} or {@link
      * TimeZoneCapabilities#CAPABILITY_NOT_ALLOWED} will have no effect and a {@code false}
-     * will be returned. Setting configuration with capabilities that are {@link
+     * will be returned. Modifying configuration settings with capabilities that are {@link
      * TimeZoneCapabilities#CAPABILITY_NOT_APPLICABLE} or {@link
      * TimeZoneCapabilities#CAPABILITY_POSSESSED} will succeed. See {@link
      * TimeZoneCapabilities} for further details.
      *
-     * <p>If the configuration is not "complete", then only the specified properties will be
-     * updated (where the user's capabilities allow) and other settings will be left unchanged. See
-     * {@link TimeZoneConfiguration#isComplete()}.
+     * <p>If the supplied configuration only has some values set, then only the specified settings
+     * will be updated (where the user's capabilities allow) and other settings will be left
+     * unchanged.
      *
-     * @return {@code true} if all the configuration properties specified have been set to the
+     * @return {@code true} if all the configuration settings specified have been set to the
      *   new values, {@code false} if none have
      */
     @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
@@ -76,14 +68,20 @@
     /**
      * An interface that can be used to listen for changes to the time zone detector configuration.
      */
+    @FunctionalInterface
     interface TimeZoneConfigurationListener {
-        /** Called when the configuration changes. There are no guarantees about the thread used. */
-        void onChange(@NonNull TimeZoneConfiguration configuration);
+        /**
+         * Called when something about the time zone configuration on the device has changed.
+         * This could be because the current user has changed, one of the device's relevant settings
+         * has changed, or something that could affect a user's capabilities has changed.
+         * There are no guarantees about the thread used.
+         */
+        void onChange();
     }
 
     /**
-     * Registers a listener that will be informed when the configuration changes. The complete
-     * configuration is passed to the listener, not just the properties that have changed.
+     * Registers a listener that will be informed when something about the time zone configuration
+     * changes.
      */
     @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
     void addConfigurationListener(@NonNull TimeZoneConfigurationListener listener);
diff --git a/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java b/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java
index 0770aff..4c69732 100644
--- a/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java
+++ b/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java
@@ -57,19 +57,6 @@
     }
 
     @Override
-    @NonNull
-    public TimeZoneConfiguration getConfiguration() {
-        if (DEBUG) {
-            Log.d(TAG, "getConfiguration called");
-        }
-        try {
-            return mITimeZoneDetectorService.getConfiguration();
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    @Override
     public boolean updateConfiguration(@NonNull TimeZoneConfiguration configuration) {
         if (DEBUG) {
             Log.d(TAG, "updateConfiguration called: " + configuration);
@@ -94,8 +81,8 @@
                 ITimeZoneConfigurationListener iListener =
                         new ITimeZoneConfigurationListener.Stub() {
                     @Override
-                    public void onChange(@NonNull TimeZoneConfiguration configuration) {
-                        notifyConfigurationListeners(configuration);
+                    public void onChange() {
+                        notifyConfigurationListeners();
                     }
                 };
                 mConfigurationReceiver = iListener;
@@ -116,14 +103,14 @@
         }
     }
 
-    private void notifyConfigurationListeners(@NonNull TimeZoneConfiguration configuration) {
+    private void notifyConfigurationListeners() {
         final ArraySet<TimeZoneConfigurationListener> configurationListeners;
         synchronized (this) {
             configurationListeners = new ArraySet<>(mConfigurationListeners);
         }
         int size = configurationListeners.size();
         for (int i = 0; i < size; i++) {
-            configurationListeners.valueAt(i).onChange(configuration);
+            configurationListeners.valueAt(i).onChange();
         }
     }
 
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index c302def..03cf0cf 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6404,6 +6404,17 @@
         public static final int LOCATION_MODE_ON = LOCATION_MODE_HIGH_ACCURACY;
 
         /**
+         * The current location time zone detection enabled state for the user.
+         *
+         * See {@link
+         * android.app.timezonedetector.TimeZoneDetector#getCapabilities} for access. See {@link
+         * android.app.timezonedetector.TimeZoneDetector#updateConfiguration} to update.
+         * @hide
+         */
+        public static final String LOCATION_TIME_ZONE_DETECTION_ENABLED =
+                "location_time_zone_detection_enabled";
+
+        /**
          * The accuracy in meters used for coarsening location for clients with only the coarse
          * location permission.
          *
diff --git a/core/java/com/android/internal/protolog/ProtoLogGroup.java b/core/java/com/android/internal/protolog/ProtoLogGroup.java
index 73d148c..0834b2d 100644
--- a/core/java/com/android/internal/protolog/ProtoLogGroup.java
+++ b/core/java/com/android/internal/protolog/ProtoLogGroup.java
@@ -36,7 +36,18 @@
             Consts.TAG_WM),
     WM_DEBUG_ADD_REMOVE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
             Consts.TAG_WM),
-    WM_DEBUG_FOCUS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM),
+    WM_DEBUG_CONFIGURATION(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+            Consts.TAG_WM),
+    WM_DEBUG_SWITCH(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+            Consts.TAG_WM),
+    WM_DEBUG_CONTAINERS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+            Consts.TAG_WM),
+    WM_DEBUG_FOCUS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+            Consts.TAG_WM),
+    WM_DEBUG_IMMERSIVE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+            Consts.TAG_WM),
+    WM_DEBUG_LOCKTASK(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+            Consts.TAG_WM),
     WM_DEBUG_STARTING_WINDOW(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
             Consts.TAG_WM),
     WM_SHOW_TRANSACTIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 23af70a..cbcbe7f 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -613,7 +613,7 @@
     }
 
     // Do not change sched policy cgroup after boot complete.
-    rc = androidSetThreadPriority(pid, pri, !boot_completed);
+    rc = androidSetThreadPriorityAndPolicy(pid, pri, !boot_completed);
     if (rc != 0) {
         if (rc == INVALID_OPERATION) {
             signalExceptionForPriorityError(env, errno, pid);
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 4aa5df2..6212bcb 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2743,4 +2743,9 @@
     // CATEGORY: SETTINGS
     // OS: S
     DIALOG_MAGNIFICATION_SWITCH_SHORTCUT = 1849;
+
+    // OPEN: Settings > Network & internet > Adaptive connectivity
+    // CATEGORY: SETTINGS
+    // OS: R QPR
+    ADAPTIVE_CONNECTIVITY_CATEGORY = 1850;
 }
diff --git a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java b/core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java
index 72391f4..db127c6 100644
--- a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java
+++ b/core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java
@@ -22,6 +22,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
 
 import org.junit.Test;
 
@@ -31,11 +32,22 @@
 
     @Test
     public void testEquals() {
-        TimeZoneCapabilities.Builder builder1 = new TimeZoneCapabilities.Builder(ARBITRARY_USER_ID)
+        TimeZoneConfiguration configuration1 = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+                .setAutoDetectionEnabled(true)
+                .setGeoDetectionEnabled(true)
+                .build();
+        TimeZoneConfiguration configuration2 = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+                .setAutoDetectionEnabled(false)
+                .setGeoDetectionEnabled(false)
+                .build();
+
+        TimeZoneCapabilities.Builder builder1 = new TimeZoneCapabilities.Builder()
+                .setConfiguration(configuration1)
                 .setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
                 .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
                 .setSuggestManualTimeZone(CAPABILITY_POSSESSED);
-        TimeZoneCapabilities.Builder builder2 = new TimeZoneCapabilities.Builder(ARBITRARY_USER_ID)
+        TimeZoneCapabilities.Builder builder2 = new TimeZoneCapabilities.Builder()
+                .setConfiguration(configuration1)
                 .setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
                 .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
                 .setSuggestManualTimeZone(CAPABILITY_POSSESSED);
@@ -45,6 +57,20 @@
             assertEquals(one, two);
         }
 
+        builder2.setConfiguration(configuration2);
+        {
+            TimeZoneCapabilities one = builder1.build();
+            TimeZoneCapabilities two = builder2.build();
+            assertNotEquals(one, two);
+        }
+
+        builder1.setConfiguration(configuration2);
+        {
+            TimeZoneCapabilities one = builder1.build();
+            TimeZoneCapabilities two = builder2.build();
+            assertEquals(one, two);
+        }
+
         builder2.setConfigureAutoDetectionEnabled(CAPABILITY_NOT_ALLOWED);
         {
             TimeZoneCapabilities one = builder1.build();
@@ -90,7 +116,12 @@
 
     @Test
     public void testParcelable() {
-        TimeZoneCapabilities.Builder builder = new TimeZoneCapabilities.Builder(ARBITRARY_USER_ID)
+        TimeZoneConfiguration configuration = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+                .setAutoDetectionEnabled(true)
+                .setGeoDetectionEnabled(true)
+                .build();
+        TimeZoneCapabilities.Builder builder = new TimeZoneCapabilities.Builder()
+                .setConfiguration(configuration)
                 .setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
                 .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
                 .setSuggestManualTimeZone(CAPABILITY_POSSESSED);
@@ -105,4 +136,51 @@
         builder.setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED);
         assertRoundTripParcelable(builder.build());
     }
+
+    @Test
+    public void testApplyUpdate_permitted() {
+        TimeZoneConfiguration oldConfiguration =
+                new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+                        .setAutoDetectionEnabled(true)
+                        .setGeoDetectionEnabled(true)
+                        .build();
+        TimeZoneCapabilities capabilities = new TimeZoneCapabilities.Builder()
+                .setConfiguration(oldConfiguration)
+                .setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
+                .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
+                .setSuggestManualTimeZone(CAPABILITY_POSSESSED)
+                .build();
+        assertEquals(oldConfiguration, capabilities.getConfiguration());
+
+        TimeZoneConfiguration configChange = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+                .setAutoDetectionEnabled(false)
+                .build();
+
+        TimeZoneConfiguration expected = new TimeZoneConfiguration.Builder(oldConfiguration)
+                .setAutoDetectionEnabled(false)
+                .build();
+        assertEquals(expected, capabilities.applyUpdate(configChange));
+    }
+
+    @Test
+    public void testApplyUpdate_notPermitted() {
+        TimeZoneConfiguration oldConfiguration =
+                new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+                        .setAutoDetectionEnabled(true)
+                        .setGeoDetectionEnabled(true)
+                        .build();
+        TimeZoneCapabilities capabilities = new TimeZoneCapabilities.Builder()
+                .setConfiguration(oldConfiguration)
+                .setConfigureAutoDetectionEnabled(CAPABILITY_NOT_ALLOWED)
+                .setConfigureGeoDetectionEnabled(CAPABILITY_NOT_ALLOWED)
+                .setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED)
+                .build();
+        assertEquals(oldConfiguration, capabilities.getConfiguration());
+
+        TimeZoneConfiguration configChange = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+                .setAutoDetectionEnabled(false)
+                .build();
+
+        assertNull(capabilities.applyUpdate(configChange));
+    }
 }
diff --git a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneConfigurationTest.java b/core/tests/coretests/src/android/app/timezonedetector/TimeZoneConfigurationTest.java
index 00dc73e..faf908d 100644
--- a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneConfigurationTest.java
+++ b/core/tests/coretests/src/android/app/timezonedetector/TimeZoneConfigurationTest.java
@@ -27,11 +27,14 @@
 
 public class TimeZoneConfigurationTest {
 
+    private static final int ARBITRARY_USER_ID = 9876;
+
     @Test
     public void testBuilder_copyConstructor() {
-        TimeZoneConfiguration.Builder builder1 = new TimeZoneConfiguration.Builder()
-                .setAutoDetectionEnabled(true)
-                .setGeoDetectionEnabled(true);
+        TimeZoneConfiguration.Builder builder1 =
+                new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+                        .setAutoDetectionEnabled(true)
+                        .setGeoDetectionEnabled(true);
         TimeZoneConfiguration configuration1 = builder1.build();
 
         TimeZoneConfiguration configuration2 =
@@ -41,28 +44,28 @@
     }
 
     @Test
-    public void testIsComplete() {
-        TimeZoneConfiguration.Builder builder =
-                new TimeZoneConfiguration.Builder();
-        assertFalse(builder.build().isComplete());
+    public void testIntrospectionMethods() {
+        TimeZoneConfiguration empty = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID).build();
+        assertFalse(empty.isComplete());
+        assertFalse(empty.hasSetting(TimeZoneConfiguration.SETTING_AUTO_DETECTION_ENABLED));
 
-        builder.setAutoDetectionEnabled(true);
-        assertFalse(builder.build().isComplete());
-
-        builder.setGeoDetectionEnabled(true);
-        assertTrue(builder.build().isComplete());
+        TimeZoneConfiguration completeConfig = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+                .setAutoDetectionEnabled(true)
+                .setGeoDetectionEnabled(true)
+                .build();
+        assertTrue(completeConfig.isComplete());
+        assertTrue(completeConfig.hasSetting(TimeZoneConfiguration.SETTING_AUTO_DETECTION_ENABLED));
     }
 
     @Test
     public void testBuilder_mergeProperties() {
-        TimeZoneConfiguration configuration1 =
-                new TimeZoneConfiguration.Builder()
-                        .setAutoDetectionEnabled(true)
-                        .build();
+        TimeZoneConfiguration configuration1 = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+                .setAutoDetectionEnabled(true)
+                .build();
 
         {
             TimeZoneConfiguration mergedEmptyAnd1 =
-                    new TimeZoneConfiguration.Builder()
+                    new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
                             .mergeProperties(configuration1)
                             .build();
             assertEquals(configuration1, mergedEmptyAnd1);
@@ -70,7 +73,7 @@
 
         {
             TimeZoneConfiguration configuration2 =
-                    new TimeZoneConfiguration.Builder()
+                    new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
                             .setAutoDetectionEnabled(false)
                             .build();
 
@@ -87,14 +90,22 @@
     @Test
     public void testEquals() {
         TimeZoneConfiguration.Builder builder1 =
-                new TimeZoneConfiguration.Builder();
+                new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID);
         {
             TimeZoneConfiguration one = builder1.build();
             assertEquals(one, one);
         }
 
+        {
+            TimeZoneConfiguration.Builder differentUserBuilder =
+                    new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID + 1);
+            TimeZoneConfiguration one = builder1.build();
+            TimeZoneConfiguration two = differentUserBuilder.build();
+            assertNotEquals(one, two);
+        }
+
         TimeZoneConfiguration.Builder builder2 =
-                new TimeZoneConfiguration.Builder();
+                new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID);
         {
             TimeZoneConfiguration one = builder1.build();
             TimeZoneConfiguration two = builder2.build();
@@ -148,7 +159,7 @@
     @Test
     public void testParcelable() {
         TimeZoneConfiguration.Builder builder =
-                new TimeZoneConfiguration.Builder();
+                new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID);
         assertRoundTripParcelable(builder.build());
 
         builder.setAutoDetectionEnabled(true);
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 73296987..03f7be7 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -13,6 +13,12 @@
       "group": "WM_DEBUG_STARTING_WINDOW",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "-2121056984": {
+      "message": "%s",
+      "level": "WARN",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/LockTaskController.java"
+    },
     "-2109936758": {
       "message": "removeAppToken make exiting: %s",
       "level": "VERBOSE",
@@ -43,6 +49,12 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-2029985709": {
+      "message": "setFocusedTask: taskId=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
     "-2024464438": {
       "message": "app-onAnimationFinished(): mOuter=%s",
       "level": "DEBUG",
@@ -139,6 +151,12 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/DisplayRotation.java"
     },
+    "-1868048288": {
+      "message": "Updating to new configuration after starting activity.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityStarter.java"
+    },
     "-1862269827": {
       "message": "applyAnimation: anim=%s transit=%s isEntrance=%b Callers=%s",
       "level": "VERBOSE",
@@ -163,6 +181,18 @@
       "group": "WM_DEBUG_RESIZE",
       "at": "com\/android\/server\/wm\/WindowState.java"
     },
+    "-1810446914": {
+      "message": "Trying to update display configuration for system\/invalid process.",
+      "level": "WARN",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "-1791031393": {
+      "message": "Ensuring correct configuration: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "-1782453012": {
       "message": "Checking theme of starting window: 0x%x",
       "level": "VERBOSE",
@@ -211,6 +241,12 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/DisplayContent.java"
     },
+    "-1699018375": {
+      "message": "Adding activity %s to task %s callers: %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
     "-1698815688": {
       "message": "Resetting app token %s of replacing window marks.",
       "level": "DEBUG",
@@ -229,12 +265,30 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-1638958146": {
+      "message": "Removing activity %s from task=%s adding to task=%s Callers=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java"
+    },
     "-1632122349": {
       "message": "Changing surface while display frozen: %s",
       "level": "VERBOSE",
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-1630752478": {
+      "message": "removeLockedTask: removed %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/LockTaskController.java"
+    },
+    "-1598452494": {
+      "message": "activityDestroyedLocked: r=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_CONTAINERS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "-1596995693": {
       "message": "startAnimation",
       "level": "DEBUG",
@@ -307,6 +361,18 @@
       "group": "WM_DEBUG_REMOTE_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
     },
+    "-1495062622": {
+      "message": "Can't report activity moved to display - client not running, activityRecord=%s, displayId=%d",
+      "level": "WARN",
+      "group": "WM_DEBUG_SWITCH",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-1492881555": {
+      "message": "Starting activity when config will change = %b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityStarter.java"
+    },
     "-1471946192": {
       "message": "Marking app token %s with replacing child windows.",
       "level": "DEBUG",
@@ -379,6 +445,12 @@
       "group": "WM_DEBUG_IME",
       "at": "com\/android\/server\/wm\/WindowState.java"
     },
+    "-1305755880": {
+      "message": "Initial config: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
     "-1292329638": {
       "message": "Added starting %s: startingWindow=%s startingView=%s",
       "level": "VERBOSE",
@@ -445,6 +517,12 @@
       "group": "WM_DEBUG_RECENTS_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RecentsAnimation.java"
     },
+    "-1155279885": {
+      "message": "Frontmost changed immersion: %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_IMMERSIVE",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
     "-1144293044": {
       "message": "SURFACE SET FREEZE LAYER: %s",
       "level": "INFO",
@@ -475,6 +553,12 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/DisplayRotation.java"
     },
+    "-1115019498": {
+      "message": "Configuration & display unchanged in %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "-1113134997": {
       "message": "Attempted to add application window with unknown token %s.  Aborting.",
       "level": "WARN",
@@ -559,12 +643,24 @@
       "group": "WM_DEBUG_STARTING_WINDOW",
       "at": "com\/android\/server\/wm\/WindowState.java"
     },
+    "-929676529": {
+      "message": "Configuration changes for %s, allChanges=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "-928291778": {
       "message": "applyAnimation: anim=%s nextAppTransition=%d transit=%s Callers=%s",
       "level": "VERBOSE",
       "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
       "at": "com\/android\/server\/wm\/AppTransition.java"
     },
+    "-927199900": {
+      "message": "Updating global configuration to: %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
     "-916108501": {
       "message": "Adding %s to %s",
       "level": "VERBOSE",
@@ -619,12 +715,24 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-846078709": {
+      "message": "Configuration doesn't matter in finishing %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "-809771899": {
       "message": "findFocusedWindow: Reached focused app=%s",
       "level": "VERBOSE",
       "group": "WM_DEBUG_FOCUS_LIGHT",
       "at": "com\/android\/server\/wm\/DisplayContent.java"
     },
+    "-804217032": {
+      "message": "Skipping config check (will change): %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "-793346159": {
       "message": "New transit into wallpaper: %s",
       "level": "VERBOSE",
@@ -673,6 +781,18 @@
       "group": "WM_DEBUG_SCREEN_ON",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-743431900": {
+      "message": "Configuration no differences in %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-716565534": {
+      "message": "moveActivityStackToFront: unfocusable activity=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "-714291355": {
       "message": "Losing delayed focus: %s",
       "level": "INFO",
@@ -739,6 +859,12 @@
       "group": "WM_DEBUG_FOCUS_LIGHT",
       "at": "com\/android\/server\/wm\/DisplayContent.java"
     },
+    "-593535526": {
+      "message": "Binding proc %s with config %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/am\/ActivityManagerService.java"
+    },
     "-583031528": {
       "message": "%s",
       "level": "INFO",
@@ -757,6 +883,12 @@
       "group": "WM_DEBUG_BOOT",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-548282316": {
+      "message": "setLockTaskMode: Locking to %s Callers=%s",
+      "level": "WARN",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/LockTaskController.java"
+    },
     "-547111355": {
       "message": "hideIme Control target: %s ",
       "level": "DEBUG",
@@ -781,6 +913,12 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-503656156": {
+      "message": "Update process config of %s to new config %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
     "-496681057": {
       "message": "Attempted to get remove mode of a display that does not exist: %d",
       "level": "WARN",
@@ -799,6 +937,12 @@
       "group": "WM_SHOW_SURFACE_ALLOC",
       "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
     },
+    "-449118559": {
+      "message": "Trying to update display configuration for invalid process, pid=%d",
+      "level": "WARN",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
     "-445944810": {
       "message": "finish(%b): mCanceled=%b",
       "level": "DEBUG",
@@ -835,6 +979,12 @@
       "group": "WM_DEBUG_STARTING_WINDOW",
       "at": "com\/android\/server\/wm\/TaskSnapshotSurface.java"
     },
+    "-401282500": {
+      "message": "destroyIfPossible: r=%s destroy returned removed=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_CONTAINERS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "-395922585": {
       "message": "InsetsSource setWin %s",
       "level": "DEBUG",
@@ -907,18 +1057,42 @@
       "group": "WM_DEBUG_ADD_REMOVE",
       "at": "com\/android\/server\/wm\/WindowState.java"
     },
+    "-317194205": {
+      "message": "clearLockedTasks: %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/LockTaskController.java"
+    },
     "-303497363": {
       "message": "reparent: moving activity=%s to task=%d at %d",
       "level": "INFO",
       "group": "WM_DEBUG_ADD_REMOVE",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "-272719931": {
+      "message": "startLockTaskModeLocked: %s",
+      "level": "WARN",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "-260960989": {
+      "message": "Removing and adding activity %s to stack at top callers=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
     "-251259736": {
       "message": "No longer freezing: %s",
       "level": "VERBOSE",
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "-235225312": {
+      "message": "Skipping config check for initializing activity: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "-198463978": {
       "message": "updateRotationUnchecked: alwaysSendConfiguration=%b forceRelayout=%b",
       "level": "VERBOSE",
@@ -943,6 +1117,12 @@
       "group": "WM_DEBUG_RECENTS_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
     },
+    "-168799453": {
+      "message": "Allowing features %d:0x%s",
+      "level": "WARN",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
     "-167822951": {
       "message": "Attempted to add starting window to token with already existing starting window",
       "level": "WARN",
@@ -979,6 +1159,12 @@
       "group": "WM_DEBUG_FOCUS_LIGHT",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-90559682": {
+      "message": "Config is skipping already pausing %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "-87705714": {
       "message": "findFocusedWindow: focusedApp=null using new focus @ %s",
       "level": "VERBOSE",
@@ -1303,6 +1489,12 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "355940361": {
+      "message": "Config is destroying non-running %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "371641947": {
       "message": "Window Manager Crash %s",
       "level": "WTF",
@@ -1315,6 +1507,12 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "374506950": {
+      "message": "Reporting activity moved to display, activityRecord=%s, displayId=%d, config=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SWITCH",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "374972436": {
       "message": "performEnableScreen: Waiting for anim complete",
       "level": "INFO",
@@ -1411,6 +1609,12 @@
       "group": "WM_DEBUG_BOOT",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "556758086": {
+      "message": "Applying new update lock state '%s' for %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_IMMERSIVE",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
     "557227556": {
       "message": "onAnimationFinished(): Notify animation finished:",
       "level": "DEBUG",
@@ -1531,12 +1735,6 @@
       "group": "WM_DEBUG_SCREEN_ON",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
-    "676824470": {
-      "message": "Test completed successfully: %b %d %o %x %e %g %f %% %s.",
-      "level": "ERROR",
-      "group": "TEST_GROUP",
-      "at": "com\/android\/server\/wm\/ProtoLogGroup.java"
-    },
     "685047360": {
       "message": "Resizing window %s",
       "level": "VERBOSE",
@@ -1561,6 +1759,18 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "715749922": {
+      "message": "Allowlisting %d:%s",
+      "level": "WARN",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "736692676": {
+      "message": "Config is relaunching %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "745391677": {
       "message": "  CREATE SURFACE %s IN SESSION %s: pid=%d format=%d flags=0x%x \/ %s",
       "level": "INFO",
@@ -1615,6 +1825,12 @@
       "group": "WM_DEBUG_RECENTS_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RecentsAnimation.java"
     },
+    "869266572": {
+      "message": "Removing activity %s from stack, reason= %s callers=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "873914452": {
       "message": "goodToGo()",
       "level": "DEBUG",
@@ -1645,12 +1861,30 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
     },
+    "950074526": {
+      "message": "setLockTaskMode: Can't lock due to auth",
+      "level": "WARN",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/LockTaskController.java"
+    },
     "954470154": {
       "message": "FORCED DISPLAY SCALING DISABLED",
       "level": "INFO",
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "956374481": {
+      "message": "removeLockedTask: task=%s last task, reverting locktask mode. Callers=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/LockTaskController.java"
+    },
+    "969323241": {
+      "message": "Sending new config to %s, config: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "972354148": {
       "message": "\tcontainer=%s",
       "level": "DEBUG",
@@ -1663,12 +1897,24 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "1040675582": {
+      "message": "Can't report activity configuration update - client not running, activityRecord=%s",
+      "level": "WARN",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "1046922686": {
       "message": "requestScrollCapture: caught exception dispatching callback: %s",
       "level": "WARN",
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "1049367566": {
+      "message": "Sending to proc %s new config %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/WindowProcessController.java"
+    },
     "1051545910": {
       "message": "Exit animation finished in %s: remove=%b",
       "level": "VERBOSE",
@@ -1681,6 +1927,12 @@
       "group": "WM_DEBUG_REMOTE_ANIMATIONS",
       "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java"
     },
+    "1088929964": {
+      "message": "onLockTaskPackagesUpdated: starting new locktask task=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/LockTaskController.java"
+    },
     "1089714158": {
       "message": "  FREEZE %s: DESTROY",
       "level": "INFO",
@@ -1789,6 +2041,12 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "1337596507": {
+      "message": "Sending to proc %s new compat %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/CompatModePackages.java"
+    },
     "1346895820": {
       "message": "ScreenRotation still animating: type: %d\nmDisplayAnimator: %s\nmEnterBlackFrameAnimator: %s\nmRotateScreenAnimator: %s\nmScreenshotRotationAnimator: %s",
       "level": "VERBOSE",
@@ -1801,6 +2059,12 @@
       "group": "WM_DEBUG_FOCUS",
       "at": "com\/android\/server\/wm\/DisplayContent.java"
     },
+    "1360551978": {
+      "message": "Trying to update display configuration for non-existing displayId=%d",
+      "level": "WARN",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
     "1364498663": {
       "message": "notifyAppResumed: wasStopped=%b %s",
       "level": "VERBOSE",
@@ -1819,6 +2083,12 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/TaskDisplayArea.java"
     },
+    "1401295262": {
+      "message": "Mode default, asking user",
+      "level": "WARN",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/LockTaskController.java"
+    },
     "1401700824": {
       "message": "Window drawn win=%s",
       "level": "DEBUG",
@@ -1927,6 +2197,12 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "1522489371": {
+      "message": "moveActivityStackToFront: activity=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "1525976603": {
       "message": "cancelAnimation(): reason=%s",
       "level": "DEBUG",
@@ -1951,6 +2227,12 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "1576607724": {
+      "message": "Report configuration: %s %s %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
     "1577579529": {
       "message": "win=%s destroySurfaces: appStopped=%b win.mWindowRemovalAllowed=%b win.mRemoveOnExit=%b",
       "level": "ERROR",
@@ -1981,6 +2263,12 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "1635062046": {
+      "message": "Skipping config check invisible: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "1635462459": {
       "message": "onMovedByResize: Moving %s",
       "level": "DEBUG",
@@ -2023,6 +2311,12 @@
       "group": "WM_DEBUG_STARTING_WINDOW",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "1679569477": {
+      "message": "Configuration doesn't matter not running %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "1720229827": {
       "message": "Creating animation bounds layer",
       "level": "INFO",
@@ -2077,12 +2371,30 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "1789603530": {
+      "message": "Removing activity %s hasSavedState=%b stateNotNeeded=%s finishing=%b state=%s callers=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "1822843721": {
       "message": "Aborted starting %s: startingData=%s",
       "level": "VERBOSE",
       "group": "WM_DEBUG_STARTING_WINDOW",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "1824105730": {
+      "message": "setLockTaskAuth: task=%s mLockTaskAuth=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
+    "1829094918": {
+      "message": "onLockTaskPackagesUpdated: removing %s mLockTaskAuth()=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/LockTaskController.java"
+    },
     "1831008694": {
       "message": "Loading animation for app transition. transit=%s enter=%b frame=%s insets=%s surfaceInsets=%s",
       "level": "DEBUG",
@@ -2161,6 +2473,12 @@
       "group": "WM_DEBUG_APP_TRANSITIONS",
       "at": "com\/android\/server\/wm\/AppTransitionController.java"
     },
+    "1975793405": {
+      "message": "setFocusedStack: stackId=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
     "1984470582": {
       "message": "Creating TaskScreenshotAnimatable: task: %s width: %d height: %d",
       "level": "DEBUG",
@@ -2173,6 +2491,12 @@
       "group": "WM_SHOW_TRANSACTIONS",
       "at": "com\/android\/server\/wm\/WindowAnimator.java"
     },
+    "1995093920": {
+      "message": "Checking to restart %s: changed=0x%s, handles=0x%s, mLastReportedConfiguration=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "2016061474": {
       "message": "Prepare app transition: transit=%s %s alwaysKeepCurrent=%b displayId=%d Callers=%s",
       "level": "VERBOSE",
@@ -2191,6 +2515,12 @@
       "group": "WM_DEBUG_STARTING_WINDOW",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "2022322588": {
+      "message": "Adding activity %s to stack to task %s callers: %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
     "2022422429": {
       "message": "createAnimationAdapter(): container=%s",
       "level": "DEBUG",
@@ -2269,6 +2599,12 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/DisplayRotation.java"
     },
+    "2134999275": {
+      "message": "moveActivityStackToFront: already on top, activity=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "2137411379": {
       "message": "applyAnimation: anim=%s animAttr=0x%x transit=%s isEntrance=%b Callers=%s",
       "level": "VERBOSE",
@@ -2277,9 +2613,6 @@
     }
   },
   "groups": {
-    "TEST_GROUP": {
-      "tag": "WindowManagetProtoLogTest"
-    },
     "WM_DEBUG_ADD_REMOVE": {
       "tag": "WindowManager"
     },
@@ -2292,6 +2625,12 @@
     "WM_DEBUG_BOOT": {
       "tag": "WindowManager"
     },
+    "WM_DEBUG_CONFIGURATION": {
+      "tag": "WindowManager"
+    },
+    "WM_DEBUG_CONTAINERS": {
+      "tag": "WindowManager"
+    },
     "WM_DEBUG_DRAW": {
       "tag": "WindowManager"
     },
@@ -2304,9 +2643,15 @@
     "WM_DEBUG_IME": {
       "tag": "WindowManager"
     },
+    "WM_DEBUG_IMMERSIVE": {
+      "tag": "WindowManager"
+    },
     "WM_DEBUG_KEEP_SCREEN_ON": {
       "tag": "WindowManager"
     },
+    "WM_DEBUG_LOCKTASK": {
+      "tag": "WindowManager"
+    },
     "WM_DEBUG_ORIENTATION": {
       "tag": "WindowManager"
     },
@@ -2325,6 +2670,9 @@
     "WM_DEBUG_STARTING_WINDOW": {
       "tag": "WindowManager"
     },
+    "WM_DEBUG_SWITCH": {
+      "tag": "WindowManager"
+    },
     "WM_DEBUG_WINDOW_MOVEMENT": {
       "tag": "WindowManager"
     },
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarGlobalRootComponent.java b/packages/CarSystemUI/src/com/android/systemui/CarGlobalRootComponent.java
index 552cadf..b17ad0f 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarGlobalRootComponent.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarGlobalRootComponent.java
@@ -16,7 +16,9 @@
 
 package com.android.systemui;
 
+import com.android.systemui.dagger.GlobalModule;
 import com.android.systemui.dagger.GlobalRootComponent;
+import com.android.systemui.dagger.WMModule;
 
 import javax.inject.Singleton;
 
@@ -26,7 +28,9 @@
 @Singleton
 @Component(
         modules = {
-                CarSysUIComponentModule.class
+                GlobalModule.class,
+                CarSysUIComponentModule.class,
+                WMModule.class
         })
 public interface CarGlobalRootComponent extends GlobalRootComponent {
     /**
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java b/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java
index 24d9d09..9039671 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java
@@ -20,7 +20,6 @@
 import com.android.systemui.dagger.DependencyProvider;
 import com.android.systemui.dagger.SysUIComponent;
 import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.SystemServicesModule;
 import com.android.systemui.dagger.SystemUIModule;
 import com.android.systemui.pip.phone.dagger.PipModule;
 
@@ -35,7 +34,6 @@
         DependencyProvider.class,
         DependencyBinder.class,
         PipModule.class,
-        SystemServicesModule.class,
         SystemUIModule.class,
         CarSystemUIModule.class,
         CarSystemUIBinder.class})
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
index 3b22fdb..38e1a48 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
@@ -299,10 +299,10 @@
         // The glass pane is used to view touch events before passed to the notification list.
         // This allows us to initialize gesture listeners and detect when to close the notifications
         glassPane.setOnTouchListener((v, event) -> {
-            if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+            if (isClosingAction(event)) {
                 mNotificationListAtEndAtTimeOfTouch = false;
             }
-            if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+            if (isOpeningAction(event)) {
                 mFirstTouchDownOnGlassPane = event.getRawX();
                 mNotificationListAtEndAtTimeOfTouch = mNotificationListAtEnd;
                 // Reset the tracker when there is a touch down on the glass pane.
@@ -355,8 +355,7 @@
             if (rect != null) {
                 clippedHeight = rect.bottom;
             }
-            if (!handled && event.getActionMasked() == MotionEvent.ACTION_UP
-                    && mIsSwipingVerticallyToClose) {
+            if (!handled && isClosingAction(event) && mIsSwipingVerticallyToClose) {
                 if (getSettleClosePercentage() < getPercentageFromEndingEdge() && isTracking) {
                     animatePanel(DEFAULT_FLING_VELOCITY, false);
                 } else if (clippedHeight != getLayout().getHeight() && isTracking) {
@@ -369,7 +368,7 @@
             // Updating the mNotificationListAtEndAtTimeOfTouch state has to be done after
             // the event has been passed to the closeGestureDetector above, such that the
             // closeGestureDetector sees the up event before the state has changed.
-            if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+            if (isClosingAction(event)) {
                 mNotificationListAtEndAtTimeOfTouch = false;
             }
             return handled || isTracking;
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java
index 45808a8..bde31f1 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java
@@ -191,6 +191,38 @@
         }
     }
 
+    /** Checks if a {@link MotionEvent} is an action to open the panel.
+     * @param e {@link MotionEvent} to check.
+     * @return true only if opening action.
+     */
+    protected boolean isOpeningAction(MotionEvent e) {
+        if (mAnimateDirection == POSITIVE_DIRECTION) {
+            return e.getActionMasked() == MotionEvent.ACTION_DOWN;
+        }
+
+        if (mAnimateDirection == NEGATIVE_DIRECTION) {
+            return e.getActionMasked() == MotionEvent.ACTION_UP;
+        }
+
+        return false;
+    }
+
+    /** Checks if a {@link MotionEvent} is an action to close the panel.
+     * @param e {@link MotionEvent} to check.
+     * @return true only if closing action.
+     */
+    protected boolean isClosingAction(MotionEvent e) {
+        if (mAnimateDirection == POSITIVE_DIRECTION) {
+            return e.getActionMasked() == MotionEvent.ACTION_UP;
+        }
+
+        if (mAnimateDirection == NEGATIVE_DIRECTION) {
+            return e.getActionMasked() == MotionEvent.ACTION_DOWN;
+        }
+
+        return false;
+    }
+
     /* ***************************************************************************************** *
      * Panel Animation
      * ***************************************************************************************** */
@@ -243,8 +275,7 @@
      * Depending on certain conditions, determines whether to fully expand or collapse the panel.
      */
     protected void maybeCompleteAnimation(MotionEvent event) {
-        if (event.getActionMasked() == MotionEvent.ACTION_UP
-                && isPanelVisible()) {
+        if (isClosingAction(event) && isPanelVisible()) {
             if (mSettleClosePercentage < mPercentageFromEndingEdge) {
                 animatePanel(DEFAULT_FLING_VELOCITY, false);
             } else {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index ecf1c2c9..5ad8cad 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -22,6 +22,7 @@
 import android.widget.TextClock;
 
 import com.android.internal.colorextraction.ColorExtractor;
+import com.android.keyguard.dagger.KeyguardStatusViewScope;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.plugins.ClockPlugin;
@@ -36,6 +37,7 @@
 /**
  * Switch to show plugin clock when plugin is connected, otherwise it will show default clock.
  */
+@KeyguardStatusViewScope
 public class KeyguardClockSwitch extends RelativeLayout {
 
     private static final String TAG = "KeyguardClockSwitch";
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index f17f1ca..fe5fcc6 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -34,10 +34,11 @@
 public class KeyguardClockSwitchController {
     private static final boolean CUSTOM_CLOCKS_ENABLED = true;
 
+    private final KeyguardClockSwitch mView;
     private final StatusBarStateController mStatusBarStateController;
     private final SysuiColorExtractor mColorExtractor;
     private final ClockManager mClockManager;
-    private KeyguardClockSwitch mView;
+    private final KeyguardSliceViewController mKeyguardSliceViewController;
 
     private final StatusBarStateController.StateListener mStateListener =
             new StatusBarStateController.StateListener() {
@@ -52,9 +53,13 @@
      *
      * The color palette changes when the wallpaper is changed.
      */
-    private final ColorExtractor.OnColorsChangedListener mColorsListener = (extractor, which) -> {
-        if ((which & WallpaperManager.FLAG_LOCK) != 0) {
-            mView.updateColors(getGradientColors());
+    private final ColorExtractor.OnColorsChangedListener mColorsListener =
+            new ColorExtractor.OnColorsChangedListener() {
+        @Override
+        public void onColorsChanged(ColorExtractor extractor, int which) {
+            if ((which & WallpaperManager.FLAG_LOCK) != 0) {
+                mView.updateColors(getGradientColors());
+            }
         }
     };
 
@@ -84,22 +89,27 @@
     };
 
     @Inject
-    public KeyguardClockSwitchController(StatusBarStateController statusBarStateController,
-            SysuiColorExtractor colorExtractor, ClockManager clockManager) {
+    public KeyguardClockSwitchController(KeyguardClockSwitch keyguardClockSwitch,
+            StatusBarStateController statusBarStateController,
+            SysuiColorExtractor colorExtractor, ClockManager clockManager,
+            KeyguardSliceViewController keyguardSliceViewController) {
+        mView = keyguardClockSwitch;
         mStatusBarStateController = statusBarStateController;
         mColorExtractor = colorExtractor;
         mClockManager = clockManager;
+        mKeyguardSliceViewController = keyguardSliceViewController;
     }
 
     /**
      * Attach the controller to the view it relates to.
      */
-    public void attach(KeyguardClockSwitch view) {
-        mView = view;
+    public void init() {
         if (mView.isAttachedToWindow()) {
             mOnAttachStateChangeListener.onViewAttachedToWindow(mView);
         }
         mView.addOnAttachStateChangeListener(mOnAttachStateChangeListener);
+
+        mKeyguardSliceViewController.init();
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index 6f19613..be21d20 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -34,12 +34,15 @@
 import android.view.WindowManager;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.keyguard.dagger.KeyguardStatusViewComponent;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.navigationbar.NavigationBarController;
 import com.android.systemui.navigationbar.NavigationBarView;
 import com.android.systemui.util.InjectionInflationController;
 
+import javax.inject.Inject;
+
 public class KeyguardDisplayManager {
     protected static final String TAG = "KeyguardDisplayManager";
     private static boolean DEBUG = KeyguardConstants.DEBUG;
@@ -47,6 +50,7 @@
     private final MediaRouter mMediaRouter;
     private final DisplayManager mDisplayService;
     private final InjectionInflationController mInjectableInflater;
+    private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
     private final Context mContext;
 
     private boolean mShowing;
@@ -86,10 +90,13 @@
         }
     };
 
+    @Inject
     public KeyguardDisplayManager(Context context,
-            InjectionInflationController injectableInflater) {
+            InjectionInflationController injectableInflater,
+            KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory) {
         mContext = context;
         mInjectableInflater = injectableInflater;
+        mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
         mMediaRouter = mContext.getSystemService(MediaRouter.class);
         mDisplayService = mContext.getSystemService(DisplayManager.class);
         mDisplayService.registerDisplayListener(mDisplayListener, null /* handler */);
@@ -124,6 +131,7 @@
         Presentation presentation = mPresentations.get(displayId);
         if (presentation == null) {
             final Presentation newPresentation = new KeyguardPresentation(mContext, display,
+                    mKeyguardStatusViewComponentFactory,
                     mInjectableInflater.injectable(LayoutInflater.from(mContext)));
             newPresentation.setOnDismissListener(dialog -> {
                 if (newPresentation.equals(mPresentations.get(displayId))) {
@@ -241,7 +249,9 @@
     static final class KeyguardPresentation extends Presentation {
         private static final int VIDEO_SAFE_REGION = 80; // Percentage of display width & height
         private static final int MOVE_CLOCK_TIMEOUT = 10000; // 10s
+        private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
         private final LayoutInflater mInjectableLayoutInflater;
+        private KeyguardClockSwitchController mKeyguardClockSwitchController;
         private View mClock;
         private int mUsableWidth;
         private int mUsableHeight;
@@ -259,8 +269,10 @@
         };
 
         KeyguardPresentation(Context context, Display display,
+                KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory,
                 LayoutInflater injectionLayoutInflater) {
             super(context, display, R.style.Theme_SystemUI_KeyguardPresentation);
+            mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
             mInjectableLayoutInflater = injectionLayoutInflater;
             getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
             setCancelable(false);
@@ -302,6 +314,12 @@
 
             // Avoid screen burn in
             mClock.post(mMoveTextRunnable);
+
+            mKeyguardClockSwitchController = mKeyguardStatusViewComponentFactory
+                    .build(findViewById(R.id.clock))
+                    .getKeyguardClockSwitchController();
+
+            mKeyguardClockSwitchController.init();
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index f639c88..a479bca 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -16,12 +16,6 @@
 
 package com.android.keyguard;
 
-import static android.app.slice.Slice.HINT_LIST_ITEM;
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.Display.INVALID_DISPLAY;
-
-import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
-
 import android.animation.LayoutTransition;
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
@@ -35,28 +29,19 @@
 import android.graphics.text.LineBreaker;
 import android.net.Uri;
 import android.os.Trace;
-import android.provider.Settings;
 import android.text.TextUtils;
 import android.text.TextUtils.TruncateAt;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.util.TypedValue;
-import android.view.Display;
 import android.view.View;
 import android.view.animation.Animation;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
-import androidx.lifecycle.LiveData;
-import androidx.lifecycle.Observer;
-import androidx.slice.Slice;
 import androidx.slice.SliceItem;
-import androidx.slice.SliceViewManager;
 import androidx.slice.core.SliceQuery;
-import androidx.slice.widget.ListContent;
 import androidx.slice.widget.RowContent;
 import androidx.slice.widget.SliceContent;
-import androidx.slice.widget.SliceLiveData;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.graphics.ColorUtils;
@@ -64,70 +49,49 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.keyguard.KeyguardSliceProvider;
-import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.tuner.TunerService;
 import com.android.systemui.util.wakelock.KeepAwakeAnimationListener;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
-
-import javax.inject.Inject;
-import javax.inject.Named;
+import java.util.Map;
 
 /**
  * View visible under the clock on the lock screen and AoD.
  */
-public class KeyguardSliceView extends LinearLayout implements View.OnClickListener,
-        Observer<Slice>, TunerService.Tunable, ConfigurationController.ConfigurationListener {
+public class KeyguardSliceView extends LinearLayout {
 
     private static final String TAG = "KeyguardSliceView";
     public static final int DEFAULT_ANIM_DURATION = 550;
 
-    private final HashMap<View, PendingIntent> mClickActions;
-    private final ActivityStarter mActivityStarter;
-    private final ConfigurationController mConfigurationController;
     private final LayoutTransition mLayoutTransition;
-    private final TunerService mTunerService;
-    private Uri mKeyguardSliceUri;
     @VisibleForTesting
     TextView mTitle;
     private Row mRow;
     private int mTextColor;
     private float mDarkAmount = 0;
 
-    private LiveData<Slice> mLiveData;
-    private int mDisplayId = INVALID_DISPLAY;
     private int mIconSize;
     private int mIconSizeWithHeader;
     /**
      * Runnable called whenever the view contents change.
      */
     private Runnable mContentChangeListener;
-    private Slice mSlice;
     private boolean mHasHeader;
     private final int mRowWithHeaderPadding;
     private final int mRowPadding;
     private float mRowTextSize;
     private float mRowWithHeaderTextSize;
+    private View.OnClickListener mOnClickListener;
 
-    @Inject
-    public KeyguardSliceView(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
-            ActivityStarter activityStarter, ConfigurationController configurationController,
-            TunerService tunerService, @Main Resources resources) {
+    public KeyguardSliceView(Context context, AttributeSet attrs) {
         super(context, attrs);
 
-        mTunerService = tunerService;
-        mClickActions = new HashMap<>();
+        Resources resources = context.getResources();
         mRowPadding = resources.getDimensionPixelSize(R.dimen.subtitle_clock_padding);
         mRowWithHeaderPadding = resources.getDimensionPixelSize(R.dimen.header_subtitle_padding);
-        mActivityStarter = activityStarter;
-        mConfigurationController = configurationController;
 
         mLayoutTransition = new LayoutTransition();
         mLayoutTransition.setStagger(LayoutTransition.CHANGE_APPEARING, DEFAULT_ANIM_DURATION / 2);
@@ -153,39 +117,10 @@
                 R.dimen.widget_label_font_size);
         mRowWithHeaderTextSize = mContext.getResources().getDimensionPixelSize(
                 R.dimen.header_row_font_size);
-        mTitle.setOnClickListener(this);
         mTitle.setBreakStrategy(LineBreaker.BREAK_STRATEGY_BALANCED);
     }
 
     @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-
-        Display display = getDisplay();
-        if (display != null) {
-            mDisplayId = display.getDisplayId();
-        }
-        mTunerService.addTunable(this, Settings.Secure.KEYGUARD_SLICE_URI);
-        // Make sure we always have the most current slice
-        if (mDisplayId == DEFAULT_DISPLAY) {
-            mLiveData.observeForever(this);
-        }
-        mConfigurationController.addCallback(this);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-
-        // TODO(b/117344873) Remove below work around after this issue be fixed.
-        if (mDisplayId == DEFAULT_DISPLAY) {
-            mLiveData.removeObserver(this);
-        }
-        mTunerService.removeTunable(this);
-        mConfigurationController.removeCallback(this);
-    }
-
-    @Override
     public void onVisibilityAggregated(boolean isVisible) {
         super.onVisibilityAggregated(isVisible);
         setLayoutTransition(isVisible ? mLayoutTransition : null);
@@ -198,44 +133,31 @@
         return mHasHeader;
     }
 
-    private void showSlice() {
-        Trace.beginSection("KeyguardSliceView#showSlice");
-        if (mSlice == null) {
-            mTitle.setVisibility(GONE);
-            mRow.setVisibility(GONE);
-            mHasHeader = false;
-            if (mContentChangeListener != null) {
-                mContentChangeListener.run();
-            }
-            Trace.endSection();
-            return;
+    void hideSlice() {
+        mTitle.setVisibility(GONE);
+        mRow.setVisibility(GONE);
+        mHasHeader = false;
+        if (mContentChangeListener != null) {
+            mContentChangeListener.run();
         }
-        mClickActions.clear();
+    }
 
-        ListContent lc = new ListContent(getContext(), mSlice);
-        SliceContent headerContent = lc.getHeader();
-        mHasHeader = headerContent != null && !headerContent.getSliceItem().hasHint(HINT_LIST_ITEM);
-        List<SliceContent> subItems = new ArrayList<>();
-        for (int i = 0; i < lc.getRowItems().size(); i++) {
-            SliceContent subItem = lc.getRowItems().get(i);
-            String itemUri = subItem.getSliceItem().getSlice().getUri().toString();
-            // Filter out the action row
-            if (!KeyguardSliceProvider.KEYGUARD_ACTION_URI.equals(itemUri)) {
-                subItems.add(subItem);
-            }
-        }
+    Map<View, PendingIntent> showSlice(RowContent header, List<SliceContent> subItems) {
+        Trace.beginSection("KeyguardSliceView#showSlice");
+        mHasHeader = header != null;
+        Map<View, PendingIntent> clickActions = new HashMap<>();
+
         if (!mHasHeader) {
             mTitle.setVisibility(GONE);
         } else {
             mTitle.setVisibility(VISIBLE);
 
-            RowContent header = lc.getHeader();
             SliceItem mainTitle = header.getTitleItem();
             CharSequence title = mainTitle != null ? mainTitle.getText() : null;
             mTitle.setText(title);
             if (header.getPrimaryAction() != null
                     && header.getPrimaryAction().getAction() != null) {
-                mClickActions.put(mTitle, header.getPrimaryAction().getAction());
+                clickActions.put(mTitle, header.getPrimaryAction().getAction());
             }
         }
 
@@ -265,7 +187,7 @@
             if (rc.getPrimaryAction() != null) {
                 pendingIntent = rc.getPrimaryAction().getAction();
             }
-            mClickActions.put(button, pendingIntent);
+            clickActions.put(button, pendingIntent);
 
             final SliceItem titleItem = rc.getTitleItem();
             button.setText(titleItem == null ? null : titleItem.getText());
@@ -286,14 +208,14 @@
                 }
             }
             button.setCompoundDrawables(iconDrawable, null, null, null);
-            button.setOnClickListener(this);
+            button.setOnClickListener(mOnClickListener);
             button.setClickable(pendingIntent != null);
         }
 
         // Removing old views
         for (int i = 0; i < mRow.getChildCount(); i++) {
             View child = mRow.getChildAt(i);
-            if (!mClickActions.containsKey(child)) {
+            if (!clickActions.containsKey(child)) {
                 mRow.removeView(child);
                 i--;
             }
@@ -303,6 +225,8 @@
             mContentChangeListener.run();
         }
         Trace.endSection();
+
+        return clickActions;
     }
 
     public void setDarkAmount(float darkAmount) {
@@ -323,14 +247,6 @@
         }
     }
 
-    @Override
-    public void onClick(View v) {
-        final PendingIntent action = mClickActions.get(v);
-        if (action != null) {
-            mActivityStarter.startPendingIntentDismissingKeyguard(action);
-        }
-    }
-
     /**
      * Runnable that gets invoked every time the title or the row visibility changes.
      * @param contentChangeListener The listener.
@@ -339,43 +255,6 @@
         mContentChangeListener = contentChangeListener;
     }
 
-    /**
-     * LiveData observer lifecycle.
-     * @param slice the new slice content.
-     */
-    @Override
-    public void onChanged(Slice slice) {
-        mSlice = slice;
-        showSlice();
-    }
-
-    @Override
-    public void onTuningChanged(String key, String newValue) {
-        setupUri(newValue);
-    }
-
-    /**
-     * Sets the slice provider Uri.
-     */
-    public void setupUri(String uriString) {
-        if (uriString == null) {
-            uriString = KeyguardSliceProvider.KEYGUARD_SLICE_URI;
-        }
-
-        boolean wasObserving = false;
-        if (mLiveData != null && mLiveData.hasActiveObservers()) {
-            wasObserving = true;
-            mLiveData.removeObserver(this);
-        }
-
-        mKeyguardSliceUri = Uri.parse(uriString);
-        mLiveData = SliceLiveData.fromUri(mContext, mKeyguardSliceUri);
-
-        if (wasObserving) {
-            mLiveData.observeForever(this);
-        }
-    }
-
     @VisibleForTesting
     int getTextColor() {
         return ColorUtils.blendARGB(mTextColor, Color.WHITE, mDarkAmount);
@@ -387,8 +266,7 @@
         updateTextColors();
     }
 
-    @Override
-    public void onDensityOrFontScaleChanged() {
+    void onDensityOrFontScaleChanged() {
         mIconSize = mContext.getResources().getDimensionPixelSize(R.dimen.widget_icon_size);
         mIconSizeWithHeader = (int) mContext.getResources().getDimension(R.dimen.header_icon_size);
         mRowTextSize = mContext.getResources().getDimensionPixelSize(
@@ -397,37 +275,21 @@
                 R.dimen.header_row_font_size);
     }
 
-    public void refresh() {
-        Slice slice;
-        Trace.beginSection("KeyguardSliceView#refresh");
-        // We can optimize performance and avoid binder calls when we know that we're bound
-        // to a Slice on the same process.
-        if (KeyguardSliceProvider.KEYGUARD_SLICE_URI.equals(mKeyguardSliceUri.toString())) {
-            KeyguardSliceProvider instance = KeyguardSliceProvider.getAttachedInstance();
-            if (instance != null) {
-                slice = instance.onBindSlice(mKeyguardSliceUri);
-            } else {
-                Log.w(TAG, "Keyguard slice not bound yet?");
-                slice = null;
-            }
-        } else {
-            slice = SliceViewManager.getInstance(getContext()).bindSlice(mKeyguardSliceUri);
-        }
-        onChanged(slice);
-        Trace.endSection();
-    }
-
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("KeyguardSliceView:");
-        pw.println("  mClickActions: " + mClickActions);
         pw.println("  mTitle: " + (mTitle == null ? "null" : mTitle.getVisibility() == VISIBLE));
         pw.println("  mRow: " + (mRow == null ? "null" : mRow.getVisibility() == VISIBLE));
         pw.println("  mTextColor: " + Integer.toHexString(mTextColor));
         pw.println("  mDarkAmount: " + mDarkAmount);
-        pw.println("  mSlice: " + mSlice);
         pw.println("  mHasHeader: " + mHasHeader);
     }
 
+    @Override
+    public void setOnClickListener(View.OnClickListener onClickListener) {
+        mOnClickListener = onClickListener;
+        mTitle.setOnClickListener(onClickListener);
+    }
+
     public static class Row extends LinearLayout {
 
         /**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java
new file mode 100644
index 0000000..35a2392
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import static android.app.slice.Slice.HINT_LIST_ITEM;
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import android.app.PendingIntent;
+import android.net.Uri;
+import android.os.Trace;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.Display;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.Observer;
+import androidx.slice.Slice;
+import androidx.slice.SliceViewManager;
+import androidx.slice.widget.ListContent;
+import androidx.slice.widget.RowContent;
+import androidx.slice.widget.SliceContent;
+import androidx.slice.widget.SliceLiveData;
+
+import com.android.keyguard.dagger.KeyguardStatusViewScope;
+import com.android.systemui.Dumpable;
+import com.android.systemui.dump.DumpManager;
+import com.android.systemui.keyguard.KeyguardSliceProvider;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.tuner.TunerService;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import javax.inject.Inject;
+
+/** Controller for a {@link KeyguardSliceView}. */
+@KeyguardStatusViewScope
+public class KeyguardSliceViewController implements Dumpable {
+    private static final String TAG = "KeyguardSliceViewCtrl";
+
+    private final KeyguardSliceView mView;
+    private final KeyguardStatusView mKeyguardStatusView;
+    private final ActivityStarter mActivityStarter;
+    private final ConfigurationController mConfigurationController;
+    private final TunerService mTunerService;
+    private final DumpManager mDumpManager;
+    private int mDisplayId;
+    private LiveData<Slice> mLiveData;
+    private Uri mKeyguardSliceUri;
+    private Slice mSlice;
+    private Map<View, PendingIntent> mClickActions;
+
+    private final View.OnAttachStateChangeListener mOnAttachStateChangeListener =
+            new View.OnAttachStateChangeListener() {
+
+                @Override
+                public void onViewAttachedToWindow(View v) {
+
+                    Display display = mView.getDisplay();
+                    if (display != null) {
+                        mDisplayId = display.getDisplayId();
+                    }
+                    mTunerService.addTunable(mTunable, Settings.Secure.KEYGUARD_SLICE_URI);
+                    // Make sure we always have the most current slice
+                    if (mDisplayId == DEFAULT_DISPLAY && mLiveData != null) {
+                        mLiveData.observeForever(mObserver);
+                    }
+                    mConfigurationController.addCallback(mConfigurationListener);
+                    mDumpManager.registerDumpable(TAG, KeyguardSliceViewController.this);
+                }
+
+                @Override
+                public void onViewDetachedFromWindow(View v) {
+
+                    // TODO(b/117344873) Remove below work around after this issue be fixed.
+                    if (mDisplayId == DEFAULT_DISPLAY) {
+                        mLiveData.removeObserver(mObserver);
+                    }
+                    mTunerService.removeTunable(mTunable);
+                    mConfigurationController.removeCallback(mConfigurationListener);
+                    mDumpManager.unregisterDumpable(TAG);
+                }
+            };
+
+    TunerService.Tunable mTunable = (key, newValue) -> setupUri(newValue);
+
+    ConfigurationController.ConfigurationListener mConfigurationListener =
+            new ConfigurationController.ConfigurationListener() {
+        @Override
+        public void onDensityOrFontScaleChanged() {
+            mView.onDensityOrFontScaleChanged();
+        }
+    };
+
+    Observer<Slice> mObserver = new Observer<Slice>() {
+        @Override
+        public void onChanged(Slice slice) {
+            mSlice = slice;
+            showSlice(slice);
+        }
+    };
+
+    private View.OnClickListener mOnClickListener = new View.OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            final PendingIntent action = mClickActions.get(v);
+            if (action != null && mActivityStarter != null) {
+                mActivityStarter.startPendingIntentDismissingKeyguard(action);
+            }
+        }
+    };
+
+    @Inject
+    public KeyguardSliceViewController(KeyguardSliceView keyguardSliceView,
+            KeyguardStatusView keyguardStatusView, ActivityStarter activityStarter,
+            ConfigurationController configurationController, TunerService tunerService,
+            DumpManager dumpManager) {
+        mView = keyguardSliceView;
+        mKeyguardStatusView = keyguardStatusView;
+        mActivityStarter = activityStarter;
+        mConfigurationController = configurationController;
+        mTunerService = tunerService;
+        mDumpManager = dumpManager;
+    }
+
+    /** Initialize the controller. */
+    public void init() {
+        if (mView.isAttachedToWindow()) {
+            mOnAttachStateChangeListener.onViewAttachedToWindow(mView);
+        }
+        mView.addOnAttachStateChangeListener(mOnAttachStateChangeListener);
+        mView.setOnClickListener(mOnClickListener);
+        // TODO: remove the line below.
+        mKeyguardStatusView.setKeyguardSliceViewController(this);
+    }
+
+    /**
+     * Sets the slice provider Uri.
+     */
+    public void setupUri(String uriString) {
+        if (uriString == null) {
+            uriString = KeyguardSliceProvider.KEYGUARD_SLICE_URI;
+        }
+
+        boolean wasObserving = false;
+        if (mLiveData != null && mLiveData.hasActiveObservers()) {
+            wasObserving = true;
+            mLiveData.removeObserver(mObserver);
+        }
+
+        mKeyguardSliceUri = Uri.parse(uriString);
+        mLiveData = SliceLiveData.fromUri(mView.getContext(), mKeyguardSliceUri);
+
+        if (wasObserving) {
+            mLiveData.observeForever(mObserver);
+        }
+    }
+
+    /**
+     * Update contents of the view.
+     */
+    public void refresh() {
+        Slice slice;
+        Trace.beginSection("KeyguardSliceViewController#refresh");
+        // We can optimize performance and avoid binder calls when we know that we're bound
+        // to a Slice on the same process.
+        if (KeyguardSliceProvider.KEYGUARD_SLICE_URI.equals(mKeyguardSliceUri.toString())) {
+            KeyguardSliceProvider instance = KeyguardSliceProvider.getAttachedInstance();
+            if (instance != null) {
+                slice = instance.onBindSlice(mKeyguardSliceUri);
+            } else {
+                Log.w(TAG, "Keyguard slice not bound yet?");
+                slice = null;
+            }
+        } else {
+            // TODO: Make SliceViewManager injectable
+            slice = SliceViewManager.getInstance(mView.getContext()).bindSlice(mKeyguardSliceUri);
+        }
+        mObserver.onChanged(slice);
+        Trace.endSection();
+    }
+
+    void showSlice(Slice slice) {
+        Trace.beginSection("KeyguardSliceViewController#showSlice");
+        if (slice == null) {
+            mView.hideSlice();
+            Trace.endSection();
+            return;
+        }
+
+        ListContent lc = new ListContent(slice);
+        RowContent headerContent = lc.getHeader();
+        boolean hasHeader =
+                headerContent != null && !headerContent.getSliceItem().hasHint(HINT_LIST_ITEM);
+
+        List<SliceContent> subItems = lc.getRowItems().stream().filter(sliceContent -> {
+            String itemUri = sliceContent.getSliceItem().getSlice().getUri().toString();
+            // Filter out the action row
+            return !KeyguardSliceProvider.KEYGUARD_ACTION_URI.equals(itemUri);
+        }).collect(Collectors.toList());
+
+
+        mClickActions = mView.showSlice(hasHeader ? headerContent : null, subItems);
+
+        Trace.endSection();
+    }
+
+
+    @Override
+    public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+        pw.println("  mSlice: " + mSlice);
+        pw.println("  mClickActions: " + mClickActions);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 4c6aafb..6e11174 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -32,7 +32,6 @@
 import android.util.TypedValue;
 import android.view.View;
 import android.widget.GridLayout;
-import android.widget.LinearLayout;
 import android.widget.TextView;
 
 import androidx.core.graphics.ColorUtils;
@@ -56,7 +55,6 @@
     private final LockPatternUtils mLockPatternUtils;
     private final IActivityManager mIActivityManager;
 
-    private LinearLayout mStatusViewContainer;
     private TextView mLogoutView;
     private KeyguardClockSwitch mClockView;
     private TextView mOwnerInfo;
@@ -64,6 +62,7 @@
     private View mNotificationIcons;
     private Runnable mPendingMarqueeStart;
     private Handler mHandler;
+    private KeyguardSliceViewController mKeyguardSliceViewController;
 
     private boolean mPulsing;
     private float mDarkAmount = 0;
@@ -179,7 +178,6 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mStatusViewContainer = findViewById(R.id.status_view_container);
         mLogoutView = findViewById(R.id.logout);
         mNotificationIcons = findViewById(R.id.clock_notification_icon_container);
         if (mLogoutView != null) {
@@ -250,7 +248,7 @@
 
     public void dozeTimeTick() {
         refreshTime();
-        mKeyguardSlice.refresh();
+        mKeyguardSliceViewController.refresh();
     }
 
     private void refreshTime() {
@@ -456,4 +454,9 @@
             Log.e(TAG, "Failed to logout user", re);
         }
     }
+
+    // TODO: remove this method when a controller is available.
+    void setKeyguardSliceViewController(KeyguardSliceViewController keyguardSliceViewController) {
+        mKeyguardSliceViewController = keyguardSliceViewController;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java
new file mode 100644
index 0000000..21ccff7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard.dagger;
+
+import com.android.keyguard.KeyguardClockSwitchController;
+import com.android.keyguard.KeyguardStatusView;
+
+import dagger.BindsInstance;
+import dagger.Subcomponent;
+
+/**
+ * Subcomponent for helping work with KeyguardStatusView and its children.
+ */
+@Subcomponent(modules = {KeyguardStatusViewModule.class})
+@KeyguardStatusViewScope
+public interface KeyguardStatusViewComponent {
+    /** Simple factory for {@link KeyguardStatusViewComponent}. */
+    @Subcomponent.Factory
+    interface Factory {
+        KeyguardStatusViewComponent build(@BindsInstance KeyguardStatusView presentation);
+    }
+
+    /** Builds a {@link com.android.keyguard.KeyguardClockSwitchController}. */
+    KeyguardClockSwitchController getKeyguardClockSwitchController();
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewModule.java
new file mode 100644
index 0000000..1d51e59
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewModule.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard.dagger;
+
+import com.android.keyguard.KeyguardClockSwitch;
+import com.android.keyguard.KeyguardSliceView;
+import com.android.keyguard.KeyguardStatusView;
+import com.android.systemui.R;
+
+import dagger.Module;
+import dagger.Provides;
+
+/** Dagger module for {@link KeyguardStatusViewComponent}. */
+@Module
+public abstract class KeyguardStatusViewModule {
+    @Provides
+    static KeyguardClockSwitch getKeyguardClockSwitch(KeyguardStatusView keyguardPresentation) {
+        return keyguardPresentation.findViewById(R.id.keyguard_clock_container);
+    }
+
+    @Provides
+    static KeyguardSliceView getKeyguardSliceView(KeyguardClockSwitch keyguardClockSwitch) {
+        return keyguardClockSwitch.findViewById(R.id.keyguard_status_area);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewScope.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewScope.java
new file mode 100644
index 0000000..880822a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewScope.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard.dagger;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Scope;
+
+/**
+ * Scope annotation for singleton items within the StatusBarComponent.
+ */
+@Documented
+@Retention(RUNTIME)
+@Scope
+public @interface KeyguardStatusViewScope {}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index 8a67e96..0dd9488 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -18,6 +18,8 @@
 
 import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME;
 
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.app.INotificationManager;
 import android.content.Context;
 import android.content.SharedPreferences;
@@ -26,6 +28,7 @@
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.util.DisplayMetrics;
 import android.view.Choreographer;
 import android.view.IWindowManager;
@@ -39,6 +42,7 @@
 import com.android.internal.util.NotificationMessagingUtil;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.ViewMediatorCallback;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.systemui.Prefs;
 import com.android.systemui.accessibility.ModeSwitchesController;
 import com.android.systemui.accessibility.SystemActions;
@@ -88,7 +92,7 @@
  * Provides dependencies for the root component of sysui injection.
  *
  * Only SystemUI owned classes and instances should go in here. Other, framework-owned classes
- * should go in {@link SystemServicesModule}.
+ * should go in {@link FrameworkServicesModule}.
  *
  * See SystemUI/docs/dagger.md
  */
@@ -163,6 +167,15 @@
 
     }
 
+    @SuppressLint("MissingPermission")
+    @SysUISingleton
+    @Provides
+    @Nullable
+    static LocalBluetoothManager provideLocalBluetoothController(Context context,
+            @Background Handler bgHandler) {
+        return LocalBluetoothManager.create(context, bgHandler, UserHandle.ALL);
+    }
+
     /** */
     @Provides
     @SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
similarity index 88%
rename from packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
rename to packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index ceb9aee..66063a8 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -17,7 +17,6 @@
 package com.android.systemui.dagger;
 
 import android.annotation.Nullable;
-import android.annotation.SuppressLint;
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
 import android.app.AlarmManager;
@@ -49,10 +48,8 @@
 import android.net.NetworkScoreManager;
 import android.net.wifi.WifiManager;
 import android.os.BatteryStats;
-import android.os.Handler;
 import android.os.PowerManager;
 import android.os.ServiceManager;
-import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.Vibrator;
 import android.service.dreams.DreamService;
@@ -68,12 +65,12 @@
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.util.LatencyTracker;
-import com.android.settingslib.bluetooth.LocalBluetoothManager;
-import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.DisplayId;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.shared.system.PackageManagerWrapper;
 
+import javax.inject.Singleton;
+
 import dagger.Module;
 import dagger.Provides;
 
@@ -81,51 +78,51 @@
  * Provides Non-SystemUI, Framework-Owned instances to the dependency graph.
  */
 @Module
-public class SystemServicesModule {
+public class FrameworkServicesModule {
     @Provides
-    @SysUISingleton
+    @Singleton
     static AccessibilityManager provideAccessibilityManager(Context context) {
         return context.getSystemService(AccessibilityManager.class);
     }
 
     @Provides
-    @SysUISingleton
+    @Singleton
     static ActivityManager provideActivityManager(Context context) {
         return context.getSystemService(ActivityManager.class);
     }
 
-    @SysUISingleton
     @Provides
+    @Singleton
     static AlarmManager provideAlarmManager(Context context) {
         return context.getSystemService(AlarmManager.class);
     }
 
     @Provides
-    @SysUISingleton
+    @Singleton
     static AudioManager provideAudioManager(Context context) {
         return context.getSystemService(AudioManager.class);
     }
 
     @Provides
-    @SysUISingleton
+    @Singleton
     static ColorDisplayManager provideColorDisplayManager(Context context) {
         return context.getSystemService(ColorDisplayManager.class);
     }
 
     @Provides
-    @SysUISingleton
+    @Singleton
     static ConnectivityManager provideConnectivityManagager(Context context) {
         return context.getSystemService(ConnectivityManager.class);
     }
 
     @Provides
-    @SysUISingleton
+    @Singleton
     static ContentResolver provideContentResolver(Context context) {
         return context.getContentResolver();
     }
 
     @Provides
-    @SysUISingleton
+    @Singleton
     static DevicePolicyManager provideDevicePolicyManager(Context context) {
         return context.getSystemService(DevicePolicyManager.class);
     }
@@ -137,39 +134,39 @@
     }
 
     @Provides
-    @SysUISingleton
+    @Singleton
     static DisplayManager provideDisplayManager(Context context) {
         return context.getSystemService(DisplayManager.class);
     }
 
-    @SysUISingleton
     @Provides
+    @Singleton
     static IActivityManager provideIActivityManager() {
         return ActivityManager.getService();
     }
 
-    @SysUISingleton
     @Provides
+    @Singleton
     static IActivityTaskManager provideIActivityTaskManager() {
         return ActivityTaskManager.getService();
     }
 
     @Provides
-    @SysUISingleton
+    @Singleton
     static IBatteryStats provideIBatteryStats() {
         return IBatteryStats.Stub.asInterface(
                 ServiceManager.getService(BatteryStats.SERVICE_NAME));
     }
 
     @Provides
-    @SysUISingleton
+    @Singleton
     static IDreamManager provideIDreamManager() {
         return IDreamManager.Stub.asInterface(
                 ServiceManager.checkService(DreamService.DREAM_SERVICE));
     }
 
     @Provides
-    @SysUISingleton
+    @Singleton
     @Nullable
     static FaceManager provideFaceManager(Context context) {
         return context.getSystemService(FaceManager.class);
@@ -177,13 +174,13 @@
     }
 
     @Provides
-    @SysUISingleton
+    @Singleton
     static IPackageManager provideIPackageManager() {
         return IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
     }
 
-    @SysUISingleton
     @Provides
+    @Singleton
     static IStatusBarService provideIStatusBarService() {
         return IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
@@ -196,39 +193,30 @@
                 ServiceManager.getService(Context.WALLPAPER_SERVICE));
     }
 
-    @SysUISingleton
     @Provides
+    @Singleton
     static IWindowManager provideIWindowManager() {
         return WindowManagerGlobal.getWindowManagerService();
     }
 
-    @SysUISingleton
     @Provides
+    @Singleton
     static KeyguardManager provideKeyguardManager(Context context) {
         return context.getSystemService(KeyguardManager.class);
     }
 
-    @SysUISingleton
     @Provides
+    @Singleton
     static LatencyTracker provideLatencyTracker(Context context) {
         return LatencyTracker.getInstance(context);
     }
 
-    @SysUISingleton
     @Provides
+    @Singleton
     static LauncherApps provideLauncherApps(Context context) {
         return context.getSystemService(LauncherApps.class);
     }
 
-    @SuppressLint("MissingPermission")
-    @SysUISingleton
-    @Provides
-    @Nullable
-    static LocalBluetoothManager provideLocalBluetoothController(Context context,
-            @Background Handler bgHandler) {
-        return LocalBluetoothManager.create(context, bgHandler, UserHandle.ALL);
-    }
-
     @Provides
     static MediaRouter2Manager provideMediaRouter2Manager(Context context) {
         return MediaRouter2Manager.getInstance(context);
@@ -240,32 +228,32 @@
     }
 
     @Provides
-    @SysUISingleton
+    @Singleton
     static NetworkScoreManager provideNetworkScoreManager(Context context) {
         return context.getSystemService(NetworkScoreManager.class);
     }
 
-    @SysUISingleton
     @Provides
+    @Singleton
     static NotificationManager provideNotificationManager(Context context) {
         return context.getSystemService(NotificationManager.class);
     }
 
-    @SysUISingleton
     @Provides
+    @Singleton
     static PackageManager providePackageManager(Context context) {
         return context.getPackageManager();
     }
 
-    @SysUISingleton
     @Provides
+    @Singleton
     static PackageManagerWrapper providePackageManagerWrapper() {
         return PackageManagerWrapper.getInstance();
     }
 
     /** */
-    @SysUISingleton
     @Provides
+    @Singleton
     static PowerManager providePowerManager(Context context) {
         return context.getSystemService(PowerManager.class);
     }
@@ -277,57 +265,63 @@
     }
 
     @Provides
-    @SysUISingleton
+    @Singleton
+    static RoleManager provideRoleManager(Context context) {
+        return context.getSystemService(RoleManager.class);
+    }
+
+    @Provides
+    @Singleton
     static SensorManager providesSensorManager(Context context) {
         return context.getSystemService(SensorManager.class);
     }
 
-    @SysUISingleton
     @Provides
+    @Singleton
     static SensorPrivacyManager provideSensorPrivacyManager(Context context) {
         return context.getSystemService(SensorPrivacyManager.class);
     }
 
-    @SysUISingleton
     @Provides
+    @Singleton
     static ShortcutManager provideShortcutManager(Context context) {
         return context.getSystemService(ShortcutManager.class);
     }
 
     @Provides
-    @SysUISingleton
+    @Singleton
     @Nullable
     static TelecomManager provideTelecomManager(Context context) {
         return context.getSystemService(TelecomManager.class);
     }
 
     @Provides
-    @SysUISingleton
+    @Singleton
     static TelephonyManager provideTelephonyManager(Context context) {
         return context.getSystemService(TelephonyManager.class);
     }
 
     @Provides
-    @SysUISingleton
+    @Singleton
     static TrustManager provideTrustManager(Context context) {
         return context.getSystemService(TrustManager.class);
     }
 
     @Provides
-    @SysUISingleton
+    @Singleton
     @Nullable
     static Vibrator provideVibrator(Context context) {
         return context.getSystemService(Vibrator.class);
     }
 
     @Provides
-    @SysUISingleton
+    @Singleton
     static ViewConfiguration provideViewConfiguration(Context context) {
         return ViewConfiguration.get(context);
     }
 
     @Provides
-    @SysUISingleton
+    @Singleton
     static UserManager provideUserManager(Context context) {
         return context.getSystemService(UserManager.class);
     }
@@ -338,21 +332,15 @@
     }
 
     @Provides
-    @SysUISingleton
+    @Singleton
     @Nullable
     static WifiManager provideWifiManager(Context context) {
         return context.getSystemService(WifiManager.class);
     }
 
-    @SysUISingleton
     @Provides
+    @Singleton
     static WindowManager provideWindowManager(Context context) {
         return context.getSystemService(WindowManager.class);
     }
-
-    @Provides
-    @SysUISingleton
-    static RoleManager provideRoleManager(Context context) {
-        return context.getSystemService(RoleManager.class);
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
index 553655b..fd4a409 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
@@ -16,63 +16,23 @@
 
 package com.android.systemui.dagger;
 
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.hardware.display.AmbientDisplayConfiguration;
-import android.util.DisplayMetrics;
-import android.view.Choreographer;
-
-import com.android.systemui.Prefs;
-import com.android.systemui.dagger.qualifiers.Main;
-
-import javax.inject.Singleton;
-
 import dagger.Module;
-import dagger.Provides;
 
 /**
- * Supplies globally scoped instances.
+ * Supplies globally scoped instances that should be available in all versions of SystemUI
  *
  * Providers in this module will be accessible to both WMComponent and SysUIComponent scoped
  * classes. They are in here because they are either needed globally or are inherently universal
  * to the application.
  *
  * Note that just because a class might be used by both WM and SysUI does not necessarily mean that
- * it should got into this module. If WM and SysUI might need the class for different purposes
+ * it should go into this module. If WM and SysUI might need the class for different purposes
  * or different semantics, it may make sense to ask them to supply their own. Something like
  * threading and concurrency provide a good example. Both components need
  * Threads/Handlers/Executors, but they need separate instances of them in many cases.
  *
  * Please use discretion when adding things to the global scope.
  */
-@Module
+@Module(includes = {FrameworkServicesModule.class})
 public class GlobalModule {
-    /** */
-    @Provides
-    @Main
-    public SharedPreferences provideSharePreferences(Context context) {
-        return Prefs.get(context);
-    }
-
-    /** */
-    @Provides
-    public AmbientDisplayConfiguration provideAmbientDisplayConfiguration(Context context) {
-        return new AmbientDisplayConfiguration(context);
-    }
-
-    /** */
-    @Provides
-    @Singleton
-    public Choreographer providesChoreographer() {
-        return Choreographer.getInstance();
-    }
-
-    /** */
-    @Provides
-    @Singleton
-    public DisplayMetrics provideDisplayMetrics(Context context) {
-        DisplayMetrics displayMetrics = new DisplayMetrics();
-        context.getDisplay().getMetrics(displayMetrics);
-        return displayMetrics;
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java
index 3d7c8ad4..36fd337 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java
@@ -28,6 +28,7 @@
  */
 @Singleton
 @Component(modules = {
+        GlobalModule.class,
         SysUISubcomponentModule.class,
         WMModule.class})
 public interface GlobalRootComponent {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index b606201..e4e3d7a 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -37,7 +37,6 @@
         DependencyProvider.class,
         DependencyBinder.class,
         PipModule.class,
-        SystemServicesModule.class,
         SystemUIBinder.class,
         SystemUIModule.class,
         SystemUIDefaultModule.class})
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index e38dce0..8364b48 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -262,11 +262,11 @@
             onWakeScreen(wakeEvent, mMachine.isExecutingTransition() ? null : mMachine.getState());
         } else if (isLongPress) {
             requestPulse(pulseReason, true /* alreadyPerformedProxCheck */,
-                    null /* onPulseSupressedListener */);
+                    null /* onPulseSuppressedListener */);
         } else if (isWakeLockScreen) {
             if (wakeEvent) {
                 requestPulse(pulseReason, true /* alreadyPerformedProxCheck */,
-                        null /* onPulseSupressedListener */);
+                        null /* onPulseSuppressedListener */);
             }
         } else {
             proximityCheckThenCall((result) -> {
@@ -536,7 +536,7 @@
             if (PULSE_ACTION.equals(intent.getAction())) {
                 if (DozeMachine.DEBUG) Log.d(TAG, "Received pulse intent");
                 requestPulse(DozeLog.PULSE_REASON_INTENT, false, /* performedProxCheck */
-                        null /* onPulseSupressedListener */);
+                        null /* onPulseSuppressedListener */);
             }
             if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(intent.getAction())) {
                 mMachine.requestState(DozeMachine.State.FINISH);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 6214a64..3340791 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -89,15 +89,14 @@
 import com.android.systemui.dagger.qualifiers.UiBackground;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.keyguard.dagger.KeyguardModule;
+import com.android.systemui.navigationbar.NavigationModeController;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.statusbar.phone.BiometricUnlockController;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.navigationbar.NavigationModeController;
 import com.android.systemui.statusbar.phone.NotificationPanelViewController;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.util.DeviceConfigProxy;
-import com.android.systemui.util.InjectionInflationController;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -228,7 +227,6 @@
 
     /** TrustManager for letting it know when we change visibility */
     private final TrustManager mTrustManager;
-    private final InjectionInflationController mInjectionInflationController;
 
     /**
      * Used to keep the device awake while to ensure the keyguard finishes opening before
@@ -345,7 +343,7 @@
     /**
      * For managing external displays
      */
-    private KeyguardDisplayManager mKeyguardDisplayManager;
+    private final KeyguardDisplayManager mKeyguardDisplayManager;
 
     private final ArrayList<IKeyguardStateCallback> mKeyguardStateCallbacks = new ArrayList<>();
 
@@ -724,7 +722,7 @@
             TrustManager trustManager,
             DeviceConfigProxy deviceConfig,
             NavigationModeController navigationModeController,
-            InjectionInflationController injectionInflationController) {
+            KeyguardDisplayManager keyguardDisplayManager) {
         super(context);
         mFalsingManager = falsingManager;
         mLockPatternUtils = lockPatternUtils;
@@ -735,7 +733,7 @@
         mUpdateMonitor = keyguardUpdateMonitor;
         mPM = powerManager;
         mTrustManager = trustManager;
-        mInjectionInflationController = injectionInflationController;
+        mKeyguardDisplayManager = keyguardDisplayManager;
         dumpManager.registerDumpable(getClass().getName(), this);
         mDeviceConfig = deviceConfig;
         mShowHomeOverLockscreen = mDeviceConfig.getBoolean(
@@ -775,9 +773,6 @@
         mContext.registerReceiver(mDelayedLockBroadcastReceiver, delayedActionFilter,
                 SYSTEMUI_PERMISSION, null /* scheduler */);
 
-        mKeyguardDisplayManager = new KeyguardDisplayManager(mContext,
-                mInjectionInflationController);
-
         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
 
         KeyguardUpdateMonitor.setCurrentUser(ActivityManager.getCurrentUser());
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index c9164f0..9d8e73a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -26,8 +26,10 @@
 import android.os.PowerManager;
 
 import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardDisplayManager;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardViewController;
+import com.android.keyguard.dagger.KeyguardStatusViewComponent;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
@@ -43,7 +45,6 @@
 import com.android.systemui.statusbar.phone.KeyguardLiftController;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.util.DeviceConfigProxy;
-import com.android.systemui.util.InjectionInflationController;
 import com.android.systemui.util.sensors.AsyncSensorManager;
 import com.android.systemui.util.settings.GlobalSettings;
 import com.android.systemui.util.settings.SystemSettings;
@@ -58,7 +59,7 @@
 /**
  * Dagger Module providing {@link StatusBar}.
  */
-@Module
+@Module(subcomponents = {KeyguardStatusViewComponent.class})
 public class KeyguardModule {
     /**
      * Provides our instance of KeyguardViewMediator which is considered optional.
@@ -79,7 +80,7 @@
             @UiBackground Executor uiBgExecutor,
             DeviceConfigProxy deviceConfig,
             NavigationModeController navigationModeController,
-            InjectionInflationController injectionInflationController) {
+            KeyguardDisplayManager keyguardDisplayManager) {
         return new KeyguardViewMediator(
                 context,
                 falsingManager,
@@ -94,7 +95,8 @@
                 trustManager,
                 deviceConfig,
                 navigationModeController,
-                injectionInflationController);
+                keyguardDisplayManager
+        );
     }
 
     @SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java
index 214088c..7037403 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java
@@ -36,8 +36,8 @@
  * Activity to show the PIP menu to control PIP.
  */
 public class PipMenuActivity extends Activity implements PipManager.Listener {
-    private static final boolean DEBUG = false;
     private static final String TAG = "PipMenuActivity";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     static final String EXTRA_CUSTOM_ACTIONS = "custom_actions";
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index d83758a..fc7e548 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -68,6 +68,7 @@
 import com.android.keyguard.KeyguardStatusView;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.keyguard.dagger.KeyguardStatusViewComponent;
 import com.android.systemui.DejankUtils;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
@@ -129,7 +130,6 @@
 import java.util.function.Function;
 
 import javax.inject.Inject;
-import javax.inject.Provider;
 
 @StatusBarComponent.StatusBarScope
 public class NotificationPanelViewController extends PanelViewController {
@@ -260,7 +260,7 @@
     private final ConversationNotificationManager mConversationNotificationManager;
     private final MediaHierarchyManager mMediaHierarchyManager;
     private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
-    private final Provider<KeyguardClockSwitchController> mKeyguardClockSwitchControllerProvider;
+    private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
     // Maximum # notifications to show on Keyguard; extras will be collapsed in an overflow card.
     // If there are exactly 1 + mMaxKeyguardNotifications, then still shows all notifications
     private final int mMaxKeyguardNotifications;
@@ -511,9 +511,9 @@
             MediaHierarchyManager mediaHierarchyManager,
             BiometricUnlockController biometricUnlockController,
             StatusBarKeyguardViewManager statusBarKeyguardViewManager,
-            Provider<KeyguardClockSwitchController> keyguardClockSwitchControllerProvider,
             NotificationStackScrollLayoutController notificationStackScrollLayoutController,
-            NotificationIconAreaController notificationIconAreaController) {
+            NotificationIconAreaController notificationIconAreaController,
+            KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory) {
         super(view, falsingManager, dozeLog, keyguardStateController,
                 (SysuiStatusBarStateController) statusBarStateController, vibratorHelper,
                 latencyTracker, flingAnimationUtilsBuilder, statusBarTouchableRegionManager);
@@ -525,9 +525,9 @@
         mFlingAnimationUtilsBuilder = flingAnimationUtilsBuilder;
         mMediaHierarchyManager = mediaHierarchyManager;
         mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
-        mKeyguardClockSwitchControllerProvider = keyguardClockSwitchControllerProvider;
         mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
         mNotificationIconAreaController = notificationIconAreaController;
+        mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
         mView.setWillNotDraw(!DEBUG);
         mInjectionInflationController = injectionInflationController;
         mFalsingManager = falsingManager;
@@ -602,8 +602,10 @@
         mKeyguardStatusView = mView.findViewById(R.id.keyguard_status_view);
 
         KeyguardClockSwitchController keyguardClockSwitchController =
-                mKeyguardClockSwitchControllerProvider.get();
-        keyguardClockSwitchController.attach(mView.findViewById(R.id.keyguard_clock_container));
+                mKeyguardStatusViewComponentFactory
+                        .build(mKeyguardStatusView)
+                        .getKeyguardClockSwitchController();
+        keyguardClockSwitchController.init();
         mBigClockContainer = mView.findViewById(R.id.big_clock_container);
         keyguardClockSwitchController.setBigClockContainer(mBigClockContainer);
 
@@ -733,8 +735,10 @@
         // Re-associate the clock container with the keyguard clock switch.
         mBigClockContainer.removeAllViews();
         KeyguardClockSwitchController keyguardClockSwitchController =
-                mKeyguardClockSwitchControllerProvider.get();
-        keyguardClockSwitchController.attach(mView.findViewById(R.id.keyguard_clock_container));
+                mKeyguardStatusViewComponentFactory
+                        .build(mKeyguardStatusView)
+                        .getKeyguardClockSwitchController();
+        keyguardClockSwitchController.init();
         keyguardClockSwitchController.setBigClockContainer(mBigClockContainer);
 
         // Update keyguard bottom area
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvGlobalRootComponent.java b/packages/SystemUI/src/com/android/systemui/tv/TvGlobalRootComponent.java
index 37aac11..df741a0 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvGlobalRootComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvGlobalRootComponent.java
@@ -16,7 +16,9 @@
 
 package com.android.systemui.tv;
 
+import com.android.systemui.dagger.GlobalModule;
 import com.android.systemui.dagger.GlobalRootComponent;
+import com.android.systemui.dagger.WMModule;
 
 import javax.inject.Singleton;
 
@@ -26,7 +28,11 @@
  * Root component for Dagger injection.
  */
 @Singleton
-@Component(modules = {TvSysUIComponentModule.class})
+@Component(modules = {
+        GlobalModule.class,
+        TvSysUIComponentModule.class,
+        WMModule.class
+})
 public interface TvGlobalRootComponent extends GlobalRootComponent {
     /**
      * Component Builder interface. This allows to bind Context instance in the component
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java b/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java
index 302301d..3577bc0 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java
@@ -21,7 +21,6 @@
 import com.android.systemui.dagger.DependencyProvider;
 import com.android.systemui.dagger.SysUIComponent;
 import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.SystemServicesModule;
 import com.android.systemui.dagger.SystemUIBinder;
 import com.android.systemui.dagger.SystemUIModule;
 
@@ -35,7 +34,6 @@
         DefaultComponentBinder.class,
         DependencyProvider.class,
         DependencyBinder.class,
-        SystemServicesModule.class,
         SystemUIBinder.class,
         SystemUIModule.class,
         TvSystemUIModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
index d278905..eb8f065 100644
--- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
@@ -24,7 +24,6 @@
 import android.view.View;
 
 import com.android.keyguard.KeyguardMessageArea;
-import com.android.keyguard.KeyguardSliceView;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.qs.QSFooterImpl;
 import com.android.systemui.qs.QSPanel;
@@ -109,11 +108,6 @@
         NotificationStackScrollLayout createNotificationStackScrollLayout();
 
         /**
-         * Creates the KeyguardSliceView.
-         */
-        KeyguardSliceView createKeyguardSliceView();
-
-        /**
          * Creates the KeyguardMessageArea.
          */
         KeyguardMessageArea createKeyguardMessageArea();
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index 657e4fb..3aa6ec0 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -62,6 +62,8 @@
     private ClockPlugin mClockPlugin;
     @Mock
     ColorExtractor.GradientColors mGradientColors;
+    @Mock
+    KeyguardSliceViewController mKeyguardSliceViewController;
 
     private KeyguardClockSwitchController mController;
 
@@ -69,28 +71,30 @@
     public void setup() {
         MockitoAnnotations.initMocks(this);
 
-        mController = new KeyguardClockSwitchController(
-                mStatusBarStateController, mColorExtractor, mClockManager);
-
         when(mView.isAttachedToWindow()).thenReturn(true);
+
+        mController = new KeyguardClockSwitchController(
+                mView, mStatusBarStateController, mColorExtractor, mClockManager,
+                mKeyguardSliceViewController);
+
         when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
         when(mColorExtractor.getColors(anyInt())).thenReturn(mGradientColors);
     }
 
     @Test
-    public void testAttach_viewAlreadyAttached() {
-        mController.attach(mView);
+    public void testInit_viewAlreadyAttached() {
+        mController.init();
 
         verifyAttachment(times(1));
     }
 
     @Test
-    public void testAttach_viewNotYetAttached() {
+    public void testInit_viewNotYetAttached() {
         ArgumentCaptor<View.OnAttachStateChangeListener> listenerArgumentCaptor =
                 ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
 
         when(mView.isAttachedToWindow()).thenReturn(false);
-        mController.attach(mView);
+        mController.init();
         verify(mView).addOnAttachStateChangeListener(listenerArgumentCaptor.capture());
 
         verifyAttachment(never());
@@ -100,12 +104,17 @@
         verifyAttachment(times(1));
     }
 
+    @Test
+    public void testInitSubControllers() {
+        mController.init();
+        verify(mKeyguardSliceViewController).init();
+    }
 
     @Test
-    public void testAttach_viewDetached() {
+    public void testInit_viewDetached() {
         ArgumentCaptor<View.OnAttachStateChangeListener> listenerArgumentCaptor =
                 ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
-        mController.attach(mView);
+        mController.init();
         verify(mView).addOnAttachStateChangeListener(listenerArgumentCaptor.capture());
 
         verifyAttachment(times(1));
@@ -122,7 +131,7 @@
     public void testBigClockPassesStatusBarState() {
         ViewGroup testView = new FrameLayout(mContext);
 
-        mController.attach(mView);
+        mController.init();
         when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
         mController.setBigClockContainer(testView);
         verify(mView).setBigClockContainer(testView, StatusBarState.SHADE);
@@ -143,7 +152,7 @@
         ArgumentCaptor<ClockManager.ClockChangedListener> listenerArgumentCaptor =
                 ArgumentCaptor.forClass(ClockManager.ClockChangedListener.class);
 
-        mController.attach(mView);
+        mController.init();
         verify(mClockManager).addOnClockChangedListener(listenerArgumentCaptor.capture());
 
         listenerArgumentCaptor.getValue().onClockChanged(mClockPlugin);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java
index 446b122..559284a 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java
@@ -16,6 +16,7 @@
 
 package com.android.keyguard;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
@@ -28,6 +29,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.keyguard.KeyguardDisplayManager.KeyguardPresentation;
+import com.android.keyguard.dagger.KeyguardStatusViewComponent;
 import com.android.systemui.R;
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.SysuiTestCase;
@@ -51,6 +53,12 @@
     KeyguardSliceView mMockKeyguardSliceView;
     @Mock
     KeyguardStatusView mMockKeyguardStatusView;
+    @Mock
+    private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
+    @Mock
+    private KeyguardStatusViewComponent mKeyguardStatusViewComponent;
+    @Mock
+    private KeyguardClockSwitchController mKeyguardClockSwitchController;
 
     LayoutInflater mLayoutInflater;
 
@@ -62,6 +70,11 @@
         when(mMockKeyguardSliceView.getContext()).thenReturn(mContext);
         when(mMockKeyguardStatusView.getContext()).thenReturn(mContext);
         when(mMockKeyguardStatusView.findViewById(R.id.clock)).thenReturn(mMockKeyguardStatusView);
+        when(mKeyguardStatusViewComponentFactory.build(any(KeyguardStatusView.class)))
+                .thenReturn(mKeyguardStatusViewComponent);
+        when(mKeyguardStatusViewComponent.getKeyguardClockSwitchController())
+                .thenReturn(mKeyguardClockSwitchController);
+
         allowTestableLooperAsMainThread();
 
         InjectionInflationController inflationController = new InjectionInflationController(
@@ -99,7 +112,8 @@
     @Test
     public void testInflation_doesntCrash() {
         KeyguardPresentation keyguardPresentation = new KeyguardPresentation(mContext,
-                mContext.getDisplayNoVerify(), mLayoutInflater);
+                mContext.getDisplayNoVerify(), mKeyguardStatusViewComponentFactory,
+                mLayoutInflater);
         keyguardPresentation.onCreate(null /*savedInstanceState */);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java
new file mode 100644
index 0000000..b7bcaa3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java
@@ -0,0 +1,99 @@
+/*
+ * 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.keyguard;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.View;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dump.DumpManager;
+import com.android.systemui.keyguard.KeyguardSliceProvider;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.tuner.TunerService;
+
+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;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper(setAsMainLooper = true)
+public class KeyguardSliceViewControllerTest extends SysuiTestCase {
+    @Mock
+    private KeyguardSliceView mView;;
+    @Mock
+    private KeyguardStatusView mKeyguardStatusView;
+    @Mock
+    private TunerService mTunerService;
+    @Mock
+    private ConfigurationController mConfigurationController;
+    @Mock
+    private ActivityStarter mActivityStarter;
+    private DumpManager mDumpManager = new DumpManager();
+
+    private KeyguardSliceViewController mController;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        when(mView.isAttachedToWindow()).thenReturn(true);
+        when(mView.getContext()).thenReturn(mContext);
+        mController = new KeyguardSliceViewController(
+                mView, mKeyguardStatusView, mActivityStarter, mConfigurationController,
+                mTunerService, mDumpManager);
+        mController.setupUri(KeyguardSliceProvider.KEYGUARD_SLICE_URI);
+    }
+
+    @Test
+    public void refresh_replacesSliceContentAndNotifiesListener() {
+        mController.refresh();
+        verify(mView).hideSlice();
+    }
+
+    @Test
+    public void onAttachedToWindow_registersListeners() {
+        mController.init();
+        verify(mTunerService).addTunable(any(TunerService.Tunable.class), anyString());
+        verify(mConfigurationController).addCallback(
+                any(ConfigurationController.ConfigurationListener.class));
+    }
+
+    @Test
+    public void onDetachedFromWindow_unregistersListeners() {
+        ArgumentCaptor<View.OnAttachStateChangeListener> attachListenerArgumentCaptor =
+                ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
+
+        mController.init();
+        verify(mView).addOnAttachStateChangeListener(attachListenerArgumentCaptor.capture());
+
+        attachListenerArgumentCaptor.getValue().onViewDetachedFromWindow(mView);
+
+        verify(mTunerService).removeTunable(any(TunerService.Tunable.class));
+        verify(mConfigurationController).removeCallback(
+                any(ConfigurationController.ConfigurationListener.class));
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
index 06552b9..1ab08c2 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
@@ -15,37 +15,27 @@
  */
 package com.android.keyguard;
 
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.verify;
-
-import android.content.Context;
-import android.content.res.Resources;
 import android.graphics.Color;
 import android.net.Uri;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
-import android.util.AttributeSet;
 import android.view.LayoutInflater;
-import android.view.View;
 
+import androidx.slice.Slice;
 import androidx.slice.SliceProvider;
 import androidx.slice.SliceSpecs;
 import androidx.slice.builders.ListBuilder;
+import androidx.slice.widget.RowContent;
 
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.keyguard.KeyguardSliceProvider;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.tuner.TunerService;
 
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
 import java.util.Collections;
@@ -53,46 +43,18 @@
 import java.util.concurrent.atomic.AtomicBoolean;
 
 @SmallTest
-@RunWithLooper
+@RunWithLooper(setAsMainLooper = true)
 @RunWith(AndroidTestingRunner.class)
 public class KeyguardSliceViewTest extends SysuiTestCase {
     private KeyguardSliceView mKeyguardSliceView;
     private Uri mSliceUri;
 
-    @Mock
-    private TunerService mTunerService;
-    @Mock
-    private ConfigurationController mConfigurationController;
-    @Mock
-    private ActivityStarter mActivityStarter;
-    @Mock
-    private Resources mResources;
-
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        allowTestableLooperAsMainThread();
         LayoutInflater layoutInflater = LayoutInflater.from(getContext());
-        layoutInflater.setPrivateFactory(new LayoutInflater.Factory2() {
-
-            @Override
-            public View onCreateView(View parent, String name, Context context,
-                    AttributeSet attrs) {
-                return onCreateView(name, context, attrs);
-            }
-
-            @Override
-            public View onCreateView(String name, Context context, AttributeSet attrs) {
-                if ("com.android.keyguard.KeyguardSliceView".equals(name)) {
-                    return new KeyguardSliceView(getContext(), attrs, mActivityStarter,
-                            mConfigurationController, mTunerService, mResources);
-                }
-                return null;
-            }
-        });
         mKeyguardSliceView = (KeyguardSliceView) layoutInflater
                 .inflate(R.layout.keyguard_status_area, null);
-        mKeyguardSliceView.setupUri(KeyguardSliceProvider.KEYGUARD_SLICE_URI);
         mSliceUri = Uri.parse(KeyguardSliceProvider.KEYGUARD_SLICE_URI);
         SliceProvider.setSpecs(new HashSet<>(Collections.singletonList(SliceSpecs.LIST)));
     }
@@ -100,9 +62,13 @@
     @Test
     public void showSlice_notifiesListener() {
         ListBuilder builder = new ListBuilder(getContext(), mSliceUri, ListBuilder.INFINITY);
+        builder.setHeader(new ListBuilder.HeaderBuilder().setTitle("header title!"));
+        Slice slice = builder.build();
+        RowContent rowContent = new RowContent(slice.getItemArray()[0], 0);
+
         AtomicBoolean notified = new AtomicBoolean();
         mKeyguardSliceView.setContentChangeListener(()-> notified.set(true));
-        mKeyguardSliceView.onChanged(builder.build());
+        mKeyguardSliceView.showSlice(rowContent, Collections.EMPTY_LIST);
         Assert.assertTrue("Listener should be notified about slice changes.",
                 notified.get());
     }
@@ -111,7 +77,7 @@
     public void showSlice_emptySliceNotifiesListener() {
         AtomicBoolean notified = new AtomicBoolean();
         mKeyguardSliceView.setContentChangeListener(()-> notified.set(true));
-        mKeyguardSliceView.onChanged(null);
+        mKeyguardSliceView.showSlice(null, Collections.EMPTY_LIST);
         Assert.assertTrue("Listener should be notified about slice changes.",
                 notified.get());
     }
@@ -119,24 +85,17 @@
     @Test
     public void hasHeader_readsSliceData() {
         ListBuilder builder = new ListBuilder(getContext(), mSliceUri, ListBuilder.INFINITY);
-        mKeyguardSliceView.onChanged(builder.build());
+        mKeyguardSliceView.showSlice(null, Collections.EMPTY_LIST);
         Assert.assertFalse("View should not have a header", mKeyguardSliceView.hasHeader());
 
         builder.setHeader(new ListBuilder.HeaderBuilder().setTitle("header title!"));
-        mKeyguardSliceView.onChanged(builder.build());
+        Slice slice = builder.build();
+        RowContent rowContent = new RowContent(slice.getItemArray()[0], 0);
+        mKeyguardSliceView.showSlice(rowContent, Collections.EMPTY_LIST);
         Assert.assertTrue("View should have a header", mKeyguardSliceView.hasHeader());
     }
 
     @Test
-    public void refresh_replacesSliceContentAndNotifiesListener() {
-        AtomicBoolean notified = new AtomicBoolean();
-        mKeyguardSliceView.setContentChangeListener(()-> notified.set(true));
-        mKeyguardSliceView.refresh();
-        Assert.assertTrue("Listener should be notified about slice changes.",
-                notified.get());
-    }
-
-    @Test
     public void getTextColor_whiteTextWhenAOD() {
         // Set text color to red since the default is white and test would always pass
         mKeyguardSliceView.setTextColor(Color.RED);
@@ -147,18 +106,4 @@
         Assert.assertEquals("Should be using AOD text color", Color.WHITE,
                 mKeyguardSliceView.getTextColor());
     }
-
-    @Test
-    public void onAttachedToWindow_registersListeners() {
-        mKeyguardSliceView.onAttachedToWindow();
-        verify(mTunerService).addTunable(eq(mKeyguardSliceView), anyString());
-        verify(mConfigurationController).addCallback(eq(mKeyguardSliceView));
-    }
-
-    @Test
-    public void onDetachedFromWindow_unregistersListeners() {
-        mKeyguardSliceView.onDetachedFromWindow();
-        verify(mTunerService).removeTunable(eq(mKeyguardSliceView));
-        verify(mConfigurationController).removeCallback(eq(mKeyguardSliceView));
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java
index 0bf1376..0431704 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java
@@ -40,7 +40,8 @@
 public class KeyguardStatusViewTest extends SysuiTestCase {
 
     @Mock
-    KeyguardSliceView mKeyguardSlice;
+    KeyguardSliceViewController mKeyguardSliceViewController;
+
     @Mock
     KeyguardClockSwitch mClockView;
     @InjectMocks
@@ -64,7 +65,7 @@
     @Test
     public void dozeTimeTick_updatesSlice() {
         mKeyguardStatusView.dozeTimeTick();
-        verify(mKeyguardSlice).refresh();
+        verify(mKeyguardSliceViewController).refresh();
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index c874b1f..f6d6f562 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -37,6 +37,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardDisplayManager;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -46,7 +47,6 @@
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.util.DeviceConfigProxy;
 import com.android.systemui.util.DeviceConfigProxyFake;
-import com.android.systemui.util.InjectionInflationController;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.time.FakeSystemClock;
 
@@ -72,7 +72,7 @@
     private @Mock PowerManager mPowerManager;
     private @Mock TrustManager mTrustManager;
     private @Mock NavigationModeController mNavigationModeController;
-    private @Mock InjectionInflationController mInjectionInflationController;
+    private @Mock KeyguardDisplayManager mKeyguardDisplayManager;
     private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake();
     private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
 
@@ -91,7 +91,7 @@
                 () -> mStatusBarKeyguardViewManager,
                 mDismissCallbackRegistry, mUpdateMonitor, mDumpManager, mUiBgExecutor,
                 mPowerManager, mTrustManager, mDeviceConfig, mNavigationModeController,
-                mInjectionInflationController);
+                mKeyguardDisplayManager);
         mViewMediator.start();
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 04e870d..a9484af 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -54,6 +54,7 @@
 import com.android.keyguard.KeyguardClockSwitchController;
 import com.android.keyguard.KeyguardStatusView;
 import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.dagger.KeyguardStatusViewComponent;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.classifier.FalsingManagerFake;
@@ -187,10 +188,16 @@
     @Mock
     private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
     @Mock
+    private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
+    @Mock
+    private KeyguardStatusViewComponent mKeyguardStatusViewComponent;
+    @Mock
     private KeyguardClockSwitchController mKeyguardClockSwitchController;
     @Mock
     private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
 
+    private FlingAnimationUtils.Builder mFlingAnimationUtilsBuilder;
+
     private NotificationPanelViewController mNotificationPanelViewController;
     private View.AccessibilityDelegate mAccessibiltyDelegate;
 
@@ -241,6 +248,10 @@
                 mock(NotificationRoundnessManager.class),
                 mStatusBarStateController,
                 new FalsingManagerFake());
+        when(mKeyguardStatusViewComponentFactory.build(any()))
+                .thenReturn(mKeyguardStatusViewComponent);
+        when(mKeyguardStatusViewComponent.getKeyguardClockSwitchController())
+                .thenReturn(mKeyguardClockSwitchController);
         mNotificationPanelViewController = new NotificationPanelViewController(mView,
                 mResources,
                 mInjectionInflationController,
@@ -254,9 +265,9 @@
                 flingAnimationUtilsBuilder, mStatusBarTouchableRegionManager,
                 mConversationNotificationManager, mMediaHiearchyManager,
                 mBiometricUnlockController, mStatusBarKeyguardViewManager,
-                () -> mKeyguardClockSwitchController,
                 mNotificationStackScrollLayoutController,
-                mNotificationAreaController);
+                mNotificationAreaController,
+                mKeyguardStatusViewComponentFactory);
         mNotificationPanelViewController.initDependencies(
                 mStatusBar,
                 mGroupManager,
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index b587dd3..d127172 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -594,15 +594,23 @@
                     if (pointerIndex < 0) {
                         return;
                     }
-                    final float deltaX =
-                            mReceivedPointerTracker.getReceivedPointerDownX(pointerId)
-                                    - rawEvent.getX(pointerIndex);
-                    final float deltaY =
-                            mReceivedPointerTracker.getReceivedPointerDownY(pointerId)
-                                    - rawEvent.getY(pointerIndex);
-                    final double moveDelta = Math.hypot(deltaX, deltaY);
-                    if (moveDelta < mTouchSlop) {
-                        return;
+                    // Require both fingers to have moved a certain amount before starting a drag.
+                    for (int index = 0; index < event.getPointerCount(); ++index) {
+                        int id = event.getPointerId(index);
+                        if (!mReceivedPointerTracker.isReceivedPointerDown(id)) {
+                            // Something is wrong with the event stream.
+                            Slog.e(LOG_TAG, "Invalid pointer id: " + id);
+                        }
+                        final float deltaX =
+                                mReceivedPointerTracker.getReceivedPointerDownX(id)
+                                        - rawEvent.getX(index);
+                        final float deltaY =
+                                mReceivedPointerTracker.getReceivedPointerDownY(id)
+                                        - rawEvent.getY(index);
+                        final double moveDelta = Math.hypot(deltaX, deltaY);
+                        if (moveDelta < mTouchSlop) {
+                            return;
+                        }
                     }
                 }
                 // More than one pointer so the user is not touch exploring
@@ -612,12 +620,20 @@
                 if (isDraggingGesture(event)) {
                     // Two pointers moving in the same direction within
                     // a given distance perform a drag.
-                    mState.startDragging();
                     computeDraggingPointerIdIfNeeded(event);
                     pointerIdBits = 1 << mDraggingPointerId;
                     event.setEdgeFlags(mReceivedPointerTracker.getLastReceivedDownEdgeFlags());
-                    mDispatcher.sendMotionEvent(
-                            event, ACTION_DOWN, rawEvent, pointerIdBits, policyFlags);
+                    MotionEvent downEvent = computeDownEventForDrag(event);
+                    if (downEvent != null) {
+                        mDispatcher.sendMotionEvent(
+                                downEvent, ACTION_DOWN, rawEvent, pointerIdBits, policyFlags);
+                        mDispatcher.sendMotionEvent(
+                                event, ACTION_MOVE, rawEvent, pointerIdBits, policyFlags);
+                    } else {
+                        mDispatcher.sendMotionEvent(
+                                event, ACTION_DOWN, rawEvent, pointerIdBits, policyFlags);
+                    }
+                    mState.startDragging();
                 } else {
                     // Two pointers moving arbitrary are delegated to the view hierarchy.
                     mState.startDelegating();
@@ -1004,6 +1020,49 @@
         return distance;
     }
 
+    /**
+     * Creates a down event using the down coordinates of the dragging pointer and other information
+     * from the supplied event. The supplied event's down time is adjusted to reflect the time when
+     * the dragging pointer initially went down.
+     */
+    private MotionEvent computeDownEventForDrag(MotionEvent event) {
+        // Creating a down event only  makes sense if we haven't started touch exploring yet.
+        if (mState.isTouchExploring()
+                || mDraggingPointerId == INVALID_POINTER_ID
+                || event == null) {
+            return null;
+        }
+        final float x = mReceivedPointerTracker.getReceivedPointerDownX(mDraggingPointerId);
+        final float y = mReceivedPointerTracker.getReceivedPointerDownY(mDraggingPointerId);
+        final long time = mReceivedPointerTracker.getReceivedPointerDownTime(mDraggingPointerId);
+        MotionEvent.PointerCoords[] coords = new MotionEvent.PointerCoords[1];
+        coords[0] = new MotionEvent.PointerCoords();
+        coords[0].x = x;
+        coords[0].y = y;
+        MotionEvent.PointerProperties[] properties = new MotionEvent.PointerProperties[1];
+        properties[0] = new MotionEvent.PointerProperties();
+        properties[0].id = mDraggingPointerId;
+        properties[0].toolType = MotionEvent.TOOL_TYPE_FINGER;
+        MotionEvent downEvent =
+                MotionEvent.obtain(
+                        time,
+                        time,
+                        ACTION_DOWN,
+                        1,
+                        properties,
+                        coords,
+                        event.getMetaState(),
+                        event.getButtonState(),
+                        event.getXPrecision(),
+                        event.getYPrecision(),
+                        event.getDeviceId(),
+                        event.getEdgeFlags(),
+                        event.getSource(),
+                        event.getFlags());
+        event.setDownTime(time);
+        return downEvent;
+    }
+
     public TouchState getState() {
         return mState;
     }
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java
index 1c4db12..59ba82e 100644
--- a/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java
@@ -34,6 +34,7 @@
 import android.content.Context;
 import android.content.pm.ParceledListSlice;
 import android.os.Binder;
+import android.os.IBinder;
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
 import android.util.Slog;
@@ -108,9 +109,9 @@
 
         @Override
         public void createPredictionSession(@NonNull AppPredictionContext context,
-                @NonNull AppPredictionSessionId sessionId) {
-            runForUserLocked("createPredictionSession", sessionId,
-                    (service) -> service.onCreatePredictionSessionLocked(context, sessionId));
+                @NonNull AppPredictionSessionId sessionId, @NonNull IBinder token) {
+            runForUserLocked("createPredictionSession", sessionId, (service) ->
+                    service.onCreatePredictionSessionLocked(context, sessionId, token));
         }
 
         @Override
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
index 7ee607c..735f420 100644
--- a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
@@ -30,6 +30,7 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ServiceInfo;
+import android.os.IBinder;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.provider.DeviceConfig;
@@ -44,8 +45,6 @@
 import com.android.server.infra.AbstractPerUserSystemService;
 import com.android.server.people.PeopleServiceInternal;
 
-import java.util.function.Consumer;
-
 /**
  * Per-user instance of {@link AppPredictionManagerService}.
  */
@@ -112,17 +111,24 @@
      */
     @GuardedBy("mLock")
     public void onCreatePredictionSessionLocked(@NonNull AppPredictionContext context,
-            @NonNull AppPredictionSessionId sessionId) {
-        if (!mSessionInfos.containsKey(sessionId)) {
-            mSessionInfos.put(sessionId, new AppPredictionSessionInfo(sessionId, context,
-                    DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI,
-                            PREDICT_USING_PEOPLE_SERVICE_PREFIX + context.getUiSurface(), false),
-                    this::removeAppPredictionSessionInfo));
-        }
-        final boolean serviceExists = resolveService(sessionId, s ->
-                s.onCreatePredictionSession(context, sessionId), true);
-        if (!serviceExists) {
-            mSessionInfos.remove(sessionId);
+            @NonNull AppPredictionSessionId sessionId, @NonNull IBinder token) {
+        final boolean usesPeopleService = DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI,
+                PREDICT_USING_PEOPLE_SERVICE_PREFIX + context.getUiSurface(), false);
+        final boolean serviceExists = resolveService(sessionId, false,
+                usesPeopleService, s -> s.onCreatePredictionSession(context, sessionId));
+        if (serviceExists && !mSessionInfos.containsKey(sessionId)) {
+            final AppPredictionSessionInfo sessionInfo = new AppPredictionSessionInfo(
+                    sessionId, context, usesPeopleService, token, () -> {
+                synchronized (mLock) {
+                    onDestroyPredictionSessionLocked(sessionId);
+                }
+            });
+            if (sessionInfo.linkToDeath()) {
+                mSessionInfos.put(sessionId, sessionInfo);
+            } else {
+                // destroy the session if calling process is already dead
+                onDestroyPredictionSessionLocked(sessionId);
+            }
         }
     }
 
@@ -132,7 +138,10 @@
     @GuardedBy("mLock")
     public void notifyAppTargetEventLocked(@NonNull AppPredictionSessionId sessionId,
             @NonNull AppTargetEvent event) {
-        resolveService(sessionId, s -> s.notifyAppTargetEvent(sessionId, event), false);
+        final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
+        if (sessionInfo == null) return;
+        resolveService(sessionId, false, sessionInfo.mUsesPeopleService,
+                s -> s.notifyAppTargetEvent(sessionId, event));
     }
 
     /**
@@ -141,8 +150,10 @@
     @GuardedBy("mLock")
     public void notifyLaunchLocationShownLocked(@NonNull AppPredictionSessionId sessionId,
             @NonNull String launchLocation, @NonNull ParceledListSlice targetIds) {
-        resolveService(sessionId, s ->
-                s.notifyLaunchLocationShown(sessionId, launchLocation, targetIds), false);
+        final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
+        if (sessionInfo == null) return;
+        resolveService(sessionId, false, sessionInfo.mUsesPeopleService,
+                s -> s.notifyLaunchLocationShown(sessionId, launchLocation, targetIds));
     }
 
     /**
@@ -151,7 +162,10 @@
     @GuardedBy("mLock")
     public void sortAppTargetsLocked(@NonNull AppPredictionSessionId sessionId,
             @NonNull ParceledListSlice targets, @NonNull IPredictionCallback callback) {
-        resolveService(sessionId, s -> s.sortAppTargets(sessionId, targets, callback), true);
+        final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
+        if (sessionInfo == null) return;
+        resolveService(sessionId, true, sessionInfo.mUsesPeopleService,
+                s -> s.sortAppTargets(sessionId, targets, callback));
     }
 
     /**
@@ -160,10 +174,12 @@
     @GuardedBy("mLock")
     public void registerPredictionUpdatesLocked(@NonNull AppPredictionSessionId sessionId,
             @NonNull IPredictionCallback callback) {
-        final boolean serviceExists = resolveService(sessionId, s ->
-                s.registerPredictionUpdates(sessionId, callback), false);
         final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
-        if (serviceExists && sessionInfo != null) {
+        if (sessionInfo == null) return;
+        final boolean serviceExists = resolveService(sessionId, false,
+                sessionInfo.mUsesPeopleService,
+                s -> s.registerPredictionUpdates(sessionId, callback));
+        if (serviceExists) {
             sessionInfo.addCallbackLocked(callback);
         }
     }
@@ -174,10 +190,12 @@
     @GuardedBy("mLock")
     public void unregisterPredictionUpdatesLocked(@NonNull AppPredictionSessionId sessionId,
             @NonNull IPredictionCallback callback) {
-        final boolean serviceExists = resolveService(sessionId, s ->
-                s.unregisterPredictionUpdates(sessionId, callback), false);
         final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
-        if (serviceExists && sessionInfo != null) {
+        if (sessionInfo == null) return;
+        final boolean serviceExists = resolveService(sessionId, false,
+                sessionInfo.mUsesPeopleService,
+                s -> s.unregisterPredictionUpdates(sessionId, callback));
+        if (serviceExists) {
             sessionInfo.removeCallbackLocked(callback);
         }
     }
@@ -187,7 +205,10 @@
      */
     @GuardedBy("mLock")
     public void requestPredictionUpdateLocked(@NonNull AppPredictionSessionId sessionId) {
-        resolveService(sessionId, s -> s.requestPredictionUpdate(sessionId), true);
+        final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
+        if (sessionInfo == null) return;
+        resolveService(sessionId, true, sessionInfo.mUsesPeopleService,
+                s -> s.requestPredictionUpdate(sessionId));
     }
 
     /**
@@ -195,12 +216,14 @@
      */
     @GuardedBy("mLock")
     public void onDestroyPredictionSessionLocked(@NonNull AppPredictionSessionId sessionId) {
-        final boolean serviceExists = resolveService(sessionId, s ->
-                s.onDestroyPredictionSession(sessionId), false);
-        final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
-        if (serviceExists && sessionInfo != null) {
-            sessionInfo.destroy();
+        if (isDebug()) {
+            Slog.d(TAG, "onDestroyPredictionSessionLocked(): sessionId=" + sessionId);
         }
+        final AppPredictionSessionInfo sessionInfo = mSessionInfos.remove(sessionId);
+        if (sessionInfo == null) return;
+        resolveService(sessionId, false, sessionInfo.mUsesPeopleService,
+                s -> s.onDestroyPredictionSession(sessionId));
+        sessionInfo.destroy();
     }
 
     @Override
@@ -291,27 +314,18 @@
         }
 
         for (AppPredictionSessionInfo sessionInfo : mSessionInfos.values()) {
-            sessionInfo.resurrectSessionLocked(this);
-        }
-    }
-
-    private void removeAppPredictionSessionInfo(AppPredictionSessionId sessionId) {
-        if (isDebug()) {
-            Slog.d(TAG, "removeAppPredictionSessionInfo(): sessionId=" + sessionId);
-        }
-        synchronized (mLock) {
-            mSessionInfos.remove(sessionId);
+            sessionInfo.resurrectSessionLocked(this, sessionInfo.mToken);
         }
     }
 
     @GuardedBy("mLock")
     @Nullable
-    protected boolean resolveService(@NonNull final AppPredictionSessionId sessionId,
-            @NonNull final AbstractRemoteService.AsyncRequest<IPredictionService> cb,
-            boolean sendImmediately) {
-        final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
-        if (sessionInfo == null) return false;
-        if (sessionInfo.mUsesPeopleService) {
+    protected boolean resolveService(
+            @NonNull final AppPredictionSessionId sessionId,
+            boolean sendImmediately,
+            boolean usesPeopleService,
+            @NonNull final AbstractRemoteService.AsyncRequest<IPredictionService> cb) {
+        if (usesPeopleService) {
             final IPredictionService service =
                     LocalServices.getService(PeopleServiceInternal.class);
             if (service != null) {
@@ -368,7 +382,9 @@
         private final AppPredictionContext mPredictionContext;
         private final boolean mUsesPeopleService;
         @NonNull
-        private final Consumer<AppPredictionSessionId> mRemoveSessionInfoAction;
+        final IBinder mToken;
+        @NonNull
+        final IBinder.DeathRecipient mDeathRecipient;
 
         private final RemoteCallbackList<IPredictionCallback> mCallbacks =
                 new RemoteCallbackList<IPredictionCallback>() {
@@ -388,14 +404,16 @@
                 @NonNull final AppPredictionSessionId id,
                 @NonNull final AppPredictionContext predictionContext,
                 final boolean usesPeopleService,
-                @NonNull final Consumer<AppPredictionSessionId> removeSessionInfoAction) {
+                @NonNull final IBinder token,
+                @NonNull final IBinder.DeathRecipient deathRecipient) {
             if (DEBUG) {
                 Slog.d(TAG, "Creating AppPredictionSessionInfo for session Id=" + id);
             }
             mSessionId = id;
             mPredictionContext = predictionContext;
             mUsesPeopleService = usesPeopleService;
-            mRemoveSessionInfoAction = removeSessionInfoAction;
+            mToken = token;
+            mDeathRecipient = deathRecipient;
         }
 
         void addCallbackLocked(IPredictionCallback callback) {
@@ -414,23 +432,38 @@
             mCallbacks.unregister(callback);
         }
 
+        boolean linkToDeath() {
+            try {
+                mToken.linkToDeath(mDeathRecipient, 0);
+            } catch (RemoteException e) {
+                if (DEBUG) {
+                    Slog.w(TAG, "Caller is dead before session can be started, sessionId: "
+                            + mSessionId);
+                }
+                return false;
+            }
+            return true;
+        }
+
         void destroy() {
             if (DEBUG) {
                 Slog.d(TAG, "Removing all callbacks for session Id=" + mSessionId
                         + " and " + mCallbacks.getRegisteredCallbackCount() + " callbacks.");
             }
+            if (mToken != null) {
+                mToken.unlinkToDeath(mDeathRecipient, 0);
+            }
             mCallbacks.kill();
-            mRemoveSessionInfoAction.accept(mSessionId);
         }
 
-        void resurrectSessionLocked(AppPredictionPerUserService service) {
+        void resurrectSessionLocked(AppPredictionPerUserService service, IBinder token) {
             int callbackCount = mCallbacks.getRegisteredCallbackCount();
             if (DEBUG) {
                 Slog.d(TAG, "Resurrecting remote service (" + service.getRemoteServiceLocked()
                         + ") for session Id=" + mSessionId + " and "
                         + callbackCount + " callbacks.");
             }
-            service.onCreatePredictionSessionLocked(mPredictionContext, mSessionId);
+            service.onCreatePredictionSessionLocked(mPredictionContext, mSessionId, token);
             mCallbacks.broadcast(
                     callback -> service.registerPredictionUpdatesLocked(mSessionId, callback));
         }
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 96d973e..687af10 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -85,6 +85,7 @@
 import java.util.Date;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
 
 public class VibratorService extends IVibratorService.Stub
         implements InputManager.InputDeviceListener {
@@ -114,6 +115,9 @@
     private static final VibrationAttributes DEFAULT_ATTRIBUTES =
             new VibrationAttributes.Builder().build();
 
+    // Used to generate globally unique vibration ids.
+    private final AtomicInteger mNextVibrationId = new AtomicInteger(1); // 0 = no callback
+
     // A mapping from the intensity adjustment to the scaling to apply, where the intensity
     // adjustment is defined as the delta between the default intensity level and the user selected
     // intensity level. It's important that we apply the scaling on the delta between the two so
@@ -171,34 +175,34 @@
     private int mRingIntensity;
     private SparseArray<Vibration> mAlwaysOnEffects = new SparseArray<>();
 
-    static native long vibratorInit();
+    static native long vibratorInit(OnCompleteListener listener);
 
     static native long vibratorGetFinalizer();
 
-    static native boolean vibratorExists(long controllerPtr);
+    static native boolean vibratorExists(long nativeServicePtr);
 
-    static native void vibratorOn(long controllerPtr, long milliseconds, Vibration vibration);
+    static native void vibratorOn(long nativeServicePtr, long milliseconds, long vibrationId);
 
-    static native void vibratorOff(long controllerPtr);
+    static native void vibratorOff(long nativeServicePtr);
 
-    static native void vibratorSetAmplitude(long controllerPtr, int amplitude);
+    static native void vibratorSetAmplitude(long nativeServicePtr, int amplitude);
 
-    static native int[] vibratorGetSupportedEffects(long controllerPtr);
+    static native int[] vibratorGetSupportedEffects(long nativeServicePtr);
 
-    static native int[] vibratorGetSupportedPrimitives(long controllerPtr);
+    static native int[] vibratorGetSupportedPrimitives(long nativeServicePtr);
 
     static native long vibratorPerformEffect(
-            long controllerPtr, long effect, long strength, Vibration vibration);
+            long nativeServicePtr, long effect, long strength, long vibrationId);
 
-    static native void vibratorPerformComposedEffect(long controllerPtr,
-            VibrationEffect.Composition.PrimitiveEffect[] effect, Vibration vibration);
+    static native void vibratorPerformComposedEffect(long nativeServicePtr,
+            VibrationEffect.Composition.PrimitiveEffect[] effect, long vibrationId);
 
-    static native void vibratorSetExternalControl(long controllerPtr, boolean enabled);
+    static native void vibratorSetExternalControl(long nativeServicePtr, boolean enabled);
 
-    static native long vibratorGetCapabilities(long controllerPtr);
-    static native void vibratorAlwaysOnEnable(long controllerPtr, long id, long effect,
+    static native long vibratorGetCapabilities(long nativeServicePtr);
+    static native void vibratorAlwaysOnEnable(long nativeServicePtr, long id, long effect,
             long strength);
-    static native void vibratorAlwaysOnDisable(long controllerPtr, long id);
+    static native void vibratorAlwaysOnDisable(long nativeServicePtr, long id);
 
     private final IUidObserver mUidObserver = new IUidObserver.Stub() {
         @Override public void onUidStateChanged(int uid, int procState, long procStateSeq,
@@ -220,12 +224,19 @@
         }
     };
 
+    /** Listener for vibration completion callbacks from native. */
+    public interface OnCompleteListener {
+
+        /** Callback triggered when vibration is complete, identified by {@link Vibration#id}. */
+        void onComplete(long vibrationId);
+    }
+
     /**
      * Holder for a vibration to be played. This class can be shared with native methods for
      * hardware callback support.
      */
-    @VisibleForTesting
-    public final class Vibration implements IBinder.DeathRecipient {
+    private final class Vibration implements IBinder.DeathRecipient {
+
         public final IBinder token;
         // Start time in CLOCK_BOOTTIME base.
         public final long startTime;
@@ -234,6 +245,7 @@
         // not to be affected by discontinuities created by RTC adjustments.
         public final long startTimeDebug;
         public final VibrationAttributes attrs;
+        public final long id;
         public final int uid;
         public final String opPkg;
         public final String reason;
@@ -248,6 +260,7 @@
                 VibrationAttributes attrs, int uid, String opPkg, String reason) {
             this.token = token;
             this.effect = effect;
+            this.id = mNextVibrationId.getAndIncrement();
             this.startTime = SystemClock.elapsedRealtime();
             this.startTimeDebug = System.currentTimeMillis();
             this.attrs = attrs;
@@ -268,19 +281,6 @@
             }
         }
 
-        /** Callback for when vibration is complete, to be called by native. */
-        @VisibleForTesting
-        public void onComplete() {
-            synchronized (mLock) {
-                if (this == mCurrentVibration) {
-                    if (DEBUG) {
-                        Slog.d(TAG, "Vibration finished by callback, cleaning up");
-                    }
-                    doCancelVibrateLocked();
-                }
-            }
-        }
-
         public boolean hasTimeoutLongerThan(long millis) {
             final long duration = effect.getDuration();
             return duration >= 0 && duration > millis;
@@ -385,14 +385,14 @@
         mNativeWrapper = injector.getNativeWrapper();
         mH = injector.createHandler(Looper.myLooper());
 
-        long controllerPtr = mNativeWrapper.vibratorInit();
+        long nativeServicePtr = mNativeWrapper.vibratorInit(this::onVibrationComplete);
         long finalizerPtr = mNativeWrapper.vibratorGetFinalizer();
 
         if (finalizerPtr != 0) {
             NativeAllocationRegistry registry =
                     NativeAllocationRegistry.createMalloced(
                             VibratorService.class.getClassLoader(), finalizerPtr);
-            registry.registerNativeAllocation(this, controllerPtr);
+            registry.registerNativeAllocation(this, nativeServicePtr);
         }
 
         // Reset the hardware to a default state, in case this is a runtime
@@ -549,6 +549,19 @@
         }
     }
 
+    /** Callback for when vibration is complete, to be called by native. */
+    @VisibleForTesting
+    public void onVibrationComplete(long vibrationId) {
+        synchronized (mLock) {
+            if (mCurrentVibration != null && mCurrentVibration.id == vibrationId) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Vibration finished by callback, cleaning up");
+                }
+                doCancelVibrateLocked();
+            }
+        }
+    }
+
     @Override // Binder call
     public boolean hasVibrator() {
         return doVibratorExists();
@@ -1266,18 +1279,18 @@
         return mNativeWrapper.vibratorExists();
     }
 
-    /** Vibrates with native callback trigger for {@link Vibration#onComplete()}. */
+    /** Vibrates with native callback trigger for {@link #onVibrationComplete(long)}. */
     private void doVibratorOn(long millis, int amplitude, Vibration vib) {
-        doVibratorOn(millis, amplitude, vib.uid, vib.attrs, vib);
+        doVibratorOn(millis, amplitude, vib.uid, vib.attrs, vib.id);
     }
 
     /** Vibrates without native callback. */
     private void doVibratorOn(long millis, int amplitude, int uid, VibrationAttributes attrs) {
-        doVibratorOn(millis, amplitude, uid, attrs, /* vib= */ null);
+        doVibratorOn(millis, amplitude, uid, attrs, /* vibrationId= */ 0);
     }
 
     private void doVibratorOn(long millis, int amplitude, int uid, VibrationAttributes attrs,
-            @Nullable Vibration vib) {
+            long vibrationId) {
         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOn");
         try {
             synchronized (mInputDeviceVibrators) {
@@ -1299,7 +1312,7 @@
                     // Note: ordering is important here! Many haptic drivers will reset their
                     // amplitude when enabled, so we always have to enable first, then set the
                     // amplitude.
-                    mNativeWrapper.vibratorOn(millis, vib);
+                    mNativeWrapper.vibratorOn(millis, vibrationId);
                     doVibratorSetAmplitude(amplitude);
                 }
             }
@@ -1348,7 +1361,7 @@
             // Input devices don't support prebaked effect, so skip trying it with them.
             if (!usingInputDeviceVibrators) {
                 long duration = mNativeWrapper.vibratorPerformEffect(
-                        prebaked.getId(), prebaked.getEffectStrength(), vib);
+                        prebaked.getId(), prebaked.getEffectStrength(), vib.id);
                 if (duration > 0) {
                     noteVibratorOnLocked(vib.uid, duration);
                     return;
@@ -1395,7 +1408,7 @@
 
             PrimitiveEffect[] primitiveEffects =
                     composed.getPrimitiveEffects().toArray(new PrimitiveEffect[0]);
-            mNativeWrapper.vibratorPerformComposedEffect(primitiveEffects, vib);
+            mNativeWrapper.vibratorPerformComposedEffect(primitiveEffects, vib.id);
 
             // Composed effects don't actually give us an estimated duration, so we just guess here.
             noteVibratorOnLocked(vib.uid, 10 * primitiveEffects.length);
@@ -1726,20 +1739,20 @@
     @VisibleForTesting
     public static class NativeWrapper {
 
-        private long mNativeControllerPtr = 0;
+        private long mNativeServicePtr = 0;
 
         /** Checks if vibrator exists on device. */
         public boolean vibratorExists() {
-            return VibratorService.vibratorExists(mNativeControllerPtr);
+            return VibratorService.vibratorExists(mNativeServicePtr);
         }
 
         /**
          * Returns native pointer to newly created controller and initializes connection to vibrator
          * HAL service.
          */
-        public long vibratorInit() {
-            mNativeControllerPtr = VibratorService.vibratorInit();
-            return mNativeControllerPtr;
+        public long vibratorInit(OnCompleteListener listener) {
+            mNativeServicePtr = VibratorService.vibratorInit(listener);
+            return mNativeServicePtr;
         }
 
         /** Returns pointer to native finalizer function to be called by GC. */
@@ -1748,60 +1761,61 @@
         }
 
         /** Turns vibrator on for given time. */
-        public void vibratorOn(long milliseconds, @Nullable Vibration vibration) {
-            VibratorService.vibratorOn(mNativeControllerPtr, milliseconds, vibration);
+        public void vibratorOn(long milliseconds, long vibrationId) {
+            VibratorService.vibratorOn(mNativeServicePtr, milliseconds, vibrationId);
         }
 
         /** Turns vibrator off. */
         public void vibratorOff() {
-            VibratorService.vibratorOff(mNativeControllerPtr);
+            VibratorService.vibratorOff(mNativeServicePtr);
         }
 
         /** Sets the amplitude for the vibrator to run. */
         public void vibratorSetAmplitude(int amplitude) {
-            VibratorService.vibratorSetAmplitude(mNativeControllerPtr, amplitude);
+            VibratorService.vibratorSetAmplitude(mNativeServicePtr, amplitude);
         }
 
         /** Returns all predefined effects supported by the device vibrator. */
         public int[] vibratorGetSupportedEffects() {
-            return VibratorService.vibratorGetSupportedEffects(mNativeControllerPtr);
+            return VibratorService.vibratorGetSupportedEffects(mNativeServicePtr);
         }
 
         /** Returns all compose primitives supported by the device vibrator. */
         public int[] vibratorGetSupportedPrimitives() {
-            return VibratorService.vibratorGetSupportedPrimitives(mNativeControllerPtr);
+            return VibratorService.vibratorGetSupportedPrimitives(mNativeServicePtr);
         }
 
         /** Turns vibrator on to perform one of the supported effects. */
-        public long vibratorPerformEffect(long effect, long strength, Vibration vibration) {
+        public long vibratorPerformEffect(long effect, long strength, long vibrationId) {
             return VibratorService.vibratorPerformEffect(
-                    mNativeControllerPtr, effect, strength, vibration);
+                    mNativeServicePtr, effect, strength, vibrationId);
         }
 
         /** Turns vibrator on to perform one of the supported composed effects. */
         public void vibratorPerformComposedEffect(
-                VibrationEffect.Composition.PrimitiveEffect[] effect, Vibration vibration) {
-            VibratorService.vibratorPerformComposedEffect(mNativeControllerPtr, effect, vibration);
+                VibrationEffect.Composition.PrimitiveEffect[] effect, long vibrationId) {
+            VibratorService.vibratorPerformComposedEffect(mNativeServicePtr, effect,
+                    vibrationId);
         }
 
         /** Enabled the device vibrator to be controlled by another service. */
         public void vibratorSetExternalControl(boolean enabled) {
-            VibratorService.vibratorSetExternalControl(mNativeControllerPtr, enabled);
+            VibratorService.vibratorSetExternalControl(mNativeServicePtr, enabled);
         }
 
         /** Returns all capabilities of the device vibrator. */
         public long vibratorGetCapabilities() {
-            return VibratorService.vibratorGetCapabilities(mNativeControllerPtr);
+            return VibratorService.vibratorGetCapabilities(mNativeServicePtr);
         }
 
         /** Enable always-on vibration with given id and effect. */
         public void vibratorAlwaysOnEnable(long id, long effect, long strength) {
-            VibratorService.vibratorAlwaysOnEnable(mNativeControllerPtr, id, effect, strength);
+            VibratorService.vibratorAlwaysOnEnable(mNativeServicePtr, id, effect, strength);
         }
 
         /** Disable always-on vibration for given id. */
         public void vibratorAlwaysOnDisable(long id) {
-            VibratorService.vibratorAlwaysOnDisable(mNativeControllerPtr, id);
+            VibratorService.vibratorAlwaysOnDisable(mNativeServicePtr, id);
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6e1e3d0..2d803437 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -83,6 +83,7 @@
 import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER;
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
 
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKGROUND_CHECK;
@@ -117,7 +118,6 @@
 import static com.android.server.am.MemoryStatUtil.hasMemcg;
 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
@@ -319,6 +319,7 @@
 import com.android.internal.os.ProcessCpuTracker;
 import com.android.internal.os.TransferPipe;
 import com.android.internal.os.Zygote;
+import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FastPrintWriter;
@@ -4946,9 +4947,8 @@
                 notifyPackageUse(instr.mClass.getPackageName(),
                                  PackageManager.NOTIFY_PACKAGE_USE_INSTRUMENTATION);
             }
-            if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Binding proc "
-                    + processName + " with config "
-                    + app.getWindowProcessController().getConfiguration());
+            ProtoLog.v(WM_DEBUG_CONFIGURATION, "Binding proc %s with config %s",
+                    processName, app.getWindowProcessController().getConfiguration());
             ApplicationInfo appInfo = instr != null ? instr.mTargetInfo : app.info;
             app.compat = compatibilityInfoForPackage(appInfo);
 
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
index 3f949ba..653323d 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
@@ -25,7 +25,7 @@
  * A helper class to build {@link HdmiCecMessage} from various cec commands.
  */
 public class HdmiCecMessageBuilder {
-    private static final int OSD_NAME_MAX_LENGTH = 13;
+    private static final int OSD_NAME_MAX_LENGTH = 14;
 
     private HdmiCecMessageBuilder() {}
 
diff --git a/services/core/java/com/android/server/location/LocationProviderManager.java b/services/core/java/com/android/server/location/LocationProviderManager.java
index 05aa315..06105bf 100644
--- a/services/core/java/com/android/server/location/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/LocationProviderManager.java
@@ -314,6 +314,14 @@
         }
 
         @Override
+        public final <Listener> void onOperationFailure(ListenerOperation<Listener> operation,
+                Exception e) {
+            synchronized (mLock) {
+                super.onOperationFailure(operation, e);
+            }
+        }
+
+        @Override
         public final LocationRequest getRequest() {
             return mProviderLocationRequest;
         }
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index dfdf115..0c4eaec3 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -88,7 +88,6 @@
 import java.util.Set;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
-import java.util.function.Consumer;
 import java.util.function.Predicate;
 import java.util.function.Supplier;
 
@@ -189,7 +188,6 @@
      * Validates the signature used to sign the container of the new apex package
      *
      * @param newApexPkg The new apex package that is being installed
-     * @throws PackageManagerException
      */
     private void validateApexSignature(PackageInfo newApexPkg)
             throws PackageManagerException {
@@ -725,12 +723,9 @@
         return ret;
     }
 
-    @NonNull
     private PackageInstallerSession createAndWriteApkSession(
-            @NonNull PackageInstallerSession originalSession, boolean preReboot)
-            throws PackageManagerException {
-        final int errorCode = preReboot ? SessionInfo.STAGED_SESSION_VERIFICATION_FAILED
-                : SessionInfo.STAGED_SESSION_ACTIVATION_FAILED;
+            PackageInstallerSession originalSession) throws PackageManagerException {
+        final int errorCode = SessionInfo.STAGED_SESSION_ACTIVATION_FAILED;
         if (originalSession.stageDir == null) {
             Slog.wtf(TAG, "Attempting to install a staged APK session with no staging dir");
             throw new PackageManagerException(errorCode,
@@ -746,12 +741,7 @@
         PackageInstaller.SessionParams params = originalSession.params.copy();
         params.isStaged = false;
         params.installFlags |= PackageManager.INSTALL_STAGED;
-        if (preReboot) {
-            params.installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK;
-            params.installFlags |= PackageManager.INSTALL_DRY_RUN;
-        } else {
-            params.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION;
-        }
+        params.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION;
         try {
             int apkSessionId = mPi.createSession(
                     params, originalSession.getInstallerPackageName(),
@@ -783,12 +773,10 @@
      * apks in the given session. Only parent session is returned for multi-package session.
      */
     @Nullable
-    private PackageInstallerSession extractApksInSession(PackageInstallerSession session,
-            boolean preReboot) throws PackageManagerException {
-        final int errorCode = preReboot ? SessionInfo.STAGED_SESSION_VERIFICATION_FAILED
-                : SessionInfo.STAGED_SESSION_ACTIVATION_FAILED;
+    private PackageInstallerSession extractApksInSession(PackageInstallerSession session)
+            throws PackageManagerException {
         if (!session.isMultiPackage() && !isApexSession(session)) {
-            return createAndWriteApkSession(session, preReboot);
+            return createAndWriteApkSession(session);
         } else if (session.isMultiPackage()) {
             // For multi-package staged sessions containing APKs, we identify which child sessions
             // contain an APK, and with those then create a new multi-package group of sessions,
@@ -810,10 +798,6 @@
             }
             final PackageInstaller.SessionParams params = session.params.copy();
             params.isStaged = false;
-            if (preReboot) {
-                params.installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK;
-                params.installFlags |= PackageManager.INSTALL_DRY_RUN;
-            }
             final int apkParentSessionId = mPi.createSession(
                     params, session.getInstallerPackageName(), session.getInstallerAttributionTag(),
                     session.userId);
@@ -823,18 +807,18 @@
             } catch (IOException e) {
                 Slog.e(TAG, "Unable to prepare multi-package session for staged session "
                         + session.sessionId);
-                throw new PackageManagerException(errorCode,
+                throw new PackageManagerException(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
                         "Unable to prepare multi-package session for staged session");
             }
 
             for (int i = 0, size = childSessions.size(); i < size; i++) {
                 final PackageInstallerSession apkChildSession = createAndWriteApkSession(
-                        childSessions.get(i), preReboot);
+                        childSessions.get(i));
                 try {
                     apkParentSession.addChildSessionId(apkChildSession.sessionId);
                 } catch (IllegalStateException e) {
                     Slog.e(TAG, "Failed to add a child session for installing the APK files", e);
-                    throw new PackageManagerException(errorCode,
+                    throw new PackageManagerException(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
                             "Failed to add a child session " + apkChildSession.sessionId);
                 }
             }
@@ -877,11 +861,9 @@
         }
     }
 
-    private void installApksInSession(@NonNull PackageInstallerSession session)
+    private void installApksInSession(PackageInstallerSession session)
             throws PackageManagerException {
-
-        final PackageInstallerSession apksToInstall = extractApksInSession(
-                session, /* preReboot */ false);
+        final PackageInstallerSession apksToInstall = extractApksInSession(session);
         if (apksToInstall == null) {
             return;
         }
@@ -1047,7 +1029,7 @@
     /**
      * <p>Abort committed staged session
      *
-     * <p>This method must be called while holding {@link PackageInstallerSession.mLock}.
+     * <p>This method must be called while holding {@link PackageInstallerSession#mLock}.
      *
      * <p>The method returns {@code false} to indicate it is not safe to clean up the session from
      * system yet. When it is safe, the method returns {@code true}.
@@ -1218,7 +1200,7 @@
         }
     }
 
-    void markStagedSessionsAsSuccessful() {
+    private void markStagedSessionsAsSuccessful() {
         synchronized (mSuccessfulStagedSessionIds) {
             for (int i = 0; i < mSuccessfulStagedSessionIds.size(); i++) {
                 mApexManager.markStagedSessionSuccessful(mSuccessfulStagedSessionIds.get(i));
@@ -1242,30 +1224,10 @@
         mFailureReasonFile.delete();
     }
 
-    private static class LocalIntentReceiverAsync {
-        final Consumer<Intent> mConsumer;
-
-        LocalIntentReceiverAsync(Consumer<Intent> consumer) {
-            mConsumer = consumer;
-        }
-
-        private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
-            @Override
-            public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
-                    IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
-                mConsumer.accept(intent);
-            }
-        };
-
-        public IntentSender getIntentSender() {
-            return new IntentSender((IIntentSender) mLocalSender);
-        }
-    }
-
     private static class LocalIntentReceiverSync {
         private final LinkedBlockingQueue<Intent> mResult = new LinkedBlockingQueue<>();
 
-        private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
+        private final IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
             @Override
             public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
                     IIntentReceiver finishedReceiver, String requiredPermission,
@@ -1300,14 +1262,14 @@
     }
 
     // TODO(b/136257624): Temporary API to let PMS communicate with StagingManager. When all
-    //  verification logic is extraced out of StagingManager into PMS, we can remove
+    //  verification logic is extracted out of StagingManager into PMS, we can remove
     //  this.
     void notifyVerificationComplete(int sessionId) {
         mPreRebootVerificationHandler.onPreRebootVerificationComplete(sessionId);
     }
 
     // TODO(b/136257624): Temporary API to let PMS communicate with StagingManager. When all
-    //  verification logic is extraced out of StagingManager into PMS, we can remove
+    //  verification logic is extracted out of StagingManager into PMS, we can remove
     //  this.
     void notifyPreRebootVerification_Apk_Complete(int sessionId) {
         mPreRebootVerificationHandler.notifyPreRebootVerification_Apk_Complete(sessionId);
@@ -1526,35 +1488,6 @@
             session.verifyStagedSession();
         }
 
-        private void verifyApksInSession(PackageInstallerSession session)
-                throws PackageManagerException {
-
-            final PackageInstallerSession apksToVerify = extractApksInSession(
-                    session,  /* preReboot */ true);
-            if (apksToVerify == null) {
-                return;
-            }
-
-            final LocalIntentReceiverAsync receiver = new LocalIntentReceiverAsync(
-                    (Intent result) -> {
-                        final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
-                                PackageInstaller.STATUS_FAILURE);
-                        if (status != PackageInstaller.STATUS_SUCCESS) {
-                            final String errorMessage = result.getStringExtra(
-                                    PackageInstaller.EXTRA_STATUS_MESSAGE);
-                            Slog.e(TAG, "Failure to verify APK staged session "
-                                    + session.sessionId + " [" + errorMessage + "]");
-                            onPreRebootVerificationFailure(session,
-                                    SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, errorMessage);
-                            return;
-                        }
-                        mPreRebootVerificationHandler.notifyPreRebootVerification_Apk_Complete(
-                                session.sessionId);
-                    });
-
-            apksToVerify.commit(receiver.getIntentSender(), false);
-        }
-
         /**
          * Pre-reboot verification state for wrapping up:
          * <p><ul>
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index c1aebd3..d137fd0 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -84,7 +84,6 @@
 import android.security.GateKeeper;
 import android.service.gatekeeper.IGateKeeperService;
 import android.stats.devicepolicy.DevicePolicyEnums;
-import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
@@ -142,6 +141,7 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * Service for {@link UserManager}.
@@ -159,10 +159,6 @@
     private static final String LOG_TAG = "UserManagerService";
     static final boolean DBG = false; // DO NOT SUBMIT WITH TRUE
     private static final boolean DBG_WITH_STACKTRACE = false; // DO NOT SUBMIT WITH TRUE
-
-    // TODO(b/164159026): remove once owner_name issue on automotive is fixed
-    // Can be used to track getUsers() / userWithNameLU() behavior
-    public static final boolean DBG_CACHED_USERINFOS = false; // DO NOT SUBMIT WITH TRUE
     // Can be used for manual testing of id recycling
     private static final boolean RELEASE_DELETED_USER_ID = false; // DO NOT SUBMIT WITH TRUE
 
@@ -276,25 +272,6 @@
     private DevicePolicyManagerInternal mDevicePolicyManagerInternal;
 
     /**
-     * Reference to the {@link UserHandle#SYSTEM} user's UserInfo; it's {@code name} was either
-     * manually set, or it's {@code null}.
-     *
-     * <p>The reference is set just once, but it's {@code name} is updated when it's manually set.
-     */
-    @GuardedBy("mUsersLock")
-    private UserInfo mSystemUserInfo;
-
-    /**
-     * Reference to the {@link UserHandle#SYSTEM} user's UserInfo, with its {@code name} set to
-     * the localized value of {@code owner_name}.
-     *
-     * <p>The reference is set just once, but it's {@code name} is updated everytime the reference
-     * is used and the locale changed.
-     */
-    @GuardedBy("mUsersLock")
-    private UserInfo mSystemUserInfoWithName;
-
-    /**
      * Internal non-parcelable wrapper for UserInfo that is not exposed to other system apps.
      */
     @VisibleForTesting
@@ -467,6 +444,11 @@
         }
     };
 
+    // TODO(b/161915546): remove once userWithName() is fixed / removed
+    // Use to debug / dump when user 0 is allocated at userWithName()
+    public static final boolean DBG_ALLOCATION = false; // DO NOT SUBMIT WITH TRUE
+    public final AtomicInteger mUser0Allocations;
+
     /**
      * Start an {@link IntentSender} when user is unlocked after disabling quiet mode.
      *
@@ -656,6 +638,7 @@
         LocalServices.addService(UserManagerInternal.class, mLocalService);
         mLockPatternUtils = new LockPatternUtils(mContext);
         mUserStates.put(UserHandle.USER_SYSTEM, UserState.STATE_BOOTING);
+        mUser0Allocations = DBG_ALLOCATION ? new AtomicInteger() : null;
     }
 
     void systemReady() {
@@ -801,7 +784,7 @@
                         || (excludePreCreated && ui.preCreated)) {
                     continue;
                 }
-                users.add(userWithNameLU(ui));
+                users.add(userWithName(ui));
             }
             return users;
         }
@@ -870,7 +853,7 @@
                 userInfo.name = null;
                 userInfo.iconPath = null;
             } else {
-                userInfo = userWithNameLU(userInfo);
+                userInfo = userWithName(userInfo);
             }
             users.add(userInfo);
         }
@@ -1327,57 +1310,26 @@
     public UserInfo getUserInfo(@UserIdInt int userId) {
         checkManageOrCreateUsersPermission("query user");
         synchronized (mUsersLock) {
-            return userWithNameLU(getUserInfoLU(userId));
+            return userWithName(getUserInfoLU(userId));
         }
     }
 
     /**
      * Returns a UserInfo object with the name filled in, for Owner, or the original
      * if the name is already set.
-     *
-     * <p>Note:</p> the Owner name is localized, so the current value must be checked every time
-     * this method is called.
      */
-    private UserInfo userWithNameLU(UserInfo orig) {
-        // Only the system user uses the owner_name string.
-        if (orig == null || orig.id != UserHandle.USER_SYSTEM) return orig;
-
-        if (mSystemUserInfo == null) {
-            mSystemUserInfo = orig;
-            if (DBG_CACHED_USERINFOS) {
-                Slog.d(LOG_TAG, "Set mSystemUserInfo:" + mSystemUserInfo.toFullString());
+    private UserInfo userWithName(UserInfo orig) {
+        if (orig != null && orig.name == null && orig.id == UserHandle.USER_SYSTEM) {
+            if (DBG_ALLOCATION) {
+                final int number = mUser0Allocations.incrementAndGet();
+                Slog.w(LOG_TAG, "System user instantiated at least " + number + " times");
             }
+            UserInfo withName = new UserInfo(orig);
+            withName.name = getOwnerName();
+            return withName;
+        } else {
+            return orig;
         }
-
-        if (mSystemUserInfo.name != null) {
-            if (DBG_CACHED_USERINFOS) {
-                Slog.v(LOG_TAG, "Returning mSystemUserInfo: " + mSystemUserInfo.toFullString());
-            }
-            return mSystemUserInfo;
-        }
-
-        final String ownerName = getOwnerName();
-
-        if (mSystemUserInfoWithName == null) {
-            mSystemUserInfoWithName = new UserInfo(orig);
-            mSystemUserInfoWithName.name = ownerName;
-            if (DBG_CACHED_USERINFOS) {
-                Slog.d(LOG_TAG, "Set mSystemUserInfoWithName: "
-                        + mSystemUserInfoWithName.toFullString());
-            }
-        } else if (!TextUtils.equals(ownerName, mSystemUserInfoWithName.name)) {
-            if (DBG_CACHED_USERINFOS) {
-                Slog.d(LOG_TAG, "Updating mSystemUserInfoWithName.name from  "
-                        + mSystemUserInfoWithName.name + " to " + ownerName);
-            }
-            mSystemUserInfoWithName.name = ownerName;
-        }
-
-        if (DBG_CACHED_USERINFOS) {
-            Slog.v(LOG_TAG, "Returning mSystemUserInfoWithName:"
-                    + mSystemUserInfoWithName.toFullString());
-        }
-        return mSystemUserInfoWithName;
     }
 
     /** Returns whether the given user type is one of the FULL user types. */
@@ -1530,7 +1482,7 @@
         }
         final int userId = UserHandle.getUserId(Binder.getCallingUid());
         synchronized (mUsersLock) {
-            UserInfo userInfo = userWithNameLU(getUserInfoLU(userId));
+            UserInfo userInfo = userWithName(getUserInfoLU(userId));
             return userInfo == null ? "" : userInfo.name;
         }
     }
@@ -1645,13 +1597,6 @@
             Slog.w(LOG_TAG, "getUserInfo: unknown user #" + userId);
             return null;
         }
-
-        if (DBG_CACHED_USERINFOS && userId == UserHandle.USER_SYSTEM && userData != null
-                && userData.info != mSystemUserInfo) {
-            Slog.wtf(LOG_TAG, "getUserInfoLU(): system user on userData (" + userData.info
-                    + ") is not the same as mSystemUserInfo (" + mSystemUserInfo + ")");
-        }
-
         return userData != null ? userData.info : null;
     }
 
@@ -4910,15 +4855,8 @@
         pw.println("  Is headless-system mode: " + UserManager.isHeadlessSystemUserMode());
         pw.println("  User version: " + mUserVersion);
         pw.println("  Owner name: " + getOwnerName());
-        if (mSystemUserInfo == null) {
-            pw.println("  (mSystemUserInfo not set)");
-        } else {
-            pw.println("  System user: " +  mSystemUserInfo.toFullString());
-        }
-        if (mSystemUserInfoWithName == null) {
-            pw.println("  (mSystemUserInfoWithName not set)");
-        } else {
-            pw.println("  System user (with name): " +  mSystemUserInfoWithName.toFullString());
+        if (DBG_ALLOCATION) {
+            pw.println("  System user allocations: " + mUser0Allocations.get());
         }
 
         // Dump UserTypes
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 548cd70..137c587 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2219,11 +2219,6 @@
     }
 
     @Override
-    public int getMaxWallpaperLayer() {
-        return getWindowLayerFromTypeLw(TYPE_NOTIFICATION_SHADE);
-    }
-
-    @Override
     public boolean isKeyguardHostWindow(WindowManager.LayoutParams attrs) {
         return attrs.type == TYPE_NOTIFICATION_SHADE;
     }
@@ -5324,15 +5319,6 @@
     }
 
     @Override
-    public boolean isTopLevelWindow(int windowType) {
-        if (windowType >= WindowManager.LayoutParams.FIRST_SUB_WINDOW
-                && windowType <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
-            return (windowType == WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG);
-        }
-        return true;
-    }
-
-    @Override
     public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         proto.write(ROTATION_MODE, mDefaultDisplayRotation.getUserRotationMode());
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 651eafd..b96d65c 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -67,7 +67,6 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.WindowConfiguration;
 import android.content.Context;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
@@ -90,7 +89,6 @@
 import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IShortcutService;
 import com.android.server.wm.DisplayRotation;
-import com.android.server.wm.WindowFrames;
 
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -181,92 +179,11 @@
      */
     public interface WindowState {
         /**
-         * Return the uid of the app that owns this window.
-         */
-        int getOwningUid();
-
-        /**
          * Return the package name of the app that owns this window.
          */
         String getOwningPackage();
 
         /**
-         * Perform standard frame computation.  The result can be obtained with
-         * getFrame() if so desired.  Must be called with the window manager
-         * lock held.
-         *
-         */
-        public void computeFrameLw();
-
-        /**
-         * Retrieve the current frame of the window that has been assigned by
-         * the window manager.  Must be called with the window manager lock held.
-         *
-         * @return Rect The rectangle holding the window frame.
-         */
-        public Rect getFrameLw();
-
-        /**
-         * Retrieve the frame of the display that this window was last
-         * laid out in.  Must be called with the
-         * window manager lock held.
-         *
-         * @return Rect The rectangle holding the display frame.
-         */
-        public Rect getDisplayFrameLw();
-
-        /**
-         * Retrieve the frame of the content area that this window was last
-         * laid out in.  This is the area in which the content of the window
-         * should be placed.  It will be smaller than the display frame to
-         * account for screen decorations such as a status bar or soft
-         * keyboard.  Must be called with the
-         * window manager lock held.
-         *
-         * @return Rect The rectangle holding the content frame.
-         */
-        public Rect getContentFrameLw();
-
-        /**
-         * Retrieve the frame of the visible area that this window was last
-         * laid out in.  This is the area of the screen in which the window
-         * will actually be fully visible.  It will be smaller than the
-         * content frame to account for transient UI elements blocking it
-         * such as an input method's candidates UI.  Must be called with the
-         * window manager lock held.
-         *
-         * @return Rect The rectangle holding the visible frame.
-         */
-        public Rect getVisibleFrameLw();
-
-        /**
-         * Returns true if this window is waiting to receive its given
-         * internal insets from the client app, and so should not impact the
-         * layout of other windows.
-         */
-        public boolean getGivenInsetsPendingLw();
-
-        /**
-         * Retrieve the insets given by this window's client for the content
-         * area of windows behind it.  Must be called with the
-         * window manager lock held.
-         *
-         * @return Rect The left, top, right, and bottom insets, relative
-         * to the window's frame, of the actual contents.
-         */
-        public Rect getGivenContentInsetsLw();
-
-        /**
-         * Retrieve the insets given by this window's client for the visible
-         * area of windows behind it.  Must be called with the
-         * window manager lock held.
-         *
-         * @return Rect The left, top, right, and bottom insets, relative
-         * to the window's frame, of the actual visible area.
-         */
-        public Rect getGivenVisibleInsetsLw();
-
-        /**
          * Retrieve the current LayoutParams of the window.
          *
          * @return WindowManager.LayoutParams The window's internal LayoutParams
@@ -275,17 +192,6 @@
         public WindowManager.LayoutParams getAttrs();
 
         /**
-         * Retrieve the current system UI visibility flags associated with
-         * this window.
-         */
-        public int getSystemUiVisibility();
-
-        /**
-         * Get the layer at which this window's surface will be Z-ordered.
-         */
-        public int getSurfaceLayer();
-
-        /**
          * Retrieve the type of the top-level window.
          *
          * @return the base type of the parent window if attached or its own type otherwise
@@ -301,22 +207,6 @@
         public IApplicationToken getAppToken();
 
         /**
-         * Return true if this window is participating in voice interaction.
-         */
-        public boolean isVoiceInteraction();
-
-        /**
-         * Return true if, at any point, the application token associated with
-         * this window has actually displayed any windows.  This is most useful
-         * with the "starting up" window to determine if any windows were
-         * displayed when it is closed.
-         *
-         * @return Returns true if one or more windows have been displayed,
-         *         else false.
-         */
-        public boolean hasAppShownWindows();
-
-        /**
          * Is this window visible?  It is not visible if there is no
          * surface, or we are in the process of running an exit animation
          * that will remove the surface.
@@ -324,42 +214,12 @@
         boolean isVisibleLw();
 
         /**
-         * Is this window currently visible to the user on-screen?  It is
-         * displayed either if it is visible or it is currently running an
-         * animation before no longer being visible.  Must be called with the
-         * window manager lock held.
-         */
-        boolean isDisplayedLw();
-
-        /**
          * Return true if this window (or a window it is attached to, but not
          * considering its app token) is currently animating.
          */
         boolean isAnimatingLw();
 
         /**
-         * Is this window considered to be gone for purposes of layout?
-         */
-        boolean isGoneForLayoutLw();
-
-        /**
-         * Returns true if the window has a surface that it has drawn a
-         * complete UI in to. Note that this is different from {@link #hasDrawnLw()}
-         * in that it also returns true if the window is READY_TO_SHOW, but was not yet
-         * promoted to HAS_DRAWN.
-         */
-        boolean isDrawnLw();
-
-        /**
-         * Returns true if this window has been shown on screen at some time in
-         * the past.  Must be called with the window manager lock held.
-         *
-         * @deprecated Use {@link #isDrawnLw} or any of the other drawn/visibility methods.
-         */
-        @Deprecated
-        public boolean hasDrawnLw();
-
-        /**
          * Can be called by the policy to force a window to be hidden,
          * regardless of whether the client or window manager would like
          * it shown.  Must be called with the window manager lock held.
@@ -377,51 +237,12 @@
         public boolean showLw(boolean doAnimation);
 
         /**
-         * Check whether the process hosting this window is currently alive.
-         */
-        public boolean isAlive();
-
-        /**
-         * Check if window is on {@link Display#DEFAULT_DISPLAY}.
-         * @return true if window is on default display.
-         */
-        public boolean isDefaultDisplay();
-
-        /**
          * Check whether the window is currently dimming.
          */
         public boolean isDimming();
 
-        /**
-         * Returns true if the window is letterboxed for the display cutout.
-         */
-        default boolean isLetterboxedForDisplayCutoutLw() {
-            return false;
-        }
-
-        /** @return the current windowing mode of this window. */
-        int getWindowingMode();
-
-        /**
-         * Returns the {@link WindowConfiguration.ActivityType} associated with the configuration
-         * of this window.
-         */
-        default int getActivityType() {
-            return WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-        }
-
-        /**
-         * Returns true if the window is current in multi-windowing mode. i.e. it shares the
-         * screen with other application windows.
-         */
-        boolean inMultiWindowMode();
-
-        public int getRotationAnimationHint();
-
         public boolean isInputMethodWindow();
 
-        public boolean isInputMethodTarget();
-
         public int getDisplayId();
 
         /**
@@ -432,42 +253,8 @@
             return false;
         }
 
-        /**
-         * Returns true if the window owner has the permission to acquire a sleep token when it's
-         * visible. That is, they have the permission {@link Manifest.permission#DEVICE_POWER}.
-         */
-        boolean canAcquireSleepToken();
-
-        /** @return true if this window desires key events. */
-        boolean canReceiveKeys();
-
         /** @return true if the window can show over keyguard. */
         boolean canShowWhenLocked();
-
-        /**
-         * Writes {@link com.android.server.wm.IdentifierProto} to stream.
-         */
-        void writeIdentifierToProto(ProtoOutputStream proto, long fieldId);
-
-        /**
-         * @return The {@link WindowFrames} associated with this {@link WindowState}
-         */
-        WindowFrames getWindowFrames();
-    }
-
-    /**
-     * Representation of a input consumer that the policy has added to the
-     * window manager to consume input events going to windows below it.
-     */
-    public interface InputConsumer {
-        /**
-         * Remove the input consumer from the window manager.
-         */
-        void dismiss();
-        /**
-         * Dispose the input consumer and input receiver from UI thread.
-         */
-        void dispose();
     }
 
     /**
@@ -538,11 +325,6 @@
         void unregisterPointerEventListener(PointerEventListener listener, int displayId);
 
         /**
-         * @return The currently active input method window.
-         */
-        WindowState getInputMethodWindowLw();
-
-        /**
          * Notifies window manager that {@link #isKeyguardTrustedLw} has changed.
          */
         void notifyKeyguardTrustedChanged();
@@ -615,17 +397,6 @@
     }
 
     /**
-     * Provides the rotation of a device.
-     *
-     * @see com.android.server.policy.WindowOrientationListener
-     */
-    public interface RotationSource {
-        int getProposedRotation();
-
-        void setCurrentRotation(int rotation);
-    }
-
-    /**
      * Interface to get public information of a display content.
      */
     public interface DisplayContentInfo {
@@ -889,12 +660,6 @@
     }
 
     /**
-     * Get the highest layer (actually one more than) that the wallpaper is
-     * allowed to be in.
-     */
-    public int getMaxWallpaperLayer();
-
-    /**
      * Return whether the given window can become the Keyguard window. Typically returns true for
      * the StatusBar.
      */
@@ -1384,17 +1149,6 @@
     void dumpDebug(ProtoOutputStream proto, long fieldId);
 
     /**
-     * Returns whether a given window type is considered a top level one.
-     * A top level window does not have a container, i.e. attached window,
-     * or if it has a container it is laid out as a top-level window, not
-     * as a child of its container.
-     *
-     * @param windowType The window type.
-     * @return True if the window is a top level one.
-     */
-    public boolean isTopLevelWindow(int windowType);
-
-    /**
      * Notifies the keyguard to start fading out.
      *
      * @param startTime the start time of the animation in uptime milliseconds
diff --git a/services/core/java/com/android/server/timezonedetector/CallerIdentityInjector.java b/services/core/java/com/android/server/timezonedetector/CallerIdentityInjector.java
new file mode 100644
index 0000000..1500cfa
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/CallerIdentityInjector.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timezonedetector;
+
+import android.annotation.UserIdInt;
+import android.os.Binder;
+import android.os.UserHandle;
+
+/**
+ * An interface to wrap various difficult-to-intercept calls that services make to access / manage
+ * caller identity, e.g. {@link Binder#clearCallingIdentity()}.
+ */
+public interface CallerIdentityInjector {
+
+    /** A singleton for the real implementation of {@link CallerIdentityInjector}. */
+    CallerIdentityInjector REAL = new Real();
+
+    /** A {@link UserHandle#getCallingUserId()} call. */
+    @UserIdInt int getCallingUserId();
+
+    /** A {@link Binder#clearCallingIdentity()} call. */
+    long clearCallingIdentity();
+
+    /** A {@link Binder#restoreCallingIdentity(long)} ()} call. */
+    void restoreCallingIdentity(long token);
+
+    /** The real implementation of {@link CallerIdentityInjector}. */
+    class Real implements CallerIdentityInjector {
+
+        protected Real() {
+        }
+
+        @Override
+        public int getCallingUserId() {
+            return UserHandle.getCallingUserId();
+        }
+
+        @Override
+        public long clearCallingIdentity() {
+            return Binder.clearCallingIdentity();
+        }
+
+        @Override
+        public void restoreCallingIdentity(long token) {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/timezonedetector/ConfigurationChangeListener.java b/services/core/java/com/android/server/timezonedetector/ConfigurationChangeListener.java
new file mode 100644
index 0000000..4c7b1f3
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/ConfigurationChangeListener.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timezonedetector;
+
+/**
+ * A listener used to receive notification that time zone configuration has changed.
+ */
+@FunctionalInterface
+public interface ConfigurationChangeListener {
+    /** Called when the current user or a configuration value has changed. */
+    void onChange();
+}
diff --git a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
new file mode 100644
index 0000000..aee3d8d
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timezonedetector;
+
+import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED;
+import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE;
+import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED;
+import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.app.timezonedetector.TimeZoneCapabilities;
+import android.app.timezonedetector.TimeZoneConfiguration;
+
+import java.util.Objects;
+
+/**
+ * Holds all configuration values that affect time zone behavior and some associated logic, e.g.
+ * {@link #getAutoDetectionEnabledBehavior()}, {@link #getGeoDetectionEnabledBehavior()} and {@link
+ * #createCapabilities()}.
+ */
+public final class ConfigurationInternal {
+
+    private final @UserIdInt int mUserId;
+    private final boolean mUserConfigAllowed;
+    private final boolean mAutoDetectionSupported;
+    private final boolean mAutoDetectionEnabled;
+    private final boolean mLocationEnabled;
+    private final boolean mGeoDetectionEnabled;
+
+    private ConfigurationInternal(Builder builder) {
+        mUserId = builder.mUserId;
+        mUserConfigAllowed = builder.mUserConfigAllowed;
+        mAutoDetectionSupported = builder.mAutoDetectionSupported;
+        mAutoDetectionEnabled = builder.mAutoDetectionEnabled;
+        mLocationEnabled = builder.mLocationEnabled;
+        mGeoDetectionEnabled = builder.mGeoDetectionEnabled;
+    }
+
+    /** Returns the ID of the user this configuration is associated with. */
+    public @UserIdInt int getUserId() {
+        return mUserId;
+    }
+
+    /** Returns true if the user allowed to modify time zone configuration. */
+    public boolean isUserConfigAllowed() {
+        return mUserConfigAllowed;
+    }
+
+    /** Returns true if the device supports some form of auto time zone detection. */
+    public boolean isAutoDetectionSupported() {
+        return mAutoDetectionSupported;
+    }
+
+    /** Returns the value of the auto time zone detection enabled setting. */
+    public boolean getAutoDetectionEnabledSetting() {
+        return mAutoDetectionEnabled;
+    }
+
+    /**
+     * Returns true if auto time zone detection behavior is actually enabled, which can be distinct
+     * from the raw setting value. */
+    public boolean getAutoDetectionEnabledBehavior() {
+        return mAutoDetectionSupported && mAutoDetectionEnabled;
+    }
+
+    /** Returns true if user's location can be used generally. */
+    public boolean isLocationEnabled() {
+        return mLocationEnabled;
+    }
+
+    /** Returns the value of the geolocation time zone detection enabled setting. */
+    public boolean getGeoDetectionEnabledSetting() {
+        return mGeoDetectionEnabled;
+    }
+
+    /**
+     * Returns true if geolocation time zone detection behavior is actually enabled, which can be
+     * distinct from the raw setting value.
+     */
+    public boolean getGeoDetectionEnabledBehavior() {
+        if (getAutoDetectionEnabledBehavior()) {
+            return mLocationEnabled && mGeoDetectionEnabled;
+        }
+        return false;
+    }
+
+    /** Creates a {@link TimeZoneCapabilities} object using the configuration values. */
+    public TimeZoneCapabilities createCapabilities() {
+        TimeZoneCapabilities.Builder builder = new TimeZoneCapabilities.Builder()
+                .setConfiguration(asConfiguration());
+
+        boolean allowConfigDateTime = isUserConfigAllowed();
+
+        // Automatic time zone detection is only supported on devices if there is a telephony
+        // network available or geolocation time zone detection is possible.
+        boolean deviceHasTimeZoneDetection = isAutoDetectionSupported();
+
+        final int configureAutoDetectionEnabledCapability;
+        if (!deviceHasTimeZoneDetection) {
+            configureAutoDetectionEnabledCapability = CAPABILITY_NOT_SUPPORTED;
+        } else if (!allowConfigDateTime) {
+            configureAutoDetectionEnabledCapability = CAPABILITY_NOT_ALLOWED;
+        } else {
+            configureAutoDetectionEnabledCapability = CAPABILITY_POSSESSED;
+        }
+        builder.setConfigureAutoDetectionEnabled(configureAutoDetectionEnabledCapability);
+
+        final int configureGeolocationDetectionEnabledCapability;
+        if (!deviceHasTimeZoneDetection) {
+            configureGeolocationDetectionEnabledCapability = CAPABILITY_NOT_SUPPORTED;
+        } else if (!allowConfigDateTime) {
+            configureGeolocationDetectionEnabledCapability = CAPABILITY_NOT_ALLOWED;
+        } else if (!isLocationEnabled()) {
+            configureGeolocationDetectionEnabledCapability = CAPABILITY_NOT_APPLICABLE;
+        } else {
+            configureGeolocationDetectionEnabledCapability = CAPABILITY_POSSESSED;
+        }
+        builder.setConfigureGeoDetectionEnabled(configureGeolocationDetectionEnabledCapability);
+
+        // The ability to make manual time zone suggestions can also be restricted by policy. With
+        // the current logic above, this could lead to a situation where a device hardware does not
+        // support auto detection, the device has been forced into "auto" mode by an admin and the
+        // user is unable to disable auto detection.
+        final int suggestManualTimeZoneCapability;
+        if (!allowConfigDateTime) {
+            suggestManualTimeZoneCapability = CAPABILITY_NOT_ALLOWED;
+        } else if (getAutoDetectionEnabledBehavior()) {
+            suggestManualTimeZoneCapability = CAPABILITY_NOT_APPLICABLE;
+        } else {
+            suggestManualTimeZoneCapability = CAPABILITY_POSSESSED;
+        }
+        builder.setSuggestManualTimeZone(suggestManualTimeZoneCapability);
+
+        return builder.build();
+    }
+
+    /** Returns a {@link TimeZoneConfiguration} from the configuration values. */
+    public TimeZoneConfiguration asConfiguration() {
+        return new TimeZoneConfiguration.Builder(mUserId)
+                .setAutoDetectionEnabled(getAutoDetectionEnabledSetting())
+                .setGeoDetectionEnabled(getGeoDetectionEnabledSetting())
+                .build();
+    }
+
+    /**
+     * Merges the configuration values from this with any properties set in {@code
+     * newConfiguration}. The new configuration has precedence. Used to apply user updates to
+     * internal configuration.
+     */
+    public ConfigurationInternal merge(TimeZoneConfiguration newConfiguration) {
+        Builder builder = new Builder(this);
+        if (newConfiguration.hasSetting(TimeZoneConfiguration.SETTING_AUTO_DETECTION_ENABLED)) {
+            builder.setAutoDetectionEnabled(newConfiguration.isAutoDetectionEnabled());
+        }
+        if (newConfiguration.hasSetting(TimeZoneConfiguration.SETTING_GEO_DETECTION_ENABLED)) {
+            builder.setGeoDetectionEnabled(newConfiguration.isGeoDetectionEnabled());
+        }
+        return builder.build();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        ConfigurationInternal that = (ConfigurationInternal) o;
+        return mUserId == that.mUserId
+                && mUserConfigAllowed == that.mUserConfigAllowed
+                && mAutoDetectionSupported == that.mAutoDetectionSupported
+                && mAutoDetectionEnabled == that.mAutoDetectionEnabled
+                && mLocationEnabled == that.mLocationEnabled
+                && mGeoDetectionEnabled == that.mGeoDetectionEnabled;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mUserId, mUserConfigAllowed, mAutoDetectionSupported,
+                mAutoDetectionEnabled, mLocationEnabled, mGeoDetectionEnabled);
+    }
+
+    @Override
+    public String toString() {
+        return "TimeZoneDetectorConfiguration{"
+                + "mUserId=" + mUserId
+                + "mUserConfigAllowed=" + mUserConfigAllowed
+                + "mAutoDetectionSupported=" + mAutoDetectionSupported
+                + "mAutoDetectionEnabled=" + mAutoDetectionEnabled
+                + "mLocationEnabled=" + mLocationEnabled
+                + "mGeoDetectionEnabled=" + mGeoDetectionEnabled
+                + '}';
+    }
+
+    /**
+     * A Builder for {@link ConfigurationInternal}.
+     */
+    public static class Builder {
+
+        private final @UserIdInt int mUserId;
+        private boolean mUserConfigAllowed;
+        private boolean mAutoDetectionSupported;
+        private boolean mAutoDetectionEnabled;
+        private boolean mLocationEnabled;
+        private boolean mGeoDetectionEnabled;
+
+        /**
+         * Creates a new Builder with only the userId set.
+         */
+        public Builder(@UserIdInt int userId) {
+            mUserId = userId;
+        }
+
+        /**
+         * Creates a new Builder by copying values from an existing instance.
+         */
+        public Builder(ConfigurationInternal toCopy) {
+            this.mUserId = toCopy.mUserId;
+            this.mUserConfigAllowed = toCopy.mUserConfigAllowed;
+            this.mAutoDetectionSupported = toCopy.mAutoDetectionSupported;
+            this.mAutoDetectionEnabled = toCopy.mAutoDetectionEnabled;
+            this.mLocationEnabled = toCopy.mLocationEnabled;
+            this.mGeoDetectionEnabled = toCopy.mGeoDetectionEnabled;
+        }
+
+        /**
+         * Sets whether the user is allowed to configure time zone settings on this device.
+         */
+        public Builder setUserConfigAllowed(boolean configAllowed) {
+            mUserConfigAllowed = configAllowed;
+            return this;
+        }
+
+        /**
+         * Sets whether automatic time zone detection is supported on this device.
+         */
+        public Builder setAutoDetectionSupported(boolean supported) {
+            mAutoDetectionSupported = supported;
+            return this;
+        }
+
+        /**
+         * Sets the value of the automatic time zone detection enabled setting for this device.
+         */
+        public Builder setAutoDetectionEnabled(boolean enabled) {
+            mAutoDetectionEnabled = enabled;
+            return this;
+        }
+
+        /**
+         * Sets the value of the location mode setting for this user.
+         */
+        public Builder setLocationEnabled(boolean enabled) {
+            mLocationEnabled = enabled;
+            return this;
+        }
+
+        /**
+         * Sets the value of the geolocation time zone detection setting for this user.
+         */
+        public Builder setGeoDetectionEnabled(boolean enabled) {
+            mGeoDetectionEnabled = enabled;
+            return this;
+        }
+
+        /** Returns a new {@link ConfigurationInternal}. */
+        @NonNull
+        public ConfigurationInternal build() {
+            return new ConfigurationInternal(this);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
index 0ca36e0..d640323 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
@@ -16,24 +16,30 @@
 
 package com.android.server.timezonedetector;
 
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED;
+import static android.content.Intent.ACTION_USER_SWITCHED;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.app.ActivityManagerInternal;
 import android.app.AlarmManager;
-import android.app.timezonedetector.TimeZoneCapabilities;
 import android.app.timezonedetector.TimeZoneConfiguration;
+import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.location.LocationManager;
 import android.net.ConnectivityManager;
+import android.os.Handler;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.util.Slog;
+
+import com.android.server.LocalServices;
 
 import java.util.Objects;
 
@@ -42,103 +48,87 @@
  */
 public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrategyImpl.Callback {
 
+    private static final String LOG_TAG = "TimeZoneDetectorCallbackImpl";
     private static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
 
-    private final Context mContext;
-    private final ContentResolver mCr;
-    private final UserManager mUserManager;
+    @NonNull private final Context mContext;
+    @NonNull private final Handler mHandler;
+    @NonNull private final ContentResolver mCr;
+    @NonNull private final UserManager mUserManager;
+    @NonNull private final boolean mGeoDetectionFeatureEnabled;
+    @NonNull private final LocationManager mLocationManager;
+    // @NonNull after setConfigChangeListener() is called.
+    private ConfigurationChangeListener mConfigChangeListener;
 
-    TimeZoneDetectorCallbackImpl(Context context) {
-        mContext = context;
+    TimeZoneDetectorCallbackImpl(@NonNull Context context, @NonNull Handler handler,
+            boolean geoDetectionFeatureEnabled) {
+        mContext = Objects.requireNonNull(context);
+        mHandler = Objects.requireNonNull(handler);
         mCr = context.getContentResolver();
         mUserManager = context.getSystemService(UserManager.class);
+        mLocationManager = context.getSystemService(LocationManager.class);
+        mGeoDetectionFeatureEnabled = geoDetectionFeatureEnabled;
+
+        // Wire up the change listener. All invocations are performed on the mHandler thread.
+
+        // Listen for the user changing / the user's location mode changing.
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(ACTION_USER_SWITCHED);
+        filter.addAction(LocationManager.MODE_CHANGED_ACTION);
+        mContext.registerReceiverForAllUsers(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                handleConfigChangeOnHandlerThread();
+            }
+        }, filter, null, mHandler);
+
+        // Add async callbacks for global settings being changed.
+        ContentResolver contentResolver = mContext.getContentResolver();
+        contentResolver.registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true,
+                new ContentObserver(mHandler) {
+                    public void onChange(boolean selfChange) {
+                        handleConfigChangeOnHandlerThread();
+                    }
+                });
+
+        // Add async callbacks for user scoped location settings being changed.
+        contentResolver.registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED),
+                true,
+                new ContentObserver(mHandler) {
+                    public void onChange(boolean selfChange) {
+                        handleConfigChangeOnHandlerThread();
+                    }
+                }, UserHandle.USER_ALL);
+    }
+
+    private void handleConfigChangeOnHandlerThread() {
+        if (mConfigChangeListener == null) {
+            Slog.wtf(LOG_TAG, "mConfigChangeListener is unexpectedly null");
+        }
+        mConfigChangeListener.onChange();
     }
 
     @Override
-    public TimeZoneCapabilities getCapabilities(@UserIdInt int userId) {
-        UserHandle userHandle = UserHandle.of(userId);
-        boolean disallowConfigDateTime =
-                mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_DATE_TIME, userHandle);
-
-        TimeZoneCapabilities.Builder builder = new TimeZoneCapabilities.Builder(userId);
-
-        // Automatic time zone detection is only supported (currently) on devices if there is a
-        // telephony network available.
-        if (!deviceHasTelephonyNetwork()) {
-            builder.setConfigureAutoDetectionEnabled(CAPABILITY_NOT_SUPPORTED);
-        } else if (disallowConfigDateTime) {
-            builder.setConfigureAutoDetectionEnabled(CAPABILITY_NOT_ALLOWED);
-        } else {
-            builder.setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED);
-        }
-
-        // TODO(b/149014708) Replace this with real logic when the settings storage is fully
-        // implemented.
-        builder.setConfigureGeoDetectionEnabled(CAPABILITY_NOT_SUPPORTED);
-
-        // The ability to make manual time zone suggestions can also be restricted by policy. With
-        // the current logic above, this could lead to a situation where a device hardware does not
-        // support auto detection, the device has been forced into "auto" mode by an admin and the
-        // user is unable to disable auto detection.
-        if (disallowConfigDateTime) {
-            builder.setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED);
-        } else if (isAutoDetectionEnabled()) {
-            builder.setSuggestManualTimeZone(CAPABILITY_NOT_APPLICABLE);
-        } else {
-            builder.setSuggestManualTimeZone(CAPABILITY_POSSESSED);
-        }
-        return builder.build();
+    public void setConfigChangeListener(@NonNull ConfigurationChangeListener listener) {
+        mConfigChangeListener = Objects.requireNonNull(listener);
     }
 
     @Override
-    public TimeZoneConfiguration getConfiguration(@UserIdInt int userId) {
-        return new TimeZoneConfiguration.Builder()
+    public ConfigurationInternal getConfigurationInternal(@UserIdInt int userId) {
+        return new ConfigurationInternal.Builder(userId)
+                .setUserConfigAllowed(isUserConfigAllowed(userId))
+                .setAutoDetectionSupported(isAutoDetectionSupported())
                 .setAutoDetectionEnabled(isAutoDetectionEnabled())
-                .setGeoDetectionEnabled(isGeoDetectionEnabled())
+                .setLocationEnabled(isLocationEnabled(userId))
+                .setGeoDetectionEnabled(isGeoDetectionEnabled(userId))
                 .build();
     }
 
     @Override
-    public void setConfiguration(
-            @UserIdInt int userId, @NonNull TimeZoneConfiguration configuration) {
-        Objects.requireNonNull(configuration);
-        if (!configuration.isComplete()) {
-            throw new IllegalArgumentException("configuration=" + configuration + " not complete");
-        }
-
-        // Avoid writing auto detection config for devices that do not support auto time zone
-        // detection: if we wrote it down then we'd set the default explicitly. That might influence
-        // what happens on later releases that do support auto detection on the same hardware.
-        if (isAutoDetectionSupported()) {
-            final int autoEnabledValue = configuration.isAutoDetectionEnabled() ? 1 : 0;
-            Settings.Global.putInt(mCr, Settings.Global.AUTO_TIME_ZONE, autoEnabledValue);
-
-            final boolean geoTzDetectionEnabledValue = configuration.isGeoDetectionEnabled();
-            // TODO(b/149014708) Write this down to user-scoped settings once implemented.
-        }
-    }
-
-    @Override
-    public boolean isAutoDetectionEnabled() {
-        // To ensure that TimeZoneConfiguration is "complete" for simplicity, devices that do not
-        // support auto detection have safe, hard coded configuration values that make it look like
-        // auto detection is turned off. It is therefore important that false is returned from this
-        // method for devices that do not support auto time zone detection. Such devices will not
-        // have a UI to turn the auto detection on/off. Returning true could prevent the user
-        // entering information manually. On devices that do support auto time detection the default
-        // is to turn auto detection on.
-        if (isAutoDetectionSupported()) {
-            return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE, 1 /* default */) > 0;
-        }
-        return false;
-    }
-
-    @Override
-    public boolean isGeoDetectionEnabled() {
-        // TODO(b/149014708) Read this from user-scoped settings once implemented. The user's
-        //  location toggle will act as an override for this setting, i.e. so that the setting will
-        //  return false if the location toggle is disabled.
-        return false;
+    public @UserIdInt int getCurrentUserId() {
+        return LocalServices.getService(ActivityManagerInternal.class).getCurrentUserId();
     }
 
     @Override
@@ -165,8 +155,55 @@
         alarmManager.setTimeZone(zoneId);
     }
 
+    @Override
+    public void storeConfiguration(TimeZoneConfiguration configuration) {
+        Objects.requireNonNull(configuration);
+
+        // Avoid writing the auto detection enabled setting for devices that do not support auto
+        // time zone detection: if we wrote it down then we'd set the value explicitly, which would
+        // prevent detecting "default" later. That might influence what happens on later releases
+        // that support new types of auto detection on the same hardware.
+        if (isAutoDetectionSupported()) {
+            final boolean autoDetectionEnabled = configuration.isAutoDetectionEnabled();
+            setAutoDetectionEnabled(autoDetectionEnabled);
+
+            final int userId = configuration.getUserId();
+            final boolean geoTzDetectionEnabled = configuration.isGeoDetectionEnabled();
+            setGeoDetectionEnabled(userId, geoTzDetectionEnabled);
+        }
+    }
+
+    private boolean isUserConfigAllowed(@UserIdInt int userId) {
+        UserHandle userHandle = UserHandle.of(userId);
+        return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_DATE_TIME, userHandle);
+    }
+
     private boolean isAutoDetectionSupported() {
-        return deviceHasTelephonyNetwork();
+        return deviceHasTelephonyNetwork() || mGeoDetectionFeatureEnabled;
+    }
+
+    private boolean isAutoDetectionEnabled() {
+        return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE, 1 /* default */) > 0;
+    }
+
+    private void setAutoDetectionEnabled(boolean enabled) {
+        Settings.Global.putInt(mCr, Settings.Global.AUTO_TIME_ZONE, enabled ? 1 : 0);
+    }
+
+    private boolean isLocationEnabled(@UserIdInt int userId) {
+        return mLocationManager.isLocationEnabledForUser(UserHandle.of(userId));
+    }
+
+    private boolean isGeoDetectionEnabled(@UserIdInt int userId) {
+        final boolean locationEnabled = isLocationEnabled(userId);
+        return Settings.Secure.getIntForUser(mCr,
+                Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED,
+                locationEnabled ? 1 : 0 /* defaultValue */, userId) != 0;
+    }
+
+    private void setGeoDetectionEnabled(@UserIdInt int userId, boolean enabled) {
+        Settings.Secure.putIntForUser(mCr, Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED,
+                enabled ? 1 : 0, userId);
     }
 
     private boolean deviceHasTelephonyNetwork() {
@@ -174,4 +211,4 @@
         return mContext.getSystemService(ConnectivityManager.class)
                 .isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
     }
-}
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
index fb7a73d..2d50390 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
@@ -27,6 +27,12 @@
  */
 public interface TimeZoneDetectorInternal extends Dumpable.Container {
 
+    /** Adds a listener that will be invoked when time zone detection configuration is changed. */
+    void addConfigurationListener(ConfigurationChangeListener listener);
+
+    /** Returns the {@link ConfigurationInternal} for the current user. */
+    ConfigurationInternal getCurrentUserConfigurationInternal();
+
     /**
      * Suggests the current time zone, determined using geolocation, to the detector. The
      * detector may ignore the signal based on system settings, whether better information is
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java
index 15412a0..f0ce827 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java
@@ -20,8 +20,8 @@
 import android.content.Context;
 import android.os.Handler;
 
-import com.android.internal.annotations.VisibleForTesting;
-
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -34,18 +34,26 @@
     @NonNull private final Context mContext;
     @NonNull private final Handler mHandler;
     @NonNull private final TimeZoneDetectorStrategy mTimeZoneDetectorStrategy;
+    @NonNull private final List<ConfigurationChangeListener> mConfigurationListeners =
+            new ArrayList<>();
 
-    static TimeZoneDetectorInternalImpl create(@NonNull Context context, @NonNull Handler handler,
-            @NonNull TimeZoneDetectorStrategy timeZoneDetectorStrategy) {
-        return new TimeZoneDetectorInternalImpl(context, handler, timeZoneDetectorStrategy);
-    }
-
-    @VisibleForTesting
     public TimeZoneDetectorInternalImpl(@NonNull Context context, @NonNull Handler handler,
             @NonNull TimeZoneDetectorStrategy timeZoneDetectorStrategy) {
         mContext = Objects.requireNonNull(context);
         mHandler = Objects.requireNonNull(handler);
         mTimeZoneDetectorStrategy = Objects.requireNonNull(timeZoneDetectorStrategy);
+
+        // Wire up a change listener so that any downstream listeners can be notified when
+        // the configuration changes for any reason.
+        mTimeZoneDetectorStrategy.addConfigChangeListener(this::handleConfigurationChanged);
+    }
+
+    private void handleConfigurationChanged() {
+        synchronized (mConfigurationListeners) {
+            for (ConfigurationChangeListener listener : mConfigurationListeners) {
+                listener.onChange();
+            }
+        }
     }
 
     @Override
@@ -54,6 +62,19 @@
     }
 
     @Override
+    public void addConfigurationListener(ConfigurationChangeListener listener) {
+        synchronized (mConfigurationListeners) {
+            mConfigurationListeners.add(Objects.requireNonNull(listener));
+        }
+    }
+
+    @Override
+    @NonNull
+    public ConfigurationInternal getCurrentUserConfigurationInternal() {
+        return mTimeZoneDetectorStrategy.getCurrentUserConfigurationInternal();
+    }
+
+    @Override
     public void suggestGeolocationTimeZone(
             @NonNull GeolocationTimeZoneSuggestion timeZoneSuggestion) {
         Objects.requireNonNull(timeZoneSuggestion);
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
index d81f949..7501d9f 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
@@ -24,32 +24,24 @@
 import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
 import android.app.timezonedetector.TimeZoneCapabilities;
 import android.app.timezonedetector.TimeZoneConfiguration;
-import android.content.ContentResolver;
 import android.content.Context;
-import android.database.ContentObserver;
-import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
-import android.os.UserHandle;
-import android.provider.Settings;
 import android.util.IndentingPrintWriter;
 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.FgThread;
 import com.android.server.SystemService;
-import com.android.server.timezonedetector.TimeZoneDetectorStrategy.StrategyListener;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Iterator;
 import java.util.Objects;
 
 /**
@@ -65,6 +57,9 @@
 
     private static final String TAG = "TimeZoneDetectorService";
 
+    /** A compile time switch for enabling / disabling geolocation-based time zone detection. */
+    private static final boolean GEOLOCATION_TIME_ZONE_DETECTION_ENABLED = false;
+
     /**
      * Handles the service lifecycle for {@link TimeZoneDetectorService} and
      * {@link TimeZoneDetectorInternalImpl}.
@@ -80,18 +75,20 @@
             // Obtain / create the shared dependencies.
             Context context = getContext();
             Handler handler = FgThread.getHandler();
+
             TimeZoneDetectorStrategy timeZoneDetectorStrategy =
-                    TimeZoneDetectorStrategyImpl.create(context);
+                    TimeZoneDetectorStrategyImpl.create(
+                            context, handler, GEOLOCATION_TIME_ZONE_DETECTION_ENABLED);
 
             // Create and publish the local service for use by internal callers.
             TimeZoneDetectorInternal internal =
-                    TimeZoneDetectorInternalImpl.create(context, handler, timeZoneDetectorStrategy);
+                    new TimeZoneDetectorInternalImpl(context, handler, timeZoneDetectorStrategy);
             publishLocalService(TimeZoneDetectorInternal.class, internal);
 
             // Publish the binder service so it can be accessed from other (appropriately
             // permissioned) processes.
-            TimeZoneDetectorService service =
-                    TimeZoneDetectorService.create(context, handler, timeZoneDetectorStrategy);
+            TimeZoneDetectorService service = TimeZoneDetectorService.create(
+                    context, handler, timeZoneDetectorStrategy);
             publishBinderService(Context.TIME_ZONE_DETECTOR_SERVICE, service);
         }
     }
@@ -103,52 +100,38 @@
     private final Handler mHandler;
 
     @NonNull
+    private final CallerIdentityInjector mCallerIdentityInjector;
+
+    @NonNull
     private final TimeZoneDetectorStrategy mTimeZoneDetectorStrategy;
 
-    /**
-     * This sparse array acts as a map from userId to listeners running as that userId. User scoped
-     * as time zone detection configuration is partially user-specific, so different users can
-     * get different configuration.
-     */
     @GuardedBy("mConfigurationListeners")
     @NonNull
-    private final SparseArray<ArrayList<ITimeZoneConfigurationListener>> mConfigurationListeners =
-            new SparseArray<>();
+    private final ArrayList<ITimeZoneConfigurationListener> mConfigurationListeners =
+            new ArrayList<>();
 
     private static TimeZoneDetectorService create(
             @NonNull Context context, @NonNull Handler handler,
             @NonNull TimeZoneDetectorStrategy timeZoneDetectorStrategy) {
 
-        TimeZoneDetectorService service =
-                new TimeZoneDetectorService(context, handler, timeZoneDetectorStrategy);
-
-        ContentResolver contentResolver = context.getContentResolver();
-        contentResolver.registerContentObserver(
-                Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true,
-                new ContentObserver(handler) {
-                    public void onChange(boolean selfChange) {
-                        service.handleAutoTimeZoneConfigChanged();
-                    }
-                });
-        // TODO(b/149014708) Listen for changes to geolocation time zone detection enabled config.
-        //  This should also include listening to the current user and the current user's location
-        //  toggle since the config is user-scoped and the location toggle overrides the geolocation
-        //  time zone enabled setting.
+        CallerIdentityInjector callerIdentityInjector = CallerIdentityInjector.REAL;
+        TimeZoneDetectorService service = new TimeZoneDetectorService(
+                context, handler, callerIdentityInjector, timeZoneDetectorStrategy);
         return service;
     }
 
     @VisibleForTesting
     public TimeZoneDetectorService(@NonNull Context context, @NonNull Handler handler,
+            @NonNull CallerIdentityInjector callerIdentityInjector,
             @NonNull TimeZoneDetectorStrategy timeZoneDetectorStrategy) {
         mContext = Objects.requireNonNull(context);
         mHandler = Objects.requireNonNull(handler);
+        mCallerIdentityInjector = Objects.requireNonNull(callerIdentityInjector);
         mTimeZoneDetectorStrategy = Objects.requireNonNull(timeZoneDetectorStrategy);
-        mTimeZoneDetectorStrategy.setStrategyListener(new StrategyListener() {
-            @Override
-            public void onConfigurationChanged() {
-                handleConfigurationChanged();
-            }
-        });
+
+        // Wire up a change listener so that ITimeZoneConfigurationListeners can be notified when
+        // the configuration changes for any reason.
+        mTimeZoneDetectorStrategy.addConfigChangeListener(this::handleConfigurationChanged);
     }
 
     @Override
@@ -156,26 +139,12 @@
     public TimeZoneCapabilities getCapabilities() {
         enforceManageTimeZoneDetectorConfigurationPermission();
 
-        int userId = UserHandle.getCallingUserId();
-        long token = Binder.clearCallingIdentity();
+        int userId = mCallerIdentityInjector.getCallingUserId();
+        long token = mCallerIdentityInjector.clearCallingIdentity();
         try {
-            return mTimeZoneDetectorStrategy.getCapabilities(userId);
+            return mTimeZoneDetectorStrategy.getConfigurationInternal(userId).createCapabilities();
         } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    @Override
-    @NonNull
-    public TimeZoneConfiguration getConfiguration() {
-        enforceManageTimeZoneDetectorConfigurationPermission();
-
-        int userId = UserHandle.getCallingUserId();
-        long token = Binder.clearCallingIdentity();
-        try {
-            return mTimeZoneDetectorStrategy.getConfiguration(userId);
-        } finally {
-            Binder.restoreCallingIdentity(token);
+            mCallerIdentityInjector.restoreCallingIdentity(token);
         }
     }
 
@@ -184,12 +153,16 @@
         enforceManageTimeZoneDetectorConfigurationPermission();
         Objects.requireNonNull(configuration);
 
-        int userId = UserHandle.getCallingUserId();
-        long token = Binder.clearCallingIdentity();
+        int callingUserId = mCallerIdentityInjector.getCallingUserId();
+        if (callingUserId != configuration.getUserId()) {
+            return false;
+        }
+
+        long token = mCallerIdentityInjector.clearCallingIdentity();
         try {
-            return mTimeZoneDetectorStrategy.updateConfiguration(userId, configuration);
+            return mTimeZoneDetectorStrategy.updateConfiguration(configuration);
         } finally {
-            Binder.restoreCallingIdentity(token);
+            mCallerIdentityInjector.restoreCallingIdentity(token);
         }
     }
 
@@ -197,25 +170,17 @@
     public void addConfigurationListener(@NonNull ITimeZoneConfigurationListener listener) {
         enforceManageTimeZoneDetectorConfigurationPermission();
         Objects.requireNonNull(listener);
-        int userId = UserHandle.getCallingUserId();
 
         synchronized (mConfigurationListeners) {
-            ArrayList<ITimeZoneConfigurationListener> listeners =
-                    mConfigurationListeners.get(userId);
-            if (listeners != null && listeners.contains(listener)) {
+            if (mConfigurationListeners.contains(listener)) {
                 return;
             }
             try {
-                if (listeners == null) {
-                    listeners = new ArrayList<>(1);
-                    mConfigurationListeners.put(userId, listeners);
-                }
-
                 // Ensure the reference to the listener will be removed if the client process dies.
                 listener.asBinder().linkToDeath(this, 0 /* flags */);
 
                 // Only add the listener if we can linkToDeath().
-                listeners.add(listener);
+                mConfigurationListeners.add(listener);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Unable to linkToDeath() for listener=" + listener, e);
             }
@@ -226,19 +191,16 @@
     public void removeConfigurationListener(@NonNull ITimeZoneConfigurationListener listener) {
         enforceManageTimeZoneDetectorConfigurationPermission();
         Objects.requireNonNull(listener);
-        int userId = UserHandle.getCallingUserId();
 
         synchronized (mConfigurationListeners) {
             boolean removedListener = false;
-            ArrayList<ITimeZoneConfigurationListener> userListeners =
-                    mConfigurationListeners.get(userId);
-            if (userListeners.remove(listener)) {
+            if (mConfigurationListeners.remove(listener)) {
                 // Stop listening for the client process to die.
                 listener.asBinder().unlinkToDeath(this, 0 /* flags */);
                 removedListener = true;
             }
             if (!removedListener) {
-                Slog.w(TAG, "Client asked to remove listenener=" + listener
+                Slog.w(TAG, "Client asked to remove listener=" + listener
                         + ", but no listeners were removed."
                         + " mConfigurationListeners=" + mConfigurationListeners);
             }
@@ -259,19 +221,14 @@
     public void binderDied(IBinder who) {
         synchronized (mConfigurationListeners) {
             boolean removedListener = false;
-            final int userCount = mConfigurationListeners.size();
-            for (int i = 0; i < userCount; i++) {
-                ArrayList<ITimeZoneConfigurationListener> userListeners =
-                        mConfigurationListeners.valueAt(i);
-                Iterator<ITimeZoneConfigurationListener> userListenerIterator =
-                        userListeners.iterator();
-                while (userListenerIterator.hasNext()) {
-                    ITimeZoneConfigurationListener userListener = userListenerIterator.next();
-                    if (userListener.asBinder().equals(who)) {
-                        userListenerIterator.remove();
-                        removedListener = true;
-                        break;
-                    }
+            final int listenerCount = mConfigurationListeners.size();
+            for (int listenerIndex = listenerCount - 1; listenerIndex >= 0; listenerIndex--) {
+                ITimeZoneConfigurationListener listener =
+                        mConfigurationListeners.get(listenerIndex);
+                if (listener.asBinder().equals(who)) {
+                    mConfigurationListeners.remove(listenerIndex);
+                    removedListener = true;
+                    break;
                 }
             }
             if (!removedListener) {
@@ -283,42 +240,25 @@
     }
 
     void handleConfigurationChanged() {
-        // Note: we could trigger an async time zone detection operation here via a call to
-        // handleAutoTimeZoneConfigChanged(), but that is triggered in response to the underlying
-        // setting value changing so it is currently unnecessary. If we get to a point where all
-        // configuration changes are guaranteed to happen in response to an updateConfiguration()
-        // call, then we can remove that path and call it here instead.
-
         // Configuration has changed, but each user may have a different view of the configuration.
         // It's possible that this will cause unnecessary notifications but that shouldn't be a
         // problem.
         synchronized (mConfigurationListeners) {
-            final int userCount = mConfigurationListeners.size();
-            for (int userIndex = 0; userIndex < userCount; userIndex++) {
-                int userId = mConfigurationListeners.keyAt(userIndex);
-                TimeZoneConfiguration configuration =
-                        mTimeZoneDetectorStrategy.getConfiguration(userId);
-
-                ArrayList<ITimeZoneConfigurationListener> listeners =
-                        mConfigurationListeners.valueAt(userIndex);
-                final int listenerCount = listeners.size();
-                for (int listenerIndex = 0; listenerIndex < listenerCount; listenerIndex++) {
-                    ITimeZoneConfigurationListener listener = listeners.get(listenerIndex);
-                    try {
-                        listener.onChange(configuration);
-                    } catch (RemoteException e) {
-                        Slog.w(TAG, "Unable to notify listener=" + listener
-                                + " for userId=" + userId
-                                + " of updated configuration=" + configuration, e);
-                    }
+            final int listenerCount = mConfigurationListeners.size();
+            for (int listenerIndex = 0; listenerIndex < listenerCount; listenerIndex++) {
+                ITimeZoneConfigurationListener listener =
+                        mConfigurationListeners.get(listenerIndex);
+                try {
+                    listener.onChange();
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Unable to notify listener=" + listener, e);
                 }
             }
         }
     }
 
     /** Provided for command-line access. This is not exposed as a binder API. */
-    void suggestGeolocationTimeZone(
-            @NonNull GeolocationTimeZoneSuggestion timeZoneSuggestion) {
+    void suggestGeolocationTimeZone(@NonNull GeolocationTimeZoneSuggestion timeZoneSuggestion) {
         enforceSuggestGeolocationTimeZonePermission();
         Objects.requireNonNull(timeZoneSuggestion);
 
@@ -331,12 +271,12 @@
         enforceSuggestManualTimeZonePermission();
         Objects.requireNonNull(timeZoneSuggestion);
 
-        int userId = UserHandle.getCallingUserId();
-        long token = Binder.clearCallingIdentity();
+        int userId = mCallerIdentityInjector.getCallingUserId();
+        long token = mCallerIdentityInjector.clearCallingIdentity();
         try {
             return mTimeZoneDetectorStrategy.suggestManualTimeZone(userId, timeZoneSuggestion);
         } finally {
-            Binder.restoreCallingIdentity(token);
+            mCallerIdentityInjector.restoreCallingIdentity(token);
         }
     }
 
@@ -358,12 +298,6 @@
         ipw.flush();
     }
 
-    /** Internal method for handling the auto time zone configuration being changed. */
-    @VisibleForTesting
-    public void handleAutoTimeZoneConfigChanged() {
-        mHandler.post(mTimeZoneDetectorStrategy::handleAutoTimeZoneConfigChanged);
-    }
-
     private void enforceManageTimeZoneDetectorConfigurationPermission() {
         // TODO Switch to a dedicated MANAGE_TIME_AND_ZONE_CONFIGURATION permission.
         mContext.enforceCallingPermission(
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
index c5b7e39..f944c56 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
@@ -19,51 +19,84 @@
 import android.annotation.UserIdInt;
 import android.app.timezonedetector.ManualTimeZoneSuggestion;
 import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
-import android.app.timezonedetector.TimeZoneCapabilities;
 import android.app.timezonedetector.TimeZoneConfiguration;
 import android.util.IndentingPrintWriter;
 
 /**
- * The interface for the class that implements the time detection algorithm used by the
- * {@link TimeZoneDetectorService}.
+ * The interface for the class that is responsible for setting the time zone on a device, used by
+ * {@link TimeZoneDetectorService} and {@link TimeZoneDetectorInternal}.
  *
- * <p>The strategy uses suggestions to decide whether to modify the device's time zone setting
- * and what to set it to.
+ * <p>The strategy receives suggestions, which it may use to modify the device's time zone setting.
+ * Suggestions are acted on or ignored as needed, depending on previously received suggestions and
+ * the current user's configuration (see {@link ConfigurationInternal}).
  *
- * <p>Most calls will be handled by a single thread, but that is not true for all calls. For example
- * {@link #dump(IndentingPrintWriter, String[])}) may be called on a different thread concurrently
- * with other operations so implementations must still handle thread safety.
+ * <p>Devices can have zero, one or two automatic time zone detection algorithm available at any
+ * point in time.
+ *
+ * <p>The two automatic detection algorithms supported are "telephony" and "geolocation". Algorithm
+ * availability and use depends on several factors:
+ * <ul>
+ * <li>Telephony is only available on devices with a telephony stack.
+ * <li>Geolocation is also optional and configured at image creation time. When enabled on a
+ * device, its availability depends on the current user's settings, so switching between users can
+ * change the automatic algorithm used by the device.</li>
+ * </ul>
+ *
+ * <p>If there are no automatic time zone detections algorithms available then the user can usually
+ * change the device time zone manually. Under most circumstances the current user can turn
+ * automatic time zone detection on or off, or choose the algorithm via settings.
+ *
+ * <p>Telephony detection is independent of the current user. The device keeps track of the most
+ * recent telephony suggestion from each slotIndex. When telephony detection is in use, the highest
+ * scoring suggestion is used to set the device time zone based on a scoring algorithm. If several
+ * slotIndexes provide the same score then the slotIndex with the lowest numeric value "wins". If
+ * the situation changes and it is no longer possible to be confident about the time zone,
+ * slotIndexes must have an empty suggestion submitted in order to "withdraw" their previous
+ * suggestion otherwise it will remain in use.
+ *
+ * <p>Geolocation detection is dependent on the current user and their settings. The device retains
+ * at most one geolocation suggestion. Generally, use of a device's location is dependent on the
+ * user's "location toggle", but even when that is enabled the user may choose to enable / disable
+ * the use of geolocation for device time zone detection. If the current user changes to one that
+ * does not have geolocation detection enabled, or the user turns off geolocation detection, then
+ * the strategy discards the latest geolocation suggestion. Devices that lose a location fix must
+ * have an empty suggestion submitted in order to "withdraw" their previous suggestion otherwise it
+ * will remain in use.
+ *
+ * <p>Threading:
+ *
+ * <p>Suggestion calls with a void return type may be handed off to a separate thread and handled
+ * asynchronously. Synchronous calls like {@link #getCurrentUserConfigurationInternal()}, and debug
+ * calls like {@link #dump(IndentingPrintWriter, String[])}, may be called on a different thread
+ * concurrently with other operations.
  *
  * @hide
  */
 public interface TimeZoneDetectorStrategy extends Dumpable, Dumpable.Container {
 
-    /** A listener for strategy events. */
-    interface StrategyListener {
-        /**
-         * Invoked when configuration has been changed.
-         */
-        void onConfigurationChanged();
-    }
+    /**
+     * Sets a listener that will be triggered whenever time zone detection configuration is
+     * changed.
+     */
+    void addConfigChangeListener(@NonNull ConfigurationChangeListener listener);
 
-    /** Sets the listener that enables the strategy to communicate with the surrounding service. */
-    void setStrategyListener(@NonNull StrategyListener listener);
-
-    /** Returns the user's time zone capabilities. */
+    /** Returns the user's time zone configuration. */
     @NonNull
-    TimeZoneCapabilities getCapabilities(@UserIdInt int userId);
+    ConfigurationInternal getConfigurationInternal(@UserIdInt int userId);
 
     /**
-     * Returns the configuration that controls time zone detector behavior.
+     * Returns the configuration that controls time zone detector behavior for the current user.
      */
     @NonNull
-    TimeZoneConfiguration getConfiguration(@UserIdInt int userId);
+    ConfigurationInternal getCurrentUserConfigurationInternal();
 
     /**
-     * Updates the configuration settings that control time zone detector behavior.
+     * Updates the configuration properties that control a device's time zone behavior.
+     *
+     * <p>This method returns {@code true} if the configuration was changed,
+     * {@code false} otherwise.
      */
-    boolean updateConfiguration(
-            @UserIdInt int userId, @NonNull TimeZoneConfiguration configuration);
+    boolean updateConfiguration(@NonNull TimeZoneConfiguration configuration);
 
     /**
      * Suggests zero, one or more time zones for the device, or withdraws a previous suggestion if
@@ -85,9 +118,4 @@
      * suggestion.
      */
     void suggestTelephonyTimeZone(@NonNull TelephonyTimeZoneSuggestion suggestion);
-
-    /**
-     * Called when there has been a change to the automatic time zone detection configuration.
-     */
-    void handleAutoTimeZoneConfigChanged();
 }
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
index d1369a2..8a42b18 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
@@ -20,10 +20,7 @@
 import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
 import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET;
 import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_SINGLE_ZONE;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE;
 import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED;
-import static android.app.timezonedetector.TimeZoneConfiguration.PROPERTY_AUTO_DETECTION_ENABLED;
-import static android.app.timezonedetector.TimeZoneConfiguration.PROPERTY_GEO_DETECTION_ENABLED;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -33,6 +30,7 @@
 import android.app.timezonedetector.TimeZoneCapabilities;
 import android.app.timezonedetector.TimeZoneConfiguration;
 import android.content.Context;
+import android.os.Handler;
 import android.util.IndentingPrintWriter;
 import android.util.LocalLog;
 import android.util.Slog;
@@ -45,15 +43,7 @@
 import java.util.Objects;
 
 /**
- * An implementation of {@link TimeZoneDetectorStrategy} that handle telephony and manual
- * suggestions. Suggestions are acted on or ignored as needed, dependent on the current "auto time
- * zone detection" setting.
- *
- * <p>For automatic detection, it keeps track of the most recent telephony suggestion from each
- * slotIndex and it uses the best suggestion based on a scoring algorithm. If several slotIndexes
- * provide the same score then the slotIndex with the lowest numeric value "wins". If the situation
- * changes and it is no longer possible to be confident about the time zone, slotIndexes must have
- * an empty suggestion submitted in order to "withdraw" their previous suggestion.
+ * The real implementation of {@link TimeZoneDetectorStrategy}.
  *
  * <p>Most public methods are marked synchronized to ensure thread safety around internal state.
  */
@@ -61,48 +51,27 @@
 
     /**
      * Used by {@link TimeZoneDetectorStrategyImpl} to interact with device configuration / settings
-     * / system properties. It can be faked for testing different scenarios.
+     * / system properties. It can be faked for testing.
      *
      * <p>Note: Because the settings / system properties-derived values can currently be modified
-     * independently and from different threads (and processes!), their use are prone to race
-     * conditions. That will be true until the responsibility for setting their values is moved to
-     * {@link TimeZoneDetectorStrategyImpl} (which is thread safe).
+     * independently and from different threads (and processes!), their use is prone to race
+     * conditions.
      */
     @VisibleForTesting
     public interface Callback {
 
         /**
-         * Returns the capabilities for the user.
+         * Sets a {@link ConfigurationChangeListener} that will be invoked when there are any
+         * changes that could affect time zone detection. This is invoked during system server
+         * setup.
          */
-        @NonNull
-        TimeZoneCapabilities getCapabilities(@UserIdInt int userId);
+        void setConfigChangeListener(@NonNull ConfigurationChangeListener listener);
 
-        /**
-         * Returns the configuration for the user.
-         * @param userId
-         */
-        @NonNull
-        TimeZoneConfiguration getConfiguration(int userId);
+        /** Returns the current user at the instant it is called. */
+        @UserIdInt int getCurrentUserId();
 
-        /**
-         * Sets the configuration for the user. This method handles storage only, the configuration
-         * must have been validated by the caller and be complete.
-         *
-         * @throws IllegalArgumentException if {@link TimeZoneConfiguration#isComplete()}
-         *     returns {@code false}
-         */
-        void setConfiguration(@UserIdInt int userId, @NonNull TimeZoneConfiguration configuration);
-
-        /**
-         * Returns true if automatic time zone detection is currently enabled.
-         */
-        boolean isAutoDetectionEnabled();
-
-        /**
-         * Returns whether geolocation can be used for time zone detection when {@link
-         * #isAutoDetectionEnabled()} returns {@code true}.
-         */
-        boolean isGeoDetectionEnabled();
+        /** Returns the {@link ConfigurationInternal} for the specified user. */
+        ConfigurationInternal getConfigurationInternal(@UserIdInt int userId);
 
         /**
          * Returns true if the device has had an explicit time zone set.
@@ -118,6 +87,13 @@
          * Sets the device's time zone.
          */
         void setDeviceTimeZone(@NonNull String zoneId);
+
+        /**
+         * Stores the configuration properties contained in {@code newConfiguration}.
+         * All checks about user capabilities must be done by the caller and
+         * {@link TimeZoneConfiguration#isComplete()} must be {@code true}.
+         */
+        void storeConfiguration(TimeZoneConfiguration newConfiguration);
     }
 
     private static final String LOG_TAG = "TimeZoneDetectorStrategy";
@@ -189,9 +165,9 @@
     @NonNull
     private final Callback mCallback;
 
-    /** Non-null after {@link #setStrategyListener(StrategyListener)} is called. */
-    @Nullable
-    private StrategyListener mListener;
+    @GuardedBy("this")
+    @NonNull
+    private List<ConfigurationChangeListener> mConfigChangeListeners = new ArrayList<>();
 
     /**
      * A log that records the decisions / decision metadata that affected the device's time zone.
@@ -211,7 +187,8 @@
             new ArrayMapWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE);
 
     /**
-     * The latest geolocation suggestion received.
+     * The latest geolocation suggestion received. If the user disabled geolocation time zone
+     * detection then the latest suggestion is cleared.
      */
     @GuardedBy("this")
     private ReferenceWithHistory<GeolocationTimeZoneSuggestion> mLatestGeoLocationSuggestion =
@@ -223,113 +200,120 @@
     /**
      * Creates a new instance of {@link TimeZoneDetectorStrategyImpl}.
      */
-    public static TimeZoneDetectorStrategyImpl create(Context context) {
-        Callback timeZoneDetectionServiceHelper = new TimeZoneDetectorCallbackImpl(context);
-        return new TimeZoneDetectorStrategyImpl(timeZoneDetectionServiceHelper);
+    public static TimeZoneDetectorStrategyImpl create(
+            @NonNull Context context, @NonNull Handler handler,
+            boolean geolocationTimeZoneDetectionEnabled) {
+
+        TimeZoneDetectorCallbackImpl callback = new TimeZoneDetectorCallbackImpl(
+                context, handler, geolocationTimeZoneDetectionEnabled);
+        return new TimeZoneDetectorStrategyImpl(callback);
     }
 
     @VisibleForTesting
-    public TimeZoneDetectorStrategyImpl(Callback callback) {
+    public TimeZoneDetectorStrategyImpl(@NonNull Callback callback) {
         mCallback = Objects.requireNonNull(callback);
+        mCallback.setConfigChangeListener(this::handleConfigChanged);
     }
 
     /**
-     * Sets a listener that allows the strategy to communicate with the surrounding service. This
-     * must be called before the instance is used and must only be called once.
+     * Adds a listener that allows the strategy to communicate with the surrounding service /
+     * internal. This must be called before the instance is used.
      */
     @Override
-    public synchronized void setStrategyListener(@NonNull StrategyListener listener) {
-        if (mListener != null) {
-            throw new IllegalStateException("Strategy already has a listener");
-        }
-        mListener = Objects.requireNonNull(listener);
+    public synchronized void addConfigChangeListener(
+            @NonNull ConfigurationChangeListener listener) {
+        Objects.requireNonNull(listener);
+        mConfigChangeListeners.add(listener);
     }
 
     @Override
     @NonNull
-    public synchronized TimeZoneCapabilities getCapabilities(@UserIdInt int userId) {
-        return mCallback.getCapabilities(userId);
+    public ConfigurationInternal getConfigurationInternal(@UserIdInt int userId) {
+        return mCallback.getConfigurationInternal(userId);
     }
 
     @Override
     @NonNull
-    public synchronized TimeZoneConfiguration getConfiguration(@UserIdInt int userId) {
-        return mCallback.getConfiguration(userId);
+    public synchronized ConfigurationInternal getCurrentUserConfigurationInternal() {
+        int currentUserId = mCallback.getCurrentUserId();
+        return getConfigurationInternal(currentUserId);
     }
 
     @Override
     public synchronized boolean updateConfiguration(
-            @UserIdInt int userId, @NonNull TimeZoneConfiguration configurationChanges) {
-        Objects.requireNonNull(configurationChanges);
+            @NonNull TimeZoneConfiguration requestedConfiguration) {
+        Objects.requireNonNull(requestedConfiguration);
 
-        // Validate the requested configuration changes before applying any of them.
-        TimeZoneCapabilities capabilities = mCallback.getCapabilities(userId);
-        boolean canManageTimeZoneDetection =
-                capabilities.getConfigureAutoDetectionEnabled() >= CAPABILITY_NOT_APPLICABLE;
-        if (!canManageTimeZoneDetection
-                && containsAutoTimeDetectionProperties(configurationChanges)) {
+        int userId = requestedConfiguration.getUserId();
+        TimeZoneCapabilities capabilities = getConfigurationInternal(userId).createCapabilities();
+
+        // Create a new configuration builder, and copy across the mutable properties users are
+        // able to modify. Other properties are therefore ignored.
+        final TimeZoneConfiguration newConfiguration =
+                capabilities.applyUpdate(requestedConfiguration);
+        if (newConfiguration == null) {
+            // The changes could not be made due to
             return false;
         }
 
-        // Create a complete configuration by merging the existing and new (possibly partial)
-        // configuration.
-        final TimeZoneConfiguration oldConfiguration = mCallback.getConfiguration(userId);
-        final TimeZoneConfiguration newConfiguration =
-                new TimeZoneConfiguration.Builder(oldConfiguration)
-                        .mergeProperties(configurationChanges)
-                        .build();
+        // Store the configuration / notify as needed. This will cause the mCallback to invoke
+        // handleConfigChanged() asynchronously.
+        mCallback.storeConfiguration(newConfiguration);
 
-        // Set the configuration / notify as needed.
-        boolean configurationChanged = !oldConfiguration.equals(newConfiguration);
-        if (configurationChanged) {
-            mCallback.setConfiguration(userId, newConfiguration);
-
-            String logMsg = "Configuration changed:"
-                    + "oldConfiguration=" + oldConfiguration
-                    + ", configuration=" + configurationChanges
-                    + ", newConfiguration=" + newConfiguration;
-            mTimeZoneChangesLog.log(logMsg);
-            if (DBG) {
-                Slog.d(LOG_TAG, logMsg);
-            }
-            mListener.onConfigurationChanged();
+        TimeZoneConfiguration oldConfiguration = capabilities.getConfiguration();
+        String logMsg = "Configuration changed:"
+                + " oldConfiguration=" + oldConfiguration
+                + ", newConfiguration=" + newConfiguration;
+        mTimeZoneChangesLog.log(logMsg);
+        if (DBG) {
+            Slog.d(LOG_TAG, logMsg);
         }
         return true;
     }
 
-    private static boolean containsAutoTimeDetectionProperties(
-            @NonNull TimeZoneConfiguration configuration) {
-        return configuration.hasProperty(PROPERTY_AUTO_DETECTION_ENABLED)
-                || configuration.hasProperty(PROPERTY_GEO_DETECTION_ENABLED);
-    }
-
     @Override
     public synchronized void suggestGeolocationTimeZone(
             @NonNull GeolocationTimeZoneSuggestion suggestion) {
+
+        int currentUserId = mCallback.getCurrentUserId();
+        ConfigurationInternal currentUserConfig = mCallback.getConfigurationInternal(currentUserId);
         if (DBG) {
-            Slog.d(LOG_TAG, "Geolocation suggestion received. newSuggestion=" + suggestion);
+            Slog.d(LOG_TAG, "Geolocation suggestion received."
+                    + " currentUserConfig=" + currentUserConfig
+                    + " newSuggestion=" + suggestion);
         }
-
         Objects.requireNonNull(suggestion);
-        mLatestGeoLocationSuggestion.set(suggestion);
 
-        // Now perform auto time zone detection. The new suggestion may be used to modify the time
-        // zone setting.
-        if (mCallback.isGeoDetectionEnabled()) {
+        if (currentUserConfig.getGeoDetectionEnabledBehavior()) {
+            // Only store a geolocation suggestion if geolocation detection is currently enabled.
+            mLatestGeoLocationSuggestion.set(suggestion);
+
+            // Now perform auto time zone detection. The new suggestion may be used to modify the
+            // time zone setting.
             String reason = "New geolocation time zone suggested. suggestion=" + suggestion;
-            doAutoTimeZoneDetection(reason);
+            doAutoTimeZoneDetection(currentUserConfig, reason);
         }
     }
 
     @Override
     public synchronized boolean suggestManualTimeZone(
             @UserIdInt int userId, @NonNull ManualTimeZoneSuggestion suggestion) {
+
+        int currentUserId = mCallback.getCurrentUserId();
+        if (userId != currentUserId) {
+            Slog.w(LOG_TAG, "Manual suggestion received but user != current user, userId=" + userId
+                    + " suggestion=" + suggestion);
+
+            // Only listen to changes from the current user.
+            return false;
+        }
+
         Objects.requireNonNull(suggestion);
 
         String timeZoneId = suggestion.getZoneId();
         String cause = "Manual time suggestion received: suggestion=" + suggestion;
 
-        TimeZoneCapabilities capabilities = mCallback.getCapabilities(userId);
+        TimeZoneCapabilities capabilities = getConfigurationInternal(userId).createCapabilities();
         if (capabilities.getSuggestManualTimeZone() != CAPABILITY_POSSESSED) {
             Slog.i(LOG_TAG, "User does not have the capability needed to set the time zone manually"
                     + ", capabilities=" + capabilities
@@ -345,8 +329,12 @@
     @Override
     public synchronized void suggestTelephonyTimeZone(
             @NonNull TelephonyTimeZoneSuggestion suggestion) {
+
+        int currentUserId = mCallback.getCurrentUserId();
+        ConfigurationInternal currentUserConfig = mCallback.getConfigurationInternal(currentUserId);
         if (DBG) {
-            Slog.d(LOG_TAG, "Telephony suggestion received. newSuggestion=" + suggestion);
+            Slog.d(LOG_TAG, "Telephony suggestion received. currentUserConfig=" + currentUserConfig
+                    + " newSuggestion=" + suggestion);
         }
         Objects.requireNonNull(suggestion);
 
@@ -360,9 +348,9 @@
 
         // Now perform auto time zone detection. The new suggestion may be used to modify the time
         // zone setting.
-        if (!mCallback.isGeoDetectionEnabled()) {
+        if (!currentUserConfig.getGeoDetectionEnabledBehavior()) {
             String reason = "New telephony time zone suggested. suggestion=" + suggestion;
-            doAutoTimeZoneDetection(reason);
+            doAutoTimeZoneDetection(currentUserConfig, reason);
         }
     }
 
@@ -392,15 +380,15 @@
      * Performs automatic time zone detection.
      */
     @GuardedBy("this")
-    private void doAutoTimeZoneDetection(@NonNull String detectionReason) {
-        if (!mCallback.isAutoDetectionEnabled()) {
-            // Avoid doing unnecessary work with this (race-prone) check.
+    private void doAutoTimeZoneDetection(
+            @NonNull ConfigurationInternal currentUserConfig, @NonNull String detectionReason) {
+        if (!currentUserConfig.getAutoDetectionEnabledBehavior()) {
+            // Avoid doing unnecessary work.
             return;
         }
 
-        // Use the right suggestions based on the current configuration. This check is potentially
-        // race-prone until this value is set via a call to TimeZoneDetectorStrategy.
-        if (mCallback.isGeoDetectionEnabled()) {
+        // Use the right suggestions based on the current configuration.
+        if (currentUserConfig.getGeoDetectionEnabledBehavior()) {
             doGeolocationTimeZoneDetection(detectionReason);
         } else  {
             doTelephonyTimeZoneDetection(detectionReason);
@@ -480,35 +468,18 @@
 
         // Paranoia: Every suggestion above the SCORE_USAGE_THRESHOLD should have a non-null time
         // zone ID.
-        String newZoneId = bestTelephonySuggestion.suggestion.getZoneId();
-        if (newZoneId == null) {
+        String zoneId = bestTelephonySuggestion.suggestion.getZoneId();
+        if (zoneId == null) {
             Slog.w(LOG_TAG, "Empty zone suggestion scored higher than expected. This is an error:"
                     + " bestTelephonySuggestion=" + bestTelephonySuggestion
                     + " detectionReason=" + detectionReason);
             return;
         }
 
-        String zoneId = bestTelephonySuggestion.suggestion.getZoneId();
         String cause = "Found good suggestion."
                 + ", bestTelephonySuggestion=" + bestTelephonySuggestion
                 + ", detectionReason=" + detectionReason;
-        setAutoDeviceTimeZoneIfRequired(zoneId, cause);
-    }
-
-    @GuardedBy("this")
-    private void setAutoDeviceTimeZoneIfRequired(@NonNull String newZoneId, @NonNull String cause) {
-        Objects.requireNonNull(newZoneId);
-        Objects.requireNonNull(cause);
-
-        if (!mCallback.isAutoDetectionEnabled()) {
-            if (DBG) {
-                Slog.d(LOG_TAG, "Auto time zone detection is not enabled."
-                        + ", newZoneId=" + newZoneId
-                        + ", cause=" + cause);
-            }
-            return;
-        }
-        setDeviceTimeZoneIfRequired(newZoneId, cause);
+        setDeviceTimeZoneIfRequired(zoneId, cause);
     }
 
     @GuardedBy("this")
@@ -582,13 +553,39 @@
         return findBestTelephonySuggestion();
     }
 
-    @Override
-    public synchronized void handleAutoTimeZoneConfigChanged() {
+    private synchronized void handleConfigChanged() {
         if (DBG) {
-            Slog.d(LOG_TAG, "handleAutoTimeZoneConfigChanged()");
+            Slog.d(LOG_TAG, "handleConfigChanged()");
         }
 
-        doAutoTimeZoneDetection("handleAutoTimeZoneConfigChanged()");
+        clearGeolocationSuggestionIfNeeded();
+
+        for (ConfigurationChangeListener listener : mConfigChangeListeners) {
+            listener.onChange();
+        }
+    }
+
+    @GuardedBy("this")
+    private void clearGeolocationSuggestionIfNeeded() {
+        // This method is called whenever the user changes or the config for any user changes. We
+        // don't know what happened, so we capture the current user's config, check to see if we
+        // need to clear state associated with a previous user, and rerun detection.
+        int currentUserId = mCallback.getCurrentUserId();
+        ConfigurationInternal currentUserConfig = mCallback.getConfigurationInternal(currentUserId);
+
+        GeolocationTimeZoneSuggestion latestGeoLocationSuggestion =
+                mLatestGeoLocationSuggestion.get();
+        if (latestGeoLocationSuggestion != null
+                && !currentUserConfig.getGeoDetectionEnabledBehavior()) {
+            // The current user's config has geodetection disabled, so clear the latest suggestion.
+            // This is done to ensure we only ever keep a geolocation suggestion if the user has
+            // said it is ok to do so.
+            mLatestGeoLocationSuggestion.set(null);
+            mTimeZoneChangesLog.log(
+                    "clearGeolocationSuggestionIfNeeded: Cleared latest Geolocation suggestion.");
+        }
+
+        doAutoTimeZoneDetection(currentUserConfig, "clearGeolocationSuggestionIfNeeded()");
     }
 
     @Override
@@ -604,11 +601,14 @@
         ipw.println("TimeZoneDetectorStrategy:");
 
         ipw.increaseIndent(); // level 1
-        ipw.println("mCallback.isAutoDetectionEnabled()=" + mCallback.isAutoDetectionEnabled());
+        int currentUserId = mCallback.getCurrentUserId();
+        ipw.println("mCallback.getCurrentUserId()=" + currentUserId);
+        ConfigurationInternal configuration = mCallback.getConfigurationInternal(currentUserId);
+        ipw.println("mCallback.getConfiguration(currentUserId)=" + configuration);
+        ipw.println("[Capabilities=" + configuration.createCapabilities() + "]");
         ipw.println("mCallback.isDeviceTimeZoneInitialized()="
                 + mCallback.isDeviceTimeZoneInitialized());
         ipw.println("mCallback.getDeviceTimeZone()=" + mCallback.getDeviceTimeZone());
-        ipw.println("mCallback.isGeoDetectionEnabled()=" + mCallback.isGeoDetectionEnabled());
 
         ipw.println("Time zone change log:");
         ipw.increaseIndent(); // level 2
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 1536473..4c2d0d0 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -700,8 +700,8 @@
                     touchableRegion.getBounds(touchableFrame);
                     RectF windowFrame = mTempRectF;
                     windowFrame.set(touchableFrame);
-                    windowFrame.offset(-windowState.getFrameLw().left,
-                            -windowState.getFrameLw().top);
+                    windowFrame.offset(-windowState.getFrame().left,
+                            -windowState.getFrame().top);
                     matrix.mapRect(windowFrame);
                     Region windowBounds = mTempRegion2;
                     windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
@@ -730,7 +730,7 @@
                     }
 
                     // Count letterbox into nonMagnifiedBounds
-                    if (windowState.isLetterboxedForDisplayCutoutLw()) {
+                    if (windowState.isLetterboxedForDisplayCutout()) {
                         Region letterboxBounds = getLetterboxBounds(windowState);
                         nonMagnifiedBounds.op(letterboxBounds, Region.Op.UNION);
                         availableBounds.op(letterboxBounds, Region.Op.DIFFERENCE);
@@ -1429,11 +1429,11 @@
                         // Account for all space in the task, whether the windows in it are
                         // touchable or not. The modal window blocks all touches from the task's
                         // area.
-                        unaccountedSpace.op(windowState.getDisplayFrameLw(), unaccountedSpace,
+                        unaccountedSpace.op(windowState.getDisplayFrame(), unaccountedSpace,
                                 Region.Op.REVERSE_DIFFERENCE);
                     } else {
                         // If a window has tap exclude region, we need to account it.
-                        final Region displayRegion = new Region(windowState.getDisplayFrameLw());
+                        final Region displayRegion = new Region(windowState.getDisplayFrame());
                         final Region tapExcludeRegion = new Region();
                         windowState.getTapExcludeRegion(tapExcludeRegion);
                         displayRegion.op(tapExcludeRegion, displayRegion,
@@ -1470,7 +1470,7 @@
                 // Move to origin as all transforms are captured by the matrix.
                 RectF windowFrame = mTempRectF;
                 windowFrame.set(rect);
-                windowFrame.offset(-windowState.getFrameLw().left, -windowState.getFrameLw().top);
+                windowFrame.offset(-windowState.getFrame().left, -windowState.getFrame().top);
 
                 matrix.mapRect(windowFrame);
 
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 76473d08..56261c4 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -110,9 +110,13 @@
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONTAINERS;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SWITCH;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 import static com.android.server.wm.ActivityRecordProto.ALL_DRAWN;
@@ -145,9 +149,6 @@
 import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_APP;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONTAINERS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_FOCUS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SAVED_STATE;
@@ -1096,15 +1097,15 @@
 
     private void scheduleActivityMovedToDisplay(int displayId, Configuration config) {
         if (!attachedToProcess()) {
-            if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.w(TAG,
-                    "Can't report activity moved to display - client not running, activityRecord="
-                            + this + ", displayId=" + displayId);
+            ProtoLog.w(WM_DEBUG_SWITCH, "Can't report activity moved "
+                    + "to display - client not running, activityRecord=%s, displayId=%d",
+                    this, displayId);
             return;
         }
         try {
-            if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
-                    "Reporting activity moved to display" + ", activityRecord=" + this
-                            + ", displayId=" + displayId + ", config=" + config);
+            ProtoLog.v(WM_DEBUG_SWITCH, "Reporting activity moved to "
+                    + "display, activityRecord=%s, displayId=%d, config=%s", this, displayId,
+                    config);
 
             mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
                     MoveToDisplayItem.obtain(displayId, config));
@@ -1115,14 +1116,13 @@
 
     private void scheduleConfigurationChanged(Configuration config) {
         if (!attachedToProcess()) {
-            if (DEBUG_CONFIGURATION) Slog.w(TAG,
-                    "Can't report activity configuration update - client not running"
-                            + ", activityRecord=" + this);
+            ProtoLog.w(WM_DEBUG_CONFIGURATION, "Can't report activity configuration "
+                    + "update - client not running, activityRecord=%s", this);
             return;
         }
         try {
-            if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + this + ", config: "
-                    + config);
+            ProtoLog.v(WM_DEBUG_CONFIGURATION, "Sending new config to %s, "
+                    + "config: %s", this, config);
 
             mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
                     ActivityConfigurationChangeItem.obtain(config));
@@ -1334,7 +1334,7 @@
         if (w == null || winHint != null && w != winHint) {
             return;
         }
-        final boolean surfaceReady = w.isDrawnLw()  // Regular case
+        final boolean surfaceReady = w.isDrawn()  // Regular case
                 || w.mWinAnimator.mSurfaceDestroyDeferred  // The preserved surface is still ready.
                 || w.isDragResizeChanged();  // Waiting for relayoutWindow to call preserveSurface.
         final boolean needsLetterbox = surfaceReady && w.isLetterboxedAppWindow() && fillsParent();
@@ -1355,7 +1355,7 @@
                     : inMultiWindowMode()
                             ? task.getBounds()
                             : getRootTask().getParent().getBounds();
-            mLetterbox.layout(spaceToFill, w.getFrameLw(), mTmpPoint);
+            mLetterbox.layout(spaceToFill, w.getFrame(), mTmpPoint);
         } else if (mLetterbox != null) {
             mLetterbox.hide();
         }
@@ -1949,10 +1949,8 @@
             startingWindow = null;
             startingDisplayed = false;
             if (surface == null) {
-                ProtoLog.v(WM_DEBUG_STARTING_WINDOW,
-                        "startingWindow was set but startingSurface==null, couldn't "
-                                + "remove");
-
+                ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "startingWindow was set but "
+                        + "startingSurface==null, couldn't remove");
                 return;
             }
         } else {
@@ -1962,9 +1960,10 @@
             return;
         }
 
+
         ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Schedule remove starting %s startingWindow=%s"
-                        + " startingView=%s Callers=%s",
-                this, startingWindow, startingSurface, Debug.getCallers(5));
+                + " startingView=%s Callers=%s", this, startingWindow, startingSurface,
+                Debug.getCallers(5));
 
 
         // Use the same thread to remove the window as we used to add it, as otherwise we end up
@@ -2399,9 +2398,8 @@
      */
     boolean moveFocusableActivityToTop(String reason) {
         if (!isFocusable()) {
-            if (DEBUG_FOCUS) {
-                Slog.d(TAG_FOCUS, "moveActivityStackToFront: unfocusable activity=" + this);
-            }
+            ProtoLog.d(WM_DEBUG_FOCUS, "moveActivityStackToFront: unfocusable "
+                    + "activity=%s", this);
             return false;
         }
 
@@ -2414,15 +2412,11 @@
 
         if (mRootWindowContainer.getTopResumedActivity() == this
                 && getDisplayContent().mFocusedApp == this) {
-            if (DEBUG_FOCUS) {
-                Slog.d(TAG_FOCUS, "moveActivityStackToFront: already on top, activity=" + this);
-            }
+            ProtoLog.d(WM_DEBUG_FOCUS, "moveActivityStackToFront: already on top, "
+                    + "activity=%s", this);
             return !isState(RESUMED);
         }
-
-        if (DEBUG_FOCUS) {
-            Slog.d(TAG_FOCUS, "moveActivityStackToFront: activity=" + this);
-        }
+        ProtoLog.d(WM_DEBUG_FOCUS, "moveActivityStackToFront: activity=%s", this);
 
         stack.moveToFront(reason, task);
         // Report top activity change to tracking services and WM
@@ -2798,10 +2792,8 @@
             mRootWindowContainer.resumeFocusedStacksTopActivities();
         }
 
-        if (DEBUG_CONTAINERS) {
-            Slog.d(TAG_CONTAINERS, "destroyIfPossible: r=" + this + " destroy returned removed="
-                    + activityRemoved);
-        }
+        ProtoLog.d(WM_DEBUG_CONTAINERS, "destroyIfPossible: r=%s destroy returned "
+                + "removed=%s", this, activityRemoved);
 
         return activityRemoved;
     }
@@ -2935,10 +2927,9 @@
         finishActivityResults(Activity.RESULT_CANCELED,
                 null /* resultData */, null /* resultGrants */);
         makeFinishingLocked();
-        if (ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE) {
-            Slog.i(TAG_ADD_REMOVE, "Removing activity " + this + " from stack, reason="
-                    + reason + ", callers=" + Debug.getCallers(5));
-        }
+
+        ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Removing activity %s from stack, reason= %s "
+                        + "callers=%s", this, reason, Debug.getCallers(5));
 
         takeFromHistory();
         removeTimeouts();
@@ -2978,7 +2969,7 @@
     void destroyed(String reason) {
         removeDestroyTimeout();
 
-        if (DEBUG_CONTAINERS) Slog.d(TAG_CONTAINERS, "activityDestroyedLocked: r=" + this);
+        ProtoLog.d(WM_DEBUG_CONTAINERS, "activityDestroyedLocked: r=%s", this);
 
         if (!isState(DESTROYING, DESTROYED)) {
             throw new IllegalStateException(
@@ -3179,12 +3170,9 @@
             remove = false;
         }
         if (remove) {
-            if (ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE || DEBUG_CLEANUP) {
-                Slog.i(TAG_ADD_REMOVE, "Removing activity " + this
-                        + " hasSavedState=" + mHaveState + " stateNotNeeded=" + stateNotNeeded
-                        + " finishing=" + finishing + " state=" + mState
-                        + " callers=" + Debug.getCallers(5));
-            }
+            ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Removing activity %s hasSavedState=%b "
+                    + "stateNotNeeded=%s finishing=%b state=%s callers=%s", this,
+                    mHaveState, stateNotNeeded, finishing, mState, Debug.getCallers(5));
             if (!finishing || (app != null && app.isRemoved())) {
                 Slog.w(TAG, "Force removing " + this + ": app died, no saved state");
                 EventLogTags.writeWmFinishActivity(mUserId, System.identityHashCode(this),
@@ -4296,7 +4284,7 @@
         } else {
             // If we are being set visible, and the starting window is not yet displayed,
             // then make sure it doesn't get displayed.
-            if (startingWindow != null && !startingWindow.isDrawnLw()) {
+            if (startingWindow != null && !startingWindow.isDrawn()) {
                 startingWindow.clearPolicyVisibilityFlag(LEGACY_POLICY_VISIBILITY);
                 startingWindow.mLegacyPolicyVisibilityAfterAnim = false;
             }
@@ -5596,9 +5584,9 @@
             if (DEBUG_VISIBILITY || WM_DEBUG_ORIENTATION.isLogToLogcat()) {
                 final boolean isAnimationSet = isAnimating(TRANSITION | PARENTS,
                         ANIMATION_TYPE_APP_TRANSITION);
-                Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw()
+                Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawn()
                         + ", isAnimationSet=" + isAnimationSet);
-                if (!w.isDrawnLw()) {
+                if (!w.isDrawn()) {
                     Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceController
                             + " pv=" + w.isVisibleByPolicy()
                             + " mDrawState=" + winAnimator.drawStateToString()
@@ -5613,7 +5601,7 @@
                     if (findMainWindow(false /* includeStartingApp */) != w) {
                         mNumInterestingWindows++;
                     }
-                    if (w.isDrawnLw()) {
+                    if (w.isDrawn()) {
                         mNumDrawnWindows++;
 
                         if (DEBUG_VISIBILITY || WM_DEBUG_ORIENTATION.isLogToLogcat()) {
@@ -5626,7 +5614,7 @@
                         isInterestingAndDrawn = true;
                     }
                 }
-            } else if (w.isDrawnLw()) {
+            } else if (w.isDrawn()) {
                 // The starting window for this container is drawn.
                 mStackSupervisor.getActivityMetricsLogger().notifyStartingWindowDrawn(this);
                 startingDisplayed = true;
@@ -6155,7 +6143,7 @@
         if (win == null) {
             return;
         }
-        final Rect frame = win.getRelativeFrameLw();
+        final Rect frame = win.getRelativeFrame();
         final int thumbnailDrawableRes = task.mUserId == mWmService.mCurrentUserId
                 ? R.drawable.ic_account_circle
                 : R.drawable.ic_corp_badge;
@@ -6181,7 +6169,7 @@
         // destination of the thumbnail header animation. If this is a full screen
         // window scenario, we use the whole display as the target.
         WindowState win = findMainWindow();
-        Rect appRect = win != null ? win.getContentFrameLw() :
+        final Rect appRect = win != null ? win.getContentFrame() :
                 new Rect(0, 0, displayInfo.appWidth, displayInfo.appHeight);
         final Rect insets = win != null ? win.getContentInsets() : null;
         final Configuration displayConfig = mDisplayContent.getConfiguration();
@@ -7007,27 +6995,27 @@
             boolean ignoreVisibility) {
         final Task stack = getRootTask();
         if (stack.mConfigWillChange) {
-            if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
-                    "Skipping config check (will change): " + this);
+            ProtoLog.v(WM_DEBUG_CONFIGURATION, "Skipping config check "
+                    + "(will change): %s", this);
             return true;
         }
 
         // We don't worry about activities that are finishing.
         if (finishing) {
-            if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
-                    "Configuration doesn't matter in finishing " + this);
+            ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration doesn't matter "
+                    + "in finishing %s", this);
             stopFreezingScreenLocked(false);
             return true;
         }
 
         if (!ignoreVisibility && (mState == STOPPING || mState == STOPPED || !shouldBeVisible())) {
-            if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
-                    "Skipping config check invisible: " + this);
+            ProtoLog.v(WM_DEBUG_CONFIGURATION, "Skipping config check "
+                    + "invisible: %s", this);
             return true;
         }
 
-        if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
-                "Ensuring correct configuration: " + this);
+        ProtoLog.v(WM_DEBUG_CONFIGURATION, "Ensuring correct "
+                + "configuration: %s", this);
 
         final int newDisplayId = getDisplayId();
         final boolean displayChanged = mLastReportedDisplayId != newDisplayId;
@@ -7043,8 +7031,8 @@
         // the combine configurations are equal, but would otherwise differ in the override config
         mTmpConfig.setTo(mLastReportedConfiguration.getMergedConfiguration());
         if (getConfiguration().equals(mTmpConfig) && !forceNewConfig && !displayChanged) {
-            if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
-                    "Configuration & display unchanged in " + this);
+            ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration & display "
+                    + "unchanged in %s", this);
             return true;
         }
 
@@ -7064,14 +7052,14 @@
             // No need to relaunch or schedule new config for activity that hasn't been launched
             // yet. We do, however, return after applying the config to activity record, so that
             // it will use it for launch transaction.
-            if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
-                    "Skipping config check for initializing activity: " + this);
+            ProtoLog.v(WM_DEBUG_CONFIGURATION, "Skipping config check for "
+                    + "initializing activity: %s", this);
             return true;
         }
 
         if (changes == 0 && !forceNewConfig) {
-            if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
-                    "Configuration no differences in " + this);
+            ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration no differences in %s",
+                    this);
             // There are no significant differences, so we won't relaunch but should still deliver
             // the new configuration to the client process.
             if (displayChanged) {
@@ -7082,26 +7070,23 @@
             return true;
         }
 
-        if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
-                "Configuration changes for " + this + ", allChanges="
-                        + Configuration.configurationDiffToString(changes));
+        ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration changes for %s, "
+                + "allChanges=%s", this, Configuration.configurationDiffToString(changes));
 
         // If the activity isn't currently running, just leave the new configuration and it will
         // pick that up next time it starts.
         if (!attachedToProcess()) {
-            if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
-                    "Configuration doesn't matter not running " + this);
+            ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration doesn't matter not running %s", this);
             stopFreezingScreenLocked(false);
             forceNewConfig = false;
             return true;
         }
 
         // Figure out how to handle the changes between the configurations.
-        if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
-                "Checking to restart " + info.name + ": changed=0x"
-                        + Integer.toHexString(changes) + ", handles=0x"
-                        + Integer.toHexString(info.getRealConfigChanged())
-                        + ", mLastReportedConfiguration=" + mLastReportedConfiguration);
+        ProtoLog.v(WM_DEBUG_CONFIGURATION, "Checking to restart %s: changed=0x%s, "
+                + "handles=0x%s, mLastReportedConfiguration=%s", info.name,
+                Integer.toHexString(changes), Integer.toHexString(info.getRealConfigChanged()),
+                mLastReportedConfiguration);
 
         if (shouldRelaunchLocked(changes, mTmpConfig) || forceNewConfig) {
             // Aha, the activity isn't handling the change, so DIE DIE DIE.
@@ -7118,20 +7103,20 @@
                 mRelaunchReason = RELAUNCH_REASON_NONE;
             }
             if (!attachedToProcess()) {
-                if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
-                        "Config is destroying non-running " + this);
+                ProtoLog.v(WM_DEBUG_CONFIGURATION,
+                        "Config is destroying non-running %s", this);
                 destroyImmediately("config");
             } else if (mState == PAUSING) {
                 // A little annoying: we are waiting for this activity to finish pausing. Let's not
                 // do anything now, but just flag that it needs to be restarted when done pausing.
-                if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
-                        "Config is skipping already pausing " + this);
+                ProtoLog.v(WM_DEBUG_CONFIGURATION,
+                        "Config is skipping already pausing %s", this);
                 deferRelaunchUntilPaused = true;
                 preserveWindowOnDeferredRelaunch = preserveWindow;
                 return true;
             } else {
-                if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
-                        "Config is relaunching " + this);
+                ProtoLog.v(WM_DEBUG_CONFIGURATION, "Config is relaunching %s",
+                        this);
                 if (DEBUG_STATES && !mVisibleRequested) {
                     Slog.v(TAG_STATES, "Config is relaunching invisible activity " + this
                             + " called by " + Debug.getCallers(4));
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 4c93b9e..be7a6ae 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -56,12 +56,12 @@
 import static android.os.Process.INVALID_UID;
 import static android.view.Display.DEFAULT_DISPLAY;
 
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
 import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME;
 import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
 import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ACTIVITY_STARTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
@@ -116,6 +116,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.HeavyWeightSwitcherActivity;
 import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.protolog.common.ProtoLog;
 import com.android.server.am.PendingIntentRecord;
 import com.android.server.pm.InstantAppResolver;
 import com.android.server.power.ShutdownCheckPoints;
@@ -669,10 +670,8 @@
                 if (stack != null) {
                     stack.mConfigWillChange = globalConfigWillChange;
                 }
-                if (DEBUG_CONFIGURATION) {
-                    Slog.v(TAG_CONFIGURATION, "Starting activity when config will change = "
-                            + globalConfigWillChange);
-                }
+                ProtoLog.v(WM_DEBUG_CONFIGURATION, "Starting activity when config "
+                        + "will change = %b", globalConfigWillChange);
 
                 final long origId = Binder.clearCallingIdentity();
 
@@ -695,10 +694,9 @@
                     if (stack != null) {
                         stack.mConfigWillChange = false;
                     }
-                    if (DEBUG_CONFIGURATION) {
-                        Slog.v(TAG_CONFIGURATION,
+                    ProtoLog.v(WM_DEBUG_CONFIGURATION,
                                 "Updating to new configuration after starting activity.");
-                    }
+
                     mService.updateConfigurationLocked(mRequest.globalConfig, null, false);
                 }
 
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java b/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java
index da0bfd6..3c562a6 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java
@@ -43,12 +43,6 @@
     // Enable all debug log categories for activities.
     private static final boolean DEBUG_ALL_ACTIVITIES = DEBUG_ALL || false;
 
-    static final boolean DEBUG_ADD_REMOVE = DEBUG_ALL_ACTIVITIES || false;
-    public static final boolean DEBUG_CONFIGURATION = DEBUG_ALL || false;
-    static final boolean DEBUG_CONTAINERS = DEBUG_ALL_ACTIVITIES || false;
-    static final boolean DEBUG_FOCUS = false;
-    static final boolean DEBUG_IMMERSIVE = DEBUG_ALL || false;
-    static final boolean DEBUG_LOCKTASK = DEBUG_ALL || false;
     static final boolean DEBUG_PAUSE = DEBUG_ALL || false;
     static final boolean DEBUG_RECENTS = DEBUG_ALL || false;
     static final boolean DEBUG_RECENTS_TRIM_TASKS = DEBUG_RECENTS || false;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 2adaa52..6a8cbfb 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -66,6 +66,10 @@
 import static android.view.Display.INVALID_DISPLAY;
 import static android.view.WindowManager.TRANSIT_NONE;
 
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IMMERSIVE;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LOCKTASK;
 import static com.android.server.am.ActivityManagerService.ANR_TRACE_DIR;
 import static com.android.server.am.ActivityManagerService.MY_PID;
 import static com.android.server.am.ActivityManagerService.STOCK_PM_FLAGS;
@@ -92,10 +96,6 @@
 import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
 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_FOCUS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_IMMERSIVE;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
@@ -242,6 +242,7 @@
 import com.android.internal.os.TransferPipe;
 import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.KeyguardDismissCallback;
+import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.FrameworkStatsLog;
@@ -813,7 +814,7 @@
             // in-place.
             updateConfigurationLocked(configuration, null, true);
             final Configuration globalConfig = getGlobalConfiguration();
-            if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Initial config: " + globalConfig);
+            ProtoLog.v(WM_DEBUG_CONFIGURATION, "Initial config: %s", globalConfig);
 
             // Load resources only after the current configuration has been set.
             final Resources res = mContext.getResources();
@@ -1960,7 +1961,7 @@
 
             // update associated state if we're frontmost
             if (r.isFocusedActivityOnDisplay()) {
-                if (DEBUG_IMMERSIVE) Slog.d(TAG_IMMERSIVE, "Frontmost changed immersion: "+ r);
+                ProtoLog.d(WM_DEBUG_IMMERSIVE, "Frontmost changed immersion: %s", r);
                 applyUpdateLockStateLocked(r);
             }
         }
@@ -1974,8 +1975,8 @@
         final boolean nextState = r != null && r.immersive;
         mH.post(() -> {
             if (mUpdateLock.isHeld() != nextState) {
-                if (DEBUG_IMMERSIVE) Slog.d(TAG_IMMERSIVE,
-                        "Applying new update lock state '" + nextState + "' for " + r);
+                ProtoLog.d(WM_DEBUG_IMMERSIVE, "Applying new update lock state '%s' for %s",
+                        nextState, r);
                 if (nextState) {
                     mUpdateLock.acquire();
                 } else {
@@ -2176,7 +2177,7 @@
     @Override
     public void setFocusedStack(int stackId) {
         mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "setFocusedStack()");
-        if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedStack: stackId=" + stackId);
+        ProtoLog.d(WM_DEBUG_FOCUS, "setFocusedStack: stackId=%d", stackId);
         final long callingId = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
@@ -2198,7 +2199,7 @@
     @Override
     public void setFocusedTask(int taskId) {
         mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "setFocusedTask()");
-        if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedTask: taskId=" + taskId);
+        ProtoLog.d(WM_DEBUG_FOCUS, "setFocusedTask: taskId=%d", taskId);
         final long callingId = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
@@ -3013,7 +3014,7 @@
     }
 
     private void startLockTaskModeLocked(@Nullable Task task, boolean isSystemCaller) {
-        if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "startLockTaskModeLocked: " + task);
+        ProtoLog.w(WM_DEBUG_LOCKTASK, "startLockTaskModeLocked: %s", task);
         if (task == null || task.mLockTaskAuth == LOCK_TASK_AUTH_DONT_LOCK) {
             return;
         }
@@ -3075,8 +3076,7 @@
                     "updateLockTaskPackages()");
         }
         synchronized (mGlobalLock) {
-            if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Allowlisting " + userId + ":"
-                    + Arrays.toString(packages));
+            ProtoLog.w(WM_DEBUG_LOCKTASK, "Allowlisting %d:%s", userId, Arrays.toString(packages));
             getLockTaskController().updateLockTaskPackages(userId, packages);
         }
     }
@@ -4001,9 +4001,9 @@
     @Override
     public void reportSizeConfigurations(IBinder token, int[] horizontalSizeConfiguration,
             int[] verticalSizeConfigurations, int[] smallestSizeConfigurations) {
-        if (DEBUG_CONFIGURATION) Slog.v(TAG, "Report configuration: " + token + " "
-                + Arrays.toString(horizontalSizeConfiguration) + " "
-                + Arrays.toString(verticalSizeConfigurations));
+        ProtoLog.v(WM_DEBUG_CONFIGURATION, "Report configuration: %s %s %s",
+                token, Arrays.toString(horizontalSizeConfiguration),
+                Arrays.toString(verticalSizeConfigurations));
         synchronized (mGlobalLock) {
             ActivityRecord record = ActivityRecord.isInStackLocked(token);
             if (record == null) {
@@ -4497,8 +4497,8 @@
                     "updateLockTaskFeatures()");
         }
         synchronized (mGlobalLock) {
-            if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Allowing features " + userId + ":0x" +
-                    Integer.toHexString(flags));
+            ProtoLog.w(WM_DEBUG_LOCKTASK, "Allowing features %d:0x%s",
+                    userId, Integer.toHexString(flags));
             getLockTaskController().updateLockTaskFeatures(userId, flags);
         }
     }
@@ -5183,8 +5183,8 @@
             return 0;
         }
 
-        if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.i(TAG_CONFIGURATION,
-                "Updating global configuration to: " + values);
+        ProtoLog.i(WM_DEBUG_CONFIGURATION, "Updating global configuration "
+                + "to: %s", values);
         writeConfigurationChanged(changes);
         FrameworkStatsLog.write(FrameworkStatsLog.RESOURCE_CONFIGURATION_CHANGED,
                 values.colorMode,
@@ -5262,10 +5262,8 @@
         for (int i = pidMap.size() - 1; i >= 0; i--) {
             final int pid = pidMap.keyAt(i);
             final WindowProcessController app = pidMap.get(pid);
-            if (DEBUG_CONFIGURATION) {
-                Slog.v(TAG_CONFIGURATION, "Update process config of "
-                        + app.mName + " to new config " + configCopy);
-            }
+            ProtoLog.v(WM_DEBUG_CONFIGURATION, "Update process config of %s to new "
+                    + "config %s", app.mName, configCopy);
             app.onConfigurationChanged(configCopy);
         }
 
@@ -6563,10 +6561,8 @@
             if (InputMethodSystemProperty.MULTI_CLIENT_IME_ENABLED) return;
 
             if (pid == MY_PID || pid < 0) {
-                if (DEBUG_CONFIGURATION) {
-                    Slog.w(TAG,
+                ProtoLog.w(WM_DEBUG_CONFIGURATION,
                             "Trying to update display configuration for system/invalid process.");
-                }
                 return;
             }
             synchronized (mGlobalLock) {
@@ -6574,18 +6570,14 @@
                         mRootWindowContainer.getDisplayContent(displayId);
                 if (displayContent == null) {
                     // Call might come when display is not yet added or has been removed.
-                    if (DEBUG_CONFIGURATION) {
-                        Slog.w(TAG, "Trying to update display configuration for non-existing "
-                                + "displayId=" + displayId);
-                    }
+                    ProtoLog.w(WM_DEBUG_CONFIGURATION, "Trying to update display "
+                            + "configuration for non-existing displayId=%d", displayId);
                     return;
                 }
                 final WindowProcessController process = mProcessMap.getProcess(pid);
                 if (process == null) {
-                    if (DEBUG_CONFIGURATION) {
-                        Slog.w(TAG, "Trying to update display configuration for invalid "
-                                + "process, pid=" + pid);
-                    }
+                    ProtoLog.w(WM_DEBUG_CONFIGURATION, "Trying to update display "
+                            + "configuration for invalid process, pid=%d", pid);
                     return;
                 }
                 process.registerDisplayConfigurationListener(displayContent);
diff --git a/services/core/java/com/android/server/wm/BarController.java b/services/core/java/com/android/server/wm/BarController.java
index c144755..8568d5f 100644
--- a/services/core/java/com/android/server/wm/BarController.java
+++ b/services/core/java/com/android/server/wm/BarController.java
@@ -222,12 +222,12 @@
     }
 
     protected boolean skipAnimation() {
-        return !mWin.isDrawnLw();
+        return !mWin.isDrawn();
     }
 
     private @StatusBarManager.WindowVisibleState int computeStateLw(
             boolean wasVis, boolean wasAnim, WindowState win, boolean change) {
-        if (win.isDrawnLw()) {
+        if (win.isDrawn()) {
             final boolean vis = win.isVisibleLw();
             final boolean anim = win.isAnimatingLw();
             if (mState == StatusBarManager.WINDOW_STATE_HIDING && !change && !vis) {
@@ -264,7 +264,7 @@
     }
 
     boolean checkHiddenLw() {
-        if (mWin != null && mWin.isDrawnLw()) {
+        if (mWin != null && mWin.isDrawn()) {
             if (!mWin.isVisibleLw() && !mWin.isAnimatingLw()) {
                 updateStateLw(StatusBarManager.WINDOW_STATE_HIDDEN);
             }
@@ -291,7 +291,7 @@
         } else if (mWin == null) {
             if (DEBUG) Slog.d(mTag, "Not showing transient bar, bar doesn't exist");
             return false;
-        } else if (mWin.isDisplayedLw()) {
+        } else if (mWin.isDisplayed()) {
             if (DEBUG) Slog.d(mTag, "Not showing transient bar, bar already visible");
             return false;
         } else {
diff --git a/services/core/java/com/android/server/wm/CompatModePackages.java b/services/core/java/com/android/server/wm/CompatModePackages.java
index 167afab..7e55f0a 100644
--- a/services/core/java/com/android/server/wm/CompatModePackages.java
+++ b/services/core/java/com/android/server/wm/CompatModePackages.java
@@ -16,8 +16,8 @@
 
 package com.android.server.wm;
 
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
 import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -37,6 +37,7 @@
 import android.util.SparseArray;
 import android.util.Xml;
 
+import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.FastXmlSerializer;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -333,8 +334,8 @@
                 }
                 try {
                     if (app.hasThread()) {
-                        if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Sending to proc "
-                                + app.mName + " new compat " + ci);
+                        ProtoLog.v(WM_DEBUG_CONFIGURATION, "Sending to proc %s "
+                                + "new compat %s", app.mName, ci);
                         app.getThread().updatePackageCompatibilityInfo(packageName, ci);
                     }
                 } catch (Exception e) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 0215ead..2f7cc69 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -694,7 +694,7 @@
         // Don't do layout of a window if it is not visible, or soon won't be visible, to avoid
         // wasting time and funky changes while a window is animating away.
         final boolean gone = (mTmpWindow != null && mWmService.mPolicy.canBeHiddenByKeyguardLw(w))
-                || w.isGoneForLayoutLw();
+                || w.isGoneForLayout();
 
         if (DEBUG_LAYOUT && !w.mLayoutAttached) {
             Slog.v(TAG, "1ST PASS " + w + ": gone=" + gone + " mHaveFrame=" + w.mHaveFrame
@@ -742,7 +742,7 @@
             if (firstLayout) {
                 // The client may compute its actual requested size according to the first layout,
                 // so we still request the window to resize if the current frame is empty.
-                if (!w.getFrameLw().isEmpty()) {
+                if (!w.getFrame().isEmpty()) {
                     w.updateLastFrames();
                 }
                 w.updateLastInsetValues();
@@ -753,9 +753,9 @@
                 w.mActivityRecord.layoutLetterbox(w);
             }
 
-            if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame=" + w.getFrameLw()
+            if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame=" + w.getFrame()
                     + " mContainingFrame=" + w.getContainingFrame()
-                    + " mDisplayFrame=" + w.getDisplayFrameLw());
+                    + " mDisplayFrame=" + w.getDisplayFrame());
         }
     };
 
@@ -780,9 +780,9 @@
                 w.prelayout();
                 getDisplayPolicy().layoutWindowLw(w, w.getParentWindow(), mDisplayFrames);
                 w.mLayoutSeq = mLayoutSeq;
-                if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.getFrameLw()
+                if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.getFrame()
                         + " mContainingFrame=" + w.getContainingFrame()
-                        + " mDisplayFrame=" + w.getDisplayFrameLw());
+                        + " mDisplayFrame=" + w.getDisplayFrame());
             }
         }
     };
@@ -807,7 +807,7 @@
         w.mObscured = mTmpApplySurfaceChangesTransactionState.obscured;
 
         if (!mTmpApplySurfaceChangesTransactionState.obscured) {
-            final boolean isDisplayed = w.isDisplayedLw();
+            final boolean isDisplayed = w.isDisplayed();
 
             if (isDisplayed && w.isObscuringDisplay()) {
                 // This window completely covers everything behind it, so we want to leave all
@@ -2549,7 +2549,7 @@
                 return;
             }
 
-            if (w.isOnScreen() && w.isVisibleLw() && w.getFrameLw().contains(x, y)) {
+            if (w.isOnScreen() && w.isVisibleLw() && w.getFrame().contains(x, y)) {
                 targetWindowType[0] = w.mAttrs.type;
                 return;
             }
@@ -2747,7 +2747,7 @@
     void adjustForImeIfNeeded() {
         final WindowState imeWin = mInputMethodWindow;
         final boolean imeVisible = imeWin != null && imeWin.isVisibleLw()
-                && imeWin.isDisplayedLw();
+                && imeWin.isDisplayed();
         final int imeHeight = mDisplayFrames.getInputMethodWindowVisibleHeight();
         mPinnedStackControllerLocked.setAdjustedForIme(imeVisible, imeHeight);
     }
@@ -3364,7 +3364,7 @@
         // Now, a special case -- if the last target's window is in the process of exiting, but
         // not removed, keep on the last target to avoid IME flicker. The exception is if the
         // current target is home since we want opening apps to become the IME target right away.
-        if (curTarget != null && !curTarget.mRemoved && curTarget.isDisplayedLw()
+        if (curTarget != null && !curTarget.mRemoved && curTarget.isDisplayed()
                 && curTarget.isClosing() && !curTarget.isActivityTypeHome()) {
             if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, "Not changing target till current window is"
                     + " closing and not removed");
@@ -3647,7 +3647,7 @@
 
         final WindowState visibleNotDrawnWindow = getWindow(w -> {
             final boolean isVisible = w.isVisible() && !w.mObscured;
-            final boolean isDrawn = w.isDrawnLw();
+            final boolean isDrawn = w.isDrawn();
             if (isVisible && !isDrawn) {
                 ProtoLog.d(WM_DEBUG_BOOT,
                         "DisplayContent: boot is waiting for window of type %d to be drawn",
@@ -4599,9 +4599,9 @@
             DisplayContent dc = this;
             do {
                 final WindowState displayParent = dc.getParentWindow();
-                location.x += displayParent.getFrameLw().left
+                location.x += displayParent.getFrame().left
                         + (dc.getLocationInParentWindow().x * displayParent.mGlobalScale + 0.5f);
-                location.y += displayParent.getFrameLw().top
+                location.y += displayParent.getFrame().top
                         + (dc.getLocationInParentWindow().y * displayParent.mGlobalScale + 0.5f);
                 dc = displayParent.getDisplayContent();
             } while (dc != null && dc.getParentWindow() != null);
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 40fc25b..1c147c2 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -195,13 +195,13 @@
 import com.android.server.LocalServices;
 import com.android.server.UiThread;
 import com.android.server.policy.WindowManagerPolicy;
-import com.android.server.policy.WindowManagerPolicy.InputConsumer;
 import com.android.server.policy.WindowManagerPolicy.NavigationBarPosition;
 import com.android.server.policy.WindowManagerPolicy.ScreenOnListener;
 import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs;
 import com.android.server.policy.WindowOrientationListener;
 import com.android.server.statusbar.StatusBarManagerInternal;
 import com.android.server.wallpaper.WallpaperManagerInternal;
+import com.android.server.wm.InputMonitor.EventReceiverInputConsumer;
 import com.android.server.wm.utils.InsetUtils;
 
 import java.io.PrintWriter;
@@ -416,7 +416,7 @@
     private boolean mAllowLockscreenWhenOn;
 
     @VisibleForTesting
-    InputConsumer mInputConsumer = null;
+    EventReceiverInputConsumer mInputConsumer;
 
     private PointerLocationView mPointerLocationView;
 
@@ -462,7 +462,7 @@
                     }
                     break;
                 case MSG_DISPOSE_INPUT_CONSUMER:
-                    disposeInputConsumer((InputConsumer) msg.obj);
+                    disposeInputConsumer((EventReceiverInputConsumer) msg.obj);
                     break;
                 case MSG_ENABLE_POINTER_LOCATION:
                     enablePointerLocation();
@@ -1126,7 +1126,7 @@
 
                         // For IME we use regular frame.
                         (displayFrames, windowState, inOutFrame) ->
-                                inOutFrame.set(windowState.getFrameLw()));
+                                inOutFrame.set(windowState.getFrame()));
 
                 mDisplayContent.setInsetProvider(ITYPE_BOTTOM_GESTURES, win,
                         (displayFrames, windowState, inOutFrame) -> {
@@ -1203,11 +1203,11 @@
                 // IME should not provide frame which is smaller than the nav bar frame. Otherwise,
                 // nav bar might be overlapped with the content of the client when IME is shown.
                 sTmpRect.set(inOutFrame);
-                sTmpRect.intersectUnchecked(mNavigationBar.getFrameLw());
-                inOutFrame.inset(windowState.getGivenContentInsetsLw());
+                sTmpRect.intersectUnchecked(mNavigationBar.getFrame());
+                inOutFrame.inset(windowState.mGivenContentInsets);
                 inOutFrame.union(sTmpRect);
             } else {
-                inOutFrame.inset(windowState.getGivenContentInsetsLw());
+                inOutFrame.inset(windowState.mGivenContentInsets);
             }
         };
     }
@@ -2075,7 +2075,7 @@
 
             // In case we forced the window to draw behind the navigation bar, restrict df to
             // DF.Restricted to simulate old compat behavior.
-            Rect parentDisplayFrame = attached.getDisplayFrameLw();
+            Rect parentDisplayFrame = attached.getDisplayFrame();
             final WindowManager.LayoutParams attachedAttrs = attached.mAttrs;
             if ((attachedAttrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
                     && (attachedAttrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
@@ -2096,14 +2096,14 @@
                 // setting {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR} flag.
                 // Otherwise, use the overscan frame.
                 cf.set((fl & FLAG_LAYOUT_ATTACHED_IN_DECOR) != 0
-                        ? attached.getContentFrameLw() : parentDisplayFrame);
+                        ? attached.getContentFrame() : parentDisplayFrame);
             } else {
                 // If the window is resizing, then we want to base the content frame on our attached
                 // content frame to resize...however, things can be tricky if the attached window is
                 // NOT in resize mode, in which case its content frame will be larger.
                 // Ungh. So to deal with that, make sure the content frame we end up using is not
                 // covering the IM dock.
-                cf.set(attached.getContentFrameLw());
+                cf.set(attached.getContentFrame());
                 if (attached.isVoiceInteraction()) {
                     cf.intersectUnchecked(displayFrames.mVoiceContent);
                 } else if (win.isInputMethodTarget() || attached.isInputMethodTarget()) {
@@ -2111,11 +2111,11 @@
                 }
             }
             df.set(insetDecors ? parentDisplayFrame : cf);
-            vf.set(attached.getVisibleFrameLw());
+            vf.set(attached.getVisibleFrame());
         }
         // The LAYOUT_IN_SCREEN flag is used to determine whether the attached window should be
         // positioned relative to its parent or the entire screen.
-        pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrameLw() : df);
+        pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrame() : df);
     }
 
     private void applyStableConstraints(int sysui, int fl, Rect r, DisplayFrames displayFrames) {
@@ -2217,8 +2217,8 @@
                 vf.set(adjust != SOFT_INPUT_ADJUST_NOTHING
                         ? displayFrames.mCurrent : displayFrames.mDock);
             } else {
-                pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrameLw() : df);
-                vf.set(attached.getVisibleFrameLw());
+                pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrame() : df);
+                vf.set(attached.getVisibleFrame());
             }
             cf.set(adjust != SOFT_INPUT_ADJUST_RESIZE
                     ? displayFrames.mDock : displayFrames.mContent);
@@ -2623,12 +2623,10 @@
         win.computeFrame(displayFrames);
         // Dock windows carve out the bottom of the screen, so normal windows
         // can't appear underneath them.
-        if (type == TYPE_INPUT_METHOD && win.isVisibleLw()
-                && !win.getGivenInsetsPendingLw()) {
+        if (type == TYPE_INPUT_METHOD && win.isVisibleLw() && !win.mGivenInsetsPending) {
             offsetInputMethodWindowLw(win, displayFrames);
         }
-        if (type == TYPE_VOICE_INTERACTION && win.isVisibleLw()
-                && !win.getGivenInsetsPendingLw()) {
+        if (type == TYPE_VOICE_INTERACTION && win.isVisibleLw() && !win.mGivenInsetsPending) {
             offsetVoiceInputWindowLw(win, displayFrames);
         }
     }
@@ -2645,8 +2643,8 @@
         final int navBarPosition = navigationBarPosition(displayFrames.mDisplayWidth,
                 displayFrames.mDisplayHeight, rotation);
 
-        int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
-        top += win.getGivenContentInsetsLw().top;
+        int top = Math.max(win.getDisplayFrame().top, win.getContentFrame().top);
+        top += win.mGivenContentInsets.top;
         displayFrames.mContent.bottom = Math.min(displayFrames.mContent.bottom, top);
         if (navBarPosition == NAV_BAR_BOTTOM) {
             // Always account for the nav bar frame height on the bottom since in all navigation
@@ -2658,8 +2656,8 @@
                     displayFrames.mUnrestricted.bottom - navFrameHeight);
         }
         displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
-        top = win.getVisibleFrameLw().top;
-        top += win.getGivenVisibleInsetsLw().top;
+        top = win.getVisibleFrame().top;
+        top += win.mGivenVisibleInsets.top;
         displayFrames.mCurrent.bottom = Math.min(displayFrames.mCurrent.bottom, top);
         if (DEBUG_LAYOUT) Slog.v(TAG, "Input method: mDockBottom="
                 + displayFrames.mDock.bottom + " mContentBottom="
@@ -2667,8 +2665,8 @@
     }
 
     private void offsetVoiceInputWindowLw(WindowState win, DisplayFrames displayFrames) {
-        int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
-        top += win.getGivenContentInsetsLw().top;
+        int top = Math.max(win.getDisplayFrame().top, win.getContentFrame().top);
+        top += win.mGivenContentInsets.top;
         displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
     }
 
@@ -2729,8 +2727,7 @@
             if (win.isDreamWindow()) {
                 // If the lockscreen was showing when the dream started then wait
                 // for the dream to draw before hiding the lockscreen.
-                if (!mDreamingLockscreen
-                        || (win.isVisibleLw() && win.hasDrawnLw())) {
+                if (!mDreamingLockscreen || (win.isVisibleLw() && win.hasDrawn())) {
                     mShowingDream = true;
                     appWindow = true;
                 }
@@ -2916,7 +2913,7 @@
         final InsetsSource request = mTopFullscreenOpaqueWindowState.getRequestedInsetsState()
                 .peekSource(ITYPE_STATUS_BAR);
         if (WindowManagerDebugConfig.DEBUG) {
-            Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw());
+            Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrame());
             Slog.d(TAG, "attr: " + attrs + " request: " + request);
         }
         return (fl & LayoutParams.FLAG_FULLSCREEN) != 0
@@ -3398,7 +3395,7 @@
         mImmersiveModeConfirmation.confirmCurrentPrompt();
     }
 
-    private void disposeInputConsumer(InputConsumer inputConsumer) {
+    private void disposeInputConsumer(EventReceiverInputConsumer inputConsumer) {
         if (inputConsumer != null) {
             inputConsumer.dispose();
         }
@@ -4171,6 +4168,6 @@
             return false;
         }
 
-        return Rect.intersects(targetWindow.getFrameLw(), navBarWindow.getFrameLw());
+        return Rect.intersects(targetWindow.getFrame(), navBarWindow.getFrame());
     }
 }
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 86e2698..f0f3385 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -93,7 +93,7 @@
                 || (mImeTargetFromIme != null
                 && isImeTargetFromDisplayContentAndImeSame()
                 && mWin != null
-                && mWin.isDrawnLw()
+                && mWin.isDrawn()
                 && !mWin.mGivenInsetsPending)) {
             mIsImeLayoutDrawn = true;
             // show IME if InputMethodService requested it to be shown.
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 16c4942..fb511e0 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -61,7 +61,6 @@
 import android.view.SurfaceControl;
 
 import com.android.internal.protolog.common.ProtoLog;
-import com.android.server.policy.WindowManagerPolicy;
 
 import java.io.PrintWriter;
 import java.util.Set;
@@ -95,8 +94,11 @@
      */
     private final ArrayMap<String, InputConsumerImpl> mInputConsumers = new ArrayMap();
 
-    private static final class EventReceiverInputConsumer extends InputConsumerImpl
-            implements WindowManagerPolicy.InputConsumer {
+    /**
+     * Representation of a input consumer that the policy has added to the window manager to consume
+     * input events going to windows below it.
+     */
+    static final class EventReceiverInputConsumer extends InputConsumerImpl {
         private InputMonitor mInputMonitor;
         private final InputEventReceiver mInputEventReceiver;
 
@@ -111,8 +113,8 @@
                     mClientChannel, looper);
         }
 
-        @Override
-        public void dismiss() {
+        /** Removes the input consumer from the window manager. */
+        void dismiss() {
             synchronized (mService.mGlobalLock) {
                 mInputMonitor.mInputConsumers.remove(mName);
                 hide(mInputMonitor.mInputTransaction);
@@ -120,8 +122,8 @@
             }
         }
 
-        @Override
-        public void dispose() {
+        /** Disposes the input consumer and input receiver from the associated thread. */
+        void dispose() {
             synchronized (mService.mGlobalLock) {
                 disposeChannelsLw(mInputMonitor.mInputTransaction);
                 mInputEventReceiver.dispose();
@@ -225,7 +227,7 @@
         }
     }
 
-    WindowManagerPolicy.InputConsumer createInputConsumer(Looper looper, String name,
+    EventReceiverInputConsumer createInputConsumer(Looper looper, String name,
             InputEventReceiver.Factory inputEventReceiverFactory) {
         if (!name.contentEquals(INPUT_CONSUMER_NAVIGATION)) {
             throw new IllegalArgumentException("Illegal input consumer : " + name
@@ -289,7 +291,7 @@
         inputWindowHandle.inputFeatures = child.mAttrs.inputFeatures;
         inputWindowHandle.displayId = child.getDisplayId();
 
-        final Rect frame = child.getFrameLw();
+        final Rect frame = child.getFrame();
         inputWindowHandle.frameLeft = frame.left;
         inputWindowHandle.frameTop = frame.top;
         inputWindowHandle.frameRight = frame.right;
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index d1eb795..e00c9e7 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -173,7 +173,7 @@
         // frame may not yet determined that server side doesn't think the window is ready to
         // visible. (i.e. No surface, pending insets that were given during layout, etc..)
         if (mServerVisible) {
-            mTmpRect.set(mWin.getFrameLw());
+            mTmpRect.set(mWin.getFrame());
             if (mFrameProvider != null) {
                 mFrameProvider.accept(mWin.getDisplayContent().mDisplayFrames, mWin, mTmpRect);
             } else {
@@ -185,14 +185,14 @@
         mSource.setFrame(mTmpRect);
 
         if (mImeFrameProvider != null) {
-            mImeOverrideFrame.set(mWin.getFrameLw());
+            mImeOverrideFrame.set(mWin.getFrame());
             mImeFrameProvider.accept(mWin.getDisplayContent().mDisplayFrames, mWin,
                     mImeOverrideFrame);
         }
 
         if (mWin.mGivenVisibleInsets.left != 0 || mWin.mGivenVisibleInsets.top != 0
                 || mWin.mGivenVisibleInsets.right != 0 || mWin.mGivenVisibleInsets.bottom != 0) {
-            mTmpRect.set(mWin.getFrameLw());
+            mTmpRect.set(mWin.getFrame());
             mTmpRect.inset(mWin.mGivenVisibleInsets);
             mSource.setVisibleFrame(mTmpRect);
         } else {
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index 8ef57f7..c8d7693 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -29,7 +29,7 @@
 import static android.os.UserHandle.USER_CURRENT;
 import static android.telecom.TelecomManager.EMERGENCY_DIALER_COMPONENT;
 
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LOCKTASK;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -65,6 +65,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.policy.IKeyguardDismissCallback;
+import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.LocalServices;
@@ -448,7 +449,7 @@
      * unlike {@link #stopLockTaskMode(Task, boolean, int)}, it doesn't perform the checks.
      */
     void clearLockedTasks(String reason) {
-        if (DEBUG_LOCKTASK) Slog.i(TAG_LOCKTASK, "clearLockedTasks: " + reason);
+        ProtoLog.i(WM_DEBUG_LOCKTASK, "clearLockedTasks: %s", reason);
         if (!mLockTaskModeTasks.isEmpty()) {
             clearLockedTask(mLockTaskModeTasks.get(0));
         }
@@ -490,10 +491,10 @@
         if (!mLockTaskModeTasks.remove(task)) {
             return;
         }
-        if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "removeLockedTask: removed " + task);
+        ProtoLog.d(WM_DEBUG_LOCKTASK, "removeLockedTask: removed %s", task);
         if (mLockTaskModeTasks.isEmpty()) {
-            if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "removeLockedTask: task=" + task +
-                    " last task, reverting locktask mode. Callers=" + Debug.getCallers(3));
+            ProtoLog.d(WM_DEBUG_LOCKTASK, "removeLockedTask: task=%s last task, "
+                    + "reverting locktask mode. Callers=%s", task, Debug.getCallers(3));
             mHandler.post(() -> performStopLockTask(task.mUserId));
         }
     }
@@ -558,7 +559,7 @@
             if (task.mLockTaskAuth == LOCK_TASK_AUTH_PINNABLE) {
                 // startLockTask() called by app, but app is not part of lock task allowlist. Show
                 // app pinning request. We will come back here with isSystemCaller true.
-                if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Mode default, asking user");
+                ProtoLog.w(WM_DEBUG_LOCKTASK, "Mode default, asking user");
                 StatusBarManagerInternal statusBarManager = LocalServices.getService(
                         StatusBarManagerInternal.class);
                 if (statusBarManager != null) {
@@ -569,8 +570,7 @@
         }
 
         // System can only initiate screen pinning, not full lock task mode
-        if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK,
-                isSystemCaller ? "Locking pinned" : "Locking fully");
+        ProtoLog.w(WM_DEBUG_LOCKTASK, "%s", isSystemCaller ? "Locking pinned" : "Locking fully");
         setLockTaskMode(task, isSystemCaller ? LOCK_TASK_MODE_PINNED : LOCK_TASK_MODE_LOCKED,
                 "startLockTask", true);
     }
@@ -584,7 +584,7 @@
                                  String reason, boolean andResume) {
         // Should have already been checked, but do it again.
         if (task.mLockTaskAuth == LOCK_TASK_AUTH_DONT_LOCK) {
-            if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK,
+            ProtoLog.w(WM_DEBUG_LOCKTASK,
                     "setLockTaskMode: Can't lock due to auth");
             return;
         }
@@ -602,8 +602,8 @@
                     task.mUserId,
                     lockTaskModeState));
         }
-        if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "setLockTaskMode: Locking to " + task +
-                " Callers=" + Debug.getCallers(4));
+        ProtoLog.w(WM_DEBUG_LOCKTASK, "setLockTaskMode: Locking to %s Callers=%s",
+                task, Debug.getCallers(4));
 
         if (!mLockTaskModeTasks.contains(task)) {
             mLockTaskModeTasks.add(task);
@@ -672,8 +672,8 @@
             }
 
             // Terminate locked tasks that have recently lost allowlist authorization.
-            if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "onLockTaskPackagesUpdated: removing " +
-                    lockedTask + " mLockTaskAuth()=" + lockedTask.lockTaskAuthToString());
+            ProtoLog.d(WM_DEBUG_LOCKTASK, "onLockTaskPackagesUpdated: removing %s"
+                    + " mLockTaskAuth()=%s", lockedTask, lockedTask.lockTaskAuthToString());
             removeLockedTask(lockedTask);
             lockedTask.performClearTaskLocked();
             taskChanged = true;
@@ -686,8 +686,8 @@
         if (mLockTaskModeTasks.isEmpty() && task!= null
                 && task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) {
             // This task must have just been authorized.
-            if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK,
-                    "onLockTaskPackagesUpdated: starting new locktask task=" + task);
+            ProtoLog.d(WM_DEBUG_LOCKTASK, "onLockTaskPackagesUpdated: starting new "
+                    + "locktask task=%s", task);
             setLockTaskMode(task, LOCK_TASK_MODE_LOCKED, "package updated", false);
             taskChanged = true;
         }
diff --git a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
index cc5ed36..c3953b4 100644
--- a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
+++ b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
@@ -16,9 +16,8 @@
 
 package com.android.server.wm;
 
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
-import static com.android.server.wm.Task.TAG_ADD_REMOVE;
 import static com.android.server.wm.Task.TAG_TASKS;
 
 import android.app.ActivityOptions;
@@ -27,6 +26,7 @@
 import android.os.Debug;
 import android.util.Slog;
 
+import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.function.pooled.PooledConsumer;
 import com.android.internal.util.function.pooled.PooledFunction;
 import com.android.internal.util.function.pooled.PooledLambda;
@@ -218,8 +218,8 @@
             if (takeOptions) {
                 noOptions = takeOption(p, noOptions);
             }
-            if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE, "Removing activity " + p + " from task="
-                    + mTask + " adding to task=" + targetTask + " Callers=" + Debug.getCallers(4));
+            ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Removing activity %s from task=%s "
+                    + "adding to task=%s Callers=%s", p, mTask,  targetTask, Debug.getCallers(4));
             if (DEBUG_TASKS) Slog.v(TAG_TASKS,
                     "Pushing next activity " + p + " out to target's task " + target);
             p.reparent(targetTask, position, "resetTargetTaskIfNeeded");
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 6dfbd21..21e30ce 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1106,14 +1106,14 @@
         final WindowManager.LayoutParams attrs = w.mAttrs;
         final int attrFlags = attrs.flags;
         final boolean onScreen = w.isOnScreen();
-        final boolean canBeSeen = w.isDisplayedLw();
+        final boolean canBeSeen = w.isDisplayed();
         final int privateflags = attrs.privateFlags;
         boolean displayHasContent = false;
 
         ProtoLog.d(WM_DEBUG_KEEP_SCREEN_ON,
                 "handleNotObscuredLocked w: %s, w.mHasSurface: %b, w.isOnScreen(): %b, w"
                         + ".isDisplayedLw(): %b, w.mAttrs.userActivityTimeout: %d",
-                w, w.mHasSurface, onScreen, w.isDisplayedLw(), w.mAttrs.userActivityTimeout);
+                w, w.mHasSurface, onScreen, w.isDisplayed(), w.mAttrs.userActivityTimeout);
         if (w.mHasSurface && onScreen) {
             if (!syswin && w.mAttrs.userActivityTimeout >= 0 && mUserActivityTimeout < 0) {
                 mUserActivityTimeout = w.mAttrs.userActivityTimeout;
diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java
index 6cf9432..7b5b0ad 100644
--- a/services/core/java/com/android/server/wm/RunningTasks.java
+++ b/services/core/java/com/android/server/wm/RunningTasks.java
@@ -99,9 +99,8 @@
                 // the task's profile
                 return;
             }
-            if (!mAllowed && !task.isActivityTypeHome()) {
-                // Skip if the caller isn't allowed to fetch this task, except for the home
-                // task which we always return.
+            if (!mAllowed) {
+                // Skip if the caller isn't allowed to fetch this task
                 return;
             }
         }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index e77a535..19bf451 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -79,6 +79,7 @@
 import static com.android.internal.policy.DecorView.DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP;
 import static com.android.internal.policy.DecorView.DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LOCKTASK;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS;
 import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN;
 import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME;
@@ -87,9 +88,7 @@
 import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
 import static com.android.server.wm.ActivityStackSupervisor.dumpHistoryList;
 import static com.android.server.wm.ActivityStackSupervisor.printThisActivity;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
@@ -1651,8 +1650,8 @@
      * Reorder the history stack so that the passed activity is brought to the front.
      */
     final void moveActivityToFrontLocked(ActivityRecord newTop) {
-        if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE, "Removing and adding activity "
-                + newTop + " to stack at top callers=" + Debug.getCallers(4));
+        ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Removing and adding activity %s to stack at top "
+                + "callers=%s", newTop, Debug.getCallers(4));
 
         positionChildAtTop(newTop);
         updateEffectiveIntent();
@@ -1951,8 +1950,8 @@
                         ? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
                 break;
         }
-        if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this
-                + " mLockTaskAuth=" + lockTaskAuthToString());
+        ProtoLog.d(WM_DEBUG_LOCKTASK, "setLockTaskAuth: task=%s mLockTaskAuth=%s", this,
+                lockTaskAuthToString());
     }
 
     @Override
@@ -6370,7 +6369,8 @@
                 // Here it is!  Now, if this is not yet visible (occluded by another task) to the
                 // user, then just add it without starting; it will get started when the user
                 // navigates back to it.
-                if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task " + task,
+                ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Adding activity %s to task %s "
+                                + "callers: %s", r, task,
                         new RuntimeException("here").fillInStackTrace());
                 rTask.positionChildAtTop(r);
                 ActivityOptions.abort(options);
@@ -6392,8 +6392,8 @@
         task = activityTask;
 
         // Slot the activity into the history stack and proceed
-        if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task,
-                new RuntimeException("here").fillInStackTrace());
+        ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Adding activity %s to stack to task %s "
+                        + "callers: %s", r, task, new RuntimeException("here").fillInStackTrace());
         task.positionChildAtTop(r);
 
         // The transition animation and starting window are not needed if {@code allowMoveToFront}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index dbbb7ff..e3112ef 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -483,7 +483,7 @@
         final InsetsState insetsState =
                 new InsetsState(insetsPolicy.getInsetsForDispatch(mainWindow));
         mergeInsetsSources(insetsState, mainWindow.getRequestedInsetsState());
-        final Rect systemBarInsets = getSystemBarInsets(mainWindow.getFrameLw(), insetsState);
+        final Rect systemBarInsets = getSystemBarInsets(mainWindow.getFrame(), insetsState);
         final SystemBarBackgroundPainter decorPainter = new SystemBarBackgroundPainter(attrs.flags,
                 attrs.privateFlags, attrs.systemUiVisibility, task.getTaskDescription(),
                 mHighResTaskSnapshotScale, insetsState);
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 6e00ab4..ce13867 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -308,7 +308,7 @@
         float defaultWallpaperX = wallpaperWin.isRtl() ? 1f : 0f;
         float wpx = mLastWallpaperX >= 0 ? mLastWallpaperX : defaultWallpaperX;
         float wpxs = mLastWallpaperXStep >= 0 ? mLastWallpaperXStep : -1.0f;
-        int availw = wallpaperWin.getFrameLw().right - wallpaperWin.getFrameLw().left - dw;
+        int availw = wallpaperWin.getFrame().right - wallpaperWin.getFrame().left - dw;
         int offset = availw > 0 ? -(int)(availw * wpx + .5f) : 0;
         if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
             offset += mLastWallpaperDisplayOffsetX;
@@ -323,7 +323,7 @@
 
         float wpy = mLastWallpaperY >= 0 ? mLastWallpaperY : 0.5f;
         float wpys = mLastWallpaperYStep >= 0 ? mLastWallpaperYStep : -1.0f;
-        int availh = wallpaperWin.getFrameLw().bottom - wallpaperWin.getFrameLw().top - dh;
+        int availh = wallpaperWin.getFrame().bottom - wallpaperWin.getFrame().top - dh;
         offset = availh > 0 ? -(int)(availh * wpy + .5f) : 0;
         if (mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
             offset += mLastWallpaperDisplayOffsetY;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2ce16b2..c45ccb6 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1848,7 +1848,7 @@
         }
         // We use the visible frame, because we want the animation to morph the window from what
         // was visible to the user to the final destination of the new window.
-        Rect frame = replacedWindow.getVisibleFrameLw();
+        Rect frame = replacedWindow.getVisibleFrame();
         // We treat this as if this activity was opening, so we can trigger the app transition
         // animation and piggy-back on existing transition animation infrastructure.
         final DisplayContent dc = activity.getDisplayContent();
@@ -2069,7 +2069,7 @@
                 outDisplayFrame.setEmpty();
                 return;
             }
-            outDisplayFrame.set(win.getDisplayFrameLw());
+            outDisplayFrame.set(win.getDisplayFrame());
             if (win.inSizeCompatMode()) {
                 outDisplayFrame.scale(win.mInvGlobalScale);
             }
@@ -2389,7 +2389,7 @@
             if (displayPolicy.areSystemBarsForcedShownLw(win)) {
                 result |= WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS;
             }
-            if (!win.isGoneForLayoutLw()) {
+            if (!win.isGoneForLayout()) {
                 win.mResizedWhileGone = false;
             }
 
@@ -2419,7 +2419,7 @@
             win.getInsetsForRelayout(outContentInsets, outVisibleInsets,
                     outStableInsets);
             outCutout.set(win.getWmDisplayCutout().getDisplayCutout());
-            outBackdropFrame.set(win.getBackdropFrame(win.getFrameLw()));
+            outBackdropFrame.set(win.getBackdropFrame(win.getFrame()));
             outInsetsState.set(win.getInsetsState(), win.isClientLocal());
             if (DEBUG) {
                 Slog.v(TAG_WM, "Relayout given client " + client.asBinder()
@@ -2883,11 +2883,6 @@
     }
 
     @Override
-    public WindowManagerPolicy.WindowState getInputMethodWindowLw() {
-        return mRoot.getCurrentInputMethodWindow();
-    }
-
-    @Override
     public void notifyKeyguardTrustedChanged() {
         mAtmInternal.notifyKeyguardTrustedChanged();
     }
@@ -5481,7 +5476,7 @@
                     // Window has been removed or hidden; no draw will now happen, so stop waiting.
                     ProtoLog.w(WM_DEBUG_SCREEN_ON, "Aborted waiting for drawn: %s", win);
                     container.mWaitingForDrawn.remove(win);
-                } else if (win.hasDrawnLw()) {
+                } else if (win.hasDrawn()) {
                     // Window is now drawn (and shown).
                     ProtoLog.d(WM_DEBUG_SCREEN_ON, "Window drawn win=%s", win);
                     container.mWaitingForDrawn.remove(win);
@@ -7356,7 +7351,7 @@
             synchronized (mGlobalLock) {
                 WindowState windowState = mWindowMap.get(token);
                 if (windowState != null) {
-                    outBounds.set(windowState.getFrameLw());
+                    outBounds.set(windowState.getFrame());
                 } else {
                     outBounds.setEmpty();
                 }
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index bb9cf2e..c5ebace 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -22,9 +22,9 @@
 import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
 import static android.view.Display.INVALID_DISPLAY;
 
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
 import static com.android.server.am.ActivityManagerService.MY_PID;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ACTIVITY_STARTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RELEASE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RELEASE;
@@ -72,6 +72,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.HeavyWeightSwitcherActivity;
+import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.Watchdog;
 import com.android.server.wm.ActivityTaskManagerService.HotPath;
@@ -1348,9 +1349,8 @@
             }
             return;
         }
-        if (DEBUG_CONFIGURATION) {
-            Slog.v(TAG_CONFIGURATION, "Sending to proc " + mName + " new config " + config);
-        }
+        ProtoLog.v(WM_DEBUG_CONFIGURATION, "Sending to proc %s new config %s", mName,
+                config);
         if (Build.IS_DEBUGGABLE && mHasImeService) {
             // TODO (b/135719017): Temporary log for debugging IME service.
             Slog.v(TAG_CONFIGURATION, "Sending to IME proc " + mName + " new config " + config);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 69d3821..9ff33b1 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1009,8 +1009,8 @@
         getDisplayContent().reapplyMagnificationSpec();
     }
 
-    @Override
-    public int getOwningUid() {
+    /** Returns the uid of the app that owns this window. */
+    int getOwningUid() {
         return mOwnerUid;
     }
 
@@ -1024,8 +1024,12 @@
         return mOwnerCanAddInternalSystemWindow;
     }
 
-    @Override
-    public boolean canAcquireSleepToken() {
+    /**
+     * Returns {@code true} if the window owner has the permission to acquire a sleep token when
+     * it's visible. That is, they have the permission
+     * {@link androidManifest.permission#DEVICE_POWER}.
+     */
+    boolean canAcquireSleepToken() {
         return mSession.mCanAcquireSleepToken;
     }
 
@@ -1046,7 +1050,7 @@
 
     void computeFrame(DisplayFrames displayFrames) {
         getLayoutingWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
-        computeFrameLw();
+        computeFrame();
         // Update the source frame to provide insets to other windows during layout. If the
         // simulated frames exist, then this is not computing a stable result so just skip.
         if (mControllableInsetProvider != null && mSimulatedWindowFrames == null) {
@@ -1054,8 +1058,10 @@
         }
     }
 
-    @Override
-    public void computeFrameLw() {
+    /**
+     * Perform standard frame computation. The result can be obtained with getFrame() if so desired.
+     */
+    void computeFrame() {
         if (mWillReplaceWindow && (mAnimatingExit || !mReplacingRemoveRequested)) {
             // This window is being replaced and either already got information that it's being
             // removed or we are still waiting for some information. Because of this we don't
@@ -1283,32 +1289,41 @@
         }
     }
 
-    @Override
-    public Rect getFrameLw() {
+    /** Retrieves the current frame of the window that the application sees. */
+    Rect getFrame() {
         return mWindowFrames.mFrame;
     }
 
     /** Accessor for testing */
-    Rect getRelativeFrameLw() {
+    Rect getRelativeFrame() {
         return mWindowFrames.mRelFrame;
     }
 
-    @Override
-    public Rect getDisplayFrameLw() {
+    /** Retrieves the frame of the display that this window was last laid out in. */
+    Rect getDisplayFrame() {
         return mWindowFrames.mDisplayFrame;
     }
 
-    @Override
-    public Rect getContentFrameLw() {
+    /**
+     * Retrieves the frame of the content area that this window was last laid out in. This is the
+     * area in which the content of the window should be placed. It will be smaller than the display
+     * frame to account for screen decorations such as a status bar or soft keyboard.
+     */
+    Rect getContentFrame() {
         return mWindowFrames.mContentFrame;
     }
 
-    @Override
-    public Rect getVisibleFrameLw() {
+    /**
+     * Retrieves the frame of the visible area that this window was last laid out in. This is the
+     * area of the screen in which the window will actually be fully visible. It will be smaller
+     * than the content frame to account for transient UI elements blocking it such as an input
+     * method's candidates UI.
+     */
+    Rect getVisibleFrame() {
         return mWindowFrames.mVisibleFrame;
     }
 
-    Rect getStableFrameLw() {
+    Rect getStableFrame() {
         return mWindowFrames.mStableFrame;
     }
 
@@ -1337,32 +1352,17 @@
     }
 
     @Override
-    public boolean getGivenInsetsPendingLw() {
-        return mGivenInsetsPending;
-    }
-
-    @Override
-    public Rect getGivenContentInsetsLw() {
-        return mGivenContentInsets;
-    }
-
-    @Override
-    public Rect getGivenVisibleInsetsLw() {
-        return mGivenVisibleInsets;
-    }
-
-    @Override
     public WindowManager.LayoutParams getAttrs() {
         return mAttrs;
     }
 
-    @Override
-    public int getSystemUiVisibility() {
+    /** Retrieves the current system UI visibility flags associated with this window. */
+    int getSystemUiVisibility() {
         return mSystemUiVisibility;
     }
 
-    @Override
-    public int getSurfaceLayer() {
+    /** Gets the layer at which this window's surface will be Z-ordered. */
+    int getSurfaceLayer() {
         return mLayer;
     }
 
@@ -1376,8 +1376,8 @@
         return mActivityRecord != null ? mActivityRecord.appToken : null;
     }
 
-    @Override
-    public boolean isVoiceInteraction() {
+    /** Returns true if this window is participating in voice interaction. */
+    boolean isVoiceInteraction() {
         return mActivityRecord != null && mActivityRecord.mVoiceInteraction;
     }
 
@@ -1391,7 +1391,7 @@
      */
     void updateResizingWindowIfNeeded() {
         final WindowStateAnimator winAnimator = mWinAnimator;
-        if (!mHasSurface || getDisplayContent().mLayoutSeq != mLayoutSeq || isGoneForLayoutLw()) {
+        if (!mHasSurface || getDisplayContent().mLayoutSeq != mLayoutSeq || isGoneForLayout()) {
             return;
         }
 
@@ -1464,7 +1464,7 @@
                 mWmService.mResizingWindows.add(this);
             }
         } else if (getOrientationChanging()) {
-            if (isDrawnLw()) {
+            if (isDrawn()) {
                 ProtoLog.v(WM_DEBUG_ORIENTATION,
                         "Orientation not waiting for draw in %s, surfaceController %s", this,
                         winAnimator.mSurfaceController);
@@ -1639,9 +1639,16 @@
                 : DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
     }
 
-    @Override
-    public boolean hasAppShownWindows() {
-        return mActivityRecord != null && (mActivityRecord.firstWindowDrawn || mActivityRecord.startingDisplayed);
+    /**
+     * Returns true if, at any point, the application token associated with this window has actually
+     * displayed any windows. This is most useful with the "starting up" window to determine if any
+     * windows were displayed when it is closed.
+     *
+     * @return {@code true} if one or more windows have been displayed, else false.
+     */
+    boolean hasAppShownWindows() {
+        return mActivityRecord != null
+                && (mActivityRecord.firstWindowDrawn || mActivityRecord.startingDisplayed);
     }
 
     boolean isIdentityMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
@@ -1663,7 +1670,7 @@
 
     @Override
     boolean hasContentToDisplay() {
-        if (!mAppFreezing && isDrawnLw() && (mViewVisibility == View.VISIBLE
+        if (!mAppFreezing && isDrawn() && (mViewVisibility == View.VISIBLE
                 || (isAnimating(TRANSITION | PARENTS)
                 && !getDisplayContent().mAppTransition.isTransitionSet()))) {
             return true;
@@ -1851,10 +1858,9 @@
      * Like isOnScreen, but returns false if the surface hasn't yet
      * been drawn.
      */
-    @Override
-    public boolean isDisplayedLw() {
+    boolean isDisplayed() {
         final ActivityRecord atoken = mActivityRecord;
-        return isDrawnLw() && isVisibleByPolicy()
+        return isDrawn() && isVisibleByPolicy()
                 && ((!isParentWindowHidden() && (atoken == null || atoken.mVisibleRequested))
                         || isAnimating(TRANSITION | PARENTS));
     }
@@ -1867,8 +1873,8 @@
         return isAnimating(TRANSITION | PARENTS);
     }
 
-    @Override
-    public boolean isGoneForLayoutLw() {
+    /** Returns {@code true} if this window considered to be gone for purposes of layout. */
+    boolean isGoneForLayout() {
         final ActivityRecord atoken = mActivityRecord;
         return mViewVisibility == View.GONE
                 || !mRelayoutCalled
@@ -1895,11 +1901,11 @@
     }
 
     /**
-     * Returns true if the window has a surface that it has drawn a
-     * complete UI in to.
+     * Returns true if the window has a surface that it has drawn a complete UI in to. Note that
+     * this is different from {@link #hasDrawn()} in that it also returns true if the window is
+     * READY_TO_SHOW, but was not yet promoted to HAS_DRAWN.
      */
-    @Override
-    public boolean isDrawnLw() {
+    boolean isDrawn() {
         return mHasSurface && !mDestroying &&
                 (mWinAnimator.mDrawState == READY_TO_SHOW || mWinAnimator.mDrawState == HAS_DRAWN);
     }
@@ -1914,7 +1920,7 @@
         // to determine if it's occluding apps.
         return ((!mIsWallpaper && mAttrs.format == PixelFormat.OPAQUE)
                 || (mIsWallpaper && mWallpaperVisible))
-                && isDrawnLw() && !isAnimating(TRANSITION | PARENTS);
+                && isDrawn() && !isAnimating(TRANSITION | PARENTS);
     }
 
     /** @see WindowManagerInternal#waitForAllWindowsDrawn */
@@ -1929,7 +1935,7 @@
                 return;
             }
             if (mAttrs.type == TYPE_APPLICATION_STARTING) {
-                if (isDrawnLw()) {
+                if (isDrawn()) {
                     // Unnecessary to redraw a drawn starting window.
                     return;
                 }
@@ -2016,11 +2022,11 @@
     @Override
     void onResize() {
         final ArrayList<WindowState> resizingWindows = mWmService.mResizingWindows;
-        if (mHasSurface && !isGoneForLayoutLw() && !resizingWindows.contains(this)) {
+        if (mHasSurface && !isGoneForLayout() && !resizingWindows.contains(this)) {
             ProtoLog.d(WM_DEBUG_RESIZE, "onResize: Resizing %s", this);
             resizingWindows.add(this);
         }
-        if (isGoneForLayoutLw()) {
+        if (isGoneForLayout()) {
             mResizedWhileGone = true;
         }
 
@@ -2514,7 +2520,7 @@
 
     /** Returns true if the replacement window was removed. */
     boolean removeReplacedWindowIfNeeded(WindowState replacement) {
-        if (mWillReplaceWindow && mReplacementWindow == replacement && replacement.hasDrawnLw()) {
+        if (mWillReplaceWindow && mReplacementWindow == replacement && replacement.hasDrawn()) {
             replacement.mSkipEnterAnimationForSeamlessReplacement = false;
             removeReplacedWindow();
             return true;
@@ -2748,7 +2754,7 @@
             mLayoutNeeded = true;
         }
 
-        if (isDrawnLw() && mToken.okToAnimate()) {
+        if (isDrawn() && mToken.okToAnimate()) {
             mWinAnimator.applyEnterAnimationLocked();
         }
     }
@@ -2873,8 +2879,8 @@
         return getWindowConfiguration().keepVisibleDeadAppWindowOnScreen();
     }
 
-    @Override
-    public boolean canReceiveKeys() {
+    /** Returns {@code true} if this window desires key events. */
+    boolean canReceiveKeys() {
         return canReceiveKeys(false /* fromUserTouch */);
     }
 
@@ -2923,8 +2929,13 @@
                 && recentsAnimationController.shouldApplyInputConsumer(mActivityRecord);
     }
 
-    @Override
-    public boolean hasDrawnLw() {
+    /**
+     * Returns {@code true} if this window has been shown on screen at some time in the past.
+     *
+     * @deprecated Use {@link #isDrawnLw} or any of the other drawn/visibility methods.
+     */
+    @Deprecated
+    boolean hasDrawn() {
         return mWinAnimator.mDrawState == WindowStateAnimator.HAS_DRAWN;
     }
 
@@ -3158,8 +3169,8 @@
         }
     }
 
-    @Override
-    public boolean isAlive() {
+    /** Checks whether the process hosting this window is currently alive. */
+    boolean isAlive() {
         return mClient.asBinder().isBinderAlive();
     }
 
@@ -3339,16 +3350,6 @@
         mLastExclusionLogUptimeMillis[EXCLUSION_RIGHT] = now;
     }
 
-    @Override
-    public boolean isDefaultDisplay() {
-        final DisplayContent displayContent = getDisplayContent();
-        if (displayContent == null) {
-            // Only a window that was on a non-default display can be detached from it.
-            return false;
-        }
-        return displayContent.isDefaultDisplay;
-    }
-
     /** @return {@code true} if this window can be shown to all users. */
     boolean showForAllUsers() {
 
@@ -3408,10 +3409,10 @@
             // All window frames that are fullscreen extend above status bar, but some don't extend
             // below navigation bar. Thus, check for display frame for top/left and stable frame for
             // bottom right.
-            if (win.getFrameLw().left <= win.getDisplayFrameLw().left
-                    && win.getFrameLw().top <= win.getDisplayFrameLw().top
-                    && win.getFrameLw().right >= win.getStableFrameLw().right
-                    && win.getFrameLw().bottom >= win.getStableFrameLw().bottom) {
+            if (win.getFrame().left <= win.getDisplayFrame().left
+                    && win.getFrame().top <= win.getDisplayFrame().top
+                    && win.getFrame().right >= win.getStableFrame().right
+                    && win.getFrame().bottom >= win.getStableFrame().bottom) {
                 // Is a fullscreen window, like the clock alarm. Show to everyone.
                 return true;
             }
@@ -3781,11 +3782,11 @@
      *          is transitioning into/out-of fullscreen. */
     boolean isLetterboxedAppWindow() {
         return !inMultiWindowMode() && !matchesDisplayBounds()
-                || isLetterboxedForDisplayCutoutLw();
+                || isLetterboxedForDisplayCutout();
     }
 
-    @Override
-    public boolean isLetterboxedForDisplayCutoutLw() {
+    /** Returns {@code true} if the window is letterboxed for the display cutout. */
+    boolean isLetterboxedForDisplayCutout() {
         if (mActivityRecord == null) {
             // Only windows with an ActivityRecord are letterboxed.
             return false;
@@ -3889,7 +3890,7 @@
         // background.
         return (getDisplayContent().mDividerControllerLocked.isResizing()
                         || mActivityRecord != null && !mActivityRecord.mFrozenBounds.isEmpty()) &&
-                !task.inFreeformWindowingMode() && !isGoneForLayoutLw();
+                !task.inFreeformWindowingMode() && !isGoneForLayout();
 
     }
 
@@ -4305,7 +4306,7 @@
 
     private boolean isParentWindowGoneForLayout() {
         final WindowState parent = getParentWindow();
-        return parent != null && parent.isGoneForLayoutLw();
+        return parent != null && parent.isGoneForLayout();
     }
 
     void setWillReplaceWindow(boolean animate) {
@@ -4418,8 +4419,7 @@
         return null;
     }
 
-    @Override
-    public int getRotationAnimationHint() {
+    int getRotationAnimationHint() {
         if (mActivityRecord != null) {
             return mActivityRecord.mRotationAnimationHint;
         } else {
@@ -4875,7 +4875,7 @@
     }
 
     boolean hasVisibleNotDrawnWallpaper() {
-        if (mWallpaperVisible && !isDrawnLw()) {
+        if (mWallpaperVisible && !isDrawn()) {
             return true;
         }
         for (int j = mChildren.size() - 1; j >= 0; --j) {
@@ -4899,9 +4899,9 @@
             return;
         }
         if (DEBUG_VISIBILITY) {
-            Slog.v(TAG, "Win " + this + ": isDrawn=" + isDrawnLw()
+            Slog.v(TAG, "Win " + this + ": isDrawn=" + isDrawn()
                     + ", animating=" + isAnimating(TRANSITION | PARENTS));
-            if (!isDrawnLw()) {
+            if (!isDrawn()) {
                 Slog.v(TAG, "Not displayed: s=" + mWinAnimator.mSurfaceController
                         + " pv=" + isVisibleByPolicy()
                         + " mDrawState=" + mWinAnimator.mDrawState
@@ -4912,7 +4912,7 @@
         }
 
         results.numInteresting++;
-        if (isDrawnLw()) {
+        if (isDrawn()) {
             results.numDrawn++;
             if (!isAnimating(TRANSITION | PARENTS)) {
                 results.numVisible++;
@@ -5048,7 +5048,7 @@
     int relayoutVisibleWindow(int result, int attrChanges) {
         final boolean wasVisible = isVisibleLw();
 
-        result |= (!wasVisible || !isDrawnLw()) ? RELAYOUT_RES_FIRST_TIME : 0;
+        result |= (!wasVisible || !isDrawn()) ? RELAYOUT_RES_FIRST_TIME : 0;
 
         if (mAnimatingExit) {
             Slog.d(TAG, "relayoutVisibleWindow: " + this + " mAnimatingExit=true, mRemoveOnExit="
@@ -5620,15 +5620,14 @@
         return !mTapExcludeRegion.isEmpty();
     }
 
-    @Override
-    public boolean isInputMethodTarget() {
+    boolean isInputMethodTarget() {
         return getDisplayContent().mInputMethodTarget == this;
     }
 
     long getFrameNumber() {
         // Return the frame number in which changes requested in this layout will be rendered or
         // -1 if we do not expect the frame to be rendered.
-        return getFrameLw().isEmpty() ? -1 : mFrameNumber;
+        return getFrame().isEmpty() ? -1 : mFrameNumber;
     }
 
     void setFrameNumber(long frameNumber) {
@@ -5691,8 +5690,8 @@
         return mWindowFrames.mVisibleInsets;
     }
 
-    @Override
-    public WindowFrames getWindowFrames() {
+    /** Returns the {@link WindowFrames} associated with this {@link WindowState}. */
+    WindowFrames getWindowFrames() {
         return mWindowFrames;
     }
 
@@ -5800,7 +5799,7 @@
         // won't exactly match the final freeform window frame (e.g. when overlapping with
         // the status bar). In that case we need to use the final frame.
         if (inFreeformWindowingMode()) {
-            outFrame.set(getFrameLw());
+            outFrame.set(getFrame());
         } else if (isLetterboxedAppWindow() || mToken.isFixedRotationTransforming()) {
             // 1. The letterbox surfaces should be animated with the owner activity, so use task
             //    bounds to include them.
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 6f48342..1bd712c 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -526,13 +526,13 @@
 
         if (DEBUG) {
             Slog.v(TAG, "Got surface: " + mSurfaceController
-                    + ", set left=" + w.getFrameLw().left + " top=" + w.getFrameLw().top);
+                    + ", set left=" + w.getFrame().left + " top=" + w.getFrame().top);
         }
 
         if (SHOW_LIGHT_TRANSACTIONS) {
             Slog.i(TAG, ">>> OPEN TRANSACTION createSurfaceLocked");
             WindowManagerService.logSurface(w, "CREATE pos=("
-                    + w.getFrameLw().left + "," + w.getFrameLw().top + ") ("
+                    + w.getFrame().left + "," + w.getFrame().top + ") ("
                     + width + "x" + height + ")" + " HIDE", false);
         }
 
@@ -896,7 +896,7 @@
 
             // There is no need to wait for an animation change if our window is gone for layout
             // already as we'll never be visible.
-            if (w.getOrientationChanging() && w.isGoneForLayoutLw()) {
+            if (w.getOrientationChanging() && w.isGoneForLayout()) {
                 ProtoLog.v(WM_DEBUG_ORIENTATION, "Orientation change skips hidden %s", w);
                 w.setOrientationChanging(false);
             }
@@ -920,7 +920,7 @@
             // really hidden (gone for layout), there is no point in still waiting for it.
             // Note that this does introduce a potential glitch if the window becomes unhidden
             // before it has drawn for the new orientation.
-            if (w.getOrientationChanging() && w.isGoneForLayoutLw()) {
+            if (w.getOrientationChanging() && w.isGoneForLayout()) {
                 w.setOrientationChanging(false);
                 ProtoLog.v(WM_DEBUG_ORIENTATION,
                         "Orientation change skips hidden %s", w);
@@ -998,7 +998,7 @@
         }
 
         if (w.getOrientationChanging()) {
-            if (!w.isDrawnLw()) {
+            if (!w.isDrawn()) {
                 mAnimator.mBulkUpdateParams &= ~SET_ORIENTATION_CHANGE_COMPLETE;
                 mAnimator.mLastWindowFreezeSource = w;
                 ProtoLog.v(WM_DEBUG_ORIENTATION,
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index b3f3a5e..9aca848 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -40,14 +40,12 @@
 namespace android {
 
 static JavaVM* sJvm = nullptr;
-
 static jmethodID sMethodIdOnComplete;
-
 static struct {
     jfieldID id;
     jfieldID scale;
     jfieldID delay;
-} gPrimitiveClassInfo;
+} sPrimitiveClassInfo;
 
 static_assert(static_cast<uint8_t>(V1_0::EffectStrength::LIGHT) ==
                 static_cast<uint8_t>(aidl::EffectStrength::LIGHT));
@@ -77,100 +75,117 @@
 static_assert(static_cast<uint8_t>(V1_3::Effect::TEXTURE_TICK) ==
                 static_cast<uint8_t>(aidl::Effect::TEXTURE_TICK));
 
-static inline void callVibrationOnComplete(jobject vibration) {
-    if (vibration == nullptr) {
-        return;
+class NativeVibratorService {
+public:
+    NativeVibratorService(JNIEnv* env, jobject callbackListener)
+          : mController(std::make_unique<vibrator::HalController>()),
+            mCallbackListener(env->NewGlobalRef(callbackListener)) {
+        LOG_ALWAYS_FATAL_IF(mCallbackListener == nullptr,
+                            "Unable to create global reference to vibration callback handler");
     }
-    auto jniEnv = GetOrAttachJNIEnvironment(sJvm);
-    jniEnv->CallVoidMethod(vibration, sMethodIdOnComplete);
-    jniEnv->DeleteGlobalRef(vibration);
-}
+
+    ~NativeVibratorService() {
+        auto jniEnv = GetOrAttachJNIEnvironment(sJvm);
+        jniEnv->DeleteGlobalRef(mCallbackListener);
+    }
+
+    vibrator::HalController* controller() const { return mController.get(); }
+
+    std::function<void()> createCallback(jlong vibrationId) {
+        return [vibrationId, this]() {
+            auto jniEnv = GetOrAttachJNIEnvironment(sJvm);
+            jniEnv->CallVoidMethod(mCallbackListener, sMethodIdOnComplete, vibrationId);
+        };
+    }
+
+private:
+    const std::unique_ptr<vibrator::HalController> mController;
+    const jobject mCallbackListener;
+};
 
 static aidl::CompositeEffect effectFromJavaPrimitive(JNIEnv* env, jobject primitive) {
     aidl::CompositeEffect effect;
     effect.primitive = static_cast<aidl::CompositePrimitive>(
-            env->GetIntField(primitive, gPrimitiveClassInfo.id));
-    effect.scale = static_cast<float>(env->GetFloatField(primitive, gPrimitiveClassInfo.scale));
-    effect.delayMs = static_cast<int32_t>(env->GetIntField(primitive, gPrimitiveClassInfo.delay));
+            env->GetIntField(primitive, sPrimitiveClassInfo.id));
+    effect.scale = static_cast<float>(env->GetFloatField(primitive, sPrimitiveClassInfo.scale));
+    effect.delayMs = static_cast<int32_t>(env->GetIntField(primitive, sPrimitiveClassInfo.delay));
     return effect;
 }
 
-static void destroyVibratorController(void* rawVibratorController) {
-    vibrator::HalController* vibratorController =
-            reinterpret_cast<vibrator::HalController*>(rawVibratorController);
-    if (vibratorController) {
-        delete vibratorController;
+static void destroyNativeService(void* servicePtr) {
+    NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
+    if (service) {
+        delete service;
     }
 }
 
-static jlong vibratorInit(JNIEnv* /* env */, jclass /* clazz */) {
-    std::unique_ptr<vibrator::HalController> controller =
-            std::make_unique<vibrator::HalController>();
-    controller->init();
-    return reinterpret_cast<jlong>(controller.release());
+static jlong vibratorInit(JNIEnv* env, jclass /* clazz */, jobject callbackListener) {
+    std::unique_ptr<NativeVibratorService> service =
+            std::make_unique<NativeVibratorService>(env, callbackListener);
+    service->controller()->init();
+    return reinterpret_cast<jlong>(service.release());
 }
 
 static jlong vibratorGetFinalizer(JNIEnv* /* env */, jclass /* clazz */) {
-    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyVibratorController));
+    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyNativeService));
 }
 
-static jboolean vibratorExists(JNIEnv* env, jclass /* clazz */, jlong controllerPtr) {
-    vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
-    if (controller == nullptr) {
-        ALOGE("vibratorExists failed because controller was not initialized");
+static jboolean vibratorExists(JNIEnv* env, jclass /* clazz */, jlong servicePtr) {
+    NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
+    if (service == nullptr) {
+        ALOGE("vibratorExists failed because native service was not initialized");
         return JNI_FALSE;
     }
-    return controller->ping().isOk() ? JNI_TRUE : JNI_FALSE;
+    return service->controller()->ping().isOk() ? JNI_TRUE : JNI_FALSE;
 }
 
-static void vibratorOn(JNIEnv* env, jclass /* clazz */, jlong controllerPtr, jlong timeoutMs,
-                       jobject vibration) {
-    vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
-    if (controller == nullptr) {
-        ALOGE("vibratorOn failed because controller was not initialized");
+static void vibratorOn(JNIEnv* env, jclass /* clazz */, jlong servicePtr, jlong timeoutMs,
+                       jlong vibrationId) {
+    NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
+    if (service == nullptr) {
+        ALOGE("vibratorOn failed because native service was not initialized");
         return;
     }
-    jobject vibrationRef = vibration == nullptr ? vibration : MakeGlobalRefOrDie(env, vibration);
-    auto callback = [vibrationRef]() { callVibrationOnComplete(vibrationRef); };
-    controller->on(std::chrono::milliseconds(timeoutMs), callback);
+    auto callback = service->createCallback(vibrationId);
+    service->controller()->on(std::chrono::milliseconds(timeoutMs), callback);
 }
 
-static void vibratorOff(JNIEnv* env, jclass /* clazz */, jlong controllerPtr) {
-    vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
-    if (controller == nullptr) {
-        ALOGE("vibratorOff failed because controller was not initialized");
+static void vibratorOff(JNIEnv* env, jclass /* clazz */, jlong servicePtr) {
+    NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
+    if (service == nullptr) {
+        ALOGE("vibratorOff failed because native service was not initialized");
         return;
     }
-    controller->off();
+    service->controller()->off();
 }
 
-static void vibratorSetAmplitude(JNIEnv* env, jclass /* clazz */, jlong controllerPtr,
+static void vibratorSetAmplitude(JNIEnv* env, jclass /* clazz */, jlong servicePtr,
                                  jint amplitude) {
-    vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
-    if (controller == nullptr) {
-        ALOGE("vibratorSetAmplitude failed because controller was not initialized");
+    NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
+    if (service == nullptr) {
+        ALOGE("vibratorSetAmplitude failed because native service was not initialized");
         return;
     }
-    controller->setAmplitude(static_cast<int32_t>(amplitude));
+    service->controller()->setAmplitude(static_cast<int32_t>(amplitude));
 }
 
-static void vibratorSetExternalControl(JNIEnv* env, jclass /* clazz */, jlong controllerPtr,
+static void vibratorSetExternalControl(JNIEnv* env, jclass /* clazz */, jlong servicePtr,
                                        jboolean enabled) {
-    vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
-    if (controller == nullptr) {
-        ALOGE("vibratorSetExternalControl failed because controller was not initialized");
+    NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
+    if (service == nullptr) {
+        ALOGE("vibratorSetExternalControl failed because native service was not initialized");
         return;
     }
-    controller->setExternalControl(enabled);
+    service->controller()->setExternalControl(enabled);
 }
 
-static jintArray vibratorGetSupportedEffects(JNIEnv* env, jclass /* clazz */, jlong controllerPtr) {
-    vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
-    if (controller == nullptr) {
-        ALOGE("vibratorGetSupportedEffects failed because controller was not initialized");
+static jintArray vibratorGetSupportedEffects(JNIEnv* env, jclass /* clazz */, jlong servicePtr) {
+    NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
+    if (service == nullptr) {
+        ALOGE("vibratorGetSupportedEffects failed because native service was not initialized");
         return nullptr;
     }
-    auto result = controller->getSupportedEffects();
+    auto result = service->controller()->getSupportedEffects();
     if (!result.isOk()) {
         return nullptr;
     }
@@ -181,14 +196,13 @@
     return effects;
 }
 
-static jintArray vibratorGetSupportedPrimitives(JNIEnv* env, jclass /* clazz */,
-                                                jlong controllerPtr) {
-    vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
-    if (controller == nullptr) {
-        ALOGE("vibratorGetSupportedPrimitives failed because controller was not initialized");
+static jintArray vibratorGetSupportedPrimitives(JNIEnv* env, jclass /* clazz */, jlong servicePtr) {
+    NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
+    if (service == nullptr) {
+        ALOGE("vibratorGetSupportedPrimitives failed because native service was not initialized");
         return nullptr;
     }
-    auto result = controller->getSupportedPrimitives();
+    auto result = service->controller()->getSupportedPrimitives();
     if (!result.isOk()) {
         return nullptr;
     }
@@ -199,26 +213,25 @@
     return primitives;
 }
 
-static jlong vibratorPerformEffect(JNIEnv* env, jclass /* clazz */, jlong controllerPtr,
-                                   jlong effect, jlong strength, jobject vibration) {
-    vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
-    if (controller == nullptr) {
-        ALOGE("vibratorPerformEffect failed because controller was not initialized");
+static jlong vibratorPerformEffect(JNIEnv* env, jclass /* clazz */, jlong servicePtr, jlong effect,
+                                   jlong strength, jlong vibrationId) {
+    NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
+    if (service == nullptr) {
+        ALOGE("vibratorPerformEffect failed because native service was not initialized");
         return -1;
     }
     aidl::Effect effectType = static_cast<aidl::Effect>(effect);
     aidl::EffectStrength effectStrength = static_cast<aidl::EffectStrength>(strength);
-    jobject vibrationRef = vibration == nullptr ? vibration : MakeGlobalRefOrDie(env, vibration);
-    auto callback = [vibrationRef]() { callVibrationOnComplete(vibrationRef); };
-    auto result = controller->performEffect(effectType, effectStrength, callback);
+    auto callback = service->createCallback(vibrationId);
+    auto result = service->controller()->performEffect(effectType, effectStrength, callback);
     return result.isOk() ? result.value().count() : -1;
 }
 
-static void vibratorPerformComposedEffect(JNIEnv* env, jclass /* clazz */, jlong controllerPtr,
-                                          jobjectArray composition, jobject vibration) {
-    vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
-    if (controller == nullptr) {
-        ALOGE("vibratorPerformComposedEffect failed because controller was not initialized");
+static void vibratorPerformComposedEffect(JNIEnv* env, jclass /* clazz */, jlong servicePtr,
+                                          jobjectArray composition, jlong vibrationId) {
+    NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
+    if (service == nullptr) {
+        ALOGE("vibratorPerformComposedEffect failed because native service was not initialized");
         return;
     }
     size_t size = env->GetArrayLength(composition);
@@ -227,54 +240,52 @@
         jobject element = env->GetObjectArrayElement(composition, i);
         effects.push_back(effectFromJavaPrimitive(env, element));
     }
-    jobject vibrationRef = vibration == nullptr ? vibration : MakeGlobalRefOrDie(env, vibration);
-    auto callback = [vibrationRef]() { callVibrationOnComplete(vibrationRef); };
-    controller->performComposedEffect(effects, callback);
+    auto callback = service->createCallback(vibrationId);
+    service->controller()->performComposedEffect(effects, callback);
 }
 
-static jlong vibratorGetCapabilities(JNIEnv* env, jclass /* clazz */, jlong controllerPtr) {
-    vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
-    if (controller == nullptr) {
-        ALOGE("vibratorGetCapabilities failed because controller was not initialized");
+static jlong vibratorGetCapabilities(JNIEnv* env, jclass /* clazz */, jlong servicePtr) {
+    NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
+    if (service == nullptr) {
+        ALOGE("vibratorGetCapabilities failed because native service was not initialized");
         return 0;
     }
-    auto result = controller->getCapabilities();
+    auto result = service->controller()->getCapabilities();
     return result.isOk() ? static_cast<jlong>(result.value()) : 0;
 }
 
-static void vibratorAlwaysOnEnable(JNIEnv* env, jclass /* clazz */, jlong controllerPtr, jlong id,
+static void vibratorAlwaysOnEnable(JNIEnv* env, jclass /* clazz */, jlong servicePtr, jlong id,
                                    jlong effect, jlong strength) {
-    vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
-    if (controller == nullptr) {
-        ALOGE("vibratorAlwaysOnEnable failed because controller was not initialized");
+    NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
+    if (service == nullptr) {
+        ALOGE("vibratorAlwaysOnEnable failed because native service was not initialized");
         return;
     }
-    controller->alwaysOnEnable(static_cast<int32_t>(id), static_cast<aidl::Effect>(effect),
-                               static_cast<aidl::EffectStrength>(strength));
+    service->controller()->alwaysOnEnable(static_cast<int32_t>(id),
+                                          static_cast<aidl::Effect>(effect),
+                                          static_cast<aidl::EffectStrength>(strength));
 }
 
-static void vibratorAlwaysOnDisable(JNIEnv* env, jclass /* clazz */, jlong controllerPtr,
-                                    jlong id) {
-    vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
-    if (controller == nullptr) {
-        ALOGE("vibratorAlwaysOnDisable failed because controller was not initialized");
+static void vibratorAlwaysOnDisable(JNIEnv* env, jclass /* clazz */, jlong servicePtr, jlong id) {
+    NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
+    if (service == nullptr) {
+        ALOGE("vibratorAlwaysOnDisable failed because native service was not initialized");
         return;
     }
-    controller->alwaysOnDisable(static_cast<int32_t>(id));
+    service->controller()->alwaysOnDisable(static_cast<int32_t>(id));
 }
 
 static const JNINativeMethod method_table[] = {
-        {"vibratorInit", "()J", (void*)vibratorInit},
+        {"vibratorInit", "(Lcom/android/server/VibratorService$OnCompleteListener;)J",
+         (void*)vibratorInit},
         {"vibratorGetFinalizer", "()J", (void*)vibratorGetFinalizer},
         {"vibratorExists", "(J)Z", (void*)vibratorExists},
-        {"vibratorOn", "(JJLcom/android/server/VibratorService$Vibration;)V", (void*)vibratorOn},
+        {"vibratorOn", "(JJJ)V", (void*)vibratorOn},
         {"vibratorOff", "(J)V", (void*)vibratorOff},
         {"vibratorSetAmplitude", "(JI)V", (void*)vibratorSetAmplitude},
-        {"vibratorPerformEffect", "(JJJLcom/android/server/VibratorService$Vibration;)J",
-         (void*)vibratorPerformEffect},
+        {"vibratorPerformEffect", "(JJJJ)J", (void*)vibratorPerformEffect},
         {"vibratorPerformComposedEffect",
-         "(J[Landroid/os/VibrationEffect$Composition$PrimitiveEffect;Lcom/android/server/"
-         "VibratorService$Vibration;)V",
+         "(J[Landroid/os/VibrationEffect$Composition$PrimitiveEffect;J)V",
          (void*)vibratorPerformComposedEffect},
         {"vibratorGetSupportedEffects", "(J)[I", (void*)vibratorGetSupportedEffects},
         {"vibratorGetSupportedPrimitives", "(J)[I", (void*)vibratorGetSupportedPrimitives},
@@ -284,18 +295,17 @@
         {"vibratorAlwaysOnDisable", "(JJ)V", (void*)vibratorAlwaysOnDisable},
 };
 
-int register_android_server_VibratorService(JavaVM* vm, JNIEnv* env) {
-    sJvm = vm;
-    sMethodIdOnComplete =
-            GetMethodIDOrDie(env,
-                             FindClassOrDie(env, "com/android/server/VibratorService$Vibration"),
-                             "onComplete", "()V");
+int register_android_server_VibratorService(JavaVM* jvm, JNIEnv* env) {
+    sJvm = jvm;
+    jclass listenerClass =
+            FindClassOrDie(env, "com/android/server/VibratorService$OnCompleteListener");
+    sMethodIdOnComplete = GetMethodIDOrDie(env, listenerClass, "onComplete", "(J)V");
 
     jclass primitiveClass =
             FindClassOrDie(env, "android/os/VibrationEffect$Composition$PrimitiveEffect");
-    gPrimitiveClassInfo.id = GetFieldIDOrDie(env, primitiveClass, "id", "I");
-    gPrimitiveClassInfo.scale = GetFieldIDOrDie(env, primitiveClass, "scale", "F");
-    gPrimitiveClassInfo.delay = GetFieldIDOrDie(env, primitiveClass, "delay", "I");
+    sPrimitiveClassInfo.id = GetFieldIDOrDie(env, primitiveClass, "id", "I");
+    sPrimitiveClassInfo.scale = GetFieldIDOrDie(env, primitiveClass, "scale", "F");
+    sPrimitiveClassInfo.delay = GetFieldIDOrDie(env, primitiveClass, "delay", "I");
 
     return jniRegisterNativeMethods(env, "com/android/server/VibratorService", method_table,
                                     NELEM(method_table));
diff --git a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
index b7a36f2..8d4f2aa 100644
--- a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
@@ -20,12 +20,13 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.AdditionalMatchers.gt;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.intThat;
-import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.ArgumentMatchers.notNull;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.never;
@@ -167,7 +168,7 @@
     @Test
     public void createService_initializesNativeService() {
         createService();
-        verify(mNativeWrapperMock).vibratorInit();
+        verify(mNativeWrapperMock).vibratorInit(notNull());
         verify(mNativeWrapperMock).vibratorOff();
     }
 
@@ -294,7 +295,7 @@
         assertTrue(service.isVibrating());
 
         verify(mNativeWrapperMock).vibratorOff();
-        verify(mNativeWrapperMock).vibratorOn(eq(100L), any(VibratorService.Vibration.class));
+        verify(mNativeWrapperMock).vibratorOn(eq(100L), gt(0L));
         verify(mNativeWrapperMock).vibratorSetAmplitude(eq(128));
     }
 
@@ -307,7 +308,7 @@
         assertTrue(service.isVibrating());
 
         verify(mNativeWrapperMock).vibratorOff();
-        verify(mNativeWrapperMock).vibratorOn(eq(100L), any(VibratorService.Vibration.class));
+        verify(mNativeWrapperMock).vibratorOn(eq(100L), gt(0L));
         verify(mNativeWrapperMock, never()).vibratorSetAmplitude(anyInt());
     }
 
@@ -321,10 +322,8 @@
         vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
 
         verify(mNativeWrapperMock).vibratorOff();
-        verify(mNativeWrapperMock).vibratorPerformEffect(
-                eq((long) VibrationEffect.EFFECT_CLICK),
-                eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG),
-                any(VibratorService.Vibration.class));
+        verify(mNativeWrapperMock).vibratorPerformEffect(eq((long) VibrationEffect.EFFECT_CLICK),
+                eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG), gt(0L));
     }
 
     @Test
@@ -343,7 +342,7 @@
 
         verify(mNativeWrapperMock).vibratorOff();
         verify(mNativeWrapperMock).vibratorPerformComposedEffect(
-                primitivesCaptor.capture(), any(VibratorService.Vibration.class));
+                primitivesCaptor.capture(), gt(0L));
 
         // Check all primitive effect fields are passed down to the HAL.
         assertEquals(1, primitivesCaptor.getValue().length);
@@ -368,7 +367,7 @@
 
         // Wait for VibrateThread to turn vibrator ON with total timing and no callback.
         Thread.sleep(5);
-        verify(mNativeWrapperMock).vibratorOn(eq(30L), isNull());
+        verify(mNativeWrapperMock).vibratorOn(eq(30L), eq(0L));
 
         // First amplitude set right away.
         verify(mNativeWrapperMock).vibratorSetAmplitude(eq(100));
@@ -384,11 +383,11 @@
 
     @Test
     public void vibrate_withOneShotAndNativeCallbackTriggered_finishesVibration() {
-        doAnswer(invocation -> {
-            ((VibratorService.Vibration) invocation.getArgument(1)).onComplete();
-            return null;
-        }).when(mNativeWrapperMock).vibratorOn(anyLong(), any(VibratorService.Vibration.class));
         VibratorService service = createService();
+        doAnswer(invocation -> {
+            service.onVibrationComplete(invocation.getArgument(1));
+            return null;
+        }).when(mNativeWrapperMock).vibratorOn(anyLong(), anyLong());
         Mockito.clearInvocations(mNativeWrapperMock);
 
         vibrate(service, VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE));
@@ -396,7 +395,7 @@
         InOrder inOrderVerifier = inOrder(mNativeWrapperMock);
         inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
         inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(100L),
-                any(VibratorService.Vibration.class));
+                gt(0L));
         inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
     }
 
@@ -404,12 +403,11 @@
     public void vibrate_withPrebakedAndNativeCallbackTriggered_finishesVibration() {
         when(mNativeWrapperMock.vibratorGetSupportedEffects())
                 .thenReturn(new int[]{VibrationEffect.EFFECT_CLICK});
-        doAnswer(invocation -> {
-            ((VibratorService.Vibration) invocation.getArgument(2)).onComplete();
-            return 10_000L; // 10s
-        }).when(mNativeWrapperMock).vibratorPerformEffect(
-                anyLong(), anyLong(), any(VibratorService.Vibration.class));
         VibratorService service = createService();
+        doAnswer(invocation -> {
+            service.onVibrationComplete(invocation.getArgument(2));
+            return 10_000L; // 10s
+        }).when(mNativeWrapperMock).vibratorPerformEffect(anyLong(), anyLong(), anyLong());
         Mockito.clearInvocations(mNativeWrapperMock);
 
         vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
@@ -419,7 +417,7 @@
         inOrderVerifier.verify(mNativeWrapperMock).vibratorPerformEffect(
                 eq((long) VibrationEffect.EFFECT_CLICK),
                 eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG),
-                any(VibratorService.Vibration.class));
+                gt(0L));
         inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
     }
 
@@ -436,20 +434,19 @@
         Thread.sleep(15);
         InOrder inOrderVerifier = inOrder(mNativeWrapperMock);
         inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
-        inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(3L), isNull());
-        inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(2L), isNull());
+        inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(3L), eq(0L));
+        inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(2L), eq(0L));
         inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
     }
 
     @Test
     public void vibrate_withComposedAndNativeCallbackTriggered_finishesVibration() {
         mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
-        doAnswer(invocation -> {
-            ((VibratorService.Vibration) invocation.getArgument(1)).onComplete();
-            return null;
-        }).when(mNativeWrapperMock).vibratorPerformComposedEffect(
-                any(), any(VibratorService.Vibration.class));
         VibratorService service = createService();
+        doAnswer(invocation -> {
+            service.onVibrationComplete(invocation.getArgument(1));
+            return null;
+        }).when(mNativeWrapperMock).vibratorPerformComposedEffect(any(), anyLong());
         Mockito.clearInvocations(mNativeWrapperMock);
 
         VibrationEffect effect = VibrationEffect.startComposition()
@@ -460,32 +457,7 @@
         InOrder inOrderVerifier = inOrder(mNativeWrapperMock);
         inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
         inOrderVerifier.verify(mNativeWrapperMock).vibratorPerformComposedEffect(
-                any(VibrationEffect.Composition.PrimitiveEffect[].class),
-                any(VibratorService.Vibration.class));
-        inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
-    }
-
-    @Test
-    public void vibrate_whenBinderDies_cancelsVibration() {
-        mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
-        doAnswer(invocation -> {
-            ((VibratorService.Vibration) invocation.getArgument(1)).binderDied();
-            return null;
-        }).when(mNativeWrapperMock).vibratorPerformComposedEffect(
-                any(), any(VibratorService.Vibration.class));
-        VibratorService service = createService();
-        Mockito.clearInvocations(mNativeWrapperMock);
-
-        VibrationEffect effect = VibrationEffect.startComposition()
-                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, 10)
-                .compose();
-        vibrate(service, effect);
-
-        InOrder inOrderVerifier = inOrder(mNativeWrapperMock);
-        inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
-        inOrderVerifier.verify(mNativeWrapperMock).vibratorPerformComposedEffect(
-                any(VibrationEffect.Composition.PrimitiveEffect[].class),
-                any(VibratorService.Vibration.class));
+                any(VibrationEffect.Composition.PrimitiveEffect[].class), gt(0L));
         inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
     }
 
@@ -513,12 +485,11 @@
 
     @Test
     public void registerVibratorStateListener_callbacksAreTriggered() throws Exception {
-        doAnswer(invocation -> {
-            ((VibratorService.Vibration) invocation.getArgument(1)).onComplete();
-            return null;
-        }).when(mNativeWrapperMock).vibratorOn(anyLong(), any(VibratorService.Vibration.class));
         VibratorService service = createService();
-
+        doAnswer(invocation -> {
+            service.onVibrationComplete(invocation.getArgument(1));
+            return null;
+        }).when(mNativeWrapperMock).vibratorOn(anyLong(), anyLong());
         service.registerVibratorStateListener(mVibratorStateListenerMock);
         verify(mVibratorStateListenerMock).onVibrating(false);
         Mockito.clearInvocations(mVibratorStateListenerMock);
@@ -569,15 +540,15 @@
 
         verify(mNativeWrapperMock).vibratorPerformEffect(
                 eq((long) VibrationEffect.EFFECT_CLICK),
-                eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG), any());
+                eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG), anyLong());
         verify(mNativeWrapperMock).vibratorPerformEffect(
                 eq((long) VibrationEffect.EFFECT_TICK),
-                eq((long) VibrationEffect.EFFECT_STRENGTH_MEDIUM), any());
+                eq((long) VibrationEffect.EFFECT_STRENGTH_MEDIUM), anyLong());
         verify(mNativeWrapperMock).vibratorPerformEffect(
                 eq((long) VibrationEffect.EFFECT_DOUBLE_CLICK),
-                eq((long) VibrationEffect.EFFECT_STRENGTH_LIGHT), any());
+                eq((long) VibrationEffect.EFFECT_STRENGTH_LIGHT), anyLong());
         verify(mNativeWrapperMock, never()).vibratorPerformEffect(
-                eq((long) VibrationEffect.EFFECT_HEAVY_CLICK), anyLong(), any());
+                eq((long) VibrationEffect.EFFECT_HEAVY_CLICK), anyLong(), anyLong());
     }
 
     @Test
@@ -644,7 +615,7 @@
 
         // Ringtone vibration is off, so only the other 3 are propagated to native.
         verify(mNativeWrapperMock, times(3)).vibratorPerformComposedEffect(
-                primitivesCaptor.capture(), any());
+                primitivesCaptor.capture(), anyLong());
 
         List<VibrationEffect.Composition.PrimitiveEffect[]> values =
                 primitivesCaptor.getAllValues();
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
index 763654d..dda81ff 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
@@ -187,7 +187,7 @@
         moveEachPointers(mLastEvent, p(10, 10), p(10, 10));
         send(mLastEvent);
         goToStateClearFrom(STATE_DRAGGING_2FINGERS);
-        assertCapturedEvents(ACTION_DOWN, ACTION_MOVE, ACTION_MOVE, ACTION_UP);
+        assertCapturedEvents(ACTION_DOWN, ACTION_MOVE, ACTION_MOVE, ACTION_MOVE, ACTION_UP);
     }
 
     @Test
@@ -288,7 +288,7 @@
         assertState(STATE_DRAGGING);
         goToStateClearFrom(STATE_DRAGGING_2FINGERS);
         assertState(STATE_CLEAR);
-        assertCapturedEvents(ACTION_DOWN, ACTION_UP);
+        assertCapturedEvents(ACTION_DOWN, ACTION_MOVE, ACTION_UP);
         assertCapturedEventsNoHistory();
     }
 
@@ -301,6 +301,7 @@
         assertState(STATE_CLEAR);
         assertCapturedEvents(
                 /* goto dragging state */ ACTION_DOWN,
+                ACTION_MOVE,
                 /* leave dragging state */ ACTION_UP,
                 ACTION_DOWN,
                 ACTION_POINTER_DOWN,
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java
index 53c4d6f..f17173f 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java
@@ -62,6 +62,32 @@
         assertThat(message).isEqualTo(buildMessage("5F:81:21:00"));
     }
 
+    @Test
+    public void buildSetOsdName_short() {
+        String deviceName = "abc";
+        HdmiCecMessage message = HdmiCecMessageBuilder.buildSetOsdNameCommand(ADDR_PLAYBACK_1,
+                ADDR_TV, deviceName);
+        assertThat(message).isEqualTo(buildMessage("40:47:61:62:63"));
+    }
+
+    @Test
+    public void buildSetOsdName_maximumLength() {
+        String deviceName = "abcdefghijklmn";
+        HdmiCecMessage message = HdmiCecMessageBuilder.buildSetOsdNameCommand(ADDR_PLAYBACK_1,
+                ADDR_TV, deviceName);
+        assertThat(message).isEqualTo(
+                buildMessage("40:47:61:62:63:64:65:66:67:68:69:6A:6B:6C:6D:6E"));
+    }
+
+    @Test
+    public void buildSetOsdName_tooLong() {
+        String deviceName = "abcdefghijklmnop";
+        HdmiCecMessage message = HdmiCecMessageBuilder.buildSetOsdNameCommand(ADDR_PLAYBACK_1,
+                ADDR_TV, deviceName);
+        assertThat(message).isEqualTo(
+                buildMessage("40:47:61:62:63:64:65:66:67:68:69:6A:6B:6C:6D:6E"));
+    }
+
     /**
      * Build a CEC message from a hex byte string with bytes separated by {@code :}.
      *
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
new file mode 100644
index 0000000..d7ed96f
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timezonedetector;
+
+import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED;
+import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE;
+import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED;
+import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.app.timezonedetector.TimeZoneCapabilities;
+
+import org.junit.Test;
+
+/**
+ * Tests for {@link ConfigurationInternal} and the {@link TimeZoneCapabilities} and
+ * {@link android.app.timezonedetector.TimeZoneConfiguration} that can be generated from it.
+ */
+public class ConfigurationInternalTest {
+
+    private static final int ARBITRARY_USER_ID = 99999;
+
+    /**
+     * Tests when {@link ConfigurationInternal#isUserConfigAllowed()} and
+     * {@link ConfigurationInternal#isAutoDetectionSupported()} are both true.
+     */
+    @Test
+    public void test_unrestricted() {
+        ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
+                .setUserConfigAllowed(true)
+                .setAutoDetectionSupported(true)
+                .setAutoDetectionEnabled(true)
+                .setLocationEnabled(true)
+                .setGeoDetectionEnabled(true)
+                .build();
+        {
+            ConfigurationInternal autoOnConfig = new ConfigurationInternal.Builder(baseConfig)
+                    .setAutoDetectionEnabled(true)
+                    .build();
+            assertTrue(autoOnConfig.getAutoDetectionEnabledSetting());
+            assertTrue(autoOnConfig.getGeoDetectionEnabledSetting());
+            assertTrue(autoOnConfig.getAutoDetectionEnabledBehavior());
+            assertTrue(autoOnConfig.getGeoDetectionEnabledBehavior());
+
+            TimeZoneCapabilities capabilities = autoOnConfig.createCapabilities();
+            assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureAutoDetectionEnabled());
+            assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureGeoDetectionEnabled());
+            assertEquals(CAPABILITY_NOT_APPLICABLE, capabilities.getSuggestManualTimeZone());
+            assertEquals(autoOnConfig.asConfiguration(), capabilities.getConfiguration());
+            assertTrue(capabilities.getConfiguration().isAutoDetectionEnabled());
+            assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled());
+        }
+
+        {
+            ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig)
+                    .setAutoDetectionEnabled(false)
+                    .build();
+            assertFalse(autoOffConfig.getAutoDetectionEnabledSetting());
+            assertTrue(autoOffConfig.getGeoDetectionEnabledSetting());
+            assertFalse(autoOffConfig.getAutoDetectionEnabledBehavior());
+            assertFalse(autoOffConfig.getGeoDetectionEnabledBehavior());
+
+            TimeZoneCapabilities capabilities = autoOffConfig.createCapabilities();
+            assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureAutoDetectionEnabled());
+            assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureGeoDetectionEnabled());
+            assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone());
+            assertEquals(autoOffConfig.asConfiguration(), capabilities.getConfiguration());
+            assertFalse(capabilities.getConfiguration().isAutoDetectionEnabled());
+            assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled());
+        }
+    }
+
+    /** Tests when {@link ConfigurationInternal#isUserConfigAllowed()} is false */
+    @Test
+    public void test_restricted() {
+        ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
+                .setUserConfigAllowed(false)
+                .setAutoDetectionSupported(true)
+                .setAutoDetectionEnabled(true)
+                .setLocationEnabled(true)
+                .setGeoDetectionEnabled(true)
+                .build();
+        {
+            ConfigurationInternal autoOnConfig = new ConfigurationInternal.Builder(baseConfig)
+                    .setAutoDetectionEnabled(true)
+                    .build();
+            assertTrue(autoOnConfig.getAutoDetectionEnabledSetting());
+            assertTrue(autoOnConfig.getGeoDetectionEnabledSetting());
+            assertTrue(autoOnConfig.getAutoDetectionEnabledBehavior());
+            assertTrue(autoOnConfig.getGeoDetectionEnabledBehavior());
+
+            TimeZoneCapabilities capabilities = autoOnConfig.createCapabilities();
+            assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureAutoDetectionEnabled());
+            assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureGeoDetectionEnabled());
+            assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSuggestManualTimeZone());
+            assertEquals(autoOnConfig.asConfiguration(), capabilities.getConfiguration());
+            assertTrue(capabilities.getConfiguration().isAutoDetectionEnabled());
+            assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled());
+        }
+
+        {
+            ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig)
+                    .setAutoDetectionEnabled(false)
+                    .build();
+            assertFalse(autoOffConfig.getAutoDetectionEnabledSetting());
+            assertTrue(autoOffConfig.getGeoDetectionEnabledSetting());
+            assertFalse(autoOffConfig.getAutoDetectionEnabledBehavior());
+            assertFalse(autoOffConfig.getGeoDetectionEnabledBehavior());
+
+            TimeZoneCapabilities capabilities = autoOffConfig.createCapabilities();
+            assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureAutoDetectionEnabled());
+            assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureGeoDetectionEnabled());
+            assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSuggestManualTimeZone());
+            assertEquals(autoOffConfig.asConfiguration(), capabilities.getConfiguration());
+            assertFalse(capabilities.getConfiguration().isAutoDetectionEnabled());
+            assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled());
+        }
+    }
+
+    /** Tests when {@link ConfigurationInternal#isAutoDetectionSupported()} is false. */
+    @Test
+    public void test_autoDetectNotSupported() {
+        ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
+                .setUserConfigAllowed(true)
+                .setAutoDetectionSupported(false)
+                .setAutoDetectionEnabled(true)
+                .setLocationEnabled(true)
+                .setGeoDetectionEnabled(true)
+                .build();
+        {
+            ConfigurationInternal autoOnConfig = new ConfigurationInternal.Builder(baseConfig)
+                    .setAutoDetectionEnabled(true)
+                    .build();
+            assertTrue(autoOnConfig.getAutoDetectionEnabledSetting());
+            assertTrue(autoOnConfig.getGeoDetectionEnabledSetting());
+            assertFalse(autoOnConfig.getAutoDetectionEnabledBehavior());
+            assertFalse(autoOnConfig.getGeoDetectionEnabledBehavior());
+
+            TimeZoneCapabilities capabilities = autoOnConfig.createCapabilities();
+            assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureAutoDetectionEnabled());
+            assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureGeoDetectionEnabled());
+            assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone());
+            assertEquals(autoOnConfig.asConfiguration(), capabilities.getConfiguration());
+            assertTrue(capabilities.getConfiguration().isAutoDetectionEnabled());
+            assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled());
+        }
+        {
+            ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig)
+                    .setAutoDetectionEnabled(false)
+                    .build();
+            assertFalse(autoOffConfig.getAutoDetectionEnabledSetting());
+            assertTrue(autoOffConfig.getGeoDetectionEnabledSetting());
+            assertFalse(autoOffConfig.getAutoDetectionEnabledBehavior());
+            assertFalse(autoOffConfig.getGeoDetectionEnabledBehavior());
+
+            TimeZoneCapabilities capabilities = autoOffConfig.createCapabilities();
+            assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureAutoDetectionEnabled());
+            assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureGeoDetectionEnabled());
+            assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone());
+            assertEquals(autoOffConfig.asConfiguration(), capabilities.getConfiguration());
+            assertFalse(capabilities.getConfiguration().isAutoDetectionEnabled());
+            assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled());
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java b/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
index e5e9311..4ef2082 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
@@ -18,6 +18,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
@@ -32,56 +33,64 @@
 
 class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy {
 
-    private StrategyListener mListener;
+    private ConfigurationChangeListener mConfigurationChangeListener;
 
     // Fake state
-    private TimeZoneCapabilities mCapabilities;
-    private TimeZoneConfiguration mConfiguration;
+    private ConfigurationInternal mConfigurationInternal;
 
     // Call tracking.
     private GeolocationTimeZoneSuggestion mLastGeolocationSuggestion;
     private ManualTimeZoneSuggestion mLastManualSuggestion;
     private TelephonyTimeZoneSuggestion mLastTelephonySuggestion;
-    private boolean mHandleAutoTimeZoneConfigChangedCalled;
     private boolean mDumpCalled;
     private final List<Dumpable> mDumpables = new ArrayList<>();
 
     @Override
-    public void setStrategyListener(@NonNull StrategyListener listener) {
-        mListener = listener;
+    public void addConfigChangeListener(@NonNull ConfigurationChangeListener listener) {
+        if (mConfigurationChangeListener != null) {
+            fail("Fake only supports one listener");
+        }
+        mConfigurationChangeListener = listener;
     }
 
     @Override
-    public TimeZoneCapabilities getCapabilities(@UserIdInt int userId) {
-        return mCapabilities;
+    public ConfigurationInternal getConfigurationInternal(int userId) {
+        if (mConfigurationInternal.getUserId() != userId) {
+            fail("Fake only supports one user");
+        }
+        return mConfigurationInternal;
     }
 
     @Override
-    public boolean updateConfiguration(
-            @UserIdInt int userId, @NonNull TimeZoneConfiguration configuration) {
-        assertNotNull(mConfiguration);
-        assertNotNull(configuration);
+    public ConfigurationInternal getCurrentUserConfigurationInternal() {
+        return mConfigurationInternal;
+    }
 
-        // Simulate the strategy's behavior: the new configuration will be the old configuration
-        // merged with the new.
-        TimeZoneConfiguration oldConfiguration = mConfiguration;
-        TimeZoneConfiguration newConfiguration =
-                new TimeZoneConfiguration.Builder(mConfiguration)
-                        .mergeProperties(configuration)
-                        .build();
+    @Override
+    public boolean updateConfiguration(@NonNull TimeZoneConfiguration requestedChanges) {
+        assertNotNull(mConfigurationInternal);
+        assertNotNull(requestedChanges);
 
-        if (newConfiguration.equals(oldConfiguration)) {
+        // Simulate the real strategy's behavior: the new configuration will be updated to be the
+        // old configuration merged with the new if the user has the capability to up the settings.
+        // Then, if the configuration changed, the change listener is invoked.
+        TimeZoneCapabilities capabilities = mConfigurationInternal.createCapabilities();
+        TimeZoneConfiguration newConfiguration = capabilities.applyUpdate(requestedChanges);
+        if (newConfiguration == null) {
             return false;
         }
-        mConfiguration = newConfiguration;
-        mListener.onConfigurationChanged();
+
+        if (!newConfiguration.equals(capabilities.getConfiguration())) {
+            mConfigurationInternal = mConfigurationInternal.merge(newConfiguration);
+
+            // Note: Unlike the real strategy, the listeners is invoked synchronously.
+            mConfigurationChangeListener.onChange();
+        }
         return true;
     }
 
-    @Override
-    @NonNull
-    public TimeZoneConfiguration getConfiguration(@UserIdInt int userId) {
-        return mConfiguration;
+    public void simulateConfigurationChangeForTests() {
+        mConfigurationChangeListener.onChange();
     }
 
     @Override
@@ -103,11 +112,6 @@
     }
 
     @Override
-    public void handleAutoTimeZoneConfigChanged() {
-        mHandleAutoTimeZoneConfigChangedCalled = true;
-    }
-
-    @Override
     public void addDumpable(Dumpable dumpable) {
         mDumpables.add(dumpable);
     }
@@ -117,19 +121,14 @@
         mDumpCalled = true;
     }
 
-    void initializeConfiguration(TimeZoneConfiguration configuration) {
-        mConfiguration = configuration;
-    }
-
-    void initializeCapabilities(TimeZoneCapabilities capabilities) {
-        mCapabilities = capabilities;
+    void initializeConfiguration(ConfigurationInternal configurationInternal) {
+        mConfigurationInternal = configurationInternal;
     }
 
     void resetCallTracking() {
         mLastGeolocationSuggestion = null;
         mLastManualSuggestion = null;
         mLastTelephonySuggestion = null;
-        mHandleAutoTimeZoneConfigChangedCalled = false;
         mDumpCalled = false;
     }
 
@@ -146,10 +145,6 @@
         assertEquals(expectedSuggestion, mLastTelephonySuggestion);
     }
 
-    void verifyHandleAutoTimeZoneConfigChangedCalled() {
-        assertTrue(mHandleAutoTimeZoneConfigChangedCalled);
-    }
-
     void verifyDumpCalled() {
         assertTrue(mDumpCalled);
     }
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TestCallerIdentityInjector.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TestCallerIdentityInjector.java
new file mode 100644
index 0000000..f45b3a8
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TestCallerIdentityInjector.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timezonedetector;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.annotation.UserIdInt;
+
+/** A fake {@link CallerIdentityInjector} used in tests. */
+public class TestCallerIdentityInjector implements CallerIdentityInjector {
+
+    private long mToken = 9999L;
+    private int mCallingUserId;
+    private Integer mCurrentCallingUserId;
+
+    public void initializeCallingUserId(@UserIdInt int userId) {
+        mCallingUserId = userId;
+        mCurrentCallingUserId = userId;
+    }
+
+    @Override
+    public int getCallingUserId() {
+        assertNotNull("callingUserId has been cleared", mCurrentCallingUserId);
+        return mCurrentCallingUserId;
+    }
+
+    @Override
+    public long clearCallingIdentity() {
+        mCurrentCallingUserId = null;
+        return mToken;
+    }
+
+    @Override
+    public void restoreCallingIdentity(long token) {
+        assertEquals(token, mToken);
+        mCurrentCallingUserId = mCallingUserId;
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java
index e9d57e5..918babc 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java
@@ -16,6 +16,7 @@
 
 package com.android.server.timezonedetector;
 
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 
 import android.content.Context;
@@ -85,6 +86,18 @@
         mFakeTimeZoneDetectorStrategy.verifyHasDumpable(stubbedDumpable);
     }
 
+    @Test
+    public void testAddConfigurationListener() throws Exception {
+        boolean[] changeCalled = new boolean[2];
+        mTimeZoneDetectorInternal.addConfigurationListener(() -> changeCalled[0] = true);
+        mTimeZoneDetectorInternal.addConfigurationListener(() -> changeCalled[1] = true);
+
+        mFakeTimeZoneDetectorStrategy.simulateConfigurationChangeForTests();
+
+        assertTrue(changeCalled[0]);
+        assertTrue(changeCalled[1]);
+    }
+
     private static GeolocationTimeZoneSuggestion createGeolocationTimeZoneSuggestion() {
         return new GeolocationTimeZoneSuggestion(ARBITRARY_ZONE_IDS);
     }
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
index 3a1ec4f..27b04b6 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
@@ -16,8 +16,6 @@
 
 package com.android.server.timezonedetector;
 
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
@@ -36,7 +34,6 @@
 import android.app.timezonedetector.ITimeZoneConfigurationListener;
 import android.app.timezonedetector.ManualTimeZoneSuggestion;
 import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
-import android.app.timezonedetector.TimeZoneCapabilities;
 import android.app.timezonedetector.TimeZoneConfiguration;
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -65,6 +62,7 @@
     private TimeZoneDetectorService mTimeZoneDetectorService;
     private HandlerThread mHandlerThread;
     private TestHandler mTestHandler;
+    private TestCallerIdentityInjector mTestCallerIdentityInjector;
 
 
     @Before
@@ -76,10 +74,14 @@
         mHandlerThread.start();
         mTestHandler = new TestHandler(mHandlerThread.getLooper());
 
+        mTestCallerIdentityInjector = new TestCallerIdentityInjector();
+        mTestCallerIdentityInjector.initializeCallingUserId(ARBITRARY_USER_ID);
+
         mFakeTimeZoneDetectorStrategy = new FakeTimeZoneDetectorStrategy();
 
         mTimeZoneDetectorService = new TimeZoneDetectorService(
-                mMockContext, mTestHandler, mFakeTimeZoneDetectorStrategy);
+                mMockContext, mTestHandler, mTestCallerIdentityInjector,
+                mFakeTimeZoneDetectorStrategy);
     }
 
     @After
@@ -107,40 +109,12 @@
     public void testGetCapabilities() {
         doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
 
-        TimeZoneCapabilities capabilities = createTimeZoneCapabilities();
-        mFakeTimeZoneDetectorStrategy.initializeCapabilities(capabilities);
-
-        assertEquals(capabilities, mTimeZoneDetectorService.getCapabilities());
-
-        verify(mMockContext).enforceCallingPermission(
-                eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
-                anyString());
-    }
-
-    @Test(expected = SecurityException.class)
-    public void testGetConfiguration_withoutPermission() {
-        doThrow(new SecurityException("Mock"))
-                .when(mMockContext).enforceCallingPermission(anyString(), any());
-
-        try {
-            mTimeZoneDetectorService.getConfiguration();
-            fail();
-        } finally {
-            verify(mMockContext).enforceCallingPermission(
-                    eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
-                    anyString());
-        }
-    }
-
-    @Test
-    public void testGetConfiguration() {
-        doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
-
-        TimeZoneConfiguration configuration =
-                createTimeZoneConfiguration(false /* autoDetectionEnabled */);
+        ConfigurationInternal configuration =
+                createConfigurationInternal(true /* autoDetectionEnabled*/);
         mFakeTimeZoneDetectorStrategy.initializeConfiguration(configuration);
 
-        assertEquals(configuration, mTimeZoneDetectorService.getConfiguration());
+        assertEquals(configuration.createCapabilities(),
+                mTimeZoneDetectorService.getCapabilities());
 
         verify(mMockContext).enforceCallingPermission(
                 eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
@@ -181,10 +155,9 @@
 
     @Test
     public void testConfigurationChangeListenerRegistrationAndCallbacks() throws Exception {
-        TimeZoneConfiguration autoDetectDisabledConfiguration =
-                createTimeZoneConfiguration(false /* autoDetectionEnabled */);
-
-        mFakeTimeZoneDetectorStrategy.initializeConfiguration(autoDetectDisabledConfiguration);
+        ConfigurationInternal initialConfiguration =
+                createConfigurationInternal(false /* autoDetectionEnabled */);
+        mFakeTimeZoneDetectorStrategy.initializeConfiguration(initialConfiguration);
 
         IBinder mockListenerBinder = mock(IBinder.class);
         ITimeZoneConfigurationListener mockListener = mock(ITimeZoneConfigurationListener.class);
@@ -210,13 +183,12 @@
             // Simulate the configuration being changed and verify the mockListener was notified.
             TimeZoneConfiguration autoDetectEnabledConfiguration =
                     createTimeZoneConfiguration(true /* autoDetectionEnabled */);
-
             mTimeZoneDetectorService.updateConfiguration(autoDetectEnabledConfiguration);
 
             verify(mMockContext).enforceCallingPermission(
                     eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
                     anyString());
-            verify(mockListener).onChange(autoDetectEnabledConfiguration);
+            verify(mockListener).onChange();
             verifyNoMoreInteractions(mockListenerBinder, mockListener, mMockContext);
             reset(mockListenerBinder, mockListener, mMockContext);
         }
@@ -242,12 +214,14 @@
         {
             doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
 
+            TimeZoneConfiguration autoDetectDisabledConfiguration =
+                    createTimeZoneConfiguration(false /* autoDetectionEnabled */);
             mTimeZoneDetectorService.updateConfiguration(autoDetectDisabledConfiguration);
 
             verify(mMockContext).enforceCallingPermission(
                     eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
                     anyString());
-            verify(mockListener, never()).onChange(any());
+            verify(mockListener, never()).onChange();
             verifyNoMoreInteractions(mockListenerBinder, mockListener, mMockContext);
             reset(mockListenerBinder, mockListener, mMockContext);
         }
@@ -379,33 +353,22 @@
         mFakeTimeZoneDetectorStrategy.verifyDumpCalled();
     }
 
-    @Test
-    public void testHandleAutoTimeZoneConfigChanged() throws Exception {
-        mTimeZoneDetectorService.handleAutoTimeZoneConfigChanged();
-        mTestHandler.assertTotalMessagesEnqueued(1);
-        mTestHandler.waitForMessagesToBeProcessed();
-        mFakeTimeZoneDetectorStrategy.verifyHandleAutoTimeZoneConfigChangedCalled();
-
-        mFakeTimeZoneDetectorStrategy.resetCallTracking();
-
-        mTimeZoneDetectorService.handleAutoTimeZoneConfigChanged();
-        mTestHandler.assertTotalMessagesEnqueued(2);
-        mTestHandler.waitForMessagesToBeProcessed();
-        mFakeTimeZoneDetectorStrategy.verifyHandleAutoTimeZoneConfigChangedCalled();
-    }
-
-    private static TimeZoneConfiguration createTimeZoneConfiguration(
-            boolean autoDetectionEnabled) {
-        return new TimeZoneConfiguration.Builder()
+    private static TimeZoneConfiguration createTimeZoneConfiguration(boolean autoDetectionEnabled) {
+        return new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
                 .setAutoDetectionEnabled(autoDetectionEnabled)
                 .build();
     }
 
-    private static TimeZoneCapabilities createTimeZoneCapabilities() {
-        return new TimeZoneCapabilities.Builder(ARBITRARY_USER_ID)
-                .setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
-                .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
-                .setSuggestManualTimeZone(CAPABILITY_POSSESSED)
+    private static ConfigurationInternal createConfigurationInternal(boolean autoDetectionEnabled) {
+        // Default geo detection settings from auto detection settings - they are not important to
+        // the tests.
+        final boolean geoDetectionEnabled = autoDetectionEnabled;
+        return new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
+                .setAutoDetectionSupported(true)
+                .setUserConfigAllowed(true)
+                .setAutoDetectionEnabled(autoDetectionEnabled)
+                .setLocationEnabled(geoDetectionEnabled)
+                .setGeoDetectionEnabled(geoDetectionEnabled)
                 .build();
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
index a6caa42..2bee5e5 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
@@ -23,10 +23,6 @@
 import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
 import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET;
 import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_SINGLE_ZONE;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED;
 
 import static com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.TELEPHONY_SCORE_HIGH;
 import static com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.TELEPHONY_SCORE_HIGHEST;
@@ -37,9 +33,9 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
@@ -47,7 +43,6 @@
 import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
 import android.app.timezonedetector.TelephonyTimeZoneSuggestion.MatchType;
 import android.app.timezonedetector.TelephonyTimeZoneSuggestion.Quality;
-import android.app.timezonedetector.TimeZoneCapabilities;
 import android.app.timezonedetector.TimeZoneConfiguration;
 import android.util.IndentingPrintWriter;
 
@@ -61,7 +56,6 @@
 import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Objects;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
@@ -94,192 +88,149 @@
                     TELEPHONY_SCORE_HIGHEST),
     };
 
-    private static final TimeZoneConfiguration CONFIG_AUTO_ENABLED =
-            new TimeZoneConfiguration.Builder()
-                    .setAutoDetectionEnabled(true)
-                    .build();
-
-    private static final TimeZoneConfiguration CONFIG_AUTO_DISABLED =
-            new TimeZoneConfiguration.Builder()
+    private static final ConfigurationInternal CONFIG_INT_USER_RESTRICTED_AUTO_DISABLED =
+            new ConfigurationInternal.Builder(USER_ID)
+                    .setUserConfigAllowed(false)
+                    .setAutoDetectionSupported(true)
                     .setAutoDetectionEnabled(false)
-                    .build();
-
-    private static final TimeZoneConfiguration CONFIG_GEO_DETECTION_DISABLED =
-            new TimeZoneConfiguration.Builder()
+                    .setLocationEnabled(true)
                     .setGeoDetectionEnabled(false)
                     .build();
 
-    private static final TimeZoneConfiguration CONFIG_GEO_DETECTION_ENABLED =
-            new TimeZoneConfiguration.Builder()
+    private static final ConfigurationInternal CONFIG_INT_USER_RESTRICTED_AUTO_ENABLED =
+            new ConfigurationInternal.Builder(USER_ID)
+                    .setUserConfigAllowed(false)
+                    .setAutoDetectionSupported(true)
+                    .setAutoDetectionEnabled(true)
+                    .setLocationEnabled(true)
                     .setGeoDetectionEnabled(true)
                     .build();
 
+    private static final ConfigurationInternal CONFIG_INT_AUTO_DETECT_NOT_SUPPORTED =
+            new ConfigurationInternal.Builder(USER_ID)
+                    .setUserConfigAllowed(true)
+                    .setAutoDetectionSupported(false)
+                    .setAutoDetectionEnabled(false)
+                    .setLocationEnabled(true)
+                    .setGeoDetectionEnabled(false)
+                    .build();
+
+    private static final ConfigurationInternal CONFIG_INT_AUTO_DISABLED_GEO_DISABLED =
+            new ConfigurationInternal.Builder(USER_ID)
+                    .setUserConfigAllowed(true)
+                    .setAutoDetectionSupported(true)
+                    .setAutoDetectionEnabled(false)
+                    .setLocationEnabled(true)
+                    .setGeoDetectionEnabled(false)
+                    .build();
+
+    private static final ConfigurationInternal CONFIG_INT_AUTO_DISABLED_GEO_ENABLED =
+            new ConfigurationInternal.Builder(USER_ID)
+                    .setUserConfigAllowed(true)
+                    .setAutoDetectionSupported(true)
+                    .setAutoDetectionEnabled(false)
+                    .setLocationEnabled(true)
+                    .setGeoDetectionEnabled(true)
+                    .build();
+
+    private static final ConfigurationInternal CONFIG_INT_AUTO_ENABLED_GEO_DISABLED =
+            new ConfigurationInternal.Builder(USER_ID)
+                    .setAutoDetectionSupported(true)
+                    .setUserConfigAllowed(true)
+                    .setAutoDetectionEnabled(true)
+                    .setLocationEnabled(true)
+                    .setGeoDetectionEnabled(false)
+                    .build();
+
+    private static final ConfigurationInternal CONFIG_INT_AUTO_ENABLED_GEO_ENABLED =
+            new ConfigurationInternal.Builder(USER_ID)
+                    .setAutoDetectionSupported(true)
+                    .setUserConfigAllowed(true)
+                    .setAutoDetectionEnabled(true)
+                    .setLocationEnabled(true)
+                    .setGeoDetectionEnabled(true)
+                    .build();
+
+    private static final TimeZoneConfiguration CONFIG_AUTO_DISABLED =
+            createConfig(false /* autoDetection */, null);
+    private static final TimeZoneConfiguration CONFIG_AUTO_ENABLED =
+            createConfig(true /* autoDetection */, null);
+    private static final TimeZoneConfiguration CONFIG_GEO_DETECTION_ENABLED =
+            createConfig(null, true /* geoDetection */);
+    private static final TimeZoneConfiguration CONFIG_GEO_DETECTION_DISABLED =
+            createConfig(null, false /* geoDetection */);
+
     private TimeZoneDetectorStrategyImpl mTimeZoneDetectorStrategy;
     private FakeCallback mFakeCallback;
-    private MockStrategyListener mMockStrategyListener;
+    private MockConfigChangeListener mMockConfigChangeListener;
+
 
     @Before
     public void setUp() {
         mFakeCallback = new FakeCallback();
-        mMockStrategyListener = new MockStrategyListener();
+        mMockConfigChangeListener = new MockConfigChangeListener();
         mTimeZoneDetectorStrategy = new TimeZoneDetectorStrategyImpl(mFakeCallback);
-        mFakeCallback.setStrategyForSettingsCallbacks(mTimeZoneDetectorStrategy);
-        mTimeZoneDetectorStrategy.setStrategyListener(mMockStrategyListener);
+        mTimeZoneDetectorStrategy.addConfigChangeListener(mMockConfigChangeListener);
     }
 
     @Test
-    public void testGetCapabilities() {
-        new Script()
-                .initializeUser(USER_ID, UserCase.UNRESTRICTED,
-                        CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
-        TimeZoneCapabilities expectedCapabilities = mFakeCallback.getCapabilities(USER_ID);
-        assertEquals(expectedCapabilities, mTimeZoneDetectorStrategy.getCapabilities(USER_ID));
-    }
-
-    @Test
-    public void testGetConfiguration() {
-        new Script()
-                .initializeUser(USER_ID, UserCase.UNRESTRICTED,
-                        CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
-        TimeZoneConfiguration expectedConfiguration = mFakeCallback.getConfiguration(USER_ID);
-        assertTrue(expectedConfiguration.isComplete());
-        assertEquals(expectedConfiguration, mTimeZoneDetectorStrategy.getConfiguration(USER_ID));
-    }
-
-    @Test
-    public void testCapabilitiesTestInfra_unrestricted() {
-        Script script = new Script();
-
-        script.initializeUser(USER_ID, UserCase.UNRESTRICTED,
-                CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
-        {
-            // Check the fake test infra is doing what is expected.
-            TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID);
-            assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureAutoDetectionEnabled());
-            assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureGeoDetectionEnabled());
-            assertEquals(CAPABILITY_NOT_APPLICABLE, capabilities.getSuggestManualTimeZone());
-        }
-
-        script.initializeUser(USER_ID, UserCase.UNRESTRICTED,
-                CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED));
-        {
-            // Check the fake test infra is doing what is expected.
-            TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID);
-            assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureAutoDetectionEnabled());
-            assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureGeoDetectionEnabled());
-            assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone());
-        }
-    }
-
-    @Test
-    public void testCapabilitiesTestInfra_restricted() {
-        Script script = new Script();
-
-        script.initializeUser(USER_ID, UserCase.RESTRICTED,
-                CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
-        {
-            // Check the fake test infra is doing what is expected.
-            TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID);
-            assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureAutoDetectionEnabled());
-            assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureGeoDetectionEnabled());
-            assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSuggestManualTimeZone());
-        }
-
-        script.initializeUser(USER_ID, UserCase.RESTRICTED,
-                CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED));
-        {
-            // Check the fake test infra is doing what is expected.
-            TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID);
-            assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureAutoDetectionEnabled());
-            assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureGeoDetectionEnabled());
-            assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSuggestManualTimeZone());
-        }
-    }
-
-    @Test
-    public void testCapabilitiesTestInfra_autoDetectNotSupported() {
-        Script script = new Script();
-
-        script.initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED,
-                CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
-        {
-            // Check the fake test infra is doing what is expected.
-            TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID);
-            assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureAutoDetectionEnabled());
-            assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureGeoDetectionEnabled());
-            assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone());
-        }
-
-        script.initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED,
-                CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED));
-        {
-            // Check the fake test infra is doing what is expected.
-            TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID);
-            assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureAutoDetectionEnabled());
-            assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureGeoDetectionEnabled());
-            assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone());
-        }
+    public void testGetCurrentUserConfiguration() {
+        new Script().initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED);
+        ConfigurationInternal expectedConfiguration =
+                mFakeCallback.getConfigurationInternal(USER_ID);
+        assertEquals(expectedConfiguration,
+                mTimeZoneDetectorStrategy.getCurrentUserConfigurationInternal());
     }
 
     @Test
     public void testUpdateConfiguration_unrestricted() {
-        Script script = new Script()
-                .initializeUser(USER_ID, UserCase.UNRESTRICTED,
-                        CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
+        Script script = new Script().initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED);
 
         // Set the configuration with auto detection enabled.
-        script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */);
+        script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */);
 
         // Nothing should have happened: it was initialized in this state.
         script.verifyConfigurationNotChanged();
 
         // Update the configuration with auto detection disabled.
-        script.simulateUpdateConfiguration(
-                USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */);
+        script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, true /* expectedResult */);
 
         // The settings should have been changed and the StrategyListener onChange() called.
-        script.verifyConfigurationChangedAndReset(USER_ID,
-                CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED));
+        script.verifyConfigurationChangedAndReset(CONFIG_INT_AUTO_DISABLED_GEO_DISABLED);
 
         // Update the configuration with auto detection enabled.
-        script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */);
+        script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */);
 
         // The settings should have been changed and the StrategyListener onChange() called.
-        script.verifyConfigurationChangedAndReset(USER_ID,
-                CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
+        script.verifyConfigurationChangedAndReset(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED);
 
         // Update the configuration to enable geolocation time zone detection.
         script.simulateUpdateConfiguration(
-                USER_ID, CONFIG_GEO_DETECTION_ENABLED,  true /* expectedResult */);
+                CONFIG_GEO_DETECTION_ENABLED,  true /* expectedResult */);
 
         // The settings should have been changed and the StrategyListener onChange() called.
-        script.verifyConfigurationChangedAndReset(USER_ID,
-                CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED));
+        script.verifyConfigurationChangedAndReset(CONFIG_INT_AUTO_ENABLED_GEO_ENABLED);
     }
 
     @Test
     public void testUpdateConfiguration_restricted() {
-        Script script = new Script()
-                .initializeUser(USER_ID, UserCase.RESTRICTED,
-                        CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
+        Script script = new Script().initializeConfig(CONFIG_INT_USER_RESTRICTED_AUTO_ENABLED);
 
         // Try to update the configuration with auto detection disabled.
-        script.simulateUpdateConfiguration(
-                USER_ID, CONFIG_AUTO_DISABLED, false /* expectedResult */);
+        script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, false /* expectedResult */);
 
         // The settings should not have been changed: user shouldn't have the capabilities.
         script.verifyConfigurationNotChanged();
 
         // Update the configuration with auto detection enabled.
-        script.simulateUpdateConfiguration(
-                USER_ID, CONFIG_AUTO_ENABLED,  false /* expectedResult */);
+        script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED,  false /* expectedResult */);
 
         // The settings should not have been changed: user shouldn't have the capabilities.
         script.verifyConfigurationNotChanged();
 
-        // Update the configuration to enable geolocation time zone detection.
+        // Try to  update the configuration to enable geolocation time zone detection.
         script.simulateUpdateConfiguration(
-                USER_ID, CONFIG_GEO_DETECTION_ENABLED,  false /* expectedResult */);
+                CONFIG_GEO_DETECTION_ENABLED,  false /* expectedResult */);
 
         // The settings should not have been changed: user shouldn't have the capabilities.
         script.verifyConfigurationNotChanged();
@@ -287,20 +238,16 @@
 
     @Test
     public void testUpdateConfiguration_autoDetectNotSupported() {
-        Script script = new Script()
-                .initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED,
-                        CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
+        Script script = new Script().initializeConfig(CONFIG_INT_AUTO_DETECT_NOT_SUPPORTED);
 
         // Try to update the configuration with auto detection disabled.
-        script.simulateUpdateConfiguration(
-                USER_ID, CONFIG_AUTO_DISABLED, false /* expectedResult */);
+        script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, false /* expectedResult */);
 
         // The settings should not have been changed: user shouldn't have the capabilities.
         script.verifyConfigurationNotChanged();
 
         // Update the configuration with auto detection enabled.
-        script.simulateUpdateConfiguration(
-                USER_ID, CONFIG_AUTO_ENABLED, false /* expectedResult */);
+        script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, false /* expectedResult */);
 
         // The settings should not have been changed: user shouldn't have the capabilities.
         script.verifyConfigurationNotChanged();
@@ -313,8 +260,7 @@
         TelephonyTimeZoneSuggestion slotIndex2TimeZoneSuggestion =
                 createEmptySlotIndex2Suggestion();
         Script script = new Script()
-                .initializeUser(USER_ID, UserCase.UNRESTRICTED,
-                        CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED))
+                .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED)
                 .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
 
         script.simulateTelephonyTimeZoneSuggestion(slotIndex1TimeZoneSuggestion)
@@ -359,9 +305,7 @@
         TelephonyTestCase testCase2 = newTelephonyTestCase(MATCH_TYPE_NETWORK_COUNTRY_ONLY,
                 QUALITY_SINGLE_ZONE, TELEPHONY_SCORE_HIGH);
 
-        Script script = new Script()
-                .initializeUser(USER_ID, UserCase.UNRESTRICTED,
-                        CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
+        Script script = new Script().initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED);
 
         // A low quality suggestions will not be taken: The device time zone setting is left
         // uninitialized.
@@ -426,8 +370,7 @@
 
         for (TelephonyTestCase testCase : TELEPHONY_TEST_CASES) {
             // Start with the device in a known state.
-            script.initializeUser(USER_ID, UserCase.UNRESTRICTED,
-                    CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED))
+            script.initializeConfig(CONFIG_INT_AUTO_DISABLED_GEO_DISABLED)
                     .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
 
             TelephonyTimeZoneSuggestion suggestion =
@@ -447,8 +390,7 @@
                     mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
 
             // Toggling the time zone setting on should cause the device setting to be set.
-            script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED,
-                    true /* expectedResult */);
+            script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */);
 
             // When time zone detection is already enabled the suggestion (if it scores highly
             // enough) should be set immediately.
@@ -465,8 +407,7 @@
                     mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
 
             // Toggling the time zone setting should off should do nothing.
-            script.simulateUpdateConfiguration(
-                    USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
+            script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, true /* expectedResult */)
                     .verifyTimeZoneNotChanged();
 
             // Assert internal service state.
@@ -480,8 +421,7 @@
     @Test
     public void testTelephonySuggestionsSingleSlotId() {
         Script script = new Script()
-                .initializeUser(USER_ID, UserCase.UNRESTRICTED,
-                        CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED))
+                .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED)
                 .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
 
         for (TelephonyTestCase testCase : TELEPHONY_TEST_CASES) {
@@ -546,8 +486,7 @@
                         TELEPHONY_SCORE_NONE);
 
         Script script = new Script()
-                .initializeUser(USER_ID, UserCase.UNRESTRICTED,
-                        CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED))
+                .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED)
                 .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID)
                 // Initialize the latest suggestions as empty so we don't need to worry about nulls
                 // below for the first loop.
@@ -632,9 +571,7 @@
      */
     @Test
     public void testTelephonySuggestionStrategyDoesNotAssumeCurrentSetting_autoTelephony() {
-        Script script = new Script()
-                .initializeUser(USER_ID, UserCase.UNRESTRICTED,
-                        CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
+        Script script = new Script().initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED);
 
         TelephonyTestCase testCase = newTelephonyTestCase(
                 MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET, QUALITY_SINGLE_ZONE, TELEPHONY_SCORE_HIGH);
@@ -652,40 +589,39 @@
 
         // Toggling time zone detection should set the device time zone only if the current setting
         // value is different from the most recent telephony suggestion.
-        script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
+        script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, true /* expectedResult */)
                 .verifyTimeZoneNotChanged()
-                .simulateUpdateConfiguration(
-                        USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
+                .simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */)
                 .verifyTimeZoneNotChanged();
 
         // Simulate a user turning auto detection off, a new suggestion being made while auto
         // detection is off, and the user turning it on again.
-        script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
+        script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, true /* expectedResult */)
                 .simulateTelephonyTimeZoneSuggestion(newYorkSuggestion)
                 .verifyTimeZoneNotChanged();
         // Latest suggestion should be used.
-        script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
+        script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */)
                 .verifyTimeZoneChangedAndReset(newYorkSuggestion);
     }
 
     @Test
-    public void testManualSuggestion_autoDetectionEnabled_autoTelephony() {
-        checkManualSuggestion_autoDetectionEnabled(false /* geoDetectionEnabled */);
+    public void testManualSuggestion_unrestricted_autoDetectionEnabled_autoTelephony() {
+        checkManualSuggestion_unrestricted_autoDetectionEnabled(false /* geoDetectionEnabled */);
     }
 
     @Test
-    public void testManualSuggestion_autoDetectionEnabled_autoGeo() {
-        checkManualSuggestion_autoDetectionEnabled(true /* geoDetectionEnabled */);
+    public void testManualSuggestion_unrestricted_autoDetectionEnabled_autoGeo() {
+        checkManualSuggestion_unrestricted_autoDetectionEnabled(true /* geoDetectionEnabled */);
     }
 
-    private void checkManualSuggestion_autoDetectionEnabled(boolean geoDetectionEnabled) {
-        TimeZoneConfiguration geoTzEnabledConfig =
-                new TimeZoneConfiguration.Builder()
+    private void checkManualSuggestion_unrestricted_autoDetectionEnabled(
+            boolean geoDetectionEnabled) {
+        ConfigurationInternal geoTzEnabledConfig =
+                new ConfigurationInternal.Builder(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED)
                         .setGeoDetectionEnabled(geoDetectionEnabled)
                         .build();
         Script script = new Script()
-                .initializeUser(USER_ID, UserCase.UNRESTRICTED,
-                        CONFIG_AUTO_ENABLED.with(geoTzEnabledConfig))
+                .initializeConfig(geoTzEnabledConfig)
                 .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
 
         // Auto time zone detection is enabled so the manual suggestion should be ignored.
@@ -697,35 +633,19 @@
     @Test
     public void testManualSuggestion_restricted_simulateAutoTimeZoneEnabled() {
         Script script = new Script()
-                .initializeUser(USER_ID, UserCase.RESTRICTED,
-                        CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED))
+                .initializeConfig(CONFIG_INT_USER_RESTRICTED_AUTO_ENABLED)
                 .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
 
-        // Auto time zone detection is enabled so the manual suggestion should be ignored.
+        // User is restricted so the manual suggestion should be ignored.
         script.simulateManualTimeZoneSuggestion(
                 USER_ID, createManualSuggestion("Europe/Paris"), false /* expectedResult */)
-            .verifyTimeZoneNotChanged();
-    }
-
-    @Test
-    public void testManualSuggestion_autoDetectNotSupported_simulateAutoTimeZoneEnabled() {
-        Script script = new Script()
-                .initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED,
-                        CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED))
-                .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
-
-        // Auto time zone detection is enabled so the manual suggestion should be ignored.
-        ManualTimeZoneSuggestion manualSuggestion = createManualSuggestion("Europe/Paris");
-        script.simulateManualTimeZoneSuggestion(
-                USER_ID, manualSuggestion, true /* expectedResult */)
-            .verifyTimeZoneChangedAndReset(manualSuggestion);
+                .verifyTimeZoneNotChanged();
     }
 
     @Test
     public void testManualSuggestion_unrestricted_autoTimeZoneDetectionDisabled() {
         Script script = new Script()
-                .initializeUser(USER_ID, UserCase.UNRESTRICTED,
-                        CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED))
+                .initializeConfig(CONFIG_INT_AUTO_DISABLED_GEO_DISABLED)
                 .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
 
         // Auto time zone detection is disabled so the manual suggestion should be used.
@@ -738,8 +658,7 @@
     @Test
     public void testManualSuggestion_restricted_autoTimeZoneDetectionDisabled() {
         Script script = new Script()
-                .initializeUser(USER_ID, UserCase.RESTRICTED,
-                        CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED))
+                .initializeConfig(CONFIG_INT_USER_RESTRICTED_AUTO_DISABLED)
                 .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
 
         // Restricted users do not have the capability.
@@ -750,10 +669,9 @@
     }
 
     @Test
-    public void testManualSuggestion_autoDetectNotSupported_autoTimeZoneDetectionDisabled() {
+    public void testManualSuggestion_autoDetectNotSupported() {
         Script script = new Script()
-                .initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED,
-                        CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED))
+                .initializeConfig(CONFIG_INT_AUTO_DETECT_NOT_SUPPORTED)
                 .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
 
         // Unrestricted users have the capability.
@@ -765,9 +683,7 @@
 
     @Test
     public void testGeoSuggestion_uncertain() {
-        Script script = new Script()
-                .initializeUser(USER_ID, UserCase.UNRESTRICTED,
-                        CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED))
+        Script script = new Script().initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_ENABLED)
                 .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
 
         GeolocationTimeZoneSuggestion uncertainSuggestion = createUncertainGeoLocationSuggestion();
@@ -783,8 +699,7 @@
     @Test
     public void testGeoSuggestion_noZones() {
         Script script = new Script()
-                .initializeUser(USER_ID, UserCase.UNRESTRICTED,
-                        CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED))
+                .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_ENABLED)
                 .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
 
         GeolocationTimeZoneSuggestion noZonesSuggestion = createGeoLocationSuggestion(list());
@@ -802,8 +717,7 @@
                 createGeoLocationSuggestion(list("Europe/London"));
 
         Script script = new Script()
-                .initializeUser(USER_ID, UserCase.UNRESTRICTED,
-                        CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED))
+                .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_ENABLED)
                 .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
 
         script.simulateGeolocationTimeZoneSuggestion(suggestion)
@@ -828,8 +742,7 @@
                 createGeoLocationSuggestion(list("Europe/Paris"));
 
         Script script = new Script()
-                .initializeUser(USER_ID, UserCase.UNRESTRICTED,
-                        CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED))
+                .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_ENABLED)
                 .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
 
         script.simulateGeolocationTimeZoneSuggestion(londonOnlySuggestion)
@@ -856,72 +769,27 @@
                 mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
     }
 
-    /**
-     * Confirms that toggling the auto time zone detection enabled setting has the expected behavior
-     * when the strategy is "opinionated" and "un-opinionated" when in geolocation detection is
-     * enabled.
-     */
     @Test
-    public void testTogglingAutoDetectionEnabled_autoGeo() {
-        GeolocationTimeZoneSuggestion geolocationSuggestion =
+    public void testGeoSuggestion_togglingGeoDetectionClearsLastSuggestion() {
+        GeolocationTimeZoneSuggestion suggestion =
                 createGeoLocationSuggestion(list("Europe/London"));
-        GeolocationTimeZoneSuggestion uncertainGeolocationSuggestion =
-                createUncertainGeoLocationSuggestion();
-        ManualTimeZoneSuggestion manualSuggestion = createManualSuggestion("Europe/Paris");
 
         Script script = new Script()
-                .initializeUser(USER_ID, UserCase.UNRESTRICTED,
-                        CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_ENABLED))
+                .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_ENABLED)
                 .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
 
-        script.simulateGeolocationTimeZoneSuggestion(geolocationSuggestion);
-
-        // When time zone detection is not enabled, the time zone suggestion will not be set.
-        script.verifyTimeZoneNotChanged();
-
-        // Assert internal service state.
-        assertEquals(geolocationSuggestion,
-                mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
-
-        // Toggling the time zone setting on should cause the device setting to be set.
-        script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
+        script.simulateGeolocationTimeZoneSuggestion(suggestion)
                 .verifyTimeZoneChangedAndReset("Europe/London");
 
-        // Toggling the time zone setting should off should do nothing because the device is now
-        // set to that time zone.
-        script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
-                .verifyTimeZoneNotChanged()
-                .simulateUpdateConfiguration(
-                        USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
-                .verifyTimeZoneNotChanged();
+        // Assert internal service state.
+        assertEquals(suggestion, mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
 
-        // Now toggle auto time zone setting, and confirm it is opinionated.
-        script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
-                .simulateManualTimeZoneSuggestion(
-                        USER_ID, manualSuggestion, true /* expectedResult */)
-                .verifyTimeZoneChangedAndReset(manualSuggestion)
-                .simulateUpdateConfiguration(
-                        USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
-                .verifyTimeZoneChangedAndReset("Europe/London");
-
-        // Now withdraw the geolocation suggestion, and assert the strategy is no longer
-        // opinionated.
-        /* expectedResult */
-        script.simulateGeolocationTimeZoneSuggestion(uncertainGeolocationSuggestion)
-                .verifyTimeZoneNotChanged()
-                .simulateUpdateConfiguration(
-                        USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
-                .verifyTimeZoneNotChanged()
-                .simulateManualTimeZoneSuggestion(
-                        USER_ID, manualSuggestion, true /* expectedResult */)
-                .verifyTimeZoneChangedAndReset(manualSuggestion)
-                .simulateUpdateConfiguration(
-                        USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
-                .verifyTimeZoneNotChanged();
+        // Turn off geo detection and verify the latest suggestion is cleared.
+        script.simulateUpdateConfiguration(CONFIG_GEO_DETECTION_DISABLED, true)
+                .verifyConfigurationChangedAndReset(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED);
 
         // Assert internal service state.
-        assertEquals(uncertainGeolocationSuggestion,
-                mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
+        assertNull(mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
     }
 
     /**
@@ -937,88 +805,48 @@
                 "Europe/Paris");
 
         Script script = new Script()
-                .initializeUser(USER_ID, UserCase.UNRESTRICTED,
-                        CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED))
+                .initializeConfig(CONFIG_INT_AUTO_DISABLED_GEO_DISABLED)
                 .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
 
         // Add suggestions. Nothing should happen as time zone detection is disabled.
         script.simulateGeolocationTimeZoneSuggestion(geolocationSuggestion)
                 .verifyTimeZoneNotChanged();
+
+        // Geolocation suggestions are only stored when geolocation detection is enabled.
+        assertNull(mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
+
         script.simulateTelephonyTimeZoneSuggestion(telephonySuggestion)
                 .verifyTimeZoneNotChanged();
 
-        // Assert internal service state.
-        assertEquals(geolocationSuggestion,
-                mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
+        // Telephony suggestions are always stored.
         assertEquals(telephonySuggestion,
                 mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1).suggestion);
 
         // Toggling the time zone detection enabled setting on should cause the device setting to be
         // set from the telephony signal, as we've started with geolocation time zone detection
         // disabled.
-        script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
+        script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */)
                 .verifyTimeZoneChangedAndReset(telephonySuggestion);
 
-        // Changing the detection to enable geo detection should cause the device tz setting to
-        // change to the geo suggestion.
-        script.simulateUpdateConfiguration(
-                USER_ID, CONFIG_GEO_DETECTION_ENABLED, true /* expectedResult */)
+        // Changing the detection to enable geo detection won't cause the device tz setting to
+        // change because the geo suggestion is empty.
+        script.simulateUpdateConfiguration(CONFIG_GEO_DETECTION_ENABLED, true /* expectedResult */)
+                .verifyTimeZoneNotChanged()
+                .simulateGeolocationTimeZoneSuggestion(geolocationSuggestion)
                 .verifyTimeZoneChangedAndReset(geolocationSuggestion.getZoneIds().get(0));
 
         // Changing the detection to disable geo detection should cause the device tz setting to
         // change to the telephony suggestion.
-        script.simulateUpdateConfiguration(
-                USER_ID, CONFIG_GEO_DETECTION_DISABLED, true /* expectedResult */)
+        script.simulateUpdateConfiguration(CONFIG_GEO_DETECTION_DISABLED, true /* expectedResult */)
                 .verifyTimeZoneChangedAndReset(telephonySuggestion);
-    }
 
-    /**
-     * The {@link TimeZoneDetectorStrategyImpl.Callback} is left to detect whether changing the time
-     * zone is actually necessary. This test proves that the strategy doesn't assume it knows the
-     * current setting.
-     */
-    @Test
-    public void testTimeZoneDetectorStrategyDoesNotAssumeCurrentSetting_autoGeo() {
-        GeolocationTimeZoneSuggestion losAngelesSuggestion =
-                createGeoLocationSuggestion(list("America/Los_Angeles"));
-        GeolocationTimeZoneSuggestion newYorkSuggestion =
-                createGeoLocationSuggestion(list("America/New_York"));
-
-        Script script = new Script()
-                .initializeUser(USER_ID, UserCase.UNRESTRICTED,
-                        CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED));
-
-        // Initialization.
-        script.simulateGeolocationTimeZoneSuggestion(losAngelesSuggestion)
-                .verifyTimeZoneChangedAndReset("America/Los_Angeles");
-        // Suggest it again - it should not be set because it is already set.
-        script.simulateGeolocationTimeZoneSuggestion(losAngelesSuggestion)
-                .verifyTimeZoneNotChanged();
-
-        // Toggling time zone detection should set the device time zone only if the current setting
-        // value is different from the most recent telephony suggestion.
-        /* expectedResult */
-        script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
-                .verifyTimeZoneNotChanged()
-                .simulateUpdateConfiguration(
-                        USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
-                .verifyTimeZoneNotChanged();
-
-        // Simulate a user turning auto detection off, a new suggestion being made while auto
-        // detection is off, and the user turning it on again.
-        script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
-                .simulateGeolocationTimeZoneSuggestion(newYorkSuggestion)
-                .verifyTimeZoneNotChanged();
-        // Latest suggestion should be used.
-        script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
-                .verifyTimeZoneChangedAndReset("America/New_York");
+        assertNull(mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
     }
 
     @Test
     public void testAddDumpable() {
         new Script()
-                .initializeUser(USER_ID, UserCase.UNRESTRICTED,
-                        CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED))
+                .initializeConfig(CONFIG_INT_AUTO_DISABLED_GEO_DISABLED)
                 .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
 
         AtomicBoolean dumpCalled = new AtomicBoolean(false);
@@ -1069,25 +897,26 @@
         return suggestion;
     }
 
+    private static TimeZoneConfiguration createConfig(
+            @Nullable Boolean autoDetection, @Nullable Boolean geoDetection) {
+        TimeZoneConfiguration.Builder builder = new TimeZoneConfiguration.Builder(USER_ID);
+        if (autoDetection != null) {
+            builder.setAutoDetectionEnabled(autoDetection);
+        }
+        if (geoDetection != null) {
+            builder.setGeoDetectionEnabled(geoDetection);
+        }
+        return builder.build();
+    }
+
     static class FakeCallback implements TimeZoneDetectorStrategyImpl.Callback {
 
-        private TimeZoneCapabilities mCapabilities;
-        private final TestState<UserConfiguration> mConfiguration = new TestState<>();
+        private final TestState<ConfigurationInternal> mConfigurationInternal = new TestState<>();
         private final TestState<String> mTimeZoneId = new TestState<>();
-        private TimeZoneDetectorStrategyImpl mStrategy;
+        private ConfigurationChangeListener mConfigChangeListener;
 
-        void setStrategyForSettingsCallbacks(TimeZoneDetectorStrategyImpl strategy) {
-            assertNotNull(strategy);
-            mStrategy = strategy;
-        }
-
-        void initializeUser(@UserIdInt int userId, TimeZoneCapabilities capabilities,
-                TimeZoneConfiguration configuration) {
-            assertEquals(userId, capabilities.getUserId());
-            mCapabilities = capabilities;
-            assertTrue("Configuration must be complete when initializing, config=" + configuration,
-                    configuration.isComplete());
-            mConfiguration.init(new UserConfiguration(userId, configuration));
+        void initializeConfig(ConfigurationInternal configurationInternal) {
+            mConfigurationInternal.init(configurationInternal);
         }
 
         void initializeTimeZoneSetting(String zoneId) {
@@ -1095,43 +924,22 @@
         }
 
         @Override
-        public TimeZoneCapabilities getCapabilities(@UserIdInt int userId) {
-            assertEquals(userId, mCapabilities.getUserId());
-            return mCapabilities;
+        public void setConfigChangeListener(ConfigurationChangeListener listener) {
+            mConfigChangeListener = listener;
         }
 
         @Override
-        public TimeZoneConfiguration getConfiguration(@UserIdInt int userId) {
-            UserConfiguration latest = mConfiguration.getLatest();
-            assertEquals(userId, latest.userId);
-            return latest.configuration;
-        }
-
-        @Override
-        public void setConfiguration(@UserIdInt int userId, TimeZoneConfiguration newConfig) {
-            assertNotNull(newConfig);
-            assertTrue(newConfig.isComplete());
-
-            UserConfiguration latestUserConfig = mConfiguration.getLatest();
-            assertEquals(userId, latestUserConfig.userId);
-            TimeZoneConfiguration oldConfig = latestUserConfig.configuration;
-
-            mConfiguration.set(new UserConfiguration(userId, newConfig));
-
-            if (!newConfig.equals(oldConfig)) {
-                // Simulate what happens when the auto detection configuration is changed.
-                mStrategy.handleAutoTimeZoneConfigChanged();
+        public ConfigurationInternal getConfigurationInternal(int userId) {
+            ConfigurationInternal configuration = mConfigurationInternal.getLatest();
+            if (userId != configuration.getUserId()) {
+                fail("FakeCallback does not support multiple users.");
             }
+            return configuration;
         }
 
         @Override
-        public boolean isAutoDetectionEnabled() {
-            return mConfiguration.getLatest().configuration.isAutoDetectionEnabled();
-        }
-
-        @Override
-        public boolean isGeoDetectionEnabled() {
-            return mConfiguration.getLatest().configuration.isGeoDetectionEnabled();
+        public int getCurrentUserId() {
+            return mConfigurationInternal.getLatest().getUserId();
         }
 
         @Override
@@ -1149,9 +957,25 @@
             mTimeZoneId.set(zoneId);
         }
 
+        @Override
+        public void storeConfiguration(TimeZoneConfiguration newConfiguration) {
+            ConfigurationInternal oldConfiguration = mConfigurationInternal.getLatest();
+            if (newConfiguration.getUserId() != oldConfiguration.getUserId()) {
+                fail("FakeCallback does not support multiple users");
+            }
+
+            ConfigurationInternal mergedConfiguration = oldConfiguration.merge(newConfiguration);
+            if (!mergedConfiguration.equals(oldConfiguration)) {
+                mConfigurationInternal.set(mergedConfiguration);
+
+                // Note: Unlike the real callback impl, the listener is invoked synchronously.
+                mConfigChangeListener.onChange();
+            }
+        }
+
         void assertKnownUser(int userId) {
-            assertEquals(userId, mCapabilities.getUserId());
-            assertEquals(userId, mConfiguration.getLatest().userId);
+            assertEquals("FakeCallback does not support multiple users",
+                    mConfigurationInternal.getLatest().getUserId(), userId);
         }
 
         void assertTimeZoneNotChanged() {
@@ -1166,43 +990,7 @@
 
         void commitAllChanges() {
             mTimeZoneId.commitLatest();
-            mConfiguration.commitLatest();
-        }
-    }
-
-    private static final class UserConfiguration {
-        public final @UserIdInt int userId;
-        public final TimeZoneConfiguration configuration;
-
-        UserConfiguration(int userId, TimeZoneConfiguration configuration) {
-            this.userId = userId;
-            this.configuration = configuration;
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (this == o) {
-                return true;
-            }
-            if (o == null || getClass() != o.getClass()) {
-                return false;
-            }
-            UserConfiguration that = (UserConfiguration) o;
-            return userId == that.userId
-                    && Objects.equals(configuration, that.configuration);
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(userId, configuration);
-        }
-
-        @Override
-        public String toString() {
-            return "UserConfiguration{"
-                    + "userId=" + userId
-                    + ", configuration=" + configuration
-                    + '}';
+            mConfigurationInternal.commitLatest();
         }
     }
 
@@ -1255,64 +1043,14 @@
         }
     }
 
-    /** Simulated user test cases. */
-    enum UserCase {
-        /** A catch-all for users that can set auto time zone config. */
-        UNRESTRICTED,
-        /** A catch-all for users that can't set auto time zone config. */
-        RESTRICTED,
-        /**
-         * Like {@link #UNRESTRICTED}, but auto tz detection is not
-         * supported on the device.
-         */
-        AUTO_DETECT_NOT_SUPPORTED,
-    }
-
-    /**
-     * Creates a {@link TimeZoneCapabilities} object for a user in the specific role with the
-     * supplied configuration.
-     */
-    private static TimeZoneCapabilities createCapabilities(
-            int userId, UserCase userCase, TimeZoneConfiguration configuration) {
-        switch (userCase) {
-            case UNRESTRICTED: {
-                int suggestManualTimeZoneCapability = configuration.isAutoDetectionEnabled()
-                        ? CAPABILITY_NOT_APPLICABLE : CAPABILITY_POSSESSED;
-                return new TimeZoneCapabilities.Builder(userId)
-                        .setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
-                        .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
-                        .setSuggestManualTimeZone(suggestManualTimeZoneCapability)
-                        .build();
-            }
-            case RESTRICTED: {
-                return new TimeZoneCapabilities.Builder(userId)
-                        .setConfigureAutoDetectionEnabled(CAPABILITY_NOT_ALLOWED)
-                        .setConfigureGeoDetectionEnabled(CAPABILITY_NOT_ALLOWED)
-                        .setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED)
-                        .build();
-            }
-            case AUTO_DETECT_NOT_SUPPORTED: {
-                return new TimeZoneCapabilities.Builder(userId)
-                        .setConfigureAutoDetectionEnabled(CAPABILITY_NOT_SUPPORTED)
-                        .setConfigureGeoDetectionEnabled(CAPABILITY_NOT_SUPPORTED)
-                        .setSuggestManualTimeZone(CAPABILITY_POSSESSED)
-                        .build();
-            }
-            default:
-                throw new AssertionError(userCase + " not recognized");
-        }
-    }
-
     /**
      * A "fluent" class allows reuse of code in tests: initialization, simulation and verification
      * logic.
      */
     private class Script {
 
-        Script initializeUser(
-                @UserIdInt int userId, UserCase userCase, TimeZoneConfiguration configuration) {
-            TimeZoneCapabilities capabilities = createCapabilities(userId, userCase, configuration);
-            mFakeCallback.initializeUser(userId, capabilities, configuration);
+        Script initializeConfig(ConfigurationInternal configuration) {
+            mFakeCallback.initializeConfig(configuration);
             return this;
         }
 
@@ -1326,10 +1064,9 @@
          * the return value.
          */
         Script simulateUpdateConfiguration(
-                @UserIdInt int userId, TimeZoneConfiguration configuration,
-                boolean expectedResult) {
+                TimeZoneConfiguration configuration, boolean expectedResult) {
             assertEquals(expectedResult,
-                    mTimeZoneDetectorStrategy.updateConfiguration(userId, configuration));
+                    mTimeZoneDetectorStrategy.updateConfiguration(configuration));
             return this;
         }
 
@@ -1392,16 +1129,14 @@
         /**
          * Verifies that the configuration has been changed to the expected value.
          */
-        Script verifyConfigurationChangedAndReset(
-                @UserIdInt int userId, TimeZoneConfiguration expected) {
-            mFakeCallback.mConfiguration.assertHasBeenSet();
-            UserConfiguration expectedUserConfig = new UserConfiguration(userId, expected);
-            assertEquals(expectedUserConfig, mFakeCallback.mConfiguration.getLatest());
+        Script verifyConfigurationChangedAndReset(ConfigurationInternal expected) {
+            mFakeCallback.mConfigurationInternal.assertHasBeenSet();
+            assertEquals(expected, mFakeCallback.mConfigurationInternal.getLatest());
             mFakeCallback.commitAllChanges();
 
             // Also confirm the listener triggered.
-            mMockStrategyListener.verifyOnConfigurationChangedCalled();
-            mMockStrategyListener.reset();
+            mMockConfigChangeListener.verifyOnChangeCalled();
+            mMockConfigChangeListener.reset();
             return this;
         }
 
@@ -1410,10 +1145,10 @@
          * {@link TimeZoneConfiguration} have been changed.
          */
         Script verifyConfigurationNotChanged() {
-            mFakeCallback.mConfiguration.assertHasNotBeenSet();
+            mFakeCallback.mConfigurationInternal.assertHasNotBeenSet();
 
             // Also confirm the listener did not trigger.
-            mMockStrategyListener.verifyOnConfigurationChangedNotCalled();
+            mMockConfigChangeListener.verifyOnChangeNotCalled();
             return this;
         }
 
@@ -1448,24 +1183,24 @@
         return new TelephonyTestCase(matchType, quality, expectedScore);
     }
 
-    private static class MockStrategyListener implements TimeZoneDetectorStrategy.StrategyListener {
-        private boolean mOnConfigurationChangedCalled;
+    private static class MockConfigChangeListener implements ConfigurationChangeListener {
+        private boolean mOnChangeCalled;
 
         @Override
-        public void onConfigurationChanged() {
-            mOnConfigurationChangedCalled = true;
+        public void onChange() {
+            mOnChangeCalled = true;
         }
 
-        void verifyOnConfigurationChangedCalled() {
-            assertTrue(mOnConfigurationChangedCalled);
+        void verifyOnChangeCalled() {
+            assertTrue(mOnChangeCalled);
         }
 
-        void verifyOnConfigurationChangedNotCalled() {
-            assertFalse(mOnConfigurationChangedCalled);
+        void verifyOnChangeNotCalled() {
+            assertFalse(mOnChangeCalled);
         }
 
         void reset() {
-            mOnConfigurationChangedCalled = false;
+            mOnChangeCalled = false;
         }
     }
 
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 d54b4a0..f8baf84 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1110,7 +1110,7 @@
         performLayout(mDisplayContent);
 
         // The frame is empty because the requested height is zero.
-        assertTrue(win.getFrameLw().isEmpty());
+        assertTrue(win.getFrame().isEmpty());
         // The window should be scheduled to resize then the client may report a new non-empty size.
         win.updateResizingWindowIfNeeded();
         assertThat(mWm.mResizingWindows).contains(win);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 0675c6d..2d834ac 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -114,7 +114,7 @@
         mWindow = spy(createWindow(null, TYPE_APPLICATION, "window"));
         // We only test window frames set by DisplayPolicy, so here prevents computeFrameLw from
         // changing those frames.
-        doNothing().when(mWindow).computeFrameLw();
+        doNothing().when(mWindow).computeFrame();
 
         final WindowManager.LayoutParams attrs = mWindow.mAttrs;
         attrs.width = MATCH_PARENT;
@@ -179,7 +179,7 @@
 
         WindowState win = createWindow(null, TYPE_STATUS_BAR_SUB_PANEL, "StatusBarSubPanel");
         win.mAttrs.providesInsetsTypes = new int[]{ITYPE_STATUS_BAR, ITYPE_TOP_GESTURES};
-        win.getFrameLw().set(0, 0, 500, 100);
+        win.getFrame().set(0, 0, 500, 100);
 
         addWindow(win);
         InsetsStateController controller = mDisplayContent.getInsetsStateController();
@@ -207,7 +207,7 @@
         mDisplayPolicy.removeWindowLw(mStatusBarWindow);  // Removes the existing one.
         WindowState win = createWindow(null, TYPE_STATUS_BAR, "StatusBar");
         win.mAttrs.providesInsetsTypes = new int[]{ITYPE_STATUS_BAR};
-        win.getFrameLw().set(0, 0, 500, 100);
+        win.getFrame().set(0, 0, 500, 100);
 
         addWindow(win);
         mDisplayContent.getInsetsStateController().onPostLayout();
@@ -232,7 +232,7 @@
         WindowState win1 = createWindow(null, TYPE_NAVIGATION_BAR_PANEL, "NavBarPanel1");
         win1.mAttrs.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR};
         win1.mAttrs.gravity = Gravity.TOP;
-        win1.getFrameLw().set(0, 0, 200, 500);
+        win1.getFrame().set(0, 0, 200, 500);
         addWindow(win1);
 
         assertEquals(mDisplayPolicy.getAlternateNavBarPosition(), ALT_BAR_TOP);
@@ -241,7 +241,7 @@
         WindowState win2 = createWindow(null, TYPE_NAVIGATION_BAR_PANEL, "NavBarPanel2");
         win2.mAttrs.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR};
         win2.mAttrs.gravity = Gravity.BOTTOM;
-        win2.getFrameLw().set(0, 0, 200, 500);
+        win2.getFrame().set(0, 0, 200, 500);
         addWindow(win2);
 
         assertEquals(mDisplayPolicy.getAlternateNavBarPosition(), ALT_BAR_BOTTOM);
@@ -250,7 +250,7 @@
         WindowState win3 = createWindow(null, TYPE_NAVIGATION_BAR_PANEL, "NavBarPanel3");
         win3.mAttrs.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR};
         win3.mAttrs.gravity = Gravity.LEFT;
-        win3.getFrameLw().set(0, 0, 200, 500);
+        win3.getFrame().set(0, 0, 200, 500);
         addWindow(win3);
 
         assertEquals(mDisplayPolicy.getAlternateNavBarPosition(), ALT_BAR_LEFT);
@@ -259,7 +259,7 @@
         WindowState win4 = createWindow(null, TYPE_NAVIGATION_BAR_PANEL, "NavBarPanel4");
         win4.mAttrs.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR};
         win4.mAttrs.gravity = Gravity.RIGHT;
-        win4.getFrameLw().set(0, 0, 200, 500);
+        win4.getFrame().set(0, 0, 200, 500);
         addWindow(win4);
 
         assertEquals(mDisplayPolicy.getAlternateNavBarPosition(), ALT_BAR_RIGHT);
@@ -274,11 +274,11 @@
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
-        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, 0);
+        assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, 0);
         assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
-        assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
         assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
     }
 
@@ -290,11 +290,11 @@
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
-        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDisplayFrame(), 0, NAV_BAR_HEIGHT);
         assertInsetByTopBottom(mWindow.getParentFrame(), 0, NAV_BAR_HEIGHT);
-        assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
         assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
     }
 
@@ -306,11 +306,11 @@
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
-        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
         assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-        assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
         assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
     }
 
@@ -322,11 +322,11 @@
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
-        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, 0);
+        assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, 0);
         assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
-        assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
         assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
     }
 
@@ -342,11 +342,11 @@
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
-        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
         assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-        assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
         assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
     }
 
@@ -362,11 +362,11 @@
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
-        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
+        assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDisplayFrame(), 0, 0);
         assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
-        assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
         assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
     }
 
@@ -381,11 +381,11 @@
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
-        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), DISPLAY_CUTOUT_HEIGHT, 0);
+        assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDisplayFrame(), DISPLAY_CUTOUT_HEIGHT, 0);
         assertInsetByTopBottom(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0);
-        assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
         assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
     }
 
@@ -402,10 +402,10 @@
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
         assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
-        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
         assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
-        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
+        assertInsetByTopBottom(mWindow.getDisplayFrame(), 0, 0);
     }
 
     @Test
@@ -422,10 +422,10 @@
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
         assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
-        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
         assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
-        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, 0);
+        assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, 0);
     }
 
     @Test
@@ -442,10 +442,10 @@
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
         assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
-        assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
-        assertInsetBy(mWindow.getContentFrameLw(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
+        assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
+        assertInsetBy(mWindow.getContentFrame(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
         assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
-        assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
+        assertInsetBy(mWindow.getDisplayFrame(), 0, 0, 0, 0);
     }
 
     @Test
@@ -462,10 +462,10 @@
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
         assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
-        assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
-        assertInsetBy(mWindow.getContentFrameLw(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
+        assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
+        assertInsetBy(mWindow.getContentFrame(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
         assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
-        assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
+        assertInsetBy(mWindow.getDisplayFrame(), 0, 0, 0, 0);
     }
 
     @Test
@@ -484,10 +484,10 @@
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
         assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
-        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
         assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
-        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
+        assertInsetByTopBottom(mWindow.getDisplayFrame(), 0, 0);
     }
 
     @Test
@@ -506,10 +506,10 @@
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
         assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
-        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
         assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
-        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, 0);
+        assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, 0);
     }
 
     @Test
@@ -529,10 +529,10 @@
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
         assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
-        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
         assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
-        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
+        assertInsetByTopBottom(mWindow.getDisplayFrame(), 0, 0);
     }
 
 
@@ -549,11 +549,11 @@
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
         assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
-        assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
-        assertInsetBy(mWindow.getContentFrameLw(),
+        assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
+        assertInsetBy(mWindow.getContentFrame(),
                 DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
         assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
-        assertInsetBy(mWindow.getDisplayFrameLw(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
+        assertInsetBy(mWindow.getDisplayFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
     }
 
     @Test
@@ -570,11 +570,11 @@
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
         assertInsetBy(mWindow.getParentFrame(), 0, 0, DISPLAY_CUTOUT_HEIGHT, 0);
-        assertInsetBy(mWindow.getStableFrameLw(), NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, 0, 0);
-        assertInsetBy(mWindow.getContentFrameLw(),
+        assertInsetBy(mWindow.getStableFrame(), NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, 0, 0);
+        assertInsetBy(mWindow.getContentFrame(),
                 NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, DISPLAY_CUTOUT_HEIGHT, 0);
         assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
-        assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, DISPLAY_CUTOUT_HEIGHT, 0);
+        assertInsetBy(mWindow.getDisplayFrame(), 0, 0, DISPLAY_CUTOUT_HEIGHT, 0);
     }
 
     @Test
@@ -594,8 +594,8 @@
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
         assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
-        assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
-        assertInsetBy(mWindow.getContentFrameLw(),
+        assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
+        assertInsetBy(mWindow.getContentFrame(),
                 DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
         assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
     }
@@ -615,7 +615,7 @@
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
         assertInsetByTopBottom(mWindow.getParentFrame(), 0, NAV_BAR_HEIGHT);
-        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
     }
 
     @Test
@@ -636,8 +636,8 @@
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
         assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
-        assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
-        assertInsetBy(mWindow.getContentFrameLw(),
+        assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
+        assertInsetBy(mWindow.getContentFrame(),
                 DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
         assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
     }
@@ -655,11 +655,11 @@
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
         assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
-        assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
-        assertInsetBy(mWindow.getContentFrameLw(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0,
+        assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
+        assertInsetBy(mWindow.getContentFrame(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0,
                 NAV_BAR_HEIGHT);
         assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
-        assertInsetBy(mWindow.getDisplayFrameLw(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
+        assertInsetBy(mWindow.getDisplayFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
     }
 
     @Test
@@ -676,12 +676,12 @@
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
         assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
-        assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, 0,
+        assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, 0,
                 NAV_BAR_HEIGHT);
-        assertInsetBy(mWindow.getContentFrameLw(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0,
+        assertInsetBy(mWindow.getContentFrame(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0,
                 NAV_BAR_HEIGHT);
         assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
-        assertInsetBy(mWindow.getDisplayFrameLw(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
+        assertInsetBy(mWindow.getDisplayFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
     }
 
     @Test
@@ -698,11 +698,11 @@
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
         assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
-        assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
-        assertInsetBy(mWindow.getContentFrameLw(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0,
+        assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
+        assertInsetBy(mWindow.getContentFrame(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0,
                 NAV_BAR_HEIGHT);
         assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
-        assertInsetBy(mWindow.getDisplayFrameLw(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
+        assertInsetBy(mWindow.getDisplayFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
     }
 
     @Test
@@ -719,11 +719,11 @@
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
         assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
-        assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
-        assertInsetBy(mWindow.getContentFrameLw(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0,
+        assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
+        assertInsetBy(mWindow.getContentFrame(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0,
                 NAV_BAR_HEIGHT);
         assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
-        assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
+        assertInsetBy(mWindow.getDisplayFrame(), 0, 0, 0, 0);
     }
 
     @Test
@@ -740,11 +740,11 @@
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
         assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
-        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-        assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
         assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
-        assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
+        assertInsetBy(mWindow.getDisplayFrame(), 0, 0, 0, 0);
     }
 
     @Test
@@ -904,34 +904,34 @@
         updateDecorWindow(decorWindow, MATCH_PARENT, DECOR_WINDOW_INSET, TOP);
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-        assertInsetByTopBottom(mWindow.getContentFrameLw(), DECOR_WINDOW_INSET, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrame(), DECOR_WINDOW_INSET, NAV_BAR_HEIGHT);
 
         // Decor on bottom
         updateDecorWindow(decorWindow, MATCH_PARENT, DECOR_WINDOW_INSET, BOTTOM);
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT,
+        assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT,
                 DECOR_WINDOW_INSET);
 
         // Decor on the left
         updateDecorWindow(decorWindow, DECOR_WINDOW_INSET, MATCH_PARENT, LEFT);
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-        assertInsetBy(mWindow.getContentFrameLw(), DECOR_WINDOW_INSET, STATUS_BAR_HEIGHT, 0,
+        assertInsetBy(mWindow.getContentFrame(), DECOR_WINDOW_INSET, STATUS_BAR_HEIGHT, 0,
                 NAV_BAR_HEIGHT);
 
         // Decor on the right
         updateDecorWindow(decorWindow, DECOR_WINDOW_INSET, MATCH_PARENT, RIGHT);
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-        assertInsetBy(mWindow.getContentFrameLw(), 0, STATUS_BAR_HEIGHT, DECOR_WINDOW_INSET,
+        assertInsetBy(mWindow.getContentFrame(), 0, STATUS_BAR_HEIGHT, DECOR_WINDOW_INSET,
                 NAV_BAR_HEIGHT);
 
         // Decor not allowed as inset
         updateDecorWindow(decorWindow, DECOR_WINDOW_INSET, DECOR_WINDOW_INSET, TOP);
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
     }
 
     private void updateDecorWindow(WindowState decorWindow, int width, int height, int gravity) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index 4483f8c..b50530e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -297,7 +297,7 @@
 
         final WindowState navigationBar = createNavigationBarWindow();
 
-        navigationBar.getFrameLw().set(new Rect(100, 200, 200, 300));
+        navigationBar.getFrame().set(new Rect(100, 200, 200, 300));
 
         assertFalse("Freeform is overlapping with navigation bar",
                 DisplayPolicy.isOverlappingWithNavBar(targetWin, navigationBar));
@@ -377,7 +377,7 @@
 
         mDisplayContent.setInputMethodWindowLocked(mImeWindow);
         mImeWindow.mAttrs.setFitInsetsSides(Side.all() & ~Side.BOTTOM);
-        mImeWindow.getGivenContentInsetsLw().set(0, displayInfo.logicalHeight, 0, 0);
+        mImeWindow.mGivenContentInsets.set(0, displayInfo.logicalHeight, 0, 0);
         mImeWindow.getControllableInsetProvider().setServerVisible(true);
 
         displayPolicy.beginLayoutLw(mDisplayContent.mDisplayFrames, 0 /* UI mode */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
index 1d6dd0b..a0fa936 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
@@ -61,7 +61,7 @@
     @Test
     public void testPostLayout() {
         final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
-        statusBar.getFrameLw().set(0, 0, 500, 100);
+        statusBar.getFrame().set(0, 0, 500, 100);
         statusBar.mHasSurface = true;
         mProvider.setWindow(statusBar, null, null);
         mProvider.onPostLayout();
@@ -76,9 +76,9 @@
     @Test
     public void testPostLayout_givenInsets() {
         final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
-        ime.getFrameLw().set(0, 0, 500, 100);
-        ime.getGivenContentInsetsLw().set(0, 0, 0, 60);
-        ime.getGivenVisibleInsetsLw().set(0, 0, 0, 75);
+        ime.getFrame().set(0, 0, 500, 100);
+        ime.mGivenContentInsets.set(0, 0, 0, 60);
+        ime.mGivenVisibleInsets.set(0, 0, 0, 75);
         ime.mHasSurface = true;
         mProvider.setWindow(ime, null, null);
         mProvider.onPostLayout();
@@ -94,7 +94,7 @@
     @Test
     public void testPostLayout_invisible() {
         final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
-        statusBar.getFrameLw().set(0, 0, 500, 100);
+        statusBar.getFrame().set(0, 0, 500, 100);
         mProvider.setWindow(statusBar, null, null);
         mProvider.onPostLayout();
         assertEquals(Insets.NONE, mProvider.getSource().calculateInsets(new Rect(0, 0, 500, 500),
@@ -104,7 +104,7 @@
     @Test
     public void testPostLayout_frameProvider() {
         final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
-        statusBar.getFrameLw().set(0, 0, 500, 100);
+        statusBar.getFrame().set(0, 0, 500, 100);
         statusBar.mHasSurface = true;
         mProvider.setWindow(statusBar,
                 (displayFrames, windowState, rect) -> {
@@ -118,7 +118,7 @@
     public void testUpdateControlForTarget() {
         final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
         final WindowState target = createWindow(null, TYPE_APPLICATION, "target");
-        statusBar.getFrameLw().set(0, 0, 500, 100);
+        statusBar.getFrame().set(0, 0, 500, 100);
 
         // We must not have control or control target before we have the insets source window.
         mProvider.updateControlForTarget(target, true /* force */);
@@ -163,7 +163,7 @@
     public void testUpdateControlForFakeTarget() {
         final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
         final WindowState target = createWindow(null, TYPE_APPLICATION, "target");
-        statusBar.getFrameLw().set(0, 0, 500, 100);
+        statusBar.getFrame().set(0, 0, 500, 100);
         mProvider.setWindow(statusBar, null, null);
         mProvider.updateControlForFakeTarget(target);
         assertNotNull(mProvider.getControl(target));
@@ -176,7 +176,7 @@
     public void testUpdateSourceFrameForIme() {
         final WindowState inputMethod = createWindow(null, TYPE_INPUT_METHOD, "inputMethod");
 
-        inputMethod.getFrameLw().set(new Rect(0, 400, 500, 500));
+        inputMethod.getFrame().set(new Rect(0, 400, 500, 500));
 
         mImeProvider.setWindow(inputMethod, null, null);
         mImeProvider.setServerVisible(false);
@@ -190,7 +190,7 @@
         mImeProvider.setServerVisible(true);
         mImeSource.setVisible(true);
         mImeProvider.updateSourceFrame();
-        assertEquals(inputMethod.getFrameLw(), mImeSource.getFrame());
+        assertEquals(inputMethod.getFrame(), mImeSource.getFrame());
         insets = mImeSource.calculateInsets(new Rect(0, 0, 500, 500),
                 false /* ignoreVisibility */);
         assertEquals(Insets.of(0, 0, 0, 100), insets);
@@ -200,7 +200,7 @@
     public void testInsetsModified() {
         final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
         final WindowState target = createWindow(null, TYPE_APPLICATION, "target");
-        statusBar.getFrameLw().set(0, 0, 500, 100);
+        statusBar.getFrame().set(0, 0, 500, 100);
         mProvider.setWindow(statusBar, null, null);
         mProvider.updateControlForTarget(target, false /* force */);
         InsetsState state = new InsetsState();
@@ -213,7 +213,7 @@
     public void testInsetsModified_noControl() {
         final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
         final WindowState target = createWindow(null, TYPE_APPLICATION, "target");
-        statusBar.getFrameLw().set(0, 0, 500, 100);
+        statusBar.getFrame().set(0, 0, 500, 100);
         mProvider.setWindow(statusBar, null, null);
         InsetsState state = new InsetsState();
         state.getSource(ITYPE_STATUS_BAR).setVisible(false);
@@ -224,7 +224,7 @@
     @Test
     public void testInsetGeometries() {
         final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
-        statusBar.getFrameLw().set(0, 0, 500, 100);
+        statusBar.getFrame().set(0, 0, 500, 100);
         statusBar.mHasSurface = true;
         mProvider.setWindow(statusBar, null, null);
         mProvider.onPostLayout();
@@ -236,7 +236,7 @@
                         false /* ignoreVisibility */));
 
         // Don't apply left insets if window is left-of inset-window but still overlaps
-        statusBar.getFrameLw().set(100, 0, 0, 0);
+        statusBar.getFrame().set(100, 0, 0, 0);
         assertEquals(Insets.of(0, 0, 0, 0),
                 mProvider.getSource().calculateInsets(new Rect(-100, 0, 400, 500),
                         false /* ignoreVisibility */));
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 4a8e8da..dc85904 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -86,11 +86,6 @@
     }
 
     @Override
-    public int getMaxWallpaperLayer() {
-        return 0;
-    }
-
-    @Override
     public boolean isKeyguardHostWindow(WindowManager.LayoutParams attrs) {
         return attrs.type == TYPE_NOTIFICATION_SHADE;
     }
@@ -377,11 +372,6 @@
     }
 
     @Override
-    public boolean isTopLevelWindow(int windowType) {
-        return false;
-    }
-
-    @Override
     public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) {
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index ed9e270..63367ac 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -133,8 +133,8 @@
         int expectedWidth = (int) (wallpaperWidth * (displayHeight / (double) wallpaperHeight));
 
         // Check that the wallpaper is correctly scaled
-        assertEquals(new Rect(0, 0, expectedWidth, displayHeight), wallpaperWindow.getFrameLw());
-        Rect portraitFrame = wallpaperWindow.getFrameLw();
+        assertEquals(new Rect(0, 0, expectedWidth, displayHeight), wallpaperWindow.getFrame());
+        Rect portraitFrame = wallpaperWindow.getFrame();
 
         // Rotate the display
         dc.getDisplayRotation().updateOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, true);
@@ -149,7 +149,7 @@
 
         // Check that the wallpaper has the same frame in landscape than in portrait
         assertEquals(Configuration.ORIENTATION_LANDSCAPE, dc.getConfiguration().orientation);
-        assertEquals(portraitFrame, wallpaperWindow.getFrameLw());
+        assertEquals(portraitFrame, wallpaperWindow.getFrame());
     }
 
     @Test
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 eb2aa41..ca3626d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
@@ -89,29 +89,29 @@
     }
 
     private void assertFrame(WindowState w, Rect frame) {
-        assertEquals(w.getFrameLw(), frame);
+        assertEquals(w.getFrame(), frame);
     }
 
     private void assertFrame(WindowState w, int left, int top, int right, int bottom) {
-        assertRect(w.getFrameLw(), left, top, right, bottom);
+        assertRect(w.getFrame(), left, top, right, bottom);
     }
 
     private void assertRelFrame(WindowState w, int left, int top, int right, int bottom) {
-        assertRect(w.getRelativeFrameLw(), left, top, right, bottom);
+        assertRect(w.getRelativeFrame(), left, top, right, bottom);
     }
 
     private void assertContentFrame(WindowState w, Rect expectedRect) {
-        assertRect(w.getContentFrameLw(), expectedRect.left, expectedRect.top, expectedRect.right,
+        assertRect(w.getContentFrame(), expectedRect.left, expectedRect.top, expectedRect.right,
                 expectedRect.bottom);
     }
 
     private void assertVisibleFrame(WindowState w, Rect expectedRect) {
-        assertRect(w.getVisibleFrameLw(), expectedRect.left, expectedRect.top, expectedRect.right,
+        assertRect(w.getVisibleFrame(), expectedRect.left, expectedRect.top, expectedRect.right,
                 expectedRect.bottom);
     }
 
     private void assertStableFrame(WindowState w, Rect expectedRect) {
-        assertRect(w.getStableFrameLw(), expectedRect.left, expectedRect.top, expectedRect.right,
+        assertRect(w.getStableFrame(), expectedRect.left, expectedRect.top, expectedRect.right,
                 expectedRect.bottom);
     }
 
@@ -155,7 +155,7 @@
         // the difference between mFrame and ContentFrame. Visible
         // and stable frames work the same way.
         w.getWindowFrames().setFrames(pf, df, cf, vf, dcf, sf);
-        w.computeFrameLw();
+        w.computeFrame();
         assertFrame(w, 0, 0, 1000, 1000);
         assertRelFrame(w, 0, 0, 1000, 1000);
         assertContentInset(w, 0, topContentInset, 0, bottomContentInset);
@@ -170,14 +170,14 @@
         w.mAttrs.width = 100; w.mAttrs.height = 100; //have to clear MATCH_PARENT
         w.mRequestedWidth = 100;
         w.mRequestedHeight = 100;
-        w.computeFrameLw();
+        w.computeFrame();
         assertFrame(w, 100, 100, 200, 200);
         assertRelFrame(w, 100, 100, 200, 200);
         assertContentInset(w, 0, 0, 0, 0);
         // In this case the frames are shrunk to the window frame.
-        assertContentFrame(w, w.getFrameLw());
-        assertVisibleFrame(w, w.getFrameLw());
-        assertStableFrame(w, w.getFrameLw());
+        assertContentFrame(w, w.getFrame());
+        assertVisibleFrame(w, w.getFrame());
+        assertStableFrame(w, w.getFrame());
     }
 
     @Test
@@ -193,7 +193,7 @@
         // Here the window has FILL_PARENT, FILL_PARENT
         // so we expect it to fill the entire available frame.
         w.getWindowFrames().setFrames(pf, pf, pf, pf, pf, pf);
-        w.computeFrameLw();
+        w.computeFrame();
         assertFrame(w, 0, 0, 1000, 1000);
         assertRelFrame(w, 0, 0, 1000, 1000);
 
@@ -202,14 +202,14 @@
         // and we use mRequestedWidth/mRequestedHeight
         w.mAttrs.width = 300;
         w.mAttrs.height = 300;
-        w.computeFrameLw();
+        w.computeFrame();
         // Explicit width and height without requested width/height
         // gets us nothing.
         assertFrame(w, 0, 0, 0, 0);
 
         w.mRequestedWidth = 300;
         w.mRequestedHeight = 300;
-        w.computeFrameLw();
+        w.computeFrame();
         // With requestedWidth/Height we can freely choose our size within the
         // parent bounds.
         assertFrame(w, 0, 0, 300, 300);
@@ -222,14 +222,14 @@
         w.mRequestedWidth = -1;
         w.mAttrs.width = 100;
         w.mAttrs.height = 100;
-        w.computeFrameLw();
+        w.computeFrame();
         assertFrame(w, 0, 0, 100, 100);
         w.mAttrs.flags = 0;
 
         // But sizes too large will be clipped to the containing frame
         w.mRequestedWidth = 1200;
         w.mRequestedHeight = 1200;
-        w.computeFrameLw();
+        w.computeFrame();
         assertFrame(w, 0, 0, 1000, 1000);
 
         // Before they are clipped though windows will be shifted
@@ -237,7 +237,7 @@
         w.mAttrs.y = 300;
         w.mRequestedWidth = 1000;
         w.mRequestedHeight = 1000;
-        w.computeFrameLw();
+        w.computeFrame();
         assertFrame(w, 0, 0, 1000, 1000);
 
         // If there is room to move around in the parent frame the window will be shifted according
@@ -247,18 +247,18 @@
         w.mRequestedWidth = 300;
         w.mRequestedHeight = 300;
         w.mAttrs.gravity = Gravity.RIGHT | Gravity.TOP;
-        w.computeFrameLw();
+        w.computeFrame();
         assertFrame(w, 700, 0, 1000, 300);
         assertRelFrame(w, 700, 0, 1000, 300);
         w.mAttrs.gravity = Gravity.RIGHT | Gravity.BOTTOM;
-        w.computeFrameLw();
+        w.computeFrame();
         assertFrame(w, 700, 700, 1000, 1000);
         assertRelFrame(w, 700, 700, 1000, 1000);
         // Window specified  x and y are interpreted as offsets in the opposite
         // direction of gravity
         w.mAttrs.x = 100;
         w.mAttrs.y = 100;
-        w.computeFrameLw();
+        w.computeFrame();
         assertFrame(w, 600, 600, 900, 900);
         assertRelFrame(w, 600, 600, 900, 900);
     }
@@ -285,12 +285,12 @@
         final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
         final WindowFrames windowFrames = w.getWindowFrames();
         windowFrames.setFrames(pf, pf, pf, pf, pf, pf);
-        w.computeFrameLw();
+        w.computeFrame();
         // For non fullscreen tasks the containing frame is based off the
         // task bounds not the parent frame.
-        assertEquals(resolvedTaskBounds, w.getFrameLw());
-        assertEquals(0, w.getRelativeFrameLw().left);
-        assertEquals(0, w.getRelativeFrameLw().top);
+        assertEquals(resolvedTaskBounds, w.getFrame());
+        assertEquals(0, w.getRelativeFrame().left);
+        assertEquals(0, w.getRelativeFrame().top);
         assertContentFrame(w, resolvedTaskBounds);
         assertContentInset(w, 0, 0, 0, 0);
 
@@ -300,10 +300,10 @@
         final int cfBottom = logicalHeight / 2;
         final Rect cf = new Rect(0, 0, cfRight, cfBottom);
         windowFrames.setFrames(pf, pf, cf, cf, pf, cf);
-        w.computeFrameLw();
-        assertEquals(resolvedTaskBounds, w.getFrameLw());
-        assertEquals(0, w.getRelativeFrameLw().left);
-        assertEquals(0, w.getRelativeFrameLw().top);
+        w.computeFrame();
+        assertEquals(resolvedTaskBounds, w.getFrame());
+        assertEquals(0, w.getRelativeFrame().left);
+        assertEquals(0, w.getRelativeFrame().top);
         int contentInsetRight = resolvedTaskBounds.right - cfRight;
         int contentInsetBottom = resolvedTaskBounds.bottom - cfBottom;
         assertContentInset(w, 0, 0, contentInsetRight, contentInsetBottom);
@@ -334,12 +334,12 @@
 
         final WindowFrames windowFrames = w.getWindowFrames();
         windowFrames.setFrames(pf, df, cf, vf, dcf, sf);
-        w.computeFrameLw();
+        w.computeFrame();
         assertPolicyCrop(w, 0, cf.top, logicalWidth, cf.bottom);
 
         windowFrames.mDecorFrame.setEmpty();
         // Likewise with no decor frame we would get no crop
-        w.computeFrameLw();
+        w.computeFrame();
         assertPolicyCrop(w, 0, 0, logicalWidth, logicalHeight);
 
         // Now we set up a window which doesn't fill the entire decor frame.
@@ -353,7 +353,7 @@
         w.mAttrs.height = logicalHeight / 2;
         w.mRequestedWidth = logicalWidth / 2;
         w.mRequestedHeight = logicalHeight / 2;
-        w.computeFrameLw();
+        w.computeFrame();
 
         // Normally the crop is shrunk from the decor frame
         // to the computed window frame.
@@ -390,7 +390,7 @@
         final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
         final WindowFrames windowFrames = w.getWindowFrames();
         windowFrames.setFrames(pf, pf, pf, pf, pf, pf);
-        w.computeFrameLw();
+        w.computeFrame();
         // For non fullscreen tasks the containing frame is based off the
         // task bounds not the parent frame.
         assertFrame(w, taskLeft, taskTop, taskRight, taskBottom);
@@ -408,7 +408,7 @@
         task.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
         task.setBounds(null);
         windowFrames.setFrames(pf, pf, cf, cf, pf, cf);
-        w.computeFrameLw();
+        w.computeFrame();
         assertFrame(w, cf);
         assertContentFrame(w, cf);
         assertContentInset(w, 0, 0, 0, 0);
@@ -430,7 +430,7 @@
         final WindowFrames windowFrames = w.getWindowFrames();
         windowFrames.setFrames(pf, pf, pf, pf, pf, pf);
         windowFrames.setDisplayCutout(cutout);
-        w.computeFrameLw();
+        w.computeFrame();
 
         assertEquals(w.getWmDisplayCutout().getDisplayCutout().getSafeInsetTop(), 50);
         assertEquals(w.getWmDisplayCutout().getDisplayCutout().getSafeInsetBottom(), 0);
@@ -469,20 +469,20 @@
 
         task.setBounds(winRect);
         w.getWindowFrames().setFrames(pf, df, cf, vf, dcf, sf);
-        w.computeFrameLw();
+        w.computeFrame();
 
         final Rect expected = new Rect(winRect.left, cf.bottom - winRect.height(),
                 winRect.right, cf.bottom);
-        assertEquals(expected, w.getFrameLw());
-        assertEquals(expected, w.getContentFrameLw());
-        assertEquals(expected, w.getVisibleFrameLw());
+        assertEquals(expected, w.getFrame());
+        assertEquals(expected, w.getContentFrame());
+        assertEquals(expected, w.getVisibleFrame());
 
         // Now check that it won't get moved beyond the top and then has appropriate insets
         winRect.bottom = 600;
         task.setBounds(winRect);
         w.setBounds(winRect);
         w.getWindowFrames().setFrames(pf, df, cf, vf, dcf, sf);
-        w.computeFrameLw();
+        w.computeFrame();
 
         assertFrame(w, winRect.left, 0, winRect.right, winRect.height());
         expected.top = 0;
@@ -492,8 +492,8 @@
 
         // Check that it's moved back without ime insets
         w.getWindowFrames().setFrames(pf, df, pf, pf, dcf, sf);
-        w.computeFrameLw();
-        assertEquals(winRect, w.getFrameLw());
+        w.computeFrame();
+        assertEquals(winRect, w.getFrame());
     }
 
     private WindowState createWindow() {
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 f095fd4..9603d28 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -479,7 +479,7 @@
         app.mHasSurface = true;
         app.mSurfaceControl = mock(SurfaceControl.class);
         try {
-            app.getFrameLw().set(10, 20, 60, 80);
+            app.getFrame().set(10, 20, 60, 80);
             app.updateSurfacePosition(t);
 
             app.seamlesslyRotateIfAllowed(t, ROTATION_0, ROTATION_90, true);
@@ -519,7 +519,7 @@
                 new Rect(95, 378, 105, 400));
         wf.setDisplayCutout(new WmDisplayCutout(cutout, new Size(200, 400)));
 
-        app.computeFrameLw();
+        app.computeFrame();
         assertThat(app.getWmDisplayCutout().getDisplayCutout(), is(cutout.inset(7, 10, 5, 20)));
     }
 
@@ -633,7 +633,7 @@
         final WindowState win0 = createWindow(null, TYPE_APPLICATION, "win0");
 
         final DisplayContent dc = createNewDisplay();
-        win0.getFrameLw().offsetTo(PARENT_WINDOW_OFFSET, 0);
+        win0.getFrame().offsetTo(PARENT_WINDOW_OFFSET, 0);
         dc.reparentDisplayContent(win0, win0.getSurfaceControl());
         dc.updateLocation(win0, DISPLAY_IN_PARENT_WINDOW_OFFSET, 0);
 
@@ -644,7 +644,7 @@
         win1.mHasSurface = true;
         win1.mSurfaceControl = mock(SurfaceControl.class);
         win1.mAttrs.surfaceInsets.set(1, 2, 3, 4);
-        win1.getFrameLw().offsetTo(WINDOW_OFFSET, 0);
+        win1.getFrame().offsetTo(WINDOW_OFFSET, 0);
         win1.updateSurfacePosition(t);
         win1.getTransformationMatrix(values, matrix);
 
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 f86d8f1..38c4e0a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -1131,7 +1131,7 @@
         }
 
         @Override
-        public boolean isGoneForLayoutLw() {
+        public boolean isGoneForLayout() {
             return false;
         }